[Erp5-report] r28229 - in /erp5/trunk/products/ERP5SyncML: ./ tests/
nobody at svn.erp5.org
nobody at svn.erp5.org
Thu Jul 30 14:34:56 CEST 2009
Author: daniele
Date: Thu Jul 30 14:34:54 2009
New Revision: 28229
URL: http://svn.erp5.org?rev=28229&view=rev
Log:
2009-05-15:
Add default Namespace
Add Conduit for Documents
2009-05-26:
Move a getXMLFromObject to be overriden by specialized conduits
Create PointFixe in the tests
2009-06-02:
Split file Subscription.py to create Conflict.py and Signature.py
Use activities in the test testSyncML
2009-06-17:
Create a test for synchronize some documents
2009-07-10:
Change the Final of the synchronisation for the synchronisation
with datas from the Subscription
Modified:
erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py
erp5/trunk/products/ERP5SyncML/tests/testERP5SyncML.py
erp5/trunk/products/ERP5SyncML/tests/testERP5SyncMLVCard.py
Modified: erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py?rev=28229&r1=28228&r2=28229&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py [utf8] (original)
+++ erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py [utf8] Thu Jul 30 14:34:54 2009
@@ -28,7 +28,7 @@
import smtplib
from Products.ERP5SyncML.SyncCode import SyncCode
-from Products.ERP5SyncML.Subscription import Signature
+from Products.ERP5SyncML.Signature import Signature
from AccessControl.SecurityManagement import newSecurityManager
from ERP5Diff import ERP5Diff
from zLOG import LOG, INFO
@@ -55,8 +55,8 @@
way to set one quickly.
"""
xml = (E.SyncHdr(
- E.VerDTD('1.1'),
- E.VerProto('SyncML/1.1'),
+ E.VerDTD('1.2'),
+ E.VerProto('SyncML/1.2'),
E.SessionID('%s' % session_id),
E.MsgID('%s' % msg_id),
))
@@ -108,13 +108,15 @@
return a status bloc with all status corresponding to the syncml
commands in remote_xml
"""
-
+ namespace = self.getNamespace(remote_xml.nsmap)
#list of element in the SyncBody bloc
- sub_syncbody_element_list = remote_xml.xpath('/SyncML/SyncBody/*')
+ sub_syncbody_element_list = remote_xml.xpath('/syncml:SyncML/syncml:SyncBody/*')
message_id = self.getMessageIdFromXml(remote_xml)
status_list = []
- target_uri = '%s' % remote_xml.xpath('string(/SyncML/SyncHdr/Target/LocURI)')
- source_uri = '%s' % remote_xml.xpath('string(/SyncML/SyncHdr/Source/LocURI)')
+ target_uri = '%s' %\
+ remote_xml.xpath('string(/syncml:SyncML/syncml:SyncHdr/syncml:Target/syncml:LocURI)')
+ source_uri = '%s' %\
+ remote_xml.xpath('string(/syncml:SyncML/syncml:SyncHdr/syncml:Source/syncml:LocURI)')
if data_code != self.AUTH_REQUIRED:
xml = (E.Status(
E.CmdID('%s' % cmd_id),
@@ -128,34 +130,36 @@
cmd_id += 1
status_list.append(xml)
for sub_syncbody_element in sub_syncbody_element_list:
- if sub_syncbody_element.tag not in ('Status', 'Final', 'Get'):
+ if sub_syncbody_element.xpath('local-name()') not in ('Status', 'Final', 'Get'):
xml = (E.Status(
E.CmdID('%s' % cmd_id),
E.MsgRef('%s' % message_id),
- E.CmdRef('%s' % sub_syncbody_element.xpath('string(.//CmdID)')),
- E.Cmd(sub_syncbody_element.tag)
+ E.CmdRef('%s' %\
+ sub_syncbody_element.xpath('string(.//syncml:CmdID)')),
+ E.Cmd('%s' % sub_syncbody_element.xpath('name()'))
))
cmd_id += 1
- target_ref = sub_syncbody_element.xpath('string(.//Target/LocURI)')
+ target_ref = sub_syncbody_element.xpath('string(.//syncml:Target/syncml:LocURI)')
if target_ref:
xml.append(E.TargetRef('%s' % target_ref))
- source_ref = sub_syncbody_element.xpath('string(.//Source/LocURI)')
+ source_ref = sub_syncbody_element.xpath('string(.//syncml:Source/syncml:LocURI)')
if source_ref:
xml.append(E.SourceRef('%s' % source_ref))
- if sub_syncbody_element.tag == 'Add':
+ if sub_syncbody_element.xpath('local-name()') == 'Add':
xml.append(E.Data('%s' % self.ITEM_ADDED))
- elif sub_syncbody_element.tag == 'Alert' and \
- sub_syncbody_element.xpath('string(.//Data)') == \
+ elif sub_syncbody_element.xpath('local-name()') == 'Alert' and \
+ sub_syncbody_element.xpath('string(.//syncml:Data)') == \
str(self.SLOW_SYNC):
xml.append(E.Data('%s' % self.REFRESH_REQUIRED))
- elif sub_syncbody_element.tag == 'Alert':
+ elif sub_syncbody_element.xpath('local-name()') == 'Alert':
xml.append(E.Item(E.Data(E.Anchor(E.Next(next_anchor)))))
else:
xml.append(E.Data('%s' % self.SUCCESS))
status_list.append(xml)
-
- if sub_syncbody_element.tag == 'Get' and subscription is not None:
- cmd_ref = '%s' % sub_syncbody_element.xpath('string(.//CmdID)')
+ #FIXME to do a test for Get
+ if sub_syncbody_element.xpath('local-name()') == 'Get'\
+ and subscription is not None:
+ cmd_ref = '%s' % sub_syncbody_element.xpath('string(.//syncml:CmdID)')
syncml_result = self.SyncMLPut(
cmd_id,
subscription,
@@ -176,10 +180,12 @@
synchronized
"""
if remote_xml is not None:
- msg_ref = '%s' % remote_xml.xpath("string(/SyncML/SyncHdr/MsgID)")
- cmd_ref = '%s' % remote_xml.xpath("string(.//CmdID)")
- target_ref = '%s' % remote_xml.xpath("string(.//Target/LocURI)")
- source_ref = '%s' % remote_xml.xpath("string(.//Source/LocURI)")
+ namespace = self.getNamespace(remote_xml.nsmap)
+ msg_ref = '%s' %\
+ remote_xml.xpath("string(/syncml:SyncML/syncml:SyncHdr/syncml:MsgID)")
+ cmd_ref = '%s' % remote_xml.xpath("string(.//syncml:CmdID)")
+ target_ref = '%s' % remote_xml.xpath("string(.//syncml:Target/syncml:LocURI)")
+ source_ref = '%s' % remote_xml.xpath("string(.//syncml:Source/syncml:LocURI)")
xml = Element('Status')
if cmd_id:
xml.append(E.CmdID('%s' % cmd_id))
@@ -296,6 +302,19 @@
#server.sendmail(fromaddr, "seb at localhost", msg)
server.quit()
+ def getNamespace(self,nsmap):
+ """
+ return the namespace with prefix of xml
+ """
+ #search urn compatible in the namespaces of nsmap
+ urns = filter(lambda v: v.upper() in self.URN_LIST, nsmap.values())
+ if urns :
+ namespace = etree.FunctionNamespace(urns[0])
+ namespace.prefix='syncml'
+ return namespace
+ else :
+ raise ValueError, "Sorry, If have a namespace isn't supported"
+
def addXMLObject(self, cmd_id=0, object=None, xml_string=None,
more_data=0, gid=None, media_type=None):
"""
@@ -400,63 +419,76 @@
"""
We will retrieve the session id of the message
"""
- return int(xml.xpath('string(/SyncML/SyncHdr/SessionID)'))
+ namespace = self.getNamespace(xml.nsmap)
+ return int(xml.xpath('string(/syncml:SyncML/syncml:SyncHdr/syncml:SessionID)'))
def getMessageIdFromXml(self, xml):
"""
We will retrieve the message id of the message
"""
- return int(xml.xpath('string(/SyncML/SyncHdr/MsgID)'))
+ namespace = self.getNamespace(xml.nsmap)
+ return int(xml.xpath('string(/syncml:SyncML/syncml:SyncHdr/syncml:MsgID)'))
def getTarget(self, xml):
"""
return the target in the SyncHdr section
"""
- return '%s' % xml.xpath('string(/SyncML/SyncHdr/Target/LocURI)')
+ namespace = self.getNamespace(xml.nsmap)
+ return '%s' % xml.xpath('string(/syncml:SyncML/syncml:SyncHdr/syncml:Target/syncml:LocURI)')
def getAlertLastAnchor(self, xml_stream):
"""
Return the value of the last anchor, in the
alert section of the xml_stream
"""
- return '%s' % xml_stream.xpath('string(.//Alert/Item/Meta/Anchor/Last)')
+ namespace = self.getNamespace(xml_stream.nsmap)
+ return '%s' % xml_stream.xpath('string(.//syncml:Alert/syncml:Item/syncml:Meta/syncml:Anchor/syncml:Last)')
def getAlertNextAnchor(self, xml_stream):
"""
Return the value of the next anchor, in the
alert section of the xml_stream
"""
- return '%s' % xml_stream.xpath('string(.//Alert/Item/Meta/Anchor/Next)')
+ namespace = self.getNamespace(xml_stream.nsmap)
+ return '%s' %\
+ xml_stream.xpath('string(.//syncml:Alert/syncml:Item/syncml:Meta/syncml:Anchor/syncml:Next)')
def getSourceURI(self, xml):
"""
return the source uri of the data base
"""
- return '%s' % xml.xpath('string(//SyncBody/Alert/Item/Source/LocURI)')
+ namespace = self.getNamespace(xml.nsmap)
+ return '%s' %\
+ xml.xpath('string(//syncml:SyncBody/syncml:Alert/syncml:Item/syncml:Source/syncml:LocURI)')
def getTargetURI(self, xml):
"""
return the target uri of the data base
"""
- return '%s' % xml.xpath('string(//SyncBody/Alert/Item/Target/LocURI)')
+ namespace = self.getNamespace(xml.nsmap)
+ return '%s' %\
+ xml.xpath('string(//syncml:SyncBody/syncml:Alert/syncml:Item/syncml:Target/syncml:LocURI)')
def getSubscriptionUrlFromXML(self, xml):
"""
return the source URI of the syncml header
"""
- return '%s' % xml.xpath('string(//SyncHdr/Source/LocURI)')
+ namespace = self.getNamespace(xml.nsmap)
+ return '%s' % xml.xpath('string(//syncml:SyncHdr/syncml:Source/syncml:LocURI)')
def getStatusTarget(self, xml):
"""
Return the value of the alert code inside the xml_stream
"""
- return '%s' % xml.xpath('string(TargetRef)')
+ namespace = self.getNamespace(xml.nsmap)
+ return '%s' % xml.xpath('string(syncml:TargetRef)')
def getStatusCode(self, xml):
"""
Return the value of the alert code inside the xml_stream
"""
- status_code = '%s' % xml.xpath('string(Data)')
+ namespace = self.getNamespace(xml.nsmap)
+ status_code = '%s' % xml.xpath('string(syncml:Data)')
if status_code:
return int(status_code)
return None
@@ -465,18 +497,22 @@
"""
Return the value of the command inside the xml_stream
"""
+ namespace = self.getNamespace(xml.nsmap)
cmd = None
- if xml.tag == 'Status':
- cmd = '%s' % xml.xpath('string(Cmd)')
+ if xml.xpath('local-name()') == 'Status':
+ cmd = '%s' % xml.xpath('string(syncml:Cmd)')
return cmd
def getCred(self, xml):
"""
return the credential information : type, format and data
"""
- format = '%s' % xml.xpath("string(/SyncML/SyncHdr/Cred/Meta/*[local-name() = 'Format'])")
- type = '%s' % xml.xpath("string(/SyncML/SyncHdr/Cred/Meta/*[local-name() = 'Type'])")
- data = '%s' % xml.xpath('string(/SyncML/SyncHdr/Cred/Data)')
+ namespace = self.getNamespace(xml.nsmap)
+ format = '%s' %\
+ xml.xpath("string(/syncml:SyncML/syncml:SyncHdr/syncml:Cred/syncml:Meta/*[local-name() = 'Format'])")
+ type = '%s' %\
+ xml.xpath("string(/syncml:SyncML/syncml:SyncHdr/syncml:Cred/syncml:Meta/*[local-name() = 'Type'])")
+ data = '%s' % xml.xpath('string(/syncml:SyncML/syncml:SyncHdr/syncml:Cred/syncml:Data)')
return (format, type, data)
@@ -484,7 +520,8 @@
"""
Check if there's a Cred section in the xml_stream
"""
- return bool(xml_stream.xpath('string(/SyncML/SyncHdr/Cred)'))
+ namespace = self.getNamespace(xml_stream.nsmap)
+ return bool(xml_stream.xpath('string(/syncml:SyncML/syncml:SyncHdr/syncml:Cred)'))
def getChal(self, xml):
"""
@@ -498,31 +535,37 @@
"""
Check if there's a Chal section in the xml_stream
"""
- return bool(xml_stream.xpath('string(/SyncML/SyncBody/Status/Chal)'))
+ namespace = self.getNamespace(xml_stream.nsmap)
+ return\
+ bool(xml_stream.xpath('string(/syncml:SyncML/syncml:SyncBody/syncml:Status/syncml:Chal)'))
def checkMap(self, xml_stream):
"""
Check if there's a Map section in the xml_stream
"""
- return bool(xml_stream.xpath('string(/SyncML/SyncBody/Map)'))
+ namespace = self.getNamespace(xml_stream.nsmap)
+ return bool(xml_stream.xpath('string(/syncml:SyncML/syncml:SyncBody/syncml:Map)'))
def setRidWithMap(self, xml_stream, subscriber):
"""
get all the local objects of the given target id and set them the rid with
the given source id (in the Map section)
"""
- item_list = xml_stream.xpath('/SyncML/SyncBody/Map/MapItem')
+ namespace = self.getNamespace(xml_stream.nsmap)
+ item_list = xml_stream.xpath('/syncml:SyncML/syncml:SyncBody/syncml:Map/syncml:MapItem')
for map_item in item_list:
- gid = '%s' % map_item.xpath('string(.//Target/LocURI)')
+ gid = '%s' % map_item.xpath('string(.//syncml:Target/syncml:LocURI)')
signature = subscriber.getSignatureFromGid(gid)
- rid = '%s' % map_item.xpath('string(.//Source/LocURI)')
+ rid = '%s' % map_item.xpath('string(.//syncml:Source/syncml:LocURI)')
signature.setRid(rid)
def getAlertCodeFromXML(self, xml_stream):
"""
Return the value of the alert code inside the full syncml message
"""
- alert_code = '%s' % xml_stream.xpath('string(/SyncML/SyncBody/Alert/Data)')
+ namespace = self.getNamespace(xml_stream.nsmap)
+ alert_code = '%s' %\
+ xml_stream.xpath('string(/syncml:SyncML/syncml:SyncBody/syncml:Alert/syncml:Data)')
if alert_code:
return int(alert_code)
else:
@@ -532,39 +575,52 @@
"""
Check if there's an Alert section in the xml_stream
"""
- return bool(xml_stream.xpath('string(/SyncML/SyncBody/Alert)'))
+ namespace = self.getNamespace(xml_stream.nsmap)
+ return bool(xml_stream.xpath('string(/syncml:SyncML/syncml:SyncBody/syncml:Alert)'))
def checkSync(self, xml_stream):
"""
- Check if there's an Sync section in the xml_xtream
- """
- return bool(xml_stream.xpath('string(/SyncML/SyncBody/Sync)'))
-
+ Check if there's an Sync section in the xml_stream
+ """
+ namespace = self.getNamespace(xml_stream.nsmap)
+ return bool(xml_stream.xpath('string(/syncml:SyncML/syncml:SyncBody/syncml:Sync)'))
+
+ def checkFinal(self, xml_stream):
+ """
+ Check if there's an Final section in the xml_stream
+ The end sections (inizialisation, modification) have this tag
+ """
+ namespace = self.getNamespace(xml_stream.nsmap)
+ return bool(xml_stream.xpath('/syncml:SyncML/syncml:SyncBody/syncml:Final'))
+
def checkStatus(self, xml_stream):
"""
- Check if there's a Status section in the xml_xtream
- """
- return bool(xml_stream.xpath('string(/SyncML/SyncBody/Status)'))
+ Check if there's a Status section in the xml_stream
+ """
+ namespace = self.getNamespace(xml_stream.nsmap)
+ return bool(xml_stream.xpath('string(/syncml:SyncML/syncml:SyncBody/syncml:Status)'))
def getSyncActionList(self, xml_stream):
"""
return the list of the action (could be "add", "replace", "delete").
"""
- return xml_stream.xpath('//Add|//Delete|//Replace')
+ namespace = self.getNamespace(xml_stream.nsmap)
+ return xml_stream.xpath('//syncml:Add|//syncml:Delete|//syncml:Replace')
def getSyncBodyStatusList(self, xml_stream):
"""
return the list of dictionary corredponding to the data of each status bloc
the data are : cmd, code and source
"""
+ namespace = self.getNamespace(xml_stream.nsmap)
status_list = []
- status_node_list = xml_stream.xpath('//Status')
+ status_node_list = xml_stream.xpath('//syncml:Status')
for status in status_node_list:
tmp_dict = {}
- tmp_dict['cmd'] = '%s' % status.xpath('string(./Cmd)')
- tmp_dict['code'] = '%s' % status.xpath('string(./Data)')
- tmp_dict['source'] = '%s' % status.xpath('string(./SourceRef)')
- tmp_dict['target'] = '%s' % status.xpath('string(./TargetRef)')
+ tmp_dict['cmd'] = '%s' % status.xpath('string(./syncml:Cmd)')
+ tmp_dict['code'] = '%s' % status.xpath('string(./syncml:Data)')
+ tmp_dict['source'] = '%s' % status.xpath('string(./syncml:SourceRef)')
+ tmp_dict['target'] = '%s' % status.xpath('string(./syncml:TargetRef)')
status_list.append(tmp_dict)
return status_list
@@ -572,13 +628,15 @@
"""
return the section data in text form, it's usefull for the VCardConduit
"""
- return '%s' % action.xpath('string(.//Item/Data)')
+ namespace = self.getNamespace(action.nsmap)
+ return '%s' % action.xpath('string(.//syncml:Item/syncml:Data)')
def getDataSubNode(self, action):
"""
Return the node starting with <object....> of the action
"""
- object_node_list = action.xpath('.//Item/Data/*[1]')
+ namespace = self.getNamespace(action.nsmap)
+ object_node_list = action.xpath('.//syncml:Item/syncml:Data/*[1]')
if object_node_list:
return object_node_list[0]
return None
@@ -587,22 +645,25 @@
"""
Return the rid of the object described by the action
"""
- id = '%s' % action.xpath('string(.//Item/Source/LocURI)')
+ namespace = self.getNamespace(action.nsmap)
+ id = '%s' % action.xpath('string(.//syncml:Item/syncml:Source/syncml:LocURI)')
if not id:
- id = '%s' % action.xpath('string(.//Item/Target/LocURI)')
+ id = '%s' % action.xpath('string(.//syncml:Item/syncml:Target/syncml:LocURI)')
return id
def checkActionMoreData(self, action):
"""
Return the rid of the object described by the action
"""
- return bool(action.xpath('.//Item/MoreData'))
+ namespace = self.getNamespace(action.nsmap)
+ return bool(action.xpath('.//syncml:Item/syncml:MoreData'))
def getActionType(self, action):
"""
Return the type of the object described by the action
"""
- return '%s' % action.xpath('string(.//Meta/Type)')
+ namespace = self.getNamespace(action.nsmap)
+ return '%s' % action.xpath('string(.//syncml:Meta/syncml:Type)')
def cutXML(self, xml_string):
"""
@@ -636,7 +697,7 @@
if isinstance(remote_xml, (str, unicode)):
remote_xml = etree.XML(remote_xml, parser=parser)
if domain.isOneWayFromServer():
- #Do not set object_path_list, subscriber send nothing
+ #Do not set object_path_list, subscriber send nothing it's a client
subscriber.setRemainingObjectPathList([])
elif subscriber.getRemainingObjectPathList() is None:
object_list = domain.getObjectList()
@@ -659,7 +720,6 @@
#LOG('getSyncMLData :', DEBUG,'gid_not_encoded_list:%s, local_gid_list:%s, gid:%s' % (gid_not_encoded_list, local_gid_list, gid))
else:
local_gid_list = [domain.getGidFromObject(x) for x in object_list]
-
# Objects to remove
#LOG('getSyncMLData remove object to remove ...', DEBUG, '')
for object_gid in subscriber.getGidList():
@@ -673,7 +733,7 @@
rid=rid,
cmd_id=cmd_id))
cmd_id += 1
- #delete Signature if object does not exist anymore
+ # Delete Signature if object does not exist anymore
subscriber.delSignature(object_gid)
local_gid_list = []
@@ -703,18 +763,18 @@
signature = subscriber.getSignatureFromGid(object_gid)
## Here we first check if the object was modified or not by looking at dates
- #if signature is not None:
- #LOG('getSyncMLData', DEBUG, 'signature.getStatus: %s' % signature.getStatus())
status = self.SENT
more_data = 0
# For the case it was never synchronized, we have to send everything
if signature is not None and signature.getXMLMapping() is None:
pass
- elif signature is None or (signature.getXML() is None and \
- signature.getStatus() != self.PARTIAL) or \
+ elif signature is None or\
+ (signature.getXML() is None and\
+ signature.getStatus() != self.PARTIAL) or\
self.getAlertCodeFromXML(remote_xml) == self.SLOW_SYNC:
#LOG('getSyncMLData', DEBUG, 'Current object.getPath: %s' % object.getPath())
- xml_string = domain.getXMLFromObject(object)
+ xml_string = conduit.getXMLFromObjectWithId(object,\
+ xml_mapping=domain.getXMLMapping())
gid = subscriber.getGidFromObject(object)
signature = Signature(id=gid, object=object).__of__(subscriber)
signature.setTempXML(xml_string)
@@ -724,7 +784,7 @@
signature.setPartialXML(rest_string)
status = self.PARTIAL
signature.setAction('Add')
- #in fisrt, we try with rid if there is one
+ #in first, we try with rid if there is one
gid = signature.getRid() or signature.getGid()
syncml_data_list.append(self.addXMLObject(
cmd_id=cmd_id,
@@ -738,8 +798,9 @@
subscriber.addSignature(signature)
elif signature.getStatus() in (self.NOT_SYNCHRONIZED,
self.PUB_CONFLICT_MERGE,):
- # We don't have synchronized this object yet
- xml_object = domain.getXMLFromObject(object)
+ # We don't have synchronized this object yet but it has a signature
+ xml_object = conduit.getXMLFromObjectWithId(object,\
+ xml_mapping=domain.getXMLMapping())
#LOG('getSyncMLData', DEBUG, 'checkMD5: %s' % str(signature.checkMD5(xml_object)))
#LOG('getSyncMLData', DEBUG, 'getStatus: %s' % str(signature.getStatus()))
if signature.getStatus() == self.PUB_CONFLICT_MERGE:
@@ -751,22 +812,21 @@
set_synchronized = 1
if not signature.checkMD5(xml_object):
set_synchronized = 0
- # This object has changed on this side, we have to generate some xmldiff
- if subscriber.getMediaType() == self.MEDIA_TYPE['TEXT_XML']:
+ if subscriber.getMediaType() != self.MEDIA_TYPE['TEXT_XML']:
+ # If there is no xml, we re-send all the objects
+ xml_string = xml_object
+ else:
+ # This object has changed on this side, we have to generate some xmldiff
xml_string = self.getXupdateObject(xml_object, signature.getXML())
- else: #if there is no xml, we re-send all the object
- xml_string = xml_object
- if subscriber.getMediaType() != self.MEDIA_TYPE['TEXT_XML']:
- xml_string = xml_object
- elif xml_string.count('\n') > self.MAX_LINES:
- # This make comment fails, so we need to replace
- xml_string, rest_string = self.cutXML(xml_string)
- more_data = 1
- signature.setPartialXML(rest_string)
- status = self.PARTIAL
- signature.setAction('Replace')
- signature.setStatus(status)
- rid = signature.getRid()#in fisrt, we try with rid if there is one
+ if xml_string.count('\n') > self.MAX_LINES:
+ # This make comment fails, so we need to replace
+ xml_string, rest_string = self.cutXML(xml_string)
+ more_data = 1
+ signature.setPartialXML(rest_string)
+ status = self.PARTIAL
+ signature.setAction('Replace')
+ signature.setStatus(status)
+ rid = signature.getRid()#in first, we try with rid if there is
gid = signature.getGid()
syncml_data_list.append(self.replaceXMLObject(
cmd_id=cmd_id, object=object,
@@ -780,6 +840,8 @@
subscriber_xupdate = signature.getSubscriberXupdate()
#LOG('getSyncMLData subscriber_xupdate', DEBUG, subscriber_xupdate)
if subscriber_xupdate is not None:
+ # The modification in the xml from signature is compare and update
+ # with xml_xupdate from subscriber
old_xml = signature.getXML()
conduit.updateNode(
xml=subscriber_xupdate,
@@ -787,7 +849,8 @@
previous_xml=old_xml,
force=(domain.getDomainType() == self.SUB),
simulate=0)
- xml_object = domain.getXMLFromObject(object)
+ xml_object = conduit.getXMLFromObjectWithId(object,\
+ xml_mapping=domain.getXMLMapping())
signature.setTempXML(xml_object)
if set_synchronized: # We have to do that after this previous update
# We should not have this case when we are in CONFLICT_MERGE
@@ -814,7 +877,8 @@
xml_to_send = Element('Partial')
xml_to_send.text = etree.CDATA(xml_string.decode('utf-8'))
if(subscriber.getMediaType() != self.MEDIA_TYPE['TEXT_XML']):
- xml_to_send = domain.getXMLFromObject(object)
+ xml_to_send = conduit.getXMLFromObjectWithId(object,\
+ xml_mapping=domain.getXMLMapping())
elif xml_string.count('\n') > self.MAX_LINES:
xml_to_send, rest_string = self.cutXML(xml_string)
more_data = 1
@@ -859,59 +923,52 @@
This just look to a list of action to do, then id applies
each action one by one, thanks to a conduit
"""
+ namespace = self.getNamespace(remote_xml.nsmap)
xml_confirmation_list = []
has_next_action = 0
gid_from_xml_list = []
destination = self.unrestrictedTraverse(domain.getDestinationPath())
- #LOG('applyActionList args', DEBUG, 'domain : %s\n subscriber : %s\n cmd_id : %s' % (domain.getPath(), subscriber.getPath(), cmd_id))
- #LOG('applyActionList', DEBUG, self.getSyncActionList(remote_xml))
+ #LOG('applyActionList args', DEBUG, 'domain : %s\n subscriber : %s\n cmd_id: %s'\
+ #% (domain.getPath(), subscriber.getPath(), cmd_id))
+ #LOG('XMLSyncUtils applyActionList', DEBUG, self.getSyncActionList(remote_xml))
for action in self.getSyncActionList(remote_xml):
conflict_list = []
status_code = self.SUCCESS
# Thirst we have to check the kind of action it is
- partial_data = '%s' % action.xpath('string(.//Item/Data/Partial)')
- rid = self.getActionId(action)
- if action.tag != 'Delete':
+
+ # The rid is the Temporary GUID (SYNCML Protocol). the rid sent by the
+ # client unlike gid. The rid is in MapItem for each Action Map it's the LocURI in
+ # the action.
+ gid = rid = self.getActionId(action)
+ #The action delete hasn't need a gid and retrieve the gid of conduit for
+ #object.
+ if action.xpath('local-name()') != 'Delete':
+ data_action = self.getDataSubNode(action)
+ if subscriber.getMediaType() != self.MEDIA_TYPE['TEXT_XML']:
+ #data in unicode
+ data_action = self.getDataText(action)
if getattr(conduit, 'getGidFromXML', None) is not None and \
- conduit.getGidFromXML(self.getDataText(action), gid_from_xml_list):
- gid = conduit.getGidFromXML(self.getDataText(action),
- gid_from_xml_list)
+ conduit.getGidFromXML(data_action, namespace, gid_from_xml_list):
+ gid = conduit.getGidFromXML(data_action, namespace, gid_from_xml_list)
gid_from_xml_list.append(gid)
gid = b16encode(gid)
- else:
- gid = rid
+ #the rid unlike gid, it's the rid or gid (if rid == gid) will use for
+ #retrieve object and send response to client
+ signature = subscriber.getSignatureFromGid(gid)
+ object = subscriber.getObjectFromGid(gid)
+ object_id = domain.generateNewIdWithGenerator(object=destination, gid=gid)
+ if rid == gid:
+ #We can't use our own gid and the temporary GUID is useless
+ rid = None
+ if signature is not None:
+ signature.setRid(rid)
else:
- gid = rid
- object_id = domain.generateNewIdWithGenerator(object=destination, gid=gid)
- signature = subscriber.getSignatureFromGid(gid)
- if signature is not None and rid != gid:
- #in this case, the object was created on another subscriber than erp5
- # and we should save it's remote id
- signature.setRid(rid)
- #LOG('gid == rid ?', DEBUG, 'gid=%s, rid=%s' % (gid, rid))
- object = subscriber.getObjectFromGid(gid)
- if object is None and not domain.getSynchronizeWithERP5Sites():
- #if the object is None, that could mean two things :
- # - the object to synchronize don't exists
- # - the id is not a gid but a rid
- #here we try to find an object with the rid
- #LOG('applyActionList, try to find an object with rid', DEBUG, '')
- object = subscriber.getObjectFromRid(rid)
- signature = subscriber.getSignatureFromRid(rid)
- if signature is not None:
- gid = signature.getId()
- #LOG('applyActionList subscriber.getObjectFromGid %s' % gid, DEBUG, object)
- if signature is None:
- #LOG('applyActionList, signature is None', DEBUG, signature)
- if gid == rid:
- signature = Signature(id=gid, status=self.NOT_SYNCHRONIZED,
- object=object).__of__(subscriber)
- else:
- signature = Signature(rid=rid, id=gid, status=self.NOT_SYNCHRONIZED,
+ signature = Signature(id=gid, rid=rid, status=self.NOT_SYNCHRONIZED,
object=object).__of__(subscriber)
signature.setObjectId(object_id)
subscriber.addSignature(signature)
force = signature.getForce()
+ partial_data = '%s' % action.xpath('string(.//syncml:Item/syncml:Data/syncml:Partial)')
if not self.checkActionMoreData(action):
data_subnode = None
if partial_data:
@@ -928,7 +985,7 @@
data_subnode = self.getDataText(action)
else:
data_subnode = self.getDataSubNode(action)
- if action.tag == 'Add':
+ if action.xpath('local-name()') == 'Add':
# Then store the xml of this new subobject
reset = 0
if object is None:
@@ -948,7 +1005,9 @@
if data_subnode is not None:
if not isinstance(data_subnode, str):
xml_string = etree.tostring(data_subnode, encoding='utf-8')
- actual_xml = subscriber.getXMLFromObject(object=object, force=1)
+ #force = 1
+ actual_xml = conduit.getXMLFromObjectWithId(object,\
+ xml_mapping=domain.getXMLMapping(force=1))
data_subnode = self.getXupdateObject(xml_string, actual_xml)
conflict_list.extend(conduit.updateNode(
xml=data_subnode,
@@ -956,7 +1015,8 @@
previous_xml=signature.getXML(),
force=force,
simulate=simulate))
- xml_object = domain.getXMLFromObject(object)
+ xml_object = conduit.getXMLFromObjectWithId(object,\
+ xml_mapping=domain.getXMLMapping())
signature.setTempXML(xml_object)
if object is not None:
#LOG('applyActionList', DEBUG, 'addNode, found the object')
@@ -968,8 +1028,9 @@
pretty_print=True)
else:
xml_object = data_subnode
- else:
- xml_object = domain.getXMLFromObject(object)
+ else:
+ xml_object = conduit.getXMLFromObjectWithId(object,\
+ xml_mapping=domain.getXMLMapping())
signature.setStatus(self.SYNCHRONIZED)
#signature.setId(object.getId())
signature.setPath(object.getPhysicalPath())
@@ -980,13 +1041,11 @@
sync_code=self.ITEM_ADDED,
remote_xml=action))
cmd_id +=1
- elif action.tag == 'Replace':
+ elif action.xpath('local-name()') == 'Replace':
#LOG('applyActionList', DEBUG, 'object: %s will be updated...' % str(object))
if object is not None:
#LOG('applyActionList', DEBUG, 'object: %s will be updated...' % object.id)
signature = subscriber.getSignatureFromGid(gid)
- if signature is None:
- signature = subscriber.getSignatureFromRid(gid)
#LOG('applyActionList', DEBUG, 'previous signature: %s' % str(signature))
previous_xml = signature.getXML()
conflict_list += conduit.updateNode(
@@ -995,7 +1054,8 @@
previous_xml=signature.getXML(),
force=force,
simulate=simulate)
- xml_object = domain.getXMLFromObject(object)
+ xml_object = conduit.getXMLFromObjectWithId(object,\
+ xml_mapping=domain.getXMLMapping())
signature.setTempXML(xml_object)
if conflict_list:
status_code = self.CONFLICT
@@ -1019,7 +1079,8 @@
#LOG('applyActionList, subscriber_xupdate:', TRACE, data_subnode_string)
signature.setSubscriberXupdate(data_subnode_string)
- elif action.tag == 'Delete':
+ elif action.xpath('local-name()') == 'Delete':
+ LOG("applyactionlist delete",INFO,"")
object_id = signature.getId()
#LOG('applyActionList Delete on : ', DEBUG, (signature.getId(), subscriber.getObjectFromGid(object_id)))
if subscriber.getMediaType() != self.MEDIA_TYPE['TEXT_XML']:
@@ -1049,7 +1110,7 @@
#LOG('applyActionList', DEBUG, 'waiting more data for :%s' % signature.getId())
xml_confirmation_list.append(self.SyncMLConfirmation(
cmd_id=cmd_id,
- cmd=action.tag,
+ cmd= "%s" % action.xpath('name()'),
sync_code=self.WAITING_DATA,
remote_xml=action))
if conflict_list and signature is not None:
@@ -1074,11 +1135,13 @@
if not object_gid:
object_gid = status['target']
status_code = int(status['code'])
+ signature = subscriber.getSignatureFromGid(object_gid)
+ if signature is None and\
+ not(subscriber.getSynchronizeWithERP5Sites()):
+ #the client give his id but not the gid
+ signature = subscriber.getSignatureFromRid(object_gid)
if status_cmd in ('Add', 'Replace',):
has_status_list = 1
- signature = subscriber.getSignatureFromGid(object_gid)
- if signature is None:
- signature = subscriber.getSignatureFromRid(object_gid)
if status_code == self.CHUNK_OK:
destination_waiting_more_data = 1
signature.setStatus(self.PARTIAL)
@@ -1097,14 +1160,9 @@
elif status_cmd == 'Delete':
has_status_list = 1
if status_code == self.SUCCESS:
- signature = subscriber.getSignatureFromGid(object_gid)
- if signature is None and \
- not(subscriber.getSynchronizeWithERP5Sites()):
- signature = subscriber.getSignatureFromRid(object_gid)
if signature is not None:
subscriber.delSignature(signature.getGid())
return (destination_waiting_more_data, has_status_list)
-
class XMLSyncUtils(XMLSyncUtilsMixin):
@@ -1152,7 +1210,8 @@
#LOG('SyncModif', DEBUG, 'Starting... domain: %s' % domain.getId())
# Get informations from the header
xml_header = remote_xml[0]
- if xml_header.tag != "SyncHdr":
+ #FIXME to apply a DTD or schema
+ if xml_header.xpath('local-name()') != "SyncHdr":
LOG('SyncModif', INFO, 'This is not a SyncML Header')
raise ValueError, "Sorry, This is not a SyncML Header"
@@ -1210,7 +1269,9 @@
subscriber=subscriber,
remote_xml=remote_xml,
conduit=conduit, simulate=simulate)
- xml = Element('SyncML')
+
+ nsmap = {None : self.XHTML_NAMESPACE}
+ xml = Element('SyncML', nsmap=nsmap)
# syncml header
if domain.domain_type == self.PUB:
@@ -1358,7 +1419,10 @@
def sendSyncModif(self, syncml_data_list, cmd_id_before_getsyncmldata,
subscriber, domain, xml_confirmation_list, remote_xml,
xml_tree, has_status_list, has_response):
+ # XXX the better is a namespace for all
sync_body = xml_tree.find('SyncBody')
+ if sync_body is None:
+ sync_body = xml_tree.xpath('syncml:SyncBody')[0]
if syncml_data_list:
sync_node = SubElement(sync_body, 'Sync')
cmd_id_node = SubElement(sync_node, 'CmdID')
@@ -1372,14 +1436,19 @@
for syncml_data in syncml_data_list:
sync_node.append(etree.XML(syncml_data, parser=parser))
for xml_confirmation in xml_confirmation_list:
- if not isinstance(xml_confirmation, str):
- sync_body.append(xml_confirmation)
- else:
- sync_body.append(etree.XML(xml_confirmation, parser=parser))
- sync_body.append(Element('Final'))
- xml_string = etree.tostring(xml_tree, encoding='utf-8', pretty_print=True)
-
+ if isinstance(xml_confirmation, str):
+ xml_confirmation = etree.XML(xml_confirmation, parser=parser)
+ sync_body.append(xml_confirmation)
+
+ self.sync_finished = 0
if domain.domain_type == self.PUB: # We always reply
+ # When the publication recieved the response Final and the modification
+ # data is finished so the publication send the tag "Final"
+ if not self.checkSync(remote_xml) and not xml_confirmation_list\
+ and not syncml_data_list and self.checkFinal(remote_xml):
+ sync_body.append(Element('Final'))
+ self.sync_finished = 1
+ xml_string = etree.tostring(xml_tree, encoding='utf-8', pretty_print=True)
subscriber.setLastSentMessage(xml_string)
self.sendResponse(
from_url=domain.publication_url,
@@ -1388,13 +1457,20 @@
xml=xml_string,
domain=domain,
content_type=domain.getSyncContentType())
- if not syncml_data_list:
+ if self.sync_finished == 1:
LOG('this is the end of the synchronisation session from PUB !!!', INFO, domain.getId())
subscriber.setAuthenticated(False)
domain.setAuthenticated(False)
has_response = 1
elif domain.domain_type == self.SUB:
- if self.checkAlert(remote_xml) or xml_confirmation_list or syncml_data_list:
+ # the modification data is finished on the subscription so the tag
+ # "Final" sent to the publication
+ if not self.checkAlert(remote_xml) and not xml_confirmation_list\
+ and not syncml_data_list:
+ sync_body.append(Element('Final'))
+ self.sync_finished = 1
+ xml_string = etree.tostring(xml_tree, encoding='utf-8', pretty_print=True)
+ if not self.sync_finished or not self.checkFinal(remote_xml):
subscriber.setLastSentMessage(xml_string)
self.sendResponse(
from_url=domain.subscription_url,
@@ -1403,6 +1479,7 @@
xml=xml_string, domain=domain,
content_type=domain.getSyncContentType())
has_response = 1
+ #When the receive the final element and the sub finished synchronization
else:
if domain.isOneWayFromServer():
self.deleteRemainObjectList(domain, subscriber)
@@ -1453,17 +1530,22 @@
xml_client = self.readResponse(from_url=publication.getPublicationUrl())
#LOG('PubSync', DEBUG, 'Starting... msg: %s' % str(xml_client))
result = None
-
if xml_client is not None:
if isinstance(xml_client, (str, unicode)):
xml_client = etree.XML(xml_client, parser=parser)
- if xml_client.tag != "SyncML":
+ if len(xml_client.nsmap) ==1:
+ namespace = xml_client.nsmap[None]
+ else :
+ namespace = xml_client.nsmap['syncml']
+ #FIXME to apply a DTD or schema
+ if xml_client.xpath('local-name()') != "SyncML":
LOG('PubSync', INFO, 'This is not a SyncML Message')
raise ValueError, "Sorry, This is not a SyncML Message"
alert_code = self.getAlertCodeFromXML(xml_client)
# Get informations from the header
client_header = xml_client[0]
- if client_header.tag != "SyncHdr":
+ #FIXME to apply a DTD or schema
+ if client_header.xpath('local-name()') != "SyncHdr":
LOG('PubSync', INFO, 'This is not a SyncML Header')
raise ValueError, "Sorry, This is not a SyncML Header"
subscription_url = self.getSubscriptionUrlFromXML(client_header)
@@ -1560,7 +1642,3 @@
else:
return response
- def getActivityType(self, domain):
- if domain.getActivityEnabled():
- return 'SQLQueue'
- return 'RAMQueue'
Modified: erp5/trunk/products/ERP5SyncML/tests/testERP5SyncML.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/tests/testERP5SyncML.py?rev=28229&r1=28228&r2=28229&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/tests/testERP5SyncML.py [utf8] (original)
+++ erp5/trunk/products/ERP5SyncML/tests/testERP5SyncML.py [utf8] Thu Jul 30 14:34:54 2009
@@ -35,6 +35,9 @@
from Products.ERP5SyncML.SyncCode import SyncCode
from zLOG import LOG
from base64 import b64encode, b64decode, b16encode, b16decode
+import transaction
+from ERP5Diff import ERP5Diff
+from lxml import etree
class TestERP5SyncMLMixin:
@@ -72,10 +75,12 @@
nb_subscription = 2
nb_publication = 1
nb_synchronization = 3
- nb_message_first_synchronization = 8
+ nb_message_first_synchronization = 10
+ nb_message_first_sync_max_lines = 10
subscription_url1 = 'file://tmp/sync_client1'
subscription_url2 = 'file://tmp/sync_client2'
publication_url = 'file://tmp/sync_server'
+ activity_enabled = False
#publication_url = 'server at localhost'
#subscription_url1 = 'client1 at localhost'
#subscription_url2 = 'client2 at localhost'
@@ -126,12 +131,12 @@
uf._doAddUser('syncml', '', ['Manager'], [])
user = uf.getUserById('fab').__of__(uf)
newSecurityManager(None, user)
-
- def populatePersonServer(self, quiet=0, run=0):
- if not run: return
- if not quiet:
- ZopeTestCase._print('\nTest Populate Person Server ')
- LOG('Testing... ',0,'populatePersonServer')
+
+ def initPersonModule(self, quiet=0, run=0):
+ if not run: return
+ if not quiet:
+ ZopeTestCase._print('\nTest Init Person Module')
+ LOG('Testing... ',0,'initPersonModule')
self.login()
portal = self.getPortal()
if not hasattr(portal,'person_server'):
@@ -146,13 +151,21 @@
portal.portal_types.constructContent(type_name = 'Person Module',
container = portal,
id = 'person_client2')
- person_id = ''
- person_server = self.getPersonServer()
- person1 = person_server.newContent(id=self.id1,portal_type='Person')
+
+ def populatePersonServer(self, quiet=0, run=0):
+ if not run: return
+ if not quiet:
+ ZopeTestCase._print('\nTest Populate Person Server ')
+ LOG('Testing... ',0,'populatePersonServer')
+ self.login()
+ portal = self.getPortal()
+ self.initPersonModule(quiet=1, run=1)
+ person_server = self.getPersonServer()
+ person1 = person_server.newContent(id=self.id1, portal_type='Person')
kw = {'first_name':self.first_name1,'last_name':self.last_name1,
'description':self.description1}
person1.edit(**kw)
- person2 = person_server.newContent(id=self.id2,portal_type='Person')
+ person2 = person_server.newContent(id=self.id2, portal_type='Person')
kw = {'first_name':self.first_name2,'last_name':self.last_name2,
'description':self.description2}
person2.edit(**kw)
@@ -160,6 +173,24 @@
self.assertEqual(nb_person, 2)
return nb_person
+ def populatePersonClient1(self, quiet=0, run=0):
+ if not run: return
+ if not quiet:
+ ZopeTestCase._print('\nTest Populate Person Client 1 ')
+ LOG('Testing... ',0,'populatePersonClient1')
+ self.login()
+ portal = self.getPortal()
+ self.initPersonModule(quiet=1, run=1)
+ person_client = self.getPersonClient1()
+ for id in range(1, 60):
+ person = person_client.newContent(id=id, portal_type='Person')
+ kw = {'first_name':self.first_name1,'last_name':self.last_name1,
+ 'description':self.description1}
+ person.edit(**kw)
+ nb_person = len(person_client.objectValues())
+ self.assertEqual(nb_person,59)
+ return nb_person
+
def synchronize(self, id, run=1):
"""
This just define how we synchronize, we have
@@ -168,25 +199,31 @@
portal_sync = self.getSynchronizationTool()
subscription = portal_sync.getSubscription(id)
publication = None
- for publication in portal_sync.getPublicationList():
- if publication.getPublicationUrl()==subscription.getSubscriptionUrl():
- publication = publication
- self.failUnless(publication is not None)
+ for pub in portal_sync.getPublicationList():
+ if pub.getPublicationUrl()==subscription.getPublicationUrl():
+ publication = pub
+ self.assertTrue(publication is not None)
# reset files, because we do sync by files
- file = open('/tmp/sync_client1','w')
+ file = open('/tmp/sync_client1', 'w')
file.write('')
file.close()
- file = open('/tmp/sync_client2','w')
+ file = open('/tmp/sync_client2', 'w')
file.write('')
file.close()
- file = open('/tmp/sync','w')
+ file = open('/tmp/sync_server', 'w')
file.write('')
file.close()
nb_message = 1
result = portal_sync.SubSync(subscription.getPath())
while result['has_response']==1:
portal_sync.PubSync(publication.getPath())
+ if self.activity_enabled:
+ transaction.commit()
+ self.tic()
result = portal_sync.SubSync(subscription.getPath())
+ if self.activity_enabled:
+ transaction.commit()
+ self.tic()
nb_message += 1 + result['has_response']
return nb_message
@@ -199,18 +236,18 @@
#portal_sync.email = None # XXX To be removed
subscription = portal_sync.getSubscription(id)
publication = None
- for publication in portal_sync.getPublicationList():
- if publication.getPublicationUrl()==subscription.getSubscriptionUrl():
- publication = publication
- self.failUnless(publication is not None)
+ for pub in portal_sync.getPublicationList():
+ if pub.getPublicationUrl()==subscription.getPublicationUrl():
+ publication = pub
+ self.assertTrue(publication is not None)
# reset files, because we do sync by files
- file = open('/tmp/sync_client1','w')
+ file = open('/tmp/sync_client1', 'w')
file.write('')
file.close()
- file = open('/tmp/sync_client2','w')
+ file = open('/tmp/sync_client2', 'w')
file.write('')
file.close()
- file = open('/tmp/sync','w')
+ file = open('/tmp/sync_server', 'w')
file.write('')
file.close()
nb_message = 1
@@ -219,11 +256,29 @@
# We do thing three times, so that we will test
# if we manage well duplicate messages
portal_sync.PubSync(publication.getPath())
+ if self.activity_enabled:
+ transaction.commit()
+ self.tic()
portal_sync.PubSync(publication.getPath())
+ if self.activity_enabled:
+ transaction.commit()
+ self.tic()
portal_sync.PubSync(publication.getPath())
+ if self.activity_enabled:
+ transaction.commit()
+ self.tic()
result = portal_sync.SubSync(subscription.getPath())
+ if self.activity_enabled:
+ transaction.commit()
+ self.tic()
result = portal_sync.SubSync(subscription.getPath())
+ if self.activity_enabled:
+ transaction.commit()
+ self.tic()
result = portal_sync.SubSync(subscription.getPath())
+ if self.activity_enabled:
+ transaction.commit()
+ self.tic()
nb_message += 1 + result['has_response']
return nb_message
@@ -254,16 +309,6 @@
for m in sub.getSignatureList():
self.assertEquals(m.getPartialXML(),None)
- def verifyFirstNameAndLastNameAreSynchronized(self, first_name,
- last_name, person_server, person_client):
- """
- verify if the first and last name are synchronized
- """
- self.assertEqual(person_server.getFirstName(), first_name)
- self.assertEqual(person_server.getLastName(), last_name)
- self.assertEqual(person_client.getFirstName(), first_name)
- self.assertEqual(person_client.getLastName(), last_name)
-
def verifyFirstNameAndLastNameAreNotSynchronized(self, first_name,
last_name, person_server, person_client):
"""
@@ -297,7 +342,54 @@
self.assertEqual(person2_c.getId(), id)
self.assertEqual(person2_c.getFirstName(), self.first_name1)
self.assertEqual(person2_c.getLastName(), self.last_name1)
-
+
+ def resetSignaturePublicationAndSubscription(self):
+ portal_sync = self.getSynchronizationTool()
+ publication = portal_sync.getPublication(self.pub_id)
+ subscription1 = portal_sync.getSubscription(self.sub_id1)
+ subscription2 = portal_sync.getSubscription(self.sub_id2)
+ publication.resetAllSubscribers()
+ subscription1.resetAllSignatures()
+ transaction.commit()
+ self.tic()
+
+ def assertXMLViewIsEqual(self, sub_id, object_pub=None, object_sub=None,\
+ force=0):
+ """
+ Check the equality between two xml objects with gid as id
+ """
+ portal_sync = self.getSynchronizationTool()
+ subscription = portal_sync.getSubscription(sub_id)
+ publication = portal_sync.getPublication(self.pub_id)
+ gid_pub = publication.getGidFromObject(object_pub)
+ gid_sub = publication.getGidFromObject(object_sub)
+ self.assertEqual(gid_pub, gid_sub)
+ conduit = ERP5Conduit()
+ xml_pub = conduit.getXMLFromObjectWithGid(object=object_pub, gid=gid_pub,\
+ xml_mapping=publication.getXMLMapping())
+ #if One Way From Server there is not xml_mapping for subscription
+ xml_sub = conduit.getXMLFromObjectWithGid(object=object_sub, gid=gid_sub,\
+ xml_mapping=subscription.getXMLMapping(force))
+ erp5diff = ERP5Diff()
+ erp5diff.compare(xml_pub, xml_sub)
+ result = erp5diff.outputString()
+ result = etree.XML(result)
+ if len(result) != 0 :
+ for update in result:
+ #XXX edit workflow is not replaced, so discard workflow checking
+ if update.get('select').find('time') != -1 or\
+ update.get('select').find('serial') !=1:
+ continue
+ else :
+ self.fail('diff between pub:\n%s \nand sub:\n%s \n => \n%s' %\
+ (xml_pub, xml_sub, etree.tostring(result, pretty_print=True)))
+
+ def deletePublicationAndSubscription(self):
+ portal_sync = self.getSynchronizationTool()
+ portal_sync.manage_deletePublication(title=self.pub_id)
+ portal_sync.manage_deleteSubscription(title=self.sub_id1)
+ if portal_sync.getSubscription(title=self.sub_id2):
+ portal_sync.manage_deleteSubscription(title=self.sub_id2)
class TestERP5SyncML(TestERP5SyncMLMixin, ERP5TypeTestCase):
@@ -306,6 +398,123 @@
"""
"""
return "ERP5 SyncML"
+
+ def setupPublicationAndSubscription(self, quiet=0, run=run_all_test):
+ portal_sync = self.getSynchronizationTool()
+ person_server = self.getPersonServer()
+ if person_server is not None:
+ portal = self.getPortal()
+ portal._delObject(id='person_server')
+ portal._delObject(id='person_client1')
+ portal._delObject(id='person_client2')
+ self.deletePublicationAndSubscription()
+ 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):
+ self.setupPublicationAndSubscription(quiet=1,run=1)
+ portal_sync = self.getSynchronizationTool()
+ sub1 = portal_sync.getSubscription(self.sub_id1)
+ sub2 = portal_sync.getSubscription(self.sub_id2)
+ pub = portal_sync.getPublication(self.pub_id)
+ sub1.setConduit('ERP5ConduitTitleGid')
+ sub2.setConduit('ERP5ConduitTitleGid')
+ pub.setConduit('ERP5ConduitTitleGid')
+ pub.setSynchronizationIdGenerator('_generateNextId')
+ sub1.setSynchronizationIdGenerator('_generateNextId')
+ sub2.setSynchronizationIdGenerator('_generateNextId')
+
+ def checkSynchronizationStateIsConflict(self, quiet=0, run=1):
+ portal_sync = self.getSynchronizationTool()
+ person_server = self.getPersonServer()
+ for person in person_server.objectValues():
+ if person.getId()==self.id1:
+ state_list = portal_sync.getSynchronizationState(person)
+ for state in state_list:
+ self.assertEqual(state[1], state[0].CONFLICT)
+ person_client1 = self.getPersonClient1()
+ for person in person_client1.objectValues():
+ if person.getId()==self.id1:
+ state_list = portal_sync.getSynchronizationState(person)
+ for state in state_list:
+ self.assertEqual(state[1], state[0].CONFLICT)
+ person_client2 = self.getPersonClient2()
+ for person in person_client2.objectValues():
+ if person.getId()==self.id1:
+ state_list = portal_sync.getSynchronizationState(person)
+ for state in state_list:
+ self.assertEqual(state[1], state[0].CONFLICT)
+ # make sure sub object are also in a conflict mode
+ person = person_client1._getOb(self.id1)
+ # use a temp_object to create a no persistent object in person
+ sub_person =\
+ person.newContent(id=self.id1, portal_type='Person', temp_object=1)
+ state_list = portal_sync.getSynchronizationState(sub_person)
+ for state in state_list:
+ self.assertEqual(state[1], state[0].CONFLICT)
+
+ def populatePersonServerWithSubObject(self, quiet=0, run=run_all_test):
+ """
+ Before this method, we need to call populatePersonServer
+ Then it will give the following tree :
+ - person_server :
+ - id1
+ - id1
+ - id2
+ - id1
+ - id2
+ """
+ if not run: return
+ if not quiet:
+ ZopeTestCase._print('\nTest Populate Person Server With Sub Object ')
+ LOG('Testing... ',0,'populatePersonServerWithSubObject')
+ person_server = self.getPersonServer()
+ person1 = person_server._getOb(self.id1)
+ sub_person1 = person1.newContent(id=self.id1, portal_type='Person')
+ kw = {'first_name':self.first_name1,'last_name':self.last_name1,
+ 'description':self.description1}
+ sub_person1.edit(**kw)
+ sub_sub_person1 = sub_person1.newContent(id=self.id1, portal_type='Person')
+ kw = {'first_name':self.first_name1,'last_name':self.last_name1,
+ 'description':self.description1, 'default_telephone_text':'0689778308'}
+ sub_sub_person1.edit(**kw)
+ sub_sub_person2 = sub_person1.newContent(id=self.id2, portal_type='Person')
+ kw = {'first_name':self.first_name2,'last_name':self.last_name2,
+ 'description':self.description2}
+ sub_sub_person2.edit(**kw)
+ # remove ('','portal...','person_server')
+ len_path = len(sub_sub_person1.getPhysicalPath()) - 3
+ self.assertEqual(len_path, 3)
+ len_path = len(sub_sub_person2.getPhysicalPath()) - 3
+ self.assertEqual(len_path, 3)
+
+ def addAuthenticationToPublication(self, publication_id, login, password,
+ auth_format, auth_type):
+ """
+ add authentication to the publication
+ """
+ portal_sync = self.getSynchronizationTool()
+ pub = portal_sync.getPublication(publication_id)
+ pub.setLogin(login)
+ pub.setPassword(password)
+ pub.setAuthenticationFormat(auth_format)
+ pub.setAuthenticationType(auth_type)
+
+
+ def addAuthenticationToSubscription(self, subscription_id, login, password,
+ auth_format, auth_type):
+ """
+ add authentication to the subscription
+ """
+ portal_sync = self.getSynchronizationTool()
+ sub = portal_sync.getSubscription(subscription_id)
+ sub.setAuthenticated(False)
+ sub.setLogin(login)
+ sub.setPassword(password)
+ sub.setAuthenticationFormat(auth_format)
+ sub.setAuthenticationType(auth_type)
+
def test_01_HasEverything(self, quiet=0, run=run_all_test):
# Test if portal_synchronizations was created
@@ -325,6 +534,8 @@
LOG('Testing... ',0,'test_02_AddPublication')
portal_id = self.getPortalName()
portal_sync = self.getSynchronizationTool()
+ if portal_sync.getPublication(self.pub_id) is not None:
+ portal_sync.manage_deletePublication(title=self.pub_id)
portal_sync.manage_addPublication(title=self.pub_id,
publication_url=self.publication_url,
destination_path='/%s/person_server' % portal_id,
@@ -333,7 +544,7 @@
xml_mapping=self.xml_mapping,
conduit='ERP5Conduit',
gpg_key='',
- activity_enabled=False,
+ activity_enabled=self.activity_enabled,
authentication_format='b64',
authentication_type='syncml:auth-basic')
pub = portal_sync.getPublication(self.pub_id)
@@ -346,6 +557,8 @@
LOG('Testing... ',0,'test_03_AddSubscription1')
portal_id = self.getPortalId()
portal_sync = self.getSynchronizationTool()
+ if portal_sync.getSubscription(self.sub_id1) is not None:
+ portal_sync.manage_deleteSubscription(title=self.sub_id1)
portal_sync.manage_addSubscription(title=self.sub_id1,
publication_url=self.publication_url,
subscription_url=self.subscription_url1,
@@ -356,7 +569,7 @@
xml_mapping=self.xml_mapping,
conduit='ERP5Conduit',
gpg_key='',
- activity_enabled=False,
+ activity_enabled=self.activity_enabled,
login='fab',
password='myPassword')
sub = portal_sync.getSubscription(self.sub_id1)
@@ -369,6 +582,8 @@
LOG('Testing... ',0,'test_04_AddSubscription2')
portal_id = self.getPortalId()
portal_sync = self.getSynchronizationTool()
+ if portal_sync.getSubscription(self.sub_id2) is not None:
+ portal_sync.manage_deleteSubscription(title=self.sub_id2)
portal_sync.manage_addSubscription(title=self.sub_id2,
publication_url=self.publication_url,
subscription_url=self.subscription_url2,
@@ -379,29 +594,11 @@
xml_mapping=self.xml_mapping,
conduit='ERP5Conduit',
gpg_key='',
- activity_enabled=False,
+ activity_enabled=self.activity_enabled,
login='fab',
password='myPassword')
sub = portal_sync.getSubscription(self.sub_id2)
self.failUnless(sub is not None)
-
- def setupPublicationAndSubscription(self, quiet=0, run=run_all_test):
- 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):
- self.setupPublicationAndSubscription(quiet=1,run=1)
- portal_sync = self.getSynchronizationTool()
- sub1 = portal_sync.getSubscription(self.sub_id1)
- sub2 = portal_sync.getSubscription(self.sub_id2)
- pub = portal_sync.getPublication(self.pub_id)
- sub1.setConduit('ERP5ConduitTitleGid')
- sub2.setConduit('ERP5ConduitTitleGid')
- pub.setConduit('ERP5ConduitTitleGid')
- pub.setSynchronizationIdGenerator('_generateNextId')
- sub1.setSynchronizationIdGenerator('_generateNextId')
- sub2.setSynchronizationIdGenerator('_generateNextId')
def test_05_GetSynchronizationList(self, quiet=0, run=run_all_test):
# This test the getSynchronizationList, ie,
@@ -445,6 +642,12 @@
publication.setQuery(query)
object_list = publication.getObjectList()
self.assertEqual(len(object_list), 1)
+ # Add the query path
+ portal_id = self.getPortalName()
+ publication.setDestinationPath('/%s/' % portal_id)
+ publication.setQuery('person_server/objectValues')
+ object_list = publication.getObjectList()
+ self.assertEqual(len(object_list), nb_person)
def test_07_ExportImport(self, quiet=0, run=run_all_test):
"""
@@ -527,9 +730,7 @@
self.assertEqual(person1_s.getLastName(), self.last_name1)
person_client1 = self.getPersonClient1()
person1_c = person_client1._getOb(self.id1)
- self.assertEqual(person1_c.getId(), self.id1)
- self.assertEqual(person1_c.getFirstName(), long_line)
- self.assertEqual(person1_c.getLastName(), self.last_name1)
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c)
def test_10_GetObjectFromGid(self, quiet=0, run=run_all_test):
# We will try to get an object from a publication
@@ -569,33 +770,6 @@
# for each subscriber
self.checkSynchronizationStateIsSynchronized()
- def checkSynchronizationStateIsConflict(self, quiet=0, run=1):
- portal_sync = self.getSynchronizationTool()
- person_server = self.getPersonServer()
- for person in person_server.objectValues():
- if person.getId()==self.id1:
- state_list = portal_sync.getSynchronizationState(person)
- for state in state_list:
- self.assertEqual(state[1], state[0].CONFLICT)
- person_client1 = self.getPersonClient1()
- for person in person_client1.objectValues():
- if person.getId()==self.id1:
- state_list = portal_sync.getSynchronizationState(person)
- for state in state_list:
- self.assertEqual(state[1], state[0].CONFLICT)
- person_client2 = self.getPersonClient2()
- for person in person_client2.objectValues():
- if person.getId()==self.id1:
- state_list = portal_sync.getSynchronizationState(person)
- for state in state_list:
- self.assertEqual(state[1], state[0].CONFLICT)
- # make sure sub object are also in a conflict mode
- person = person_client1._getOb(self.id1)
- sub_person = person.newContent(id=self.id1,portal_type='Person')
- state_list = portal_sync.getSynchronizationState(sub_person)
- for state in state_list:
- self.assertEqual(state[1], state[0].CONFLICT)
-
def test_12_UpdateSimpleData(self, quiet=0, run=run_all_test):
if not run: return
if not quiet:
@@ -614,32 +788,29 @@
person1_c = person_client1._getOb(self.id1)
self.assertEqual(person1_s.getFirstName(), self.first_name3)
self.assertEqual(person1_s.getLastName(), self.last_name3)
- self.assertEqual(person1_c.getFirstName(), self.first_name3)
- self.assertEqual(person1_c.getLastName(), self.last_name3)
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c)
# Then we do only modification on a client
kw = {'first_name':self.first_name1,'last_name':self.last_name1}
person1_c.edit(**kw)
#person1_c.setModificationDate(DateTime()+1)
self.synchronize(self.sub_id1)
self.checkSynchronizationStateIsSynchronized()
+ #person1_s = person_server._getOb(self.id1)
self.assertEqual(person1_s.getFirstName(), self.first_name1)
self.assertEqual(person1_s.getLastName(), self.last_name1)
- self.assertEqual(person1_c.getFirstName(), self.first_name1)
- self.assertEqual(person1_c.getLastName(), self.last_name1)
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c)
# Then we do only modification on both the client and the server
# and of course, on the same object
kw = {'first_name':self.first_name3}
person1_s.edit(**kw)
- #person1_s.setModificationDate(DateTime()+2)
kw = {'description':self.description3}
person1_c.edit(**kw)
- #person1_c.setModificationDate(DateTime()+2)
- self.synchronize(self.sub_id1)
- self.checkSynchronizationStateIsSynchronized()
+ self.synchronize(self.sub_id1)
+ self.checkSynchronizationStateIsSynchronized()
+ #person1_s = person_server._getOb(self.id1)
self.assertEqual(person1_s.getFirstName(), self.first_name3)
self.assertEqual(person1_s.getDescription(), self.description3)
- self.assertEqual(person1_c.getFirstName(), self.first_name3)
- self.assertEqual(person1_c.getDescription(), self.description3)
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c)
def test_13_GetConflictList(self, quiet=0, run=run_all_test):
# We will try to generate a conflict and then to get it
@@ -709,7 +880,7 @@
self.synchronize(self.sub_id1)
self.checkSynchronizationStateIsSynchronized()
self.assertEqual(person1_c.getDescription(), self.description2)
- self.assertEqual(person1_s.getDescription(), self.description2)
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c)
conflict_list = portal_sync.getConflictList()
self.assertEqual(len(conflict_list), 0)
@@ -732,44 +903,9 @@
self.synchronize(self.sub_id1)
self.checkSynchronizationStateIsSynchronized()
self.assertEqual(person1_s.getDescription(), self.description3)
- self.assertEqual(person1_c.getDescription(), self.description3)
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c)
conflict_list = portal_sync.getConflictList()
self.assertEqual(len(conflict_list), 0)
-
- def populatePersonServerWithSubObject(self, quiet=0, run=run_all_test):
- """
- Before this method, we need to call populatePersonServer
- Then it will give the following tree :
- - person_server :
- - id1
- - id1
- - id2
- - id1
- - id2
- """
- if not run: return
- if not quiet:
- ZopeTestCase._print('\nTest Populate Person Server With Sub Object ')
- LOG('Testing... ',0,'populatePersonServerWithSubObject')
- person_server = self.getPersonServer()
- person1 = person_server._getOb(self.id1)
- sub_person1 = person1.newContent(id=self.id1,portal_type='Person')
- kw = {'first_name':self.first_name1,'last_name':self.last_name1,
- 'description':self.description1}
- sub_person1.edit(**kw)
- sub_sub_person1 = sub_person1.newContent(id=self.id1,portal_type='Person')
- kw = {'first_name':self.first_name1,'last_name':self.last_name1,
- 'description':self.description1, 'default_telephone_text':'0689778308'}
- sub_sub_person1.edit(**kw)
- sub_sub_person2 = sub_person1.newContent(id=self.id2,portal_type='Person')
- kw = {'first_name':self.first_name2,'last_name':self.last_name2,
- 'description':self.description2}
- sub_sub_person2.edit(**kw)
- # remove ('','portal...','person_server')
- len_path = len(sub_sub_person1.getPhysicalPath()) - 3
- self.assertEqual(len_path, 3)
- len_path = len(sub_sub_person2.getPhysicalPath()) - 3
- self.assertEqual(len_path, 3)
def test_17_AddSubObject(self, quiet=0, run=run_all_test):
"""
@@ -803,6 +939,10 @@
self.assertEquals(sub_sub_person2.getDescription(), self.description2)
self.assertEquals(sub_sub_person2.getFirstName(), self.first_name2)
self.assertEquals(sub_sub_person2.getLastName(), self.last_name2)
+ #check two side (client, server)
+ person_server = self.getPersonServer()
+ sub_sub_person_s = person_server._getOb(self.id1)._getOb(self.id1)._getOb(self.id1)
+ self.assertXMLViewIsEqual(self.sub_id1, sub_sub_person_s, sub_sub_person1)
def test_18_UpdateSubObject(self, quiet=0, run=run_all_test):
"""
@@ -831,8 +971,7 @@
self.checkSynchronizationStateIsSynchronized()
self.assertEqual(sub_sub_person_c.getDescription(), self.description3)
self.assertEqual(sub_sub_person_c.getFirstName(), self.first_name3)
- self.assertEqual(sub_sub_person_s.getDescription(), self.description3)
- self.assertEqual(sub_sub_person_s.getFirstName(), self.first_name3)
+ self.assertXMLViewIsEqual(self.sub_id1, sub_sub_person_s, sub_sub_person_c)
def test_19_DeleteObject(self, quiet=0, run=run_all_test):
"""
@@ -951,10 +1090,8 @@
self.checkSynchronizationStateIsSynchronized()
self.assertEqual(sub_object_s.getDescription(), self.description2)
self.assertEqual(sub_object_s.getLanguage(), self.lang2)
- self.assertEqual(sub_object_c1.getDescription(), self.description2)
- self.assertEqual(sub_object_c1.getLanguage(), self.lang2)
- self.assertEqual(sub_object_c2.getDescription(), self.description2)
- self.assertEqual(sub_object_c2.getLanguage(), self.lang2)
+ self.assertXMLViewIsEqual(self.sub_id1, sub_object_s, sub_object_c1)
+ self.assertXMLViewIsEqual(self.sub_id2, sub_object_s, sub_object_c2)
def test_23_ApplySubscriberDocumentOnSubObject(self, quiet=0, run=run_all_test):
"""
@@ -981,10 +1118,8 @@
self.checkSynchronizationStateIsSynchronized()
self.assertEqual(sub_object_s.getDescription(), self.description3)
self.assertEqual(sub_object_s.getLanguage(), self.lang3)
- self.assertEqual(sub_object_c1.getDescription(), self.description3)
- self.assertEqual(sub_object_c1.getLanguage(), self.lang3)
- self.assertEqual(sub_object_c2.getDescription(), self.description3)
- self.assertEqual(sub_object_c2.getLanguage(), self.lang3)
+ self.assertXMLViewIsEqual(self.sub_id1, sub_object_s, sub_object_c1)
+ self.assertXMLViewIsEqual(self.sub_id2, sub_object_s, sub_object_c2)
def test_24_SynchronizeWithStrangeGid(self, quiet=0, run=run_all_test):
"""
@@ -1021,6 +1156,7 @@
self.checkSynchronizationStateIsSynchronized()
self.assertEqual(person_s.getDescription(), self.description3)
self.assertEqual(person_c1.getDescription(), self.description3)
+ self.assertXMLViewIsEqual(self.sub_id1, person_s, person_c1)
# This will test deleting object
person_server = self.getPersonServer()
person_client1 = self.getPersonClient1()
@@ -1032,7 +1168,7 @@
person_s = publication.getSubscriber(self.subscription_url1).getObjectFromGid(gid)
person_c1 = subscription1.getObjectFromGid(gid)
self.assertEqual(person_s.getDescription(), self.description3)
- self.assertEqual(person_c1.getDescription(), self.description3)
+ self.assertXMLViewIsEqual(self.sub_id1, person_s, person_c1)
def test_25_MultiNodeConflict(self, quiet=0, run=run_all_test):
"""
@@ -1066,12 +1202,12 @@
self.assertEqual(len(conflict_list), 6)
# check if we have the state conflict on all clients
self.checkSynchronizationStateIsConflict()
-
# we will take :
# description on person_server
# language on person_client1
# format on person_client2
- for conflict in conflict_list:
+
+ for conflict in conflict_list :
subscriber = conflict.getSubscriber()
property = conflict.getPropertyId()
resolve = 0
@@ -1088,15 +1224,18 @@
self.synchronize(self.sub_id1)
self.synchronize(self.sub_id2)
self.checkSynchronizationStateIsSynchronized()
+ self.assertEqual(person1_c1.getDescription(), self.description2)
+ self.assertEqual(person1_c1.getLanguage(), self.lang3)
+ self.assertEqual(person1_c1.getFormat(), self.format4)
self.assertEqual(person1_s.getDescription(), self.description2)
- self.assertEqual(person1_c1.getDescription(), self.description2)
- self.assertEqual(person1_c2.getDescription(), self.description2)
self.assertEqual(person1_s.getLanguage(), self.lang3)
- self.assertEqual(person1_c1.getLanguage(), self.lang3)
- self.assertEqual(person1_c2.getLanguage(), self.lang3)
self.assertEqual(person1_s.getFormat(), self.format4)
- self.assertEqual(person1_c1.getFormat(), self.format4)
- self.assertEqual(person1_c2.getFormat(), self.format4)
+ self.assertXMLViewIsEqual(self.sub_id2, person1_s, person1_c2)
+ # the workflow has one more "edit_workflow" in person1_c1
+ self.synchronize(self.sub_id1)
+ self.synchronize(self.sub_id2)
+ self.assertXMLViewIsEqual(self.sub_id2, person1_s, person1_c2)
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c1)
def test_26_SynchronizeWorkflowHistory(self, quiet=0, run=run_all_test):
@@ -1123,6 +1262,7 @@
person1_c.edit(**kw1)
self.synchronize(self.sub_id1)
self.checkSynchronizationStateIsSynchronized()
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c)
self.assertEqual(len(person1_s.workflow_history[self.workflow_id]), len_wf+4)
self.assertEqual(len(person1_c.workflow_history[self.workflow_id]), len_wf+4)
@@ -1152,6 +1292,8 @@
person2_s.manage_delLocalRoles(['fab'])
self.synchronize(self.sub_id1)
self.synchronize(self.sub_id2)
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c)
+ self.assertXMLViewIsEqual(self.sub_id2, person2_s, person2_c)
role_1_s = person1_s.get_local_roles()
role_2_s = person2_s.get_local_roles()
role_1_c = person1_c.get_local_roles()
@@ -1220,14 +1362,12 @@
person_server = self.getPersonServer() # We also check we don't
# modify initial ob
person1_s = person_server._getOb(self.id1)
+ person_client1 = self.getPersonClient1()
+ person1_c = person_client1._getOb(self.id1)
self.assertEqual(person1_s.getId(), self.id1)
self.assertEqual(person1_s.getFirstName(), self.first_name1)
self.assertEqual(person1_s.getLastName(), self.last_name1)
- person_client1 = self.getPersonClient1()
- person1_c = person_client1._getOb(self.id1)
- self.assertEqual(person1_c.getId(), self.id1)
- self.assertEqual(person1_c.getFirstName(), self.first_name1)
- self.assertEqual(person1_c.getLastName(), self.last_name1)
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c)
SyncCode.MAX_LINES = previous_max_lines
def test_30_GetSynchronizationType(self, quiet=0, run=run_all_test):
@@ -1252,9 +1392,11 @@
# Then we do only modification on a client
person_client1 = self.getPersonClient1()
person1_c = person_client1._getOb(self.id1)
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c)
kw = {'first_name':self.first_name1,'last_name':self.last_name1}
person1_c.edit(**kw)
self.synchronize(self.sub_id1)
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c)
for sub in portal_sync.getSubscriptionList():
self.assertEquals(sub.getSynchronizationType(),SyncCode.TWO_WAY)
# Then we do only modification on both the client and the server
@@ -1264,6 +1406,7 @@
kw = {'description':self.description3}
person1_c.edit(**kw)
self.synchronize(self.sub_id1)
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c)
for sub in portal_sync.getSubscriptionList():
self.assertEquals(sub.getSynchronizationType(),SyncCode.TWO_WAY)
@@ -1295,6 +1438,8 @@
role_2_c = person2_c.get_local_permissions()
self.assertEqual(role_1_s,role_1_c)
self.assertEqual(role_2_s,role_2_c)
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c)
+ self.assertXMLViewIsEqual(self.sub_id2, person2_s, person2_c)
person1_s.manage_setLocalPermissions('View',['Owner'])
person2_s.manage_setLocalPermissions('View',None)
person2_s.manage_setLocalPermissions('View management screens',())
@@ -1306,6 +1451,8 @@
role_2_c = person2_c.get_local_permissions()
self.assertEqual(role_1_s,role_1_c)
self.assertEqual(role_2_s,role_2_c)
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c)
+ self.assertXMLViewIsEqual(self.sub_id2, person2_s, person2_c)
def test_32_AddOneWaySubscription(self, quiet=0, run=run_all_test):
if not run: return
@@ -1314,6 +1461,8 @@
LOG('Testing... ',0,'test_32_AddOneWaySubscription')
portal_id = self.getPortalId()
portal_sync = self.getSynchronizationTool()
+ if portal_sync.getSubscription(self.sub_id1) is not None:
+ portal_sync.manage_deleteSubscription(title=self.sub_id1)
portal_sync.manage_addSubscription(title=self.sub_id1,
publication_url=self.publication_url,
subscription_url=self.subscription_url1,
@@ -1324,7 +1473,7 @@
xml_mapping=self.xml_mapping,
conduit='ERP5Conduit',
gpg_key='',
- activity_enabled=False,
+ activity_enabled=self.activity_enabled,
alert_code = SyncCode.ONE_WAY_FROM_SERVER,
login = 'fab',
password = 'myPassword')
@@ -1342,6 +1491,13 @@
if not quiet:
ZopeTestCase._print('\nTest One Way Sync ')
LOG('Testing... ',0,'test_33_OneWaySync')
+ person_server = self.getPersonServer()
+ if person_server is not None:
+ portal = self.getPortal()
+ portal._delObject(id='person_server')
+ portal._delObject(id='person_client1')
+ portal._delObject(id='person_client2')
+ self.deletePublicationAndSubscription()
self.test_02_AddPublication(quiet=1,run=1)
self.test_32_AddOneWaySubscription(quiet=1,run=1)
@@ -1359,21 +1515,32 @@
person_server = self.getPersonServer() # We also check we don't
# modify initial ob
person1_s = person_server._getOb(self.id1)
+ person_client1 = self.getPersonClient1()
+ person1_c = person_client1._getOb(self.id1)
self.assertEqual(person1_s.getId(), self.id1)
self.assertEqual(person1_s.getFirstName(), self.first_name1)
self.assertEqual(person1_s.getLastName(), self.last_name1)
- person_client1 = self.getPersonClient1()
- person1_c = person_client1._getOb(self.id1)
- self.assertEqual(person1_c.getId(), self.id1)
- self.assertEqual(person1_c.getFirstName(), self.first_name1)
- self.assertEqual(person1_c.getLastName(), self.last_name1)
+ self.checkSynchronizationStateIsSynchronized()
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c, force=1)
# 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)
+ #In One_From_Server Sync not modify the first_name in client because any
+ #datas client sent
+ self.assertEquals(person1_c.getFirstName(), self.first_name2)
+ self.assertEquals(person1_c.getLastName(), self.last_name2)
+ self.assertEquals(person1_s.getFirstName(), self.first_name1)
+ self.assertEquals(person1_s.getLastName(), self.last_name2)
+ #reset for refresh sync
+ #after synchronize, the client object retrieve value of server
+ self.resetSignaturePublicationAndSubscription()
+ nb_message1 = self.synchronize(self.sub_id1)
+ self.assertEquals(person1_s.getFirstName(), self.first_name1)
+ self.assertEquals(person1_s.getLastName(), self.last_name2)
+ self.checkSynchronizationStateIsSynchronized()
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c, force=1)
def test_34_encoding(self, quiet=0, run=run_all_test):
"""
@@ -1396,13 +1563,12 @@
PQRSTUVWXYZéèçà@^~µ&²0123456789!@#0^&*();:<>,. []{}\xc3\xa7sdf__\
sdf\xc3\xa7\xc3\xa7\xc3\xa7_df___&&\xc3\xa9]]]\xc2\xb0\xc2\xb0\xc2\
\xb0\xc2\xb0\xc2\xb0\xc2\xb0"
-#= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZéèçà@^~µ&²012345
-#6789!@#0^&*();:<>,. []{}çsdf__sdfççç_df___&&é]]]°°°°°°'"
-
- awaited_result_long_string = 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZH\
+ #= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZéèçà@^~µ&²012345
+ #6789!@#0^&*();:<>,. []{}çsdf__sdfççç_df___&&é]]]°°°°°°'"
+
+ awaited_result_long_string = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZH\
SElKS0xNTk9QUVJTVFVWV1hZWsOpw6jDp8OgQF5+wrUmwrIwMTIzNDU2Nzg5IUAjMF4mKigpOzo8Pi\
-wuIFtde33Dp3NkZl9fc2Rmw6fDp8OnX2RmX19fJibDqV1dXcKwwrDCsMKwwrDCsA=='
-
+wuIFtde33Dp3NkZl9fc2Rmw6fDp8OnX2RmX19fJibDqV1dXcKwwrDCsMKwwrDCsA=="
#test just b64encode
self.assertEqual(b64encode(python), awaited_result_python)
self.assertEqual(b64encode(""), "")
@@ -1440,32 +1606,6 @@
self.failUnless(subscription1.isDecodeEncodeTheSame(
subscription1.encode('b64', ''), '', 'b64'))
- def addAuthenticationToPublication(self, publication_id, login, password,
- auth_format, auth_type):
- """
- add authentication to the publication
- """
- portal_sync = self.getSynchronizationTool()
- pub = portal_sync.getPublication(publication_id)
- pub.setLogin(login)
- pub.setPassword(password)
- pub.setAuthenticationFormat(auth_format)
- pub.setAuthenticationType(auth_type)
-
-
- def addAuthenticationToSubscription(self, subscription_id, login, password,
- auth_format, auth_type):
- """
- add authentication to the subscription
- """
- portal_sync = self.getSynchronizationTool()
- sub = portal_sync.getSubscription(subscription_id)
- sub.setAuthenticated(False)
- sub.setLogin(login)
- sub.setPassword(password)
- sub.setAuthenticationFormat(auth_format)
- sub.setAuthenticationType(auth_type)
-
def test_35_authentication(self, quiet=0, run=run_all_test):
"""
we will test
@@ -1497,8 +1637,9 @@
self.synchronize(self.sub_id1)
#now it should be synchronize
self.checkSynchronizationStateIsSynchronized()
- self.verifyFirstNameAndLastNameAreSynchronized(self.first_name3,
- self.last_name3, person1_s, person1_c)
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c)
+ self.assertEquals(person1_s.getFirstName(), self.first_name3)
+ self.assertEquals(person1_s.getLastName(), self.last_name3)
#adding authentication :
@@ -1524,8 +1665,9 @@
#now it should be correctly synchronize
self.synchronize(self.sub_id1)
self.checkSynchronizationStateIsSynchronized()
- self.verifyFirstNameAndLastNameAreSynchronized(self.first_name2,
- self.last_name2, person1_s, person1_c)
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c)
+ self.assertEquals(person1_s.getFirstName(), self.first_name2)
+ self.assertEquals(person1_s.getLastName(), self.last_name2)
#try to synchronize with a bad login and/or password
#test if login is case sensitive (it should be !)
@@ -1552,8 +1694,9 @@
#now it should be correctly synchronize
self.synchronize(self.sub_id1)
self.checkSynchronizationStateIsSynchronized()
- self.verifyFirstNameAndLastNameAreSynchronized(self.first_name1,
- self.last_name1, person1_s, person1_c)
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c)
+ self.assertEquals(person1_s.getFirstName(), self.first_name1)
+ self.assertEquals(person1_s.getLastName(), self.last_name1)
#verify that the login and password with utf8 caracters are accecpted
@@ -1579,9 +1722,43 @@
self.addAuthenticationToSubscription(self.sub_id1, '\xc3\xa9pouet', 'ploum',
'b64', 'syncml:auth-basic')
self.synchronize(self.sub_id1)
- self.verifyFirstNameAndLastNameAreSynchronized(self.first_name3,
- self.last_name3, person1_s, person1_c)
- self.checkSynchronizationStateIsSynchronized()
+ self.assertXMLViewIsEqual(self.sub_id1, person1_s, person1_c)
+ self.assertEquals(person1_s.getFirstName(), self.first_name3)
+ self.assertEquals(person1_s.getLastName(), self.last_name3)
+ self.checkSynchronizationStateIsSynchronized()
+
+ def test_36_SynchronizationSubscriptionMaxLines(self, quiet=0, run=run_all_test):
+ # We will try to populate the folder person_server
+ # with the data form person_client
+ # with the data which over max line of messages
+ if not run: return
+ if not quiet:
+ ZopeTestCase._print('\nTest Synchronization Subscription Max Lines')
+ LOG('Testing... ',0,'test_36_SynchronizationSubscriptionMaxLines')
+ self.login()
+ self.setupPublicationAndSubscription(quiet=1, run=1)
+ nb_person = self.populatePersonClient1(quiet=1, run=1)
+ portal_sync = self.getSynchronizationTool()
+ for sub in portal_sync.getSubscriptionList():
+ self.assertEquals(sub.getSynchronizationType(), SyncCode.SLOW_SYNC)
+ # Synchronize the first client
+ # data_Sub1 -> Pub (the data are in sub1 to pub is empty)
+ nb_message1 = self.synchronize(self.sub_id1)
+ #Verification number object synchronized
+ self.assertEqual(nb_message1, self.nb_message_first_sync_max_lines)
+ # Synchronize the second client
+ # data_Pub -> data_Sub2 the data are in pub to sub2 is empty so add +2 messages)
+ nb_message2 = self.synchronize(self.sub_id2)
+ self.assertEqual(nb_message2, self.nb_message_first_sync_max_lines + 2)
+ person_server = self.getPersonServer()
+ person_client1 = self.getPersonClient1()
+ person_client2 = self.getPersonClient2()
+ for id in range(1, 60):
+ person_s = person_server._getOb(str(id))
+ person_c = person_client1._getOb(str(id))
+ self.assertXMLViewIsEqual(self.sub_id1, person_s, person_c)
+ self.assertEqual(nb_person, len(person_server.objectValues()))
+ self.assertEqual(nb_person, len(person_client2.objectValues()))
def test_suite():
suite = unittest.TestSuite()
Modified: erp5/trunk/products/ERP5SyncML/tests/testERP5SyncMLVCard.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/tests/testERP5SyncMLVCard.py?rev=28229&r1=28228&r2=28229&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/tests/testERP5SyncMLVCard.py [utf8] (original)
+++ erp5/trunk/products/ERP5SyncML/tests/testERP5SyncMLVCard.py [utf8] Thu Jul 30 14:34:54 2009
@@ -59,6 +59,16 @@
"""
return ('erp5_base','erp5_syncml')
+ def verifyFirstNameAndLastNameAreSynchronized(self, first_name,
+ last_name, person_server, person_client):
+ """
+ verify if the first and last name are synchronized
+ """
+ self.assertEqual(person_server.getFirstName(), first_name)
+ self.assertEqual(person_server.getLastName(), last_name)
+ self.assertEqual(person_client.getFirstName(), first_name)
+ self.assertEqual(person_client.getLastName(), last_name)
+
def getTitle(self):
return 'testERP5SyncMLVCard'
More information about the Erp5-report
mailing list