[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