Commit be3df2e3 authored by Sebastien Robin's avatar Sebastien Robin

added one way synchronization


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@1860 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent ea38db70
......@@ -97,7 +97,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
"""
return the string corresponding to the local encoding
"""
return "iso-8859-1"
#return "iso-8859-1"
return "utf-8"
security.declareProtected(Permissions.ModifyPortalContent, '__init__')
def __init__(self):
......
......@@ -47,6 +47,8 @@ class ERP5ShopOrderConduit(ERP5Conduit):
"""
This conduit is used in the synchronisation process of Storever and ERP5 to convert
a Storever Shop Order to a ERP5 Sale Order.
Don't forget to add this base categories in portal_category :
'hd_size', 'memory_size', 'optical_drive', 'keyboad_layout', 'cpu_type'
"""
......@@ -72,17 +74,17 @@ class ERP5ShopOrderConduit(ERP5Conduit):
if portal_type == 'Shop Order':
# The random part of the id can be removed. It's only used for the developpement
new_object_id = 'storever-' + object_id + '-' + str(random.randint(1000, 9999))
object.newContent ( portal_type = 'Sale Order'
, id = new_object_id)
subobject = object.newContent( portal_type = 'Sale Order'
, id = new_object_id)
if portal_type == 'Order Line':
last_line_num = self.getLastOrderLineNumber(object)
new_object_id = "storever-" + str(last_line_num + 1) + "-" + object_id
object.newContent ( portal_type = 'Sale Order Line'
, id = new_object_id)
subobject = object._getOb(new_object_id)
subobject = object.newContent( portal_type = 'Sale Order Line'
, id = new_object_id)
return subobject
# # Not needed yet
# security.declareProtected(Permissions.ModifyPortalContent, 'addWorkflowNode')
# def addWorkflowNode(self, object, xml, simulate):
......@@ -178,9 +180,8 @@ class ERP5ShopOrderConduit(ERP5Conduit):
if product_id == erp5_product_id:
return erp5_site.restrictedTraverse(erp5_site_path + '/product/' + erp5_product_id)
# We have to create a new product
product_folder.newContent ( portal_type = 'Product'
, id = erp5_product_id)
return product_folder._getOb(erp5_product_id)
return product_folder.newContent( portal_type = 'Product'
, id = erp5_product_id)
......@@ -190,18 +191,25 @@ class ERP5ShopOrderConduit(ERP5Conduit):
This function set the validation workflow to indicate if a product
is discontinued (workflow state = invalidate) or not (workflow state = validate)
"""
#!!!!!!!!!!!!!!!!!!!!!!!!!!
# return
#!!!!!!!!!!!!!!!!!!!!!!!!!!
action = None
if hasattr(product_object, 'workflow_history'):
LOG('Info needed from portal_workflow >>>>>>>>> ', 0, '')
workflow_state = product_object.portal_workflow.getInfoFor(product_object, 'validation_state')
LOG('workflow_state is >>>>>>>>> ', 0, repr(workflow_state))
if product_title.lower().find('discontinued') != -1:
if workflow_state != 'invalidated':
action = 'invalidate_action'
elif workflow_state in ('draft', 'invalidated'):
action = 'validate_action'
LOG('action is >>>>>>>>> ', 0, repr(action))
if action != None:
product_object.portal_workflow.doActionFor( product_object
, action
, wf_id = 'validation_workflow')
LOG('end of workflow action >>>>>>>>> ', 0, repr(action))
......@@ -248,6 +256,43 @@ class ERP5ShopOrderConduit(ERP5Conduit):
security.declarePrivate('updateObjProperty')
def updateObjProperty(self, object, property, kw, key):
"""
This function update the property of an object with a given value stored in a dictionnary. This function help the Conduit to make decision about the synchronisation of values.
Example of call : self.updateObjProperty(person_object, 'DefaultAddressStreetAddress', kw, 'address')
Solution (d'apres seb) :
* machin = getattr (object, methos)
* machin()
"""
if kw.has_key(key):
new_value = kw[key]
if new_value != None:
if type(new_value) is type('s'):
new_value = new_value.title()
current_value = eval('object.get' + property + '()')
LOG("I have to run this >>>>>>>> ", 0, 'object.get' + property + '()')
LOG("current_value >>>>>>>> ", 0, repr(current_value))
# The current property value is not consistent
if current_value == None or len(current_value) == 0:
# Erase the current value with the new one
LOG("I have to run this to set the property >>>>>>>> " + 'object.set' + str(property) + '(' + str(new_value) + ')' + str(current_value), 0, '')
# A previous consistent value exist
elif current_value.strip().lower() != new_value.strip().lower():
# TODO : We need to choose if we replace it or not, or mix the current with the new one
LOG('We have to make the fusion of previous address with the current one >>>>>>>', 0, '')
return False
return True
return False
security.declareProtected(Permissions.ModifyPortalContent, 'editDocument')
def editDocument(self, object=None, **kw):
"""
......@@ -258,6 +303,10 @@ class ERP5ShopOrderConduit(ERP5Conduit):
LOG('KW >>>>>>>> ', 0, kw)
# This list contain a list of object to check to know if their workflow need to be mofified
# We store these objects into a list and we will apply modification at the end to avoid mysql lock problem
workflow_joblist = []
# Get the ERP5 root object
portal_types = getToolByName(object, 'portal_types')
erp5_site = portal_types.getPortalObject()
......@@ -265,12 +314,11 @@ class ERP5ShopOrderConduit(ERP5Conduit):
# The object is a ShopOrder
if kw.has_key('country'):
# Find the organisation and the person folder
person_path = erp5_site_path + '/person'
person_folder = erp5_site.restrictedTraverse(person_path)
organisation_path = erp5_site_path + '/organisation'
organisation_folder = erp5_site.restrictedTraverse(organisation_path)
org_folder = erp5_site.restrictedTraverse(organisation_path)
# Find the service folder
service_path = erp5_site_path + '/service'
service_folder = erp5_site.restrictedTraverse(service_path)
......@@ -284,23 +332,23 @@ class ERP5ShopOrderConduit(ERP5Conduit):
# Try to find the identity created for a previous ShopOrder of the same Storever member account
person_object = None
organisation_object = None
org_object = None
for person_id in person_folder.objectIds():
if person_id == owner_id:
person_object = erp5_site.restrictedTraverse(erp5_site_path + '/person/' + person_id)
LOG("Previous person found ! >>>>>>>>",0,repr(person_object))
break
for organisation_id in organisation_folder.objectIds():
for organisation_id in org_folder.objectIds():
if organisation_id == owner_id:
organisation_object = erp5_site.restrictedTraverse(erp5_site_path + '/organisation/' + organisation_id)
LOG("Previous organisation found ! >>>>>>>>",0,repr(organisation_object))
org_object = erp5_site.restrictedTraverse(erp5_site_path + '/organisation/' + organisation_id)
LOG("Previous organisation found ! >>>>>>>>",0,repr(org_object))
break
# Define the previous customer structure
previous_owner_type = ''
if person_object != None:
previous_owner_type += 'p'
if organisation_object != None:
if org_object != None:
previous_owner_type += 'o'
if len(previous_owner_type) == 0:
previous_owner_type = None
......@@ -324,27 +372,25 @@ class ERP5ShopOrderConduit(ERP5Conduit):
if previous_owner_type != owner_type:
# There is difference between the two (previous and current) representation of the customer
# We have to manage the differences to create a unique customer representation
LOG("There is difference between previous and current >>>>>>>>",0,None)
LOG("There is difference between previous and current >>>>>>>>",0,'')
if previous_owner_type == None:
# No previous customer found, create one
if owner_type.find('o') != -1:
organisation_folder.newContent ( portal_type = 'Organisation'
, id = owner_id)
organisation_object = organisation_folder._getOb(owner_id)
LOG("new organisation created >>>>>>>>",0,repr(organisation_object))
org_object = org_folder.newContent( portal_type = 'Organisation'
, id = owner_id)
LOG("new organisation created >>>>>>>>",0,repr(org_object))
if owner_type.find('p') != -1:
person_folder.newContent ( portal_type = 'Person'
, id = owner_id)
person_object = person_folder._getOb(owner_id)
person_object = person_folder.newContent( portal_type = 'Person'
, id = owner_id)
LOG("new person created >>>>>>>>",0,repr(person_object))
else:
if owner_type == None:
# Use the previous Structure
owner_type = previous_owner_type
LOG("Use the previous Structure >>>>>>>>",0,None)
LOG("Use the previous Structure >>>>>>>>",0,'')
else:
LOG("We have to convert the structure >>>>>>>>",0,None)
# # XXX Be aware of that problem: the invoice for a sale order must be the same
LOG("We have to convert the structure >>>>>>>>",0,'')
# # XXX Be aware of that problem: the invoice for a sale order must look the same (I mean when we generate the pdf version)
# Case to process :
# previous current
# o --> p
......@@ -364,9 +410,8 @@ class ERP5ShopOrderConduit(ERP5Conduit):
if owner_type.find('p') != -1 and owner_type.find('o') != -1:
# Create a new organisation
# # TODO : factorise this code with the same above
organisation_folder.newContent ( portal_type = 'Organisation'
, id = owner_id)
organisation_object = organisation_folder._getOb(owner_id)
org_object = org_folder.newContent( portal_type = 'Organisation'
, id = owner_id)
else:
# # TODO : Transform a person to an organisation ? Is it a good idea ?
pass
......@@ -390,19 +435,18 @@ class ERP5ShopOrderConduit(ERP5Conduit):
# a person and there is no previous record
# By default, we consider the customer as a person, so we have to force to create one
owner_type = 'p'
person_folder.newContent ( portal_type = 'Person'
, id = owner_id)
person_object = person_folder._getOb(owner_id)
person_object = person_folder.newContent( portal_type = 'Person'
, id = owner_id)
LOG("Create a person by default >>>>>>>>",0,repr(person_object))
else:
# The structure is the same
# We only need to be aware of data fusion between the previous and the current representation
# So we don't need to do something because the information fusion process take place below
LOG("The structure is the same. don't do anything >>>>>>>>",0,None)
LOG("The structure is the same. don't do anything >>>>>>>>",0,'')
pass
LOG("Person object >>>>>>>>",0,repr(person_object))
LOG("Organisation object >>>>>>>>",0,repr(organisation_object))
LOG("Organisation object >>>>>>>>",0,repr(org_object))
# Copy informations related to the customer in the ERP5 representation of the customer
# Be carefull because all informations from the storever ShopOrder are optionnals
......@@ -415,12 +459,20 @@ class ERP5ShopOrderConduit(ERP5Conduit):
# # TODO : before doing something working well in every case, copy the previou value in the comment field to traceback the modification and let me evaluate the solidity of my algorithm
# # TODO : perhaps it's possible to factorize the code using a generic function
# Synchronise the street address
if kw.has_key('address'):
previous_address = person_object.getDefaultAddressStreetAddress()
if len(previous_address) == 0:
person_object.setDefaultAddressStreetAddress(kw['address'].title())
elif previous_address.strip().lower() != kw['address'].strip().lower():
LOG('We have to make the fusion of previous address with the current one >>>>>>>', 0, None)
# Solution (d'apres seb)
# machin = getattr (object, methos)
# method(machin)
machin = self.updateObjProperty(person_object, 'DefaultAddressStreetAddress', kw, 'address')
LOG("My new updateObjProperty() return >>>>>>>>",0,repr(machin))
# if kw.has_key('address') and kw['address'] != None:
# previous_address = person_object.getDefaultAddressStreetAddress()
# if len(previous_address) == 0:
# person_object.setDefaultAddressStreetAddress(kw['address'].title())
# elif previous_address.strip().lower() != kw['address'].strip().lower():
# LOG('We have to make the fusion of previous address with the current one >>>>>>>', 0, '')
person_object.setDefaultAddressCity(kw['city'].title())
person_object.setDefaultAddressZipCode(kw['zipcode'])
......@@ -432,8 +484,10 @@ class ERP5ShopOrderConduit(ERP5Conduit):
person_object.setDefaultAddressRegion(region_path)
# else:
# # TODO : Ask the user to select an appropriate region
person_object.setDefaultEmailText(kw['email'])
person_object.setDefaultTelephoneText(kw['phone'])
if kw.has_key('email') and kw['email'] != None:
person_object.setDefaultEmailText(kw['email'])
if kw.has_key('phone') and kw['phone'] != None:
person_object.setDefaultTelephoneText(kw['phone'])
# # TODO : Don't work
# person_object.setDefaultCareerRole("client")
# Split the name to give at least a required LastName
......@@ -450,39 +504,44 @@ class ERP5ShopOrderConduit(ERP5Conduit):
if owner_type.find('o') != -1:
# # TODO : fix this
# person_object.setSubordination("organisation/" + owner_id)
organisation_object.setTitle(kw['organisation'].title())
organisation_object.setCorporateName(kw['organisation'].title())
organisation_object.setRole("client")
if kw.has_key('eu_vat'):
organisation_object.setEuVatCode(kw['eu_vat'])
if kw.has_key('organisation') and kw['organisation'] != None:
org_object.setTitle(kw['organisation'].title())
if kw.has_key('eu_vat') and kw['eu_vat'] != None:
org_object.setEuVatCode(kw['eu_vat'])
# Test for debug
if (not (kw.has_key('organisation')) or (kw.has_key('organisation') and kw['organisation'] != None)) and (not (kw.has_key('eu_vat')) or (kw.has_key('eu_vat') and kw['eu_vat'] != None)):
LOG("AARRGG ! Big conflict detected : this organisation has no title or eu_vat. These properties are primary key to deduced that the storever member account was an organisation >>>>>>>>>>", 0, '')
org_object.setCorporateName(kw['organisation'].title())
org_object.setRole("client")
# The customer is not a person or a person of an organisation, so the customer is an organisation...
else:
# Link the customer with the Sale Order
object.setDestination("organisation/" + owner_id)
object.setDestinationDecision("organisation/" + owner_id)
# All informations describe the organisation
organisation_object.setTitle(kw['organisation'].title())
organisation_object.setCorporateName(kw['organisation'].title())
organisation_object.setRole("client")
organisation_object.setEuVatCode(kw['eu_vat'])
organisation_object.setDefaultAddressStreetAddress(kw['address'].title())
organisation_object.setDefaultAddressCity(kw['city'].title())
organisation_object.setDefaultAddressZipCode(kw['zipcode'])
org_object.setTitle(kw['organisation'].title())
org_object.setCorporateName(kw['organisation'].title())
org_object.setRole("client")
org_object.setEuVatCode(kw['eu_vat'])
org_object.setDefaultAddressStreetAddress(kw['address'].title())
org_object.setDefaultAddressCity(kw['city'].title())
org_object.setDefaultAddressZipCode(kw['zipcode'])
# Search the country in the region category
if kw['country'] != None:
region_path = self.countrySearch(erp5_site, None, kw['country'])
if region_path != None:
organisation_object.setDefaultAddressRegion(region_path)
org_object.setDefaultAddressRegion(region_path)
# else:
# # TODO : Ask the user to select an appropriate region
organisation_object.setDefaultEmailText(kw['email'])
organisation_object.setDefaultTelephoneText(kw['phone'])
org_object.setDefaultEmailText(kw['email'])
org_object.setDefaultTelephoneText(kw['phone'])
# Save the billing address in the description, because there is no dedicated place for it
if kw.has_key('billing_address') and len(kw['billing_address']) > 0:
object.setDescription("Send the bill to : " + kw['billing_address'])
# Set the Title because its required
object.setTitle("Storever Order " + kw['order_id'])
object.setTitle("Storever Order " + str(kw['order_id']))
# # ONLY for information (will be used in the future)
object.setDescription(str(object.getDescription()) + "\n\nTotal Price (with transport fees) :" + str(kw['total_price']))
......@@ -531,9 +590,8 @@ class ERP5ShopOrderConduit(ERP5Conduit):
# Create a new order line in this order to represent the shipment service
ship_order_line_id = "storever-" + shipment_id
object.newContent( portal_type = 'Sale Order Line'
, id = ship_order_line_id)
ship_order_object = object._getOb(ship_order_line_id)
ship_order_object = object.newContent( portal_type = 'Sale Order Line'
, id = ship_order_line_id)
ship_order_object.setQuantity(1.0)
ship_order_object.setPrice(kw['send_fee'])
ship_order_object.setQuantityUnit('Unit')
......@@ -579,15 +637,13 @@ class ERP5ShopOrderConduit(ERP5Conduit):
product_object.setSourceBasePriceValidity(kw['product_expiration_date'])
product_object.setBasePrice(kw['product_price'])
product_object.setQuantityUnit('Unit')
# Set the worflow status
self.setProductWorkflow(product_object, kw['product_title'])
# Save the worflow status for later modification
workflow_joblist.append((product_object, kw['product_title']))
# In storever, every option are set as string in the title of the OrderLine
# This part of code create a list of all options choosen by the customer for this product
splitted_title = kw['title'].strip().split(":")
option_list = (":".join(splitted_title[1:])).split("/")
LOG('Customer option list: ', 0, repr(option_list))
LOG('Customer option list >>>>>> ', 0, repr(option_list))
# Now, we will find the price of each option
option_classes = [ kw['product_disk_price']
......@@ -603,7 +659,7 @@ class ERP5ShopOrderConduit(ERP5Conduit):
if option == option_key.strip():
priced_list[option] = option_class[option_key]
# # TODO : there is no default options in the final priced_list. Is the option 'default' important ?
LOG('Customer option priced list: ', 0, repr(priced_list))
LOG('Customer option priced list >>>>>>>>> ', 0, repr(priced_list))
# In ERP5, we have decided to represent some options as variation of a product
# and some options as new order line of product
......@@ -621,8 +677,8 @@ class ERP5ShopOrderConduit(ERP5Conduit):
keyboard_options[option_key] = options_prices[option_key]
elif option_key.lower().find("cd") != -1 or option_key.lower().find("dvd") != -1:
optical_options[option_key] = options_prices[option_key]
LOG('Product keyboard layout priced list: ', 0, repr(keyboard_options))
LOG('Product optical drive priced list: ', 0, repr(optical_options))
LOG('Product keyboard layout priced list >>>>>>>>> ', 0, repr(keyboard_options))
LOG('Product optical drive priced list >>>>>>>>> ', 0, repr(optical_options))
# Create a data structure containing all allowed variations
variant_category_list = [ ('hd_size', kw['product_disk_price'])
......@@ -644,7 +700,7 @@ class ERP5ShopOrderConduit(ERP5Conduit):
cat_base_object = portal_cat._getOb(cat_base)
cat_base_object.newContent ( portal_type = 'Category'
, id = cat_id)
LOG("New category '", 0, cat_path + "' created")
LOG("New created category >>>>>>>>>>> ", 0, cat_path)
# Set the base variation of the product
product_object.setVariationBaseCategoryList(base_cat_list)
......@@ -661,6 +717,7 @@ class ERP5ShopOrderConduit(ERP5Conduit):
for option in priced_list:
option_is_variant = None
for (cat_base, cat_data) in variant_category_list:
LOG('editDocument, cat_base',0,cat_base)
base_cat_object = portal_cat.resolveCategory(cat_base)
cat_list = base_cat_object.getCategoryChildIdItemList()
for (category, category_bis) in cat_list:
......@@ -675,7 +732,7 @@ class ERP5ShopOrderConduit(ERP5Conduit):
if option_is_variant == None:
customer_product_option_list[option] = priced_list[option]
if len(customer_product_option_list) + len(customer_product_variation_list) != len(priced_list):
LOG('Wrong repartition of the customer priced list', 200)
LOG('>>>>>>> Wrong repartition of the customer priced list', 200)
LOG('>>>>>> Customer product option priced list: ', 0, repr(customer_product_option_list))
LOG('>>>>>> Customer product variation priced list: ', 0, repr(customer_product_variation_list))
LOG('>>>>>> Customer product base variation list: ', 0, repr(customer_product_base_variation_list))
......@@ -700,20 +757,18 @@ class ERP5ShopOrderConduit(ERP5Conduit):
opt_prod_object.setTitle(opt_prod_title.title())
opt_prod_object.setBasePrice(opt_prod_price)
opt_prod_object.setQuantityUnit('Unit')
# Set the workflow state of the optionnal product
self.setProductWorkflow(opt_prod_object, opt_prod_key)
# Save the workflow state changing for later modification
workflow_joblist.append((opt_prod_object, opt_prod_key))
# Get the last number of order lines
# This process is needed to distinguish the same option created for two different product
# and avoid problem when a new Order line is created for a option product already used
# and avoid problem when a new Order line is created for an option product already used
# inside the same Sale Order
last_line_num = self.getLastOrderLineNumber(parent_order_object)
opt_prod_line_id = "storever-" + str(last_line_num) + "-" + opt_prod_key
# Create an order line for the product
parent_order_object.newContent ( portal_type = 'Sale Order Line'
, id = opt_prod_line_id)
opt_order_line_object = parent_order_object._getOb(opt_prod_line_id)
opt_order_line_object = parent_order_object.newContent( portal_type = 'Sale Order Line'
, id = opt_prod_line_id)
# Set several properties of the new orderLine
opt_order_line_object.setQuantityUnit('Unit')
opt_order_line_object.setPrice(opt_prod_price)
......@@ -725,13 +780,6 @@ class ERP5ShopOrderConduit(ERP5Conduit):
# Calcul the sum of option prices
options_price_sum += float(opt_prod_price)
# # TODO: don't forget to manage the VAT values
# TODO: # Try to find a previous OrderLine to update
......@@ -761,4 +809,10 @@ class ERP5ShopOrderConduit(ERP5Conduit):
# # TODO : fix this
# object.setVariationCategoryList(category_list)
return
\ No newline at end of file
# Do all workflow change at the end
LOG("enter workflow loop >>>>>>>>",0,repr(workflow_joblist))
for (object, object_title) in workflow_joblist:
LOG("Workflow to change :: >>>>>>>>",0,repr(object, object_title))
self.setProductWorkflow(object, object_title)
return
......@@ -33,6 +33,7 @@ from Products.ERP5Type import Permissions
from Products.ERP5Type.Document.Folder import Folder
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import PropertySheet
from zLOG import LOG
def addSubscriber( self, id, title='', REQUEST=None ):
"""
......@@ -83,6 +84,16 @@ class Subscriber(Subscription):
Send ACK for a group of documents
"""
def getConduit(self):
"""
Return the conduit of the publication
"""
#LOG('Subscriber.getConduit, self.getPhysicalPath()',0,self.getPhysicalPath())
#LOG('Subscriber.getConduit, self.getParent().getPhysicalPath()',0,self.aq_parent.getPhysicalPath())
#LOG('Subscriber.getConduit, self.getParent()',0,self.getParent())
return self.aq_parent.getConduit()
#return self.conduit
def SendDocuments(self):
"""
We send all the updated documents (ie. documents not marked
......@@ -142,7 +153,7 @@ class Publication(Subscription):
constructors = (addPublication,)
# Constructor
def __init__(self, id, title, publication_url, destination_path, query, xml_mapping, gpg_key):
def __init__(self, id, title, publication_url, destination_path, query, xml_mapping, conduit, gpg_key):
"""
constructor
"""
......@@ -156,6 +167,7 @@ class Publication(Subscription):
self.gpg_key = gpg_key
self.setGidGenerator(None)
self.setIdGenerator(None)
self.setConduit(conduit)
Folder.__init__(self, id)
self.title = title
......
......@@ -342,7 +342,10 @@ class Signature(Folder,SyncCode):
"""
set the XML corresponding to the object
"""
return self.xml
xml = getattr(self,'xml',None)
if xml == '':
xml = None
return xml
def setTempXML(self, xml):
"""
......@@ -610,7 +613,7 @@ class Subscription(Folder, SyncCode):
)
# Constructor
def __init__(self, id, title, publication_url, subscription_url, destination_path, query, xml_mapping, gpg_key):
def __init__(self, id, title, publication_url, subscription_url, destination_path, query, xml_mapping, conduit, gpg_key):
"""
We need to create a dictionnary of
signatures of documents which belong to the synchronisation
......@@ -621,7 +624,7 @@ class Subscription(Folder, SyncCode):
self.subscription_url = str(subscription_url)
self.destination_path = str(destination_path)
self.setQuery(query)
self.xml_mapping = xml_mapping
self.setXMLMapping(xml_mapping)
self.anchor = None
self.session_id = 0
#self.signatures = PersistentMapping()
......@@ -631,6 +634,7 @@ class Subscription(Folder, SyncCode):
self.gpg_key = gpg_key
self.setGidGenerator(None)
self.setIdGenerator(None)
self.setConduit(conduit)
Folder.__init__(self, id)
self.title = title
......@@ -675,6 +679,14 @@ class Subscription(Folder, SyncCode):
LOG('Subscription',0,'getSynchronizationType: %s' % code)
return code
def setXMLMapping(self, value):
"""
this the name of the method used in order to get the xml
"""
if value == '':
value = None
self.xml_mapping = value
def checkCorrectRemoteSessionId(self, session_id):
"""
We will see if the last session id was the same
......@@ -726,6 +738,19 @@ class Subscription(Folder, SyncCode):
"""
self.id = id
def setConduit(self, value):
"""
set the Conduit
"""
self.conduit = value
def getConduit(self):
"""
get the Conduit
"""
return getattr(self,'conduit',None)
def getQuery(self):
"""
return the query
......@@ -748,8 +773,8 @@ class Subscription(Folder, SyncCode):
"""
set the query
"""
if query in (None,''):
query = 'objectValues'
if query == '':
query = None
self.query = query
def getPublicationUrl(self):
......@@ -777,11 +802,17 @@ class Subscription(Folder, SyncCode):
xml_mapping = getattr(self,'xml_mapping','asXML')
return xml_mapping
def setXMLMapping(self, xml_mapping):
def getXMLFromObject(self,object):
"""
return the xml mapping
"""
self.xml_mapping = xml_mapping
xml_mapping = self.getXMLMapping()
xml = ''
if xml_mapping is not None:
func = getattr(object,xml_mapping,None)
if func is not None:
xml = func()
return xml
def setGidGenerator(self, method):
"""
......@@ -843,6 +874,15 @@ class Subscription(Folder, SyncCode):
LOG('getObjectFromGid',0,'returning None')
return None
# def setOneWaySyncFromServer(self,value):
# """
# If this option is enabled, then we will not
# send our own modifications
# """
# self.one_way_sync_from_server = value
#
def getObjectList(self):
"""
This returns the list of sub-object corresponding
......@@ -851,6 +891,8 @@ class Subscription(Folder, SyncCode):
destination = self.getDestination()
query = self.getQuery()
query_list = []
if query is None:
return query_list
if type(query) is type('a'):
query_method = getattr(destination,query,None)
if query_method is not None:
......
......@@ -36,6 +36,7 @@ from Globals import InitializeClass, DTMLFile, PersistentMapping, Persistent
from AccessControl import ClassSecurityInfo, getSecurityManager
from Products.CMFCore import CMFCorePermissions
from Products.ERP5SyncML import _dtmldir
from Products.ERP5SyncML import Conduit
from Publication import Publication,Subscriber
from Products.BTreeFolder2.BTreeFolder2 import BTreeFolder2
from Subscription import Subscription,Signature
......@@ -158,7 +159,7 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
security.declareProtected(Permissions.ModifyPortalContent, 'manage_addPublication')
def manage_addPublication(self, title, publication_url, destination_path,
query, xml_mapping, gpg_key, RESPONSE=None):
query, xml_mapping, conduit, gpg_key, RESPONSE=None):
"""
create a new publication
"""
......@@ -168,7 +169,7 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
folder = self.getObjectContainer()
new_id = self.getPublicationIdFromTitle(title)
pub = Publication(new_id, title, publication_url, destination_path,
query, xml_mapping, gpg_key)
query, xml_mapping, conduit, gpg_key)
folder._setObject( new_id, pub )
#if len(self.list_publications) == 0:
# self.list_publications = PersistentMapping()
......@@ -178,7 +179,7 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
security.declareProtected(Permissions.ModifyPortalContent, 'manage_addSubscription')
def manage_addSubscription(self, title, publication_url, subscription_url,
destination_path, query, xml_mapping, gpg_key, RESPONSE=None):
destination_path, query, xml_mapping, conduit, gpg_key, RESPONSE=None):
"""
XXX should be renamed as addSubscription
create a new subscription
......@@ -189,7 +190,7 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
folder = self.getObjectContainer()
new_id = self.getSubscriptionIdFromTitle(title)
sub = Subscription(new_id, title, publication_url, subscription_url,
destination_path, query, xml_mapping, gpg_key)
destination_path, query, xml_mapping, conduit, gpg_key)
folder._setObject( new_id, sub )
#if len(self.list_subscriptions) == 0:
# self.list_subscriptions = PersistentMapping()
......@@ -199,7 +200,7 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
security.declareProtected(Permissions.ModifyPortalContent, 'manage_editPublication')
def manage_editPublication(self, title, publication_url, destination_path,
query, xml_mapping, gpg_key, RESPONSE=None):
query, xml_mapping, conduit, gpg_key, RESPONSE=None):
"""
modify a publication
"""
......@@ -208,6 +209,7 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
pub.setPublicationUrl(publication_url)
pub.setDestinationPath(destination_path)
pub.setQuery(query)
pub.setConduit(conduit)
pub.setXMLMapping(xml_mapping)
pub.setGPGKey(gpg_key)
if RESPONSE is not None:
......@@ -215,7 +217,7 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
security.declareProtected(Permissions.ModifyPortalContent, 'manage_editSubscription')
def manage_editSubscription(self, title, publication_url, subscription_url,
destination_path, query, xml_mapping, gpg_key, RESPONSE=None):
destination_path, query, xml_mapping, conduit, gpg_key, RESPONSE=None):
"""
modify a subscription
"""
......@@ -224,6 +226,7 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
sub.setPublicationUrl(publication_url)
sub.setDestinationPath(destination_path)
sub.setQuery(query)
sub.setConduit(conduit)
sub.setXMLMapping(xml_mapping)
sub.setGPGKey(gpg_key)
sub.setSubscriptionUrl(subscription_url)
......@@ -370,20 +373,22 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
#conflict.setDomain('Publication')
conflict.setSubscriber(subscriber)
#conflict.setDomainId(subscriber.getId())
conflict_list += [conflict.__of__(self)]
if path is None or conflict.getObjectPath() == path:
conflict_list += [conflict.__of__(subscriber)]
for subscription in self.getSubscriptionList():
sub_conflict_list = subscription.getConflictList()
for conflict in sub_conflict_list:
#conflict.setDomain('Subscription')
conflict.setSubscriber(subscription)
#conflict.setDomainId(subscription.getId())
conflict_list += [conflict.__of__(self)]
if path is not None: # Retrieve only conflicts for a given path
new_list = []
for conflict in conflict_list:
if conflict.getObjectPath() == path:
new_list += [conflict.__of__(self)]
return new_list
if path is None or conflict.getObjectPath() == path:
conflict_list += [conflict.__of__(subscription)]
#if path is not None: # Retrieve only conflicts for a given path
# new_list = []
# for conflict in conflict_list:
# if conflict.getObjectPath() == path:
# new_list += [conflict.__of__(self)]
# return new_list
return conflict_list
security.declareProtected(Permissions.AccessContentsInformation,'getDocumentConflictList')
......@@ -530,7 +535,9 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
object_id = docid
if object_id in directory.objectIds():
directory._delObject(object_id)
conduit = ERP5Conduit()
#conduit = ERP5Conduit()
conduit_name = subscriber.getConduit()
conduit = getattr(getattr(Conduit,conduit_name),conduit_name)()
conduit.addNode(xml=publisher_xml,object=directory,object_id=object_id)
subscriber_document = directory._getOb(object_id)
for c in self.getConflictList(conflict.getObjectPath()):
......@@ -565,7 +572,9 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
publisher_xml = self.getXMLObject(object=publisher_object,xml_mapping = subscriber.getXMLMapping())
directory = publisher_object.aq_inner.aq_parent
object_id = self._getCopyId(publisher_object)
conduit = ERP5Conduit()
#conduit = ERP5Conduit()
conduit_name = subscriber.getConduit()
conduit = getattr(getattr(Conduit,conduit_name),conduit_name)()
conduit.addNode(xml=publisher_xml,object=directory,object_id=object_id)
subscriber_document = directory._getOb(object_id)
subscriber_document._conflict_resolution = 1
......@@ -576,7 +585,6 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
conflict.setCopyPath(copy_path)
return copy_path
security.declareProtected(Permissions.AccessContentsInformation, 'getSubscriberDocument')
def getSubscriberDocument(self, conflict):
"""
......@@ -613,7 +621,9 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
# get the signature:
LOG('p_sync.setRemoteObject, subscriber: ',0,subscriber)
signature = subscriber.getSignature(object.getId()) # XXX may be change for rid
conduit = ERP5Conduit()
#conduit = ERP5Conduit()
conduit_name = subscriber.getConduit()
conduit = getattr(getattr(Conduit,conduit_name),conduit_name)()
for xupdate in conflict.getXupdateList():
conduit.updateNode(xml=xupdate,object=object,force=1)
if solve_conflict:
......@@ -632,7 +642,6 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
directory._delObject(copy_id)
signature.setStatus(self.PUB_CONFLICT_MERGE)
security.declareProtected(Permissions.ModifyPortalContent, 'manageLocalValue')
def managePublisherValue(self, subscription_url, property_id, object_path, RESPONSE=None):
"""
......
......@@ -218,12 +218,13 @@ class XMLSyncUtilsMixin(SyncCode):
"""
xml_method = None
xml = ""
if hasattr(object,xml_mapping):
xml_method = getattr(object,xml_mapping)
elif hasattr(object,'manage_FTPget'):
xml_method = getattr(object,'manage_FTPget')
if xml_method is not None:
xml = xml_method()
if xml_mapping is not None:
if hasattr(object,xml_mapping):
xml_method = getattr(object,xml_mapping)
elif hasattr(object,'manage_FTPget'):
xml_method = getattr(object,'manage_FTPget')
if xml_method is not None:
xml = xml_method()
return xml
def getSessionId(self, xml):
......@@ -601,23 +602,12 @@ class XMLSyncUtilsMixin(SyncCode):
# Here we first check if the object was modified or not by looking at dates
if signature is not None:
signature.checkSynchronizationNeeded(object)
# LOG('getSyncMLData',0,'signature.status: %s' % str(signature.getStatus()))
# LOG('getSyncMLData',0,'signature.action: %s' % str(signature.getAction()))
# last_modification = DateTime(object.ModificationDate())
# LOG('getSyncMLData object.ModificationDate()',0,object.ModificationDate())
# last_synchronization = signature.getLastSynchronizationDate()
# parent = object.aq_parent
# # XXX CPS Specific
# #if parent.id == 'portal_repository':
# if 1:
# if last_synchronization is not None and last_modification is not None:
# if last_synchronization > last_modification:
# LOG('getSyncMLData, no modification on: ',0,object.id)
# signature.setStatus(self.SYNCHRONIZED)
status = self.SENT
more_data=0
# For the case it was never synchronized, we have to send everything
if signature==None or (signature.getXML()==None and signature.getStatus()!=self.PARTIAL) or \
if signature is not None and signature.getXMLMapping()==None:
pass
elif signature==None or (signature.getXML()==None and signature.getStatus()!=self.PARTIAL) or \
self.getAlertCode(remote_xml)==self.SLOW_SYNC:
#LOG('PubSyncModif',0,'Current object.getPath: %s' % object.getPath())
LOG('getSyncMLData',0,'no signature for gid: %s' % object_gid)
......@@ -781,10 +771,10 @@ class XMLSyncUtilsMixin(SyncCode):
LOG('applyActionList',0,'object after add: %s' % repr(object))
if object is not None:
LOG('SyncModif',0,'addNode, found the object')
mapping = getattr(object,domain.getXMLMapping(),None)
xml_object = ''
if mapping is not None:
xml_object = mapping()
#mapping = getattr(object,domain.getXMLMapping(),None)
xml_object = domain.getXMLFromObject(object)
#if mapping is not None:
# xml_object = mapping()
signature.setStatus(self.SYNCHRONIZED)
signature.setId(object.getId())
signature.setXML(xml_object)
......@@ -798,14 +788,14 @@ class XMLSyncUtilsMixin(SyncCode):
signature = subscriber.getSignature(object_gid)
LOG('SyncModif',0,'previous signature: %s' % str(signature))
previous_xml = signature.getXML()
LOG('SyncModif',0,'previous signature: %i' % len(previous_xml))
#LOG('SyncModif',0,'previous signature: %i' % len(previous_xml))
conflict_list += conduit.updateNode(xml=data_subnode, object=object,
previous_xml=signature.getXML(),force=force,
simulate=simulate)
mapping = getattr(object,domain.getXMLMapping(),None)
xml_object = ''
if mapping is not None:
xml_object = mapping()
#mapping = getattr(object,domain.getXMLMapping(),None)
xml_object = domain.getXMLFromObject(object)
#if mapping is not None:
# xml_object = mapping()
signature.setTempXML(xml_object)
if conflict_list != []:
status_code = self.CONFLICT
......@@ -922,7 +912,8 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
Send the server modification, this happens after the Synchronization
initialization
"""
from Products.ERP5SyncML.Conduit.ERP5Conduit import ERP5Conduit
#from Products.ERP5SyncML.Conduit.ERP5Conduit import ERP5Conduit
from Products.ERP5SyncML import Conduit
has_response = 0 #check if syncmodif replies to this messages
cmd_id = 1 # specifies a SyncML message-unique command identifier
LOG('SyncModif',0,'Starting... domain: %s' % str(domain))
......@@ -968,7 +959,9 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
remote_xml=remote_xml)
alert_code = self.getAlertCode(remote_xml)
conduit = ERP5Conduit()
#conduit = ERP5Conduit()
conduit_name = subscriber.getConduit()
conduit = getattr(getattr(Conduit,conduit_name),conduit_name)()
LOG('SyncModif, subscriber: ',0,subscriber)
# Then apply the list of actions
(xml_confirmation,has_next_action,cmd_id) = self.applyActionList(cmd_id=cmd_id,
......
......@@ -87,6 +87,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<input type="text" name="xml_mapping" value="<dtml-var getXMLMapping>" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Conduit
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="conduit" value="<dtml-var getConduit>" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
......
......@@ -97,6 +97,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<input type="text" name="xml_mapping" value="<dtml-var getXMLMapping>" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Conduit
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="conduit" value="<dtml-var getConduit>" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
......
......@@ -83,6 +83,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<input type="text" name="xml_mapping" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Conduit
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="conduit" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
......
......@@ -93,6 +93,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<input type="text" name="xml_mapping" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Conduit
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="conduit" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
......
......@@ -107,7 +107,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
/person_client2 : empty
"""
#return ('sync_crm',)
return ('erp5_core',)
return ()
def getSynchronizationTool(self):
return getattr(self.getPortal(), 'portal_synchronizations', None)
......@@ -124,57 +124,57 @@ class TestERP5SyncML(ERP5TypeTestCase):
def getPortalId(self):
return self.getPortal().getId()
def testHasEverything(self, quiet=0, run=run_all_test):
def test_01_HasEverything(self, quiet=0, run=run_all_test):
# Test if portal_synchronizations was created
if not run: return
if not quiet:
ZopeTestCase._print('\nTest Has Everything ')
LOG('Testing... ',0,'testHasEverything')
LOG('Testing... ',0,'test_01_HasEverything')
self.failUnless(self.getSynchronizationTool()!=None)
#self.failUnless(self.getPersonServer()!=None)
#self.failUnless(self.getPersonClient1()!=None)
#self.failUnless(self.getPersonClient2()!=None)
def testAddPublication(self, quiet=0, run=run_all_test):
def test_02_AddPublication(self, quiet=0, run=run_all_test):
if not run: return
if not quiet:
ZopeTestCase._print('\nTest Add a Publication ')
LOG('Testing... ',0,'testAddPublication')
LOG('Testing... ',0,'test_02_AddPublication')
portal_id = self.getPortalName()
portal_sync = self.getSynchronizationTool()
portal_sync.manage_addPublication(self.pub_id,self.publication_url,
'/%s/person_server' % portal_id,'',
self.xml_mapping,'')
'/%s/person_server' % portal_id,'objectValues',
self.xml_mapping,'ERP5Conduit','')
pub = portal_sync.getPublication(self.pub_id)
self.failUnless(pub is not None)
def testAddSubscription1(self, quiet=0, run=run_all_test):
def test_03_AddSubscription1(self, quiet=0, run=run_all_test):
if not run: return
if not quiet:
ZopeTestCase._print('\nTest Add First Subscription ')
LOG('Testing... ',0,'testAddSubscription1')
LOG('Testing... ',0,'test_03_AddSubscription1')
portal_id = self.getPortalId()
portal_sync = self.getSynchronizationTool()
portal_sync.manage_addSubscription(self.sub_id1,self.publication_url,
self.subscription_url1,'/%s/person_client1' % portal_id,'',
self.xml_mapping,'')
self.subscription_url1,'/%s/person_client1' % portal_id,'objectValues',
self.xml_mapping,'ERP5Conduit','')
sub = portal_sync.getSubscription(self.sub_id1)
self.failUnless(sub is not None)
def testAddSubscription2(self, quiet=0, run=run_all_test):
def test_04_AddSubscription2(self, quiet=0, run=run_all_test):
if not run: return
if not quiet:
ZopeTestCase._print('\nTest Add Second Subscription ')
LOG('Testing... ',0,'testAddSubscription2')
LOG('Testing... ',0,'test_04_AddSubscription2')
portal_id = self.getPortalId()
portal_sync = self.getSynchronizationTool()
portal_sync.manage_addSubscription(self.sub_id2,self.publication_url,
self.subscription_url2,'/%s/person_client2' % portal_id,'',
self.xml_mapping,'')
self.subscription_url2,'/%s/person_client2' % portal_id,'objectValues',
self.xml_mapping,'ERP5Conduit','')
sub = portal_sync.getSubscription(self.sub_id2)
self.failUnless(sub is not None)
def login(self, quiet=0, run=run_all_test):
def login(self, quiet=0):
uf = self.getPortal().acl_users
uf._doAddUser('seb', '', ['Manager'], [])
user = uf.getUserById('seb').__of__(uf)
......@@ -213,12 +213,12 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.failUnless(nb_person==2)
return nb_person
def setupPublicationAndSubscription(self, quiet=0, run=run_all_test):
self.testAddPublication(quiet=1,run=1)
self.testAddSubscription1(quiet=1,run=1)
self.testAddSubscription2(quiet=1,run=1)
def setupPublicationAndSubscription(self, quiet=0, run=1):
self.test_02_AddPublication(quiet=1,run=1)
self.test_03_AddSubscription1(quiet=1,run=1)
self.test_04_AddSubscription2(quiet=1,run=1)
def setupPublicationAndSubscriptionAndGid(self, quiet=0, run=run_all_test):
def setupPublicationAndSubscriptionAndGid(self, quiet=0, run=1):
self.setupPublicationAndSubscription(quiet=1,run=1)
def getGid(object):
return object.getTitle()
......@@ -233,20 +233,20 @@ class TestERP5SyncML(ERP5TypeTestCase):
sub1.setIdGenerator('generateNewId')
sub2.setIdGenerator('generateNewId')
def testGetSynchronizationList(self, quiet=0, run=run_all_test):
def test_05_GetSynchronizationList(self, quiet=0, run=run_all_test):
# This test the getSynchronizationList, ie,
# We want to see if we retrieve both the subscription
# and the publication
if not run: return
if not quiet:
ZopeTestCase._print('\nTest getSynchronizationList ')
LOG('Testing... ',0,'testGetSynchronizationList')
LOG('Testing... ',0,'test_05_GetSynchronizationList')
self.setupPublicationAndSubscription(quiet=1,run=1)
portal_sync = self.getSynchronizationTool()
synchronization_list = portal_sync.getSynchronizationList()
self.failUnless(len(synchronization_list)==self.nb_synchronization)
def testGetObjectList(self, quiet=0, run=run_all_test):
def test_06_GetObjectList(self, quiet=0, run=run_all_test):
"""
This test the default getObjectList, ie, when the
query is 'objectValues', and this also test if we enter
......@@ -255,7 +255,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
if not run: return
if not quiet:
ZopeTestCase._print('\nTest getObjectList ')
LOG('Testing... ',0,'testGetObjectList')
LOG('Testing... ',0,'test_06_GetObjectList')
self.login()
self.setupPublicationAndSubscription(quiet=1,run=1)
nb_person = self.populatePersonServer(quiet=1,run=1)
......@@ -276,7 +276,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
object_list = publication.getObjectList()
self.failUnless(len(object_list)==1)
def testExportImport(self, quiet=0, run=run_all_test):
def test_07_ExportImport(self, quiet=0, run=run_all_test):
"""
We will try to export a person with asXML
And then try to add it to another folder with a conduit
......@@ -284,7 +284,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
if not run: return
if not quiet:
ZopeTestCase._print('\nTest Export and Import ')
LOG('Testing... ',0,'testExportImport')
LOG('Testing... ',0,'test_07_ExportImport')
self.login()
self.populatePersonServer(quiet=1,run=1)
person_server = self.getPersonServer()
......@@ -303,7 +303,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
c_local_role = person_client1.get_local_roles()
self.assertEqual(s_local_role,c_local_role)
def synchronize(self, id, run=run_all_test):
def synchronize(self, id, run=1):
"""
This just define how we synchronize, we have
to define it here because it is specific to the unit testing
......@@ -334,7 +334,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
nb_message += 1 + result['has_response']
return nb_message
def synchronizeWithBrokenMessage(self, id, run=run_all_test):
def synchronizeWithBrokenMessage(self, id, run=1):
"""
This just define how we synchronize, we have
to define it here because it is specific to the unit testing
......@@ -371,13 +371,13 @@ class TestERP5SyncML(ERP5TypeTestCase):
nb_message += 1 + result['has_response']
return nb_message
def testFirstSynchronization(self, quiet=0, run=run_all_test):
def test_08_FirstSynchronization(self, quiet=0, run=run_all_test):
# We will try to populate the folder person_client1
# with the data form person_server
if not run: return
if not quiet:
ZopeTestCase._print('\nTest First Synchronization ')
LOG('Testing... ',0,'testFirstSynchronization')
LOG('Testing... ',0,'test_08_FirstSynchronization')
self.login()
self.setupPublicationAndSubscription(quiet=1,run=1)
nb_person = self.populatePersonServer(quiet=1,run=1)
......@@ -418,13 +418,13 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.failUnless(person2_c.getFirstName()==self.first_name1)
self.failUnless(person2_c.getLastName()==self.last_name1)
def testFirstSynchronizationWithLongLines(self, quiet=0, run=run_all_test):
def test_09_FirstSynchronizationWithLongLines(self, quiet=0, run=run_all_test):
# We will try to populate the folder person_client1
# with the data form person_server
if not run: return
if not quiet:
ZopeTestCase._print('\nTest First Synchronization With Long Lines ')
LOG('Testing... ',0,'testFirstSynchronizationWithLongLines')
LOG('Testing... ',0,'test_09_FirstSynchronizationWithLongLines')
self.login()
self.setupPublicationAndSubscription(quiet=1,run=1)
nb_person = self.populatePersonServer(quiet=1,run=1)
......@@ -448,13 +448,13 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.failUnless(person1_c.getFirstName()==long_line)
self.failUnless(person1_c.getLastName()==self.last_name1)
def testGetObjectFromGid(self, quiet=0, run=run_all_test):
def test_10_GetObjectFromGid(self, quiet=0, run=run_all_test):
# We will try to get an object from a publication
# just by givin the gid
if not run: return
if not quiet:
ZopeTestCase._print('\nTest getObjectFromGid ')
LOG('Testing... ',0,'testGetObjectFromGid')
LOG('Testing... ',0,'test_10_GetObjectFromGid')
self.login()
self.setupPublicationAndSubscription(quiet=1,run=1)
self.populatePersonServer(quiet=1,run=1)
......@@ -465,14 +465,14 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.failUnless(object is not None)
self.failUnless(object.getId()==self.id1)
def testGetSynchronizationState(self, quiet=0, run=run_all_test):
def test_11_GetSynchronizationState(self, quiet=0, run=run_all_test):
# We will try to get the state of objects
# that are just synchronized,
if not run: return
if not quiet:
ZopeTestCase._print('\nTest getSynchronizationState ')
LOG('Testing... ',0,'testGetSynchronizationState')
self.testFirstSynchronization(quiet=1,run=1)
LOG('Testing... ',0,'test_11_GetSynchronizationState')
self.test_08_FirstSynchronization(quiet=1,run=1)
portal_sync = self.getSynchronizationTool()
person_server = self.getPersonServer()
person1_s = person_server._getOb(self.id1)
......@@ -486,7 +486,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
# for each subscriber
self.checkSynchronizationStateIsSynchronized()
def checkSynchronizationStateIsSynchronized(self, quiet=0, run=run_all_test):
def checkSynchronizationStateIsSynchronized(self, quiet=0, run=1):
portal_sync = self.getSynchronizationTool()
person_server = self.getPersonServer()
for person in person_server.objectValues():
......@@ -513,7 +513,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
for m in sub.getSignatureList():
self.assertEquals(m.getPartialXML(),None)
def checkSynchronizationStateIsConflict(self, quiet=0, run=run_all_test):
def checkSynchronizationStateIsConflict(self, quiet=0, run=1):
portal_sync = self.getSynchronizationTool()
person_server = self.getPersonServer()
for person in person_server.objectValues():
......@@ -540,12 +540,12 @@ class TestERP5SyncML(ERP5TypeTestCase):
for state in state_list:
self.failUnless(state[1]==state[0].CONFLICT)
def testUpdateSimpleData(self, quiet=0, run=run_all_test):
def test_12_UpdateSimpleData(self, quiet=0, run=run_all_test):
if not run: return
if not quiet:
ZopeTestCase._print('\nTest Update Simple Data ')
LOG('Testing... ',0,'testUpdateSimpleData')
self.testFirstSynchronization(quiet=1,run=1)
LOG('Testing... ',0,'test_12_UpdateSimpleData')
self.test_08_FirstSynchronization(quiet=1,run=1)
# First we do only modification on server
portal_sync = self.getSynchronizationTool()
person_server = self.getPersonServer()
......@@ -585,14 +585,14 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.failUnless(person1_c.getFirstName()==self.first_name3)
self.failUnless(person1_c.getDescription()==self.description3)
def testGetConflictList(self, quiet=0, run=run_all_test):
def test_13_GetConflictList(self, quiet=0, run=run_all_test):
# We will try to generate a conflict and then to get it
# We will also make sure it contains what we want
if not run: return
if not quiet:
ZopeTestCase._print('\nTest Get Conflict List ')
LOG('Testing... ',0,'testGetConflictList')
self.testFirstSynchronization(quiet=1,run=1)
LOG('Testing... ',0,'test_13_GetConflictList')
self.test_08_FirstSynchronization(quiet=1,run=1)
# First we do only modification on server
portal_sync = self.getSynchronizationTool()
person_server = self.getPersonServer()
......@@ -613,14 +613,14 @@ class TestERP5SyncML(ERP5TypeTestCase):
subscriber = conflict.getSubscriber()
self.failUnless(subscriber.getSubscriptionUrl()==self.subscription_url1)
def testGetPublisherAndSubscriberDocument(self, quiet=0, run=run_all_test):
def test_14_GetPublisherAndSubscriberDocument(self, quiet=0, run=run_all_test):
# We will try to generate a conflict and then to get it
# We will also make sure it contains what we want
if not run: return
if not quiet:
ZopeTestCase._print('\nTest Get Publisher And Subscriber Document ')
LOG('Testing... ',0,'testGetPublisherAndSubscriberDocument')
self.testGetConflictList(quiet=1,run=1)
LOG('Testing... ',0,'test_14_GetPublisherAndSubscriberDocument')
self.test_13_GetConflictList(quiet=1,run=1)
# First we do only modification on server
portal_sync = self.getSynchronizationTool()
person_server = self.getPersonServer()
......@@ -634,14 +634,14 @@ class TestERP5SyncML(ERP5TypeTestCase):
subscriber_document = conflict.getSubscriberDocument()
self.failUnless(subscriber_document.getDescription()==self.description3)
def testApplyPublisherValue(self, quiet=0, run=run_all_test):
def test_15_ApplyPublisherValue(self, quiet=0, run=run_all_test):
# We will try to generate a conflict and then to get it
# We will also make sure it contains what we want
if not run: return
self.testGetConflictList(quiet=1,run=1)
self.test_13_GetConflictList(quiet=1,run=1)
if not quiet:
ZopeTestCase._print('\nTest Apply Publisher Value ')
LOG('Testing... ',0,'testApplyPublisherValue')
LOG('Testing... ',0,'test_15_ApplyPublisherValue')
portal_sync = self.getSynchronizationTool()
conflict_list = portal_sync.getConflictList()
conflict = conflict_list[0]
......@@ -657,16 +657,16 @@ class TestERP5SyncML(ERP5TypeTestCase):
conflict_list = portal_sync.getConflictList()
self.failUnless(len(conflict_list)==0)
def testApplySubscriberValue(self, quiet=0, run=run_all_test):
def test_16_ApplySubscriberValue(self, quiet=0, run=run_all_test):
# We will try to generate a conflict and then to get it
# We will also make sure it contains what we want
if not run: return
self.testGetConflictList(quiet=1,run=1)
self.test_13_GetConflictList(quiet=1,run=1)
portal_sync = self.getSynchronizationTool()
conflict_list = portal_sync.getConflictList()
if not quiet:
ZopeTestCase._print('\nTest Apply Subscriber Value ')
LOG('Testing... ',0,'testApplySubscriberValue')
LOG('Testing... ',0,'test_16_ApplySubscriberValue')
conflict = conflict_list[0]
person_server = self.getPersonServer()
person1_s = person_server._getOb(self.id1)
......@@ -715,17 +715,17 @@ class TestERP5SyncML(ERP5TypeTestCase):
len_path = len(sub_sub_person2.getPhysicalPath()) - 3
self.failUnless(len_path==3)
def testAddSubObject(self, quiet=0, run=run_all_test):
def test_17_AddSubObject(self, quiet=0, run=run_all_test):
"""
In this test, we synchronize, then add sub object on the
server and then see if the next synchronization will also
create sub-objects on the client
"""
if not run: return
self.testFirstSynchronization(quiet=1,run=1)
self.test_08_FirstSynchronization(quiet=1,run=1)
if not quiet:
ZopeTestCase._print('\nTest Add Sub Object ')
LOG('Testing... ',0,'testAddSubObject')
LOG('Testing... ',0,'test_17_AddSubObject')
self.populatePersonServerWithSubObject(quiet=1,run=1)
self.synchronize(self.sub_id1)
self.synchronize(self.sub_id2)
......@@ -747,7 +747,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.failUnless(sub_sub_person2.getFirstName()==self.first_name2)
self.failUnless(sub_sub_person2.getLastName()==self.last_name2)
def testUpdateSubObject(self, quiet=0, run=run_all_test):
def test_18_UpdateSubObject(self, quiet=0, run=run_all_test):
"""
In this test, we start with a tree of object already
synchronized, then we update a subobject, and we will see
......@@ -756,10 +756,10 @@ class TestERP5SyncML(ERP5TypeTestCase):
the client and the server by the same time
"""
if not run: return
self.testAddSubObject(quiet=1,run=1)
self.test_17_AddSubObject(quiet=1,run=1)
if not quiet:
ZopeTestCase._print('\nTest Update Sub Object ')
LOG('Testing... ',0,'testUpdateSubObject')
LOG('Testing... ',0,'test_18_UpdateSubObject')
person_client1 = self.getPersonClient1()
person1_c = person_client1._getOb(self.id1)
sub_person1_c = person1_c._getOb(self.id1)
......@@ -777,17 +777,17 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.failUnless(sub_sub_person_s.getDescription()==self.description3)
self.failUnless(sub_sub_person_s.getFirstName()==self.first_name3)
def testDeleteObject(self, quiet=0, run=run_all_test):
def test_19_DeleteObject(self, quiet=0, run=run_all_test):
"""
We will do a first synchronization, then delete an object on both
sides, and we will see if nothing is left on the server and also
on the two clients
"""
if not run: return
self.testFirstSynchronization(quiet=1,run=1)
self.test_08_FirstSynchronization(quiet=1,run=1)
if not quiet:
ZopeTestCase._print('\nTest Delete Object ')
LOG('Testing... ',0,'testDeleteObject')
LOG('Testing... ',0,'test_19_DeleteObject')
person_server = self.getPersonServer()
person_server.manage_delObjects(self.id1)
person_client1 = self.getPersonClient1()
......@@ -803,7 +803,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.failUnless(len(subscription1.getObjectList())==0)
self.failUnless(len(subscription2.getObjectList())==0)
def testDeleteSubObject(self, quiet=0, run=run_all_test):
def test_20_DeleteSubObject(self, quiet=0, run=run_all_test):
"""
We will do a first synchronization, then delete a sub-object on both
sides, and we will see if nothing is left on the server and also
......@@ -816,10 +816,10 @@ class TestERP5SyncML(ERP5TypeTestCase):
- id2
"""
if not run: return
self.testAddSubObject(quiet=1,run=1)
self.test_17_AddSubObject(quiet=1,run=1)
if not quiet:
ZopeTestCase._print('\nTest Delete Sub Object ')
LOG('Testing... ',0,'testDeleteSubObject')
LOG('Testing... ',0,'test_20_DeleteSubObject')
person_server = self.getPersonServer()
sub_object_s = person_server._getOb(self.id1)._getOb(self.id1)
sub_object_s.manage_delObjects(self.id1)
......@@ -836,16 +836,16 @@ class TestERP5SyncML(ERP5TypeTestCase):
len_c2 = len(sub_object_c2.objectValues())
self.failUnless(len_s==len_c1==len_c2==0)
def testGetConflictListOnSubObject(self, quiet=0, run=run_all_test):
def test_21_GetConflictListOnSubObject(self, quiet=0, run=run_all_test):
"""
We will change several attributes on a sub object on both the server
and a client, then we will see if we have correctly the conflict list
"""
if not run: return
self.testAddSubObject(quiet=1,run=1)
self.test_17_AddSubObject(quiet=1,run=1)
if not quiet:
ZopeTestCase._print('\nTest Get Conflict List On Sub Object ')
LOG('Testing... ',0,'testGetConflictListOnSubObject')
LOG('Testing... ',0,'test_21_GetConflictListOnSubObject')
person_server = self.getPersonServer()
object_s = person_server._getOb(self.id1)
sub_object_s = object_s._getOb(self.id1)
......@@ -869,16 +869,16 @@ class TestERP5SyncML(ERP5TypeTestCase):
conflict_list = portal_sync.getConflictList(sub_object_s)
self.failUnless(len(conflict_list)==2)
def testApplyPublisherDocumentOnSubObject(self, quiet=0, run=run_all_test):
def test_22_ApplyPublisherDocumentOnSubObject(self, quiet=0, run=run_all_test):
"""
there's several conflict on a sub object, we will see if we can
correctly have the publisher version of this document
"""
if not run: return
self.testGetConflictListOnSubObject(quiet=1,run=1)
self.test_21_GetConflictListOnSubObject(quiet=1,run=1)
if not quiet:
ZopeTestCase._print('\nTest Apply Publisher Document On Sub Object ')
LOG('Testing... ',0,'testApplyPublisherDocumentOnSubObject')
LOG('Testing... ',0,'test_22_ApplyPublisherDocumentOnSubObject')
portal_sync = self.getSynchronizationTool()
conflict_list = portal_sync.getConflictList()
conflict = conflict_list[0]
......@@ -899,16 +899,16 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.failUnless(sub_object_c2.getDescription()==self.description2)
self.failUnless(sub_object_c2.getLanguage()==self.lang2)
def testApplySubscriberDocumentOnSubObject(self, quiet=0, run=run_all_test):
def test_23_ApplySubscriberDocumentOnSubObject(self, quiet=0, run=run_all_test):
"""
there's several conflict on a sub object, we will see if we can
correctly have the subscriber version of this document
"""
if not run: return
self.testGetConflictListOnSubObject(quiet=1,run=1)
self.test_21_GetConflictListOnSubObject(quiet=1,run=1)
if not quiet:
ZopeTestCase._print('\nTest Apply Subscriber Document On Sub Object ')
LOG('Testing... ',0,'testApplySubscriberDocumentOnSubObject')
LOG('Testing... ',0,'test_23_ApplySubscriberDocumentOnSubObject')
portal_sync = self.getSynchronizationTool()
conflict_list = portal_sync.getConflictList()
conflict = conflict_list[0]
......@@ -929,7 +929,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.failUnless(sub_object_c2.getDescription()==self.description3)
self.failUnless(sub_object_c2.getLanguage()==self.lang3)
def testSynchronizeWithStrangeGid(self, quiet=0, run=run_all_test):
def test_24_SynchronizeWithStrangeGid(self, quiet=0, run=run_all_test):
"""
By default, the synchronization process use the id in order to
recognize objects (because by default, getGid==getId. Here, we will see
......@@ -938,7 +938,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
if not run: return
if not quiet:
ZopeTestCase._print('\nTest Synchronize With Strange Gid ')
LOG('Testing... ',0,'testSynchronizeWithStrangeGid')
LOG('Testing... ',0,'test_24_SynchronizeWithStrangeGid')
self.login()
self.setupPublicationAndSubscriptionAndGid(quiet=1,run=1)
nb_person = self.populatePersonServer(quiet=1,run=1)
......@@ -976,16 +976,16 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.failUnless(person_s.getDescription()==self.description3)
self.failUnless(person_c1.getDescription()==self.description3)
def testMultiNodeConflict(self, quiet=0, run=run_all_test):
def test_25_MultiNodeConflict(self, quiet=0, run=run_all_test):
"""
We will create conflicts with 3 differents nodes, and we will
solve it by taking one full version of documents.
"""
if not run: return
self.testFirstSynchronization(quiet=1,run=1)
self.test_08_FirstSynchronization(quiet=1,run=1)
if not quiet:
ZopeTestCase._print('\nTest Multi Node Conflict ')
LOG('Testing... ',0,'testMultiNodeConflict')
LOG('Testing... ',0,'test_25_MultiNodeConflict')
portal_sync = self.getSynchronizationTool()
person_server = self.getPersonServer()
person1_s = person_server._getOb(self.id1)
......@@ -1041,17 +1041,17 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.failUnless(person1_c2.getFormat()==self.format4)
def testSynchronizeWorkflowHistory(self, quiet=0, run=run_all_test):
def test_26_SynchronizeWorkflowHistory(self, quiet=0, run=run_all_test):
"""
We will do a synchronization, then we will edit two times
the object on the server, then two times the object on the
client, and see if the global history as 4 more actions.
"""
if not run: return
self.testFirstSynchronization(quiet=1,run=1)
self.test_08_FirstSynchronization(quiet=1,run=1)
if not quiet:
ZopeTestCase._print('\nTest Synchronize WorkflowHistory ')
LOG('Testing... ',0,'testSynchronizeWorkflowHistory')
LOG('Testing... ',0,'test_26_SynchronizeWorkflowHistory')
person_server = self.getPersonServer()
person1_s = person_server._getOb(self.id1)
person_client1 = self.getPersonClient1()
......@@ -1068,16 +1068,16 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.failUnless(len(person1_s.workflow_history[self.workflow_id])==len_wf+4)
self.failUnless(len(person1_c.workflow_history[self.workflow_id])==len_wf+4)
def testUpdateLocalRole(self, quiet=0, run=run_all_test):
def test_27_UpdateLocalRole(self, quiet=0, run=run_all_test):
"""
We will do a first synchronization, then modify, add and delete
an user role and see if it is correctly synchronized
"""
if not run: return
self.testFirstSynchronization(quiet=1,run=1)
self.test_08_FirstSynchronization(quiet=1,run=1)
if not quiet:
ZopeTestCase._print('\nTest Update Local Role ')
LOG('Testing... ',0,'testUpdateLocalRole')
LOG('Testing... ',0,'test_27_UpdateLocalRole')
# First, Create a new user
uf = self.getPortal().acl_users
uf._doAddUser('jp', '', ['Manager'], [])
......@@ -1101,17 +1101,17 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.assertEqual(role_1_s,role_1_c)
self.assertEqual(role_2_s,role_2_c)
def testPartialData(self, quiet=0, run=run_all_test):
def test_28_PartialData(self, quiet=0, run=run_all_test):
"""
We will do a first synchronization, then we will do a change, then
we will modify the SyncCode max_line value so it
it will generate many messages
"""
if not run: return
self.testFirstSynchronization(quiet=1,run=1)
self.test_08_FirstSynchronization(quiet=1,run=1)
if not quiet:
ZopeTestCase._print('\nTest Partial Data ')
LOG('Testing... ',0,'testPartialData')
LOG('Testing... ',0,'test_28_PartialData')
previous_max_lines = SyncCode.MAX_LINES
SyncCode.MAX_LINES = 10
self.populatePersonServerWithSubObject(quiet=1,run=1)
......@@ -1136,7 +1136,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.assertEquals(sub_sub_person2.getLastName(),self.last_name2)
SyncCode.MAX_LINES = previous_max_lines
def testBrokenMessage(self, quiet=0, run=run_all_test):
def test_29_BrokenMessage(self, quiet=0, run=run_all_test):
"""
With http synchronization, when a message is not well
received, then we send message again, we want to
......@@ -1148,7 +1148,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
if not run: return
if not quiet:
ZopeTestCase._print('\nTest Broken Message ')
LOG('Testing... ',0,'testBrokenMessage')
LOG('Testing... ',0,'test_29_BrokenMessage')
previous_max_lines = SyncCode.MAX_LINES
SyncCode.MAX_LINES = 10
self.setupPublicationAndSubscription(quiet=1,run=1)
......@@ -1172,14 +1172,14 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.failUnless(person1_c.getLastName()==self.last_name1)
SyncCode.MAX_LINES = previous_max_lines
def testGetSynchronizationType(self, quiet=0, run=run_all_test):
def test_30_GetSynchronizationType(self, quiet=0, run=run_all_test):
# We will try to update some simple data, first
# we change on the server side, the on the client side
if not run: return
if not quiet:
ZopeTestCase._print('\nTest Get Synchronization Type ')
LOG('Testing... ',0,'testGetSynchronizationType')
self.testFirstSynchronization(quiet=1,run=1)
LOG('Testing... ',0,'test_30_GetSynchronizationType')
self.test_08_FirstSynchronization(quiet=1,run=1)
# First we do only modification on server
# Check for each subsription that the synchronization type
# is TWO WAY
......@@ -1209,16 +1209,16 @@ class TestERP5SyncML(ERP5TypeTestCase):
for sub in portal_sync.getSubscriptionList():
self.assertEquals(sub.getSynchronizationType(),SyncCode.TWO_WAY)
def testUpdateLocalPermission(self, quiet=0, run=run_all_test):
def test_31_UpdateLocalPermission(self, quiet=0, run=run_all_test):
"""
We will do a first synchronization, then modify, add and delete
an user role and see if it is correctly synchronized
"""
if not run: return
self.testFirstSynchronization(quiet=1,run=1)
self.test_08_FirstSynchronization(quiet=1,run=1)
if not quiet:
ZopeTestCase._print('\nTest Update Local Permission ')
LOG('Testing... ',0,'testUpdateLocalPermission')
LOG('Testing... ',0,'test_31_UpdateLocalPermission')
# then create roles
person_server = self.getPersonServer()
person1_s = person_server._getOb(self.id1)
......@@ -1249,9 +1249,64 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.assertEqual(role_1_s,role_1_c)
self.assertEqual(role_2_s,role_2_c)
# We may add a test in order to check if the slow_sync mode works fine, ie
# if we do have both object on the client and server side, we must make sure
# that the server first sends is own data
def test_32_AddOneWaySubscription(self, quiet=0, run=1):
if not run: return
if not quiet:
ZopeTestCase._print('\nTest Add One Way Subscription ')
LOG('Testing... ',0,'test_32_AddOneWaySubscription')
portal_id = self.getPortalId()
portal_sync = self.getSynchronizationTool()
portal_sync.manage_addSubscription(self.sub_id1,self.publication_url,
self.subscription_url1,'/%s/person_client1' % portal_id,'objectValues',
'','ERP5Conduit','')
sub = portal_sync.getSubscription(self.sub_id1)
#sub.setOneWaySyncFromServer(1)
self.failUnless(sub is not None)
def test_33_OneWaySync(self, quiet=0, run=1):
"""
We will test if we can synchronize only from to server to the client.
We want to make sure in this case that all modifications on the client
will not be taken into account.
"""
if not run: return
if not quiet:
ZopeTestCase._print('\nTest One Way Sync ')
LOG('Testing... ',0,'test_33_OneWaySync')
self.test_02_AddPublication(quiet=1,run=1)
self.test_32_AddOneWaySubscription(quiet=1,run=1)
nb_person = self.populatePersonServer(quiet=1,run=1)
portal_sync = self.getSynchronizationTool()
for sub in portal_sync.getSubscriptionList():
self.assertEquals(sub.getSynchronizationType(),SyncCode.SLOW_SYNC)
# First do the sync from the server to the client
nb_message1 = self.synchronize(self.sub_id1)
for sub in portal_sync.getSubscriptionList():
self.assertEquals(sub.getSynchronizationType(),SyncCode.TWO_WAY)
self.assertEquals(nb_message1,self.nb_message_first_synchronization)
subscription1 = portal_sync.getSubscription(self.sub_id1)
self.assertEquals(len(subscription1.getObjectList()),nb_person)
person_server = self.getPersonServer() # We also check we don't
# modify initial ob
person1_s = person_server._getOb(self.id1)
self.failUnless(person1_s.getId()==self.id1)
self.failUnless(person1_s.getFirstName()==self.first_name1)
self.failUnless(person1_s.getLastName()==self.last_name1)
person_client1 = self.getPersonClient1()
person1_c = person_client1._getOb(self.id1)
self.failUnless(person1_c.getId()==self.id1)
self.failUnless(person1_c.getFirstName()==self.first_name1)
self.failUnless(person1_c.getLastName()==self.last_name1)
# Then we change things on both sides and we look if there
# is synchronization from only one way
person1_c.setFirstName(self.first_name2)
person1_s.setLastName(self.last_name2)
nb_message1 = self.synchronize(self.sub_id1)
self.assertEquals(person1_c.getLastName(),self.last_name2)
self.assertEquals(person1_s.getFirstName(),self.first_name1)
if __name__ == '__main__':
framework()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment