Merge branch 'master' of http://git.tine20.org/git/Syncope
authorLars Kneschke <l.kneschke@metaways.de>
Wed, 22 Feb 2012 15:24:32 +0000 (16:24 +0100)
committerLars Kneschke <l.kneschke@metaways.de>
Wed, 22 Feb 2012 15:24:32 +0000 (16:24 +0100)
tine20/library/Syncope/lib/Syncope/Backend/Content.php
tine20/library/Syncope/lib/Syncope/Backend/SyncState.php
tine20/library/Syncope/lib/Syncope/Command/Sync.php
tine20/library/Syncope/lib/Syncope/Data/Contacts.php
tine20/library/Syncope/lib/Syncope/Model/IContent.php
tine20/library/Syncope/tests/Syncope/Backend/ContentTests.php
tine20/library/Syncope/tests/Syncope/Command/GetItemEstimateTests.php
tine20/library/Syncope/tests/Syncope/Command/SyncTests.php
tine20/library/Syncope/tests/bootstrap.php

index 3790ddc..a974086 100644 (file)
@@ -47,12 +47,13 @@ class Syncope_Backend_Content implements Syncope_Backend_IContent
         $folderId = $_state->folder_id instanceof Syncope_Model_IFolder ? $_state->folder_id->id : $_state->folder_id;
         
         $this->_db->insert($this->_tablePrefix . 'content', array(
-            'id'            => $id, 
-            'device_id'     => $deviceId,
-            'folder_id'     => $folderId,
-            'contentid'     => $_state->contentid,
-            'creation_time' => $_state->creation_time->format('Y-m-d H:i:s'),
-            'is_deleted'    => isset($_state->is_deleted) ? (int)!!$_state->is_deleted : 0
+            'id'               => $id, 
+            'device_id'        => $deviceId,
+            'folder_id'        => $folderId,
+            'contentid'        => $_state->contentid,
+            'creation_time'    => $_state->creation_time->format('Y-m-d H:i:s'),
+            'creation_synckey' => $_state->creation_synckey,
+            'is_deleted'       => isset($_state->is_deleted) ? (int)!!$_state->is_deleted : 0
         ));
         
         return $this->get($id);
index 0ee12bd..290550e 100644 (file)
@@ -223,16 +223,17 @@ class Syncope_Backend_SyncState implements Syncope_Backend_ISyncState
             $this->_db->update($this->_tablePrefix . 'content', array(
                 'is_deleted'  => 0,
             ), array(
-                'device_id = ?'  => $deviceId,
-                'folder_id = ?'  => $folderId,
-                'is_deleted = ?' => 1
+                'device_id = ?'        => $deviceId,
+                'folder_id = ?'        => $folderId,
+                'creation_synckey = ?' => $state->counter,
+                'is_deleted = ?'       => 1
             ));
             
             // remove entries added during latest sync in syncope_content table
             $this->_db->delete($this->_tablePrefix . 'content', array(
-                'device_id = ?'     => $deviceId,
-                'folder_id = ?'     => $folderId,
-                'creation_time > ?' => $state->lastsync->format('Y-m-d H:i:s'),
+                'device_id = ?'        => $deviceId,
+                'folder_id = ?'        => $folderId,
+                'creation_synckey > ?' => $state->counter,
             ));
             
         } else {
index 25b73d2..7a95245 100644 (file)
@@ -246,11 +246,11 @@ class Syncope_Command_Sync extends Syncope_Command_Wbxml
                             'serverId'     => $serverId,
                             'status'       => self::STATUS_SUCCESS,
                             'contentState' => $this->_contentStateBackend->create(new Syncope_Model_Content(array(
-                                'device_id'     => $this->_device,
-                                'folder_id'     => $collectionData['folder'],
-                                'contentid'     => $serverId,
-                                'creation_time' => $this->_syncTimeStamp
-                            
+                                'device_id'        => $this->_device,
+                                'folder_id'        => $collectionData['folder'],
+                                'contentid'        => $serverId,
+                                'creation_time'    => $this->_syncTimeStamp,
+                                'creation_synckey' => $collectionData['syncKey'] + 1
                             )))
                         );
                         
@@ -557,25 +557,25 @@ class Syncope_Command_Sync extends Syncope_Command_Wbxml
                         break;
                     }
                     
-                    /**
-                     * somewhere is a problem in the logic for handling moreAvailable
-                     * 
-                     * it can happen, that we have a contentstate (which means we sent the entry to the client
-                     * and that this entry is yet in $collectionData['syncState']->pendingdata['serverAdds']
-                     * I have no idea how this can happen, but the next lines of code work around this problem
-                     */
-                    try {
-                        $this->_contentStateBackend->getContentState($this->_device, $collectionData['folder'], $serverId);
-                    
-                        if ($this->_logger instanceof Zend_Log) 
-                            $this->_logger->info(__METHOD__ . '::' . __LINE__ . " skipped an entry($serverId) which is already on the client");
-                        
-                        unset($serverAdds[$id]);
-                        continue;
-                        
-                    } catch (Syncope_Exception_NotFound $senf) {
-                        // do nothing => content state should not exist yet
-                    }
+                    #/**
+                    # * somewhere is a problem in the logic for handling moreAvailable
+                    # * 
+                    # * it can happen, that we have a contentstate (which means we sent the entry to the client
+                    # * and that this entry is yet in $collectionData['syncState']->pendingdata['serverAdds']
+                    # * I have no idea how this can happen, but the next lines of code work around this problem
+                    # */
+                    #try {
+                    #    $this->_contentStateBackend->getContentState($this->_device, $collectionData['folder'], $serverId);
+                    # 
+                    #    if ($this->_logger instanceof Zend_Log) 
+                    #        $this->_logger->info(__METHOD__ . '::' . __LINE__ . " skipped an entry($serverId) which is already on the client");
+                    #    
+                    #    unset($serverAdds[$id]);
+                    #    continue;
+                    #    
+                    #} catch (Syncope_Exception_NotFound $senf) {
+                    #    // do nothing => content state should not exist yet
+                    #}
                     
                     try {
                         $add = $this->_outputDom->createElementNS('uri:AirSync', 'Add');
@@ -594,10 +594,11 @@ class Syncope_Command_Sync extends Syncope_Command_Wbxml
                     
                     // mark as send to the client, even the conversion to xml might have failed 
                     $newContentStates[] = new Syncope_Model_Content(array(
-                        'device_id'     => $this->_device,
-                        'folder_id'     => $collectionData['folder'],
-                        'contentid'     => $serverId,
-                        'creation_time' => $this->_syncTimeStamp
+                        'device_id'        => $this->_device,
+                        'folder_id'        => $collectionData['folder'],
+                        'contentid'        => $serverId,
+                        'creation_time'    => $this->_syncTimeStamp,
+                        'creation_synckey' => $collectionData['syncState']->counter
                     ));
                     unset($serverAdds[$id]);    
                 }
index 94d8996..8517df9 100644 (file)
@@ -86,16 +86,48 @@ class Syncope_Data_Contacts extends Syncope_Data_AData
          */
         if (!isset(Syncope_Data_AData::$entries[get_class($this)])) {
             Syncope_Data_AData::$entries[get_class($this)] = array(
-                       'addressbookFolderId' => array(
-                        'contact1' => array(
-                               'FirstName' => 'Lars', 
-                               'LastName'  => 'Kneschke'
-                       ),
-                        'contact2' => array(
-                               'FirstName' => 'Cornelius', 
-                               'LastName'  => 'Weiß'
-                           )
-                   )
+                'addressbookFolderId' => array(
+                    'contact1' => array(
+                        'FirstName' => 'Lars', 
+                        'LastName'  => 'Kneschke'
+                    ),
+                    'contact2' => array(
+                        'FirstName' => 'Cornelius', 
+                        'LastName'  => 'Weiß'
+                    ),
+                    'contact3' => array(
+                        'FirstName' => 'Lars', 
+                        'LastName'  => 'Kneschke'
+                    ),
+                    'contact4' => array(
+                        'FirstName' => 'Cornelius', 
+                        'LastName'  => 'Weiß'
+                    ),
+                    'contact5' => array(
+                        'FirstName' => 'Lars', 
+                        'LastName'  => 'Kneschke'
+                    ),
+                    'contact6' => array(
+                        'FirstName' => 'Cornelius', 
+                        'LastName'  => 'Weiß'
+                    ),
+                    'contact7' => array(
+                        'FirstName' => 'Lars', 
+                        'LastName'  => 'Kneschke'
+                    ),
+                    'contact8' => array(
+                        'FirstName' => 'Cornelius', 
+                        'LastName'  => 'Weiß'
+                    ),
+                    'contact9' => array(
+                        'FirstName' => 'Lars', 
+                        'LastName'  => 'Kneschke'
+                    ),
+                    'contact10' => array(
+                        'FirstName' => 'Cornelius', 
+                        'LastName'  => 'Weiß'
+                    )
+                )
             );
         }
     }
index 7970945..a8233f4 100644 (file)
@@ -18,6 +18,7 @@
  * @property    string    folder_id
  * @property    string    contentid
  * @property    DateTime  creation_time
+ * @property    string    creation_synckey
  * @property    string    is_deleted
  */
 
index af428cb..bc8fc74 100644 (file)
@@ -162,10 +162,11 @@ class Syncope_Backend_ContentTests extends PHPUnit_Framework_TestCase
     public static function getTestContent(Syncope_Model_IDevice $_device, Syncope_Model_IFolder $_folder)
     {
         return new Syncope_Model_Content(array(
-            'device_id'     => $_device,
-            'folder_id'     => $_folder,
-            'contentid'     => 'abc1234',
-            'creation_time' => new DateTime(null, new DateTimeZone('utc'))
+            'device_id'        => $_device,
+            'folder_id'        => $_folder,
+            'contentid'        => 'abc1234',
+            'creation_time'    => new DateTime(null, new DateTimeZone('utc')),
+            'creation_synckey' => 1
         ));
     }
 }
index 41c180d..eb90bda 100644 (file)
@@ -91,7 +91,7 @@ class Syncope_Command_GetItemEstimateTests extends Syncope_Command_ATestCase
                 
         $nodes = $xpath->query('//ItemEstimate:GetItemEstimate/ItemEstimate:Response/ItemEstimate:Collection/ItemEstimate:Estimate');
         $this->assertEquals(1, $nodes->length, $responseDoc->saveXML());
-        $this->assertEquals(2, $nodes->item(0)->nodeValue, $responseDoc->saveXML());
+        $this->assertEquals(10, $nodes->item(0)->nodeValue, $responseDoc->saveXML());
         
     }    
 }
index c63bba9..8dbe73b 100644 (file)
@@ -139,7 +139,7 @@ class Syncope_Command_SyncTests extends Syncope_Command_ATestCase
         $doc = new DOMDocument();
         $doc->loadXML('<?xml version="1.0" encoding="utf-8"?>
             <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
-            <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"><Collections><Collection><Class>Contacts</Class><SyncKey>0</SyncKey><CollectionId>addressbookFolderId</CollectionId><DeletesAsMoves/><GetChanges/><WindowSize>100</WindowSize><Options><AirSyncBase:BodyPreference><AirSyncBase:Type>1</AirSyncBase:Type><AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize></AirSyncBase:BodyPreference><Conflict>1</Conflict></Options></Collection></Collections></Sync>'
+            <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"><Collections><Collection><Class>Contacts</Class><SyncKey>0</SyncKey><CollectionId>addressbookFolderId</CollectionId><DeletesAsMoves/><GetChanges/><WindowSize>2</WindowSize><Options><AirSyncBase:BodyPreference><AirSyncBase:Type>1</AirSyncBase:Type><AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize></AirSyncBase:BodyPreference><Conflict>1</Conflict></Options></Collection></Collections></Sync>'
         );
         
         $sync = new Syncope_Command_Sync($doc, $this->_device, $this->_device->policykey);
@@ -169,7 +169,7 @@ class Syncope_Command_SyncTests extends Syncope_Command_ATestCase
         $doc = new DOMDocument();
         $doc->loadXML('<?xml version="1.0" encoding="utf-8"?>
             <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
-            <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"><Collections><Collection><Class>Contacts</Class><SyncKey>1</SyncKey><CollectionId>addressbookFolderId</CollectionId><DeletesAsMoves/><GetChanges/><WindowSize>100</WindowSize><Options><AirSyncBase:BodyPreference><AirSyncBase:Type>1</AirSyncBase:Type><AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize></AirSyncBase:BodyPreference><Conflict>1</Conflict></Options></Collection></Collections></Sync>'
+            <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"><Collections><Collection><Class>Contacts</Class><SyncKey>1</SyncKey><CollectionId>addressbookFolderId</CollectionId><DeletesAsMoves/><GetChanges/><WindowSize>2</WindowSize><Options><AirSyncBase:BodyPreference><AirSyncBase:Type>1</AirSyncBase:Type><AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize></AirSyncBase:BodyPreference><Conflict>1</Conflict></Options></Collection></Collections></Sync>'
         );
         
         $sync = new Syncope_Command_Sync($doc, $this->_device, $this->_device->policykey);
@@ -194,6 +194,9 @@ class Syncope_Command_SyncTests extends Syncope_Command_ATestCase
         $this->assertEquals(1, $nodes->length, $syncDoc->saveXML());
         $this->assertEquals(Syncope_Command_Sync::STATUS_SUCCESS, $nodes->item(0)->nodeValue, $syncDoc->saveXML());
         
+        $nodes = $xpath->query('//AirSync:Sync/AirSync:Collections/AirSync:Collection/AirSync:MoreAvailable');
+        $this->assertEquals(1, $nodes->length, $syncDoc->saveXML());
+        
         $nodes = $xpath->query('//AirSync:Sync/AirSync:Collections/AirSync:Collection/AirSync:Commands');
         $this->assertEquals(1, $nodes->length, $syncDoc->saveXML());
         #$this->assertEquals(Syncope_Command_Sync::STATUS_SUCCESS, $nodes->item(0)->nodeValue, $syncDoc->saveXML());
@@ -203,6 +206,41 @@ class Syncope_Command_SyncTests extends Syncope_Command_ATestCase
         $this->assertEquals(0, $nodes->length, $syncDoc->saveXML());
                 
         $this->assertEquals("uri:Contacts", $syncDoc->lookupNamespaceURI('Contacts'), $syncDoc->saveXML());
+        
+        // try with previous synckey again
+        $doc = new DOMDocument();
+        $doc->loadXML('<?xml version="1.0" encoding="utf-8"?>
+            <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
+            <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"><Collections><Collection><Class>Contacts</Class><SyncKey>1</SyncKey><CollectionId>addressbookFolderId</CollectionId><DeletesAsMoves/><GetChanges/><WindowSize>2</WindowSize><Options><AirSyncBase:BodyPreference><AirSyncBase:Type>1</AirSyncBase:Type><AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize></AirSyncBase:BodyPreference><Conflict>1</Conflict></Options></Collection></Collections></Sync>'
+        );
+        
+        $sync = new Syncope_Command_Sync($doc, $this->_device, $this->_device->policykey);
+        
+        $sync->handle();
+        
+        $syncDoc = $sync->getResponse();
+        #$syncDoc->formatOutput = true; echo $syncDoc->saveXML();
+        
+        
+        // and now fetch the rest
+        $doc = new DOMDocument();
+        $doc->loadXML('<?xml version="1.0" encoding="utf-8"?>
+            <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
+            <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"><Collections><Collection><Class>Contacts</Class><SyncKey>2</SyncKey><CollectionId>addressbookFolderId</CollectionId><DeletesAsMoves/><GetChanges/><WindowSize>20</WindowSize><Options><AirSyncBase:BodyPreference><AirSyncBase:Type>1</AirSyncBase:Type><AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize></AirSyncBase:BodyPreference><Conflict>1</Conflict></Options></Collection></Collections></Sync>'
+        );
+        
+        $sync = new Syncope_Command_Sync($doc, $this->_device, $this->_device->policykey);
+        
+        $sync->handle();
+        
+        $syncDoc = $sync->getResponse();
+        #$syncDoc->formatOutput = true; echo $syncDoc->saveXML();
+        
+        $xpath = new DomXPath($syncDoc);
+        $xpath->registerNamespace('AirSync', 'uri:AirSync');
+        
+        $nodes = $xpath->query('//AirSync:Sync/AirSync:Collections/AirSync:Collection/AirSync:MoreAvailable');
+        $this->assertEquals(0, $nodes->length, $syncDoc->saveXML());
     }
         
     /**
@@ -441,7 +479,7 @@ class Syncope_Command_SyncTests extends Syncope_Command_ATestCase
             <!DOCTYPE AirSync PUBLIC "-//AIRSYNC//DTD AirSync//EN" "http://www.microsoft.com/">
             <Sync xmlns="uri:AirSync" xmlns:AirSyncBase="uri:AirSyncBase"><Collections>
                 <Collection>
-                    <Class>Contacts</Class><SyncKey>2</SyncKey><CollectionId>addressbookFolderId</CollectionId><DeletesAsMoves/><GetChanges/><WindowSize>100</WindowSize>
+                    <Class>Contacts</Class><SyncKey>3</SyncKey><CollectionId>addressbookFolderId</CollectionId><DeletesAsMoves/><GetChanges/><WindowSize>100</WindowSize>
                     <Options><AirSyncBase:BodyPreference><AirSyncBase:Type>1</AirSyncBase:Type><AirSyncBase:TruncationSize>5120</AirSyncBase:TruncationSize></AirSyncBase:BodyPreference><Conflict>1</Conflict></Options>
                 </Collection>
             </Collections></Sync>'
@@ -459,7 +497,7 @@ class Syncope_Command_SyncTests extends Syncope_Command_ATestCase
         
         $nodes = $xpath->query('//AirSync:Sync/AirSync:Collections/AirSync:Collection/AirSync:SyncKey');
         $this->assertEquals(1, $nodes->length, $syncDoc->saveXML());
-        $this->assertEquals(2, $nodes->item(0)->nodeValue, $syncDoc->saveXML());
+        $this->assertEquals(3, $nodes->item(0)->nodeValue, $syncDoc->saveXML());
         
         $nodes = $xpath->query('//AirSync:Sync/AirSync:Collections/AirSync:Collection/AirSync:Status');
         $this->assertEquals(1, $nodes->length, $syncDoc->saveXML());
index 39bc9cc..98c1b82 100644 (file)
@@ -74,6 +74,7 @@ function getTestDatabase()
         `folder_id` varchar(40) NOT NULL,
         `contentid` varchar(64) NOT NULL,
         `creation_time` datetime NOT NULL,
+        `creation_synckey` int(11) NOT NULL,
         `is_deleted` int(11) DEFAULT '0',
         PRIMARY KEY (`id`),
         UNIQUE (`device_id`,`folder_id`,`contentid`)