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


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