diff --git a/tests/Sync/FoldersTest.php b/tests/Sync/FoldersTest.php index ed234c5..91cf0f0 100644 --- a/tests/Sync/FoldersTest.php +++ b/tests/Sync/FoldersTest.php @@ -1,389 +1,467 @@ deleteTestFolder('Test Folder', 'mail'); $this->deleteTestFolder('Test Folder New', 'mail'); $this->deleteTestFolder('Test Contacts Folder', 'contact'); $this->deleteTestFolder('Test Contacts New', 'contact'); + parent::setUp(); + } + + /** + * Test FolderSync command + */ + public function testFolderSyncBasic() + { + $request = << + + + 0 + + EOF; + + $response = $this->request($request, 'FolderSync'); + + $this->assertEquals(200, $response->getStatusCode()); + + $dom = $this->fromWbxml($response->getBody()); + $xpath = $this->xpath($dom); + + $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); + $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); + // We expect some folders to exist (dont' know how many) + $this->assertTrue(intval($xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue) > 2); + + $request = << + + + 1 + + EOF; + + $response = $this->request($request, 'FolderSync'); + + $this->assertEquals(200, $response->getStatusCode()); + + $dom = $this->fromWbxml($response->getBody()); + $xpath = $this->xpath($dom); + + $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); + $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); + // No changes on second sync + $this->assertSame(strval(0), $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue); + } + + /** + * Test invalid sync key + */ + public function testFolderInvalidSyncKey() + { + $request = << + + + 999 + + EOF; + + $response = $this->request($request, 'FolderSync'); + + $this->assertEquals(200, $response->getStatusCode()); + + $dom = $this->fromWbxml($response->getBody()); + $xpath = $this->xpath($dom); + + $this->assertSame('9', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); + } + + + /** + * Test FolderSync command + */ + public function testFolderSync() + { $request = << 0 EOF; $response = $this->request($request, 'FolderSync'); $this->assertEquals(200, $response->getStatusCode()); $dom = $this->fromWbxml($response->getBody()); $xpath = $this->xpath($dom); // Note: We're expecting activesync_init_subscriptions=0 here. if ($this->isStorageDriver('kolab4')) { $folders = [ ['Calendar', Syncroton_Command_FolderSync::FOLDERTYPE_CALENDAR], ['Contacts', Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT], ['INBOX', Syncroton_Command_FolderSync::FOLDERTYPE_INBOX], ['Drafts', Syncroton_Command_FolderSync::FOLDERTYPE_DRAFTS], ['Sent', Syncroton_Command_FolderSync::FOLDERTYPE_SENTMAIL], ['Trash', Syncroton_Command_FolderSync::FOLDERTYPE_DELETEDITEMS], ['Tasks', Syncroton_Command_FolderSync::FOLDERTYPE_TASK], ]; } else { $folders = [ ['Calendar', Syncroton_Command_FolderSync::FOLDERTYPE_CALENDAR], ['Contacts', Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT], ['INBOX', Syncroton_Command_FolderSync::FOLDERTYPE_INBOX], ['Drafts', Syncroton_Command_FolderSync::FOLDERTYPE_DRAFTS], ['Sent', Syncroton_Command_FolderSync::FOLDERTYPE_SENTMAIL], ['Trash', Syncroton_Command_FolderSync::FOLDERTYPE_DELETEDITEMS], ['Notes', Syncroton_Command_FolderSync::FOLDERTYPE_NOTE], ['Tasks', Syncroton_Command_FolderSync::FOLDERTYPE_TASK], ]; } $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); $this->assertSame(strval(count($folders)), $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue); foreach ($folders as $idx => $folder) { $this->assertSame($folder[0], $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:DisplayName")->item($idx)->nodeValue); $this->assertSame((string) $folder[1], $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:Type")->item($idx)->nodeValue); $this->assertSame('0', $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:ParentId")->item($idx)->nodeValue); } // Test with multi-folder support enabled self::$deviceType = 'iphone'; $response = $this->request($request, 'FolderSync'); $this->assertEquals(200, $response->getStatusCode()); $dom = $this->fromWbxml($response->getBody()); $xpath = $this->xpath($dom); if ($this->isStorageDriver('kolab4')) { $folders = [ ['Calendar', Syncroton_Command_FolderSync::FOLDERTYPE_CALENDAR], // Note: Kolab 4 with Cyrus DAV uses Addressbook, but Kolab 3 with iRony would use 'Contacts' ['/^(Contacts|Addressbook)$/', Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT], ['INBOX', Syncroton_Command_FolderSync::FOLDERTYPE_INBOX], ['Drafts', Syncroton_Command_FolderSync::FOLDERTYPE_DRAFTS], ['Sent', Syncroton_Command_FolderSync::FOLDERTYPE_SENTMAIL], ['Trash', Syncroton_Command_FolderSync::FOLDERTYPE_DELETEDITEMS], // Note: For now Kolab 4 uses the same Calendar folder for calendar and tasks ['/^(Tasks|Calendar)$/', Syncroton_Command_FolderSync::FOLDERTYPE_TASK], ]; } $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); $this->assertSame(strval(count($folders)), $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue); foreach ($folders as $idx => $folder) { $displayName = $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:DisplayName")->item($idx)->nodeValue; if (str_starts_with($folder[0], '/')) { $this->assertMatchesRegularExpression($folder[0], $displayName); } else { $this->assertSame($folder[0], $displayName); } $this->assertSame((string) $folder[1], $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:Type")->item($idx)->nodeValue); $this->assertSame('0', $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:ParentId")->item($idx)->nodeValue); $idx++; } // After we switched to multi-folder supported mode we expect next FolderSync // to delete the old "collective" folders $request = << 1 EOF; $response = $this->request($request, 'FolderSync'); $this->assertEquals(200, $response->getStatusCode()); $dom = $this->fromWbxml($response->getBody()); $xpath = $this->xpath($dom); $deleted = $this->isStorageDriver('kolab4') ? 3 : 4; // No Notes folder in Kolab4 $syncKey = 2; $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); $this->assertSame(strval($syncKey), $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); $this->assertSame(strval($deleted), $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue); $this->assertSame($deleted, $xpath->query("//ns:FolderSync/ns:Changes/ns:Delete")->length); return $syncKey; } /** * Test FolderCreate command * * @depends testFolderSync */ public function testFolderCreate($syncKey) { // Multi-folder mode self::$deviceType = 'iphone'; // Create a mail folder $folderName1 = 'Test Folder'; $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_MAIL_USER_CREATED; $request = << {$syncKey} 0 {$folderName1} {$folderType} EOF; $response = $this->request($request, 'FolderCreate'); $this->assertEquals(200, $response->getStatusCode()); $dom = $this->fromWbxml($response->getBody()); $xpath = $this->xpath($dom); $this->assertSame('1', $xpath->query("//ns:FolderCreate/ns:Status")->item(0)->nodeValue); $this->assertSame(strval(++$syncKey), $xpath->query("//ns:FolderCreate/ns:SyncKey")->item(0)->nodeValue); $this->assertSame(1, $xpath->query("//ns:FolderCreate/ns:ServerId")->count()); $folder1 = $xpath->query("//ns:FolderCreate/ns:ServerId")->item(0)->nodeValue; // Note: After FolderCreate there are no changes in the following FolderSync expected // Create a contacts folder $folderName2 = 'Test Contacts Folder'; $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT_USER_CREATED; $request = << {$syncKey} 0 {$folderName2} {$folderType} EOF; $response = $this->request($request, 'FolderCreate'); $this->assertEquals(200, $response->getStatusCode()); $dom = $this->fromWbxml($response->getBody()); $xpath = $this->xpath($dom); $this->assertSame('1', $xpath->query("//ns:FolderCreate/ns:Status")->item(0)->nodeValue); $this->assertSame(strval(++$syncKey), $xpath->query("//ns:FolderCreate/ns:SyncKey")->item(0)->nodeValue); $this->assertSame(1, $xpath->query("//ns:FolderCreate/ns:ServerId")->count()); $folder2 = $xpath->query("//ns:FolderCreate/ns:ServerId")->item(0)->nodeValue; // Note: After FolderCreate there are no changes in the following FolderSync expected // TODO: Test folder with a parent return [ 'SyncKey' => $syncKey, 'folders' => [ $folder1, $folder2, ], ]; } /** * Test FolderUpdate command * * @depends testFolderCreate */ public function testFolderUpdate($params) { // Multi-folder mode self::$deviceType = 'iphone'; // Test renaming a mail folder $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_MAIL_USER_CREATED; $request = << {$params['SyncKey']} {$params['folders'][0]} Test Folder New {$folderType} EOF; $response = $this->request($request, 'FolderUpdate'); $this->assertEquals(200, $response->getStatusCode()); $dom = $this->fromWbxml($response->getBody()); $xpath = $this->xpath($dom); $this->assertSame('1', $xpath->query("//ns:FolderUpdate/ns:Status")->item(0)->nodeValue); $this->assertSame(strval(++$params['SyncKey']), $xpath->query("//ns:FolderUpdate/ns:SyncKey")->item(0)->nodeValue); // Test FolderSync after folder update, get the new folder id (for delete test) $request = << {$params['SyncKey']} EOF; $response = $this->request($request, 'FolderSync'); $dom = $this->fromWbxml($response->getBody()); $xpath = $this->xpath($dom); // Note we expect Add+Delete here, instead of Update (but this could change in the future) $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); $this->assertSame(strval(++$params['SyncKey']), $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); $this->assertSame(1, $xpath->query("//ns:FolderSync/ns:Changes/ns:Add")->length); $this->assertSame(1, $xpath->query("//ns:FolderSync/ns:Changes/ns:Delete")->length); $this->assertSame($params['folders'][0], $xpath->query("//ns:FolderSync/ns:Changes/ns:Delete/ns:ServerId")->item(0)->nodeValue); $this->assertSame('0', $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:ParentId")->item(0)->nodeValue); $this->assertSame('Test Folder New', $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:DisplayName")->item(0)->nodeValue); $this->assertSame(strval($folderType), $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:Type")->item(0)->nodeValue); $params['folders'][0] = $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:ServerId")->item(0)->nodeValue; // Test renaming a contacts folder $folderType = Syncroton_Command_FolderSync::FOLDERTYPE_CONTACT_USER_CREATED; $request = << {$params['SyncKey']} {$params['folders'][1]} Test Contacts New {$folderType} EOF; $response = $this->request($request, 'FolderUpdate'); $this->assertEquals(200, $response->getStatusCode()); $dom = $this->fromWbxml($response->getBody()); $xpath = $this->xpath($dom); $this->assertSame('1', $xpath->query("//ns:FolderUpdate/ns:Status")->item(0)->nodeValue); $this->assertSame(strval(++$params['SyncKey']), $xpath->query("//ns:FolderUpdate/ns:SyncKey")->item(0)->nodeValue); // Test FolderSync after folder update, get the new folder id (for delete test) $request = << {$params['SyncKey']} EOF; $response = $this->request($request, 'FolderSync'); $dom = $this->fromWbxml($response->getBody()); $xpath = $this->xpath($dom); $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Status")->item(0)->nodeValue); $this->assertSame(strval(++$params['SyncKey']), $xpath->query("//ns:FolderSync/ns:SyncKey")->item(0)->nodeValue); if ($this->isStorageDriver('kolab4')) { // Note we expect Update here, not Add+Delete, folder ID does not change $this->assertSame('1', $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue); $this->assertSame($params['folders'][1], $xpath->query("//ns:FolderSync/ns:Changes/ns:Update/ns:ServerId")->item(0)->nodeValue); $this->assertSame('Test Contacts New', $xpath->query("//ns:FolderSync/ns:Changes/ns:Update/ns:DisplayName")->item(0)->nodeValue); $this->assertSame(strval($folderType), $xpath->query("//ns:FolderSync/ns:Changes/ns:Update/ns:Type")->item(0)->nodeValue); } else { // Note we expect Add+Delete here, instead of Update (but this could change in the future) $this->assertSame('2', $xpath->query("//ns:FolderSync/ns:Changes/ns:Count")->item(0)->nodeValue); $this->assertSame($params['folders'][1], $xpath->query("//ns:FolderSync/ns:Changes/ns:Delete/ns:ServerId")->item(0)->nodeValue); $this->assertSame('0', $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:ParentId")->item(0)->nodeValue); $this->assertSame('Test Contacts New', $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:DisplayName")->item(0)->nodeValue); $this->assertSame(strval($folderType), $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:Type")->item(0)->nodeValue); $params['folders'][1] = $xpath->query("//ns:FolderSync/ns:Changes/ns:Add/ns:ServerId")->item(0)->nodeValue; } // TODO: Test folder with a parent change // TODO: Assert the folder name has changed in the storage // TODO: Test Sync after a DAV folder rename made in another client return $params; } /** * Test FolderDelete command * * @depends testFolderUpdate */ public function testFolderDelete($params) { // Multi-folder mode self::$deviceType = 'iphone'; // Delete mail folder $request = << {$params['SyncKey']} {$params['folders'][0]} EOF; $response = $this->request($request, 'FolderDelete'); $this->assertEquals(200, $response->getStatusCode()); $dom = $this->fromWbxml($response->getBody()); $xpath = $this->xpath($dom); $this->assertSame('1', $xpath->query("//ns:FolderDelete/ns:Status")->item(0)->nodeValue); $this->assertSame(strval(++$params['SyncKey']), $xpath->query("//ns:FolderDelete/ns:SyncKey")->item(0)->nodeValue); // Note: After FolderDelete there are no changes in the following FolderSync expected // Delete contacts folder $request = << {$params['SyncKey']} {$params['folders'][1]} EOF; $response = $this->request($request, 'FolderDelete'); $this->assertEquals(200, $response->getStatusCode()); $dom = $this->fromWbxml($response->getBody()); $xpath = $this->xpath($dom); $this->assertSame('1', $xpath->query("//ns:FolderDelete/ns:Status")->item(0)->nodeValue); $this->assertSame(strval(++$params['SyncKey']), $xpath->query("//ns:FolderDelete/ns:SyncKey")->item(0)->nodeValue); // Note: After FolderDelete there are no changes in the following FolderSync expected // TODO: Assert the folders no longer exist } }