public function testParentItemPatch() { $xml = API::createItem("book", false, $this); $data = API::parseDataFromAtomEntry($xml); $json = json_decode($data['content'], true); $parentKey = $data['key']; $parentVersion = $data['version']; $xml = API::createAttachmentItem("linked_url", [], $parentKey, $this); $data = API::parseDataFromAtomEntry($xml); $json = json_decode($data['content'], true); $childKey = $data['key']; $childVersion = $data['version']; $this->assertArrayHasKey('parentItem', $json); $this->assertEquals($parentKey, $json['parentItem']); $json = array('title' => 'Test'); // With PATCH, parent shouldn't be removed even though unspecified $response = API::userPatch(self::$config['userID'], "items/{$childKey}?key=" . self::$config['apiKey'], json_encode($json), array("If-Unmodified-Since-Version: " . $childVersion)); $this->assert204($response); $xml = API::getItemXML($childKey); $data = API::parseDataFromAtomEntry($xml); $json = json_decode($data['content'], true); $this->assertArrayHasKey('parentItem', $json); }
/** * @depends testGetFile */ public function testAddFilePartial($getFileData) { // Get serverDateModified $response = API::userGet(self::$config['userID'], "items/{$getFileData['key']}?key=" . self::$config['apiKey'] . "&content=json"); $xml = API::getXMLFromResponse($response); $serverDateModified = (string) array_shift($xml->xpath('/atom:entry/atom:updated')); sleep(1); $data = API::parseDataFromAtomEntry($xml); $originalVersion = $data['version']; // Get a sync timestamp from before the file is updated require_once 'include/sync.inc.php'; $sessionID = Sync::login(); $xml = Sync::updated($sessionID); $lastsync = (int) $xml['timestamp']; Sync::logout($sessionID); $oldFilename = "work/old"; $fileContents = $getFileData['response']->getBody(); file_put_contents($oldFilename, $fileContents); $newFilename = "work/new"; $patchFilename = "work/patch"; $algorithms = array("bsdiff" => "bsdiff " . escapeshellarg($oldFilename) . " " . escapeshellarg($newFilename) . " " . escapeshellarg($patchFilename), "xdelta" => "xdelta3 -f -e -9 -S djw -s " . escapeshellarg($oldFilename) . " " . escapeshellarg($newFilename) . " " . escapeshellarg($patchFilename), "vcdiff" => "vcdiff encode " . "-dictionary " . escapeshellarg($oldFilename) . " " . " -target " . escapeshellarg($newFilename) . " " . " -delta " . escapeshellarg($patchFilename)); foreach ($algorithms as $algo => $cmd) { clearstatcache(); // Create random contents file_put_contents($newFilename, uniqid(self::getRandomUnicodeString(), true)); $newHash = md5_file($newFilename); // Get upload authorization $fileParams = array("md5" => $newHash, "filename" => "test_" . $fileContents, "filesize" => filesize($newFilename), "mtime" => filemtime($newFilename) * 1000, "contentType" => "text/plain", "charset" => "utf-8"); $response = API::userPost(self::$config['userID'], "items/{$getFileData['key']}/file?key=" . self::$config['apiKey'], $this->implodeParams($fileParams), array("Content-Type: application/x-www-form-urlencoded", "If-Match: " . md5_file($oldFilename))); $this->assert200($response); $json = json_decode($response->getBody()); $this->assertNotNull($json); exec($cmd, $output, $ret); if ($ret != 0) { echo "Warning: Error running {$algo} -- skipping file upload test\n"; continue; } $patch = file_get_contents($patchFilename); $this->assertNotEquals("", $patch); self::$toDelete[] = "{$newHash}"; // Upload patch file $response = API::userPatch(self::$config['userID'], "items/{$getFileData['key']}/file?key=" . self::$config['apiKey'] . "&algorithm={$algo}&upload=" . $json->uploadKey, $patch, array("If-Match: " . md5_file($oldFilename))); $this->assert204($response); unlink($patchFilename); rename($newFilename, $oldFilename); // Verify attachment item metadata $response = API::userGet(self::$config['userID'], "items/{$getFileData['key']}?key=" . self::$config['apiKey'] . "&content=json"); $xml = API::getXMLFromResponse($response); $data = API::parseDataFromAtomEntry($xml); $json = json_decode($data['content']); $this->assertEquals($fileParams['md5'], $json->md5); $this->assertEquals($fileParams['mtime'], $json->mtime); $this->assertEquals($fileParams['contentType'], $json->contentType); $this->assertEquals($fileParams['charset'], $json->charset); // Make sure version has changed $this->assertNotEquals($originalVersion, $data['version']); // Make sure new attachment is passed via sync $sessionID = Sync::login(); $xml = Sync::updated($sessionID, $lastsync); Sync::logout($sessionID); $this->assertGreaterThan(0, $xml->updated[0]->count()); // Verify file on S3 $response = API::userGet(self::$config['userID'], "items/{$getFileData['key']}/file?key=" . self::$config['apiKey']); $this->assert302($response); $location = $response->getHeader("Location"); $response = HTTP::get($location); $this->assert200($response); $this->assertEquals($fileParams['md5'], md5($response->getBody())); $t = $fileParams['contentType']; $this->assertEquals($t . ($t && $fileParams['charset'] ? "; charset={$fileParams['charset']}" : ""), $response->getHeader("Content-Type")); } }
public function testCollectionItemChange() { $collectionKey1 = API::createCollection('Test', false, $this, 'key'); $collectionKey2 = API::createCollection('Test', false, $this, 'key'); $xml = API::createItem("book", array('collections' => array($collectionKey1)), $this, 'atom'); $data = API::parseDataFromAtomEntry($xml); $itemKey1 = $data['key']; $itemVersion1 = $data['version']; $json = json_decode($data['content']); $this->assertEquals(array($collectionKey1), $json->collections); $xml = API::createItem("journalArticle", array('collections' => array($collectionKey2)), $this, 'atom'); $data = API::parseDataFromAtomEntry($xml); $itemKey2 = $data['key']; $itemVersion2 = $data['version']; $json = json_decode($data['content']); $this->assertEquals(array($collectionKey2), $json->collections); $xml = API::getCollectionXML($collectionKey1); $collectionData1 = API::parseDataFromAtomEntry($xml); $this->assertEquals(1, (int) array_shift($xml->xpath('//atom:entry/zapi:numItems'))); $xml = API::getCollectionXML($collectionKey2); $collectionData2 = API::parseDataFromAtomEntry($xml); $this->assertEquals(1, (int) array_shift($xml->xpath('//atom:entry/zapi:numItems'))); $libraryVersion = API::getLibraryVersion(); // Add items to collection $response = API::userPatch(self::$config['userID'], "items/{$itemKey1}?key=" . self::$config['apiKey'], json_encode(array("collections" => array($collectionKey1, $collectionKey2))), array("Content-Type: application/json", "If-Unmodified-Since-Version: {$itemVersion1}")); $this->assert204($response); // Item version should change $xml = API::getItemXML($itemKey1); $data = API::parseDataFromAtomEntry($xml); $this->assertEquals($libraryVersion + 1, $data['version']); // Collection timestamp shouldn't change, but numItems should $xml = API::getCollectionXML($collectionKey2); $data = API::parseDataFromAtomEntry($xml); $this->assertEquals(2, (int) array_shift($xml->xpath('//atom:entry/zapi:numItems'))); $this->assertEquals($collectionData2['version'], $data['version']); $collectionData2 = $data; $libraryVersion = API::getLibraryVersion(); // Remove collections $response = API::userPatch(self::$config['userID'], "items/{$itemKey2}?key=" . self::$config['apiKey'], json_encode(array("collections" => array())), array("Content-Type: application/json", "If-Unmodified-Since-Version: {$itemVersion2}")); $this->assert204($response); // Item version should change $xml = API::getItemXML($itemKey2); $data = API::parseDataFromAtomEntry($xml); $this->assertEquals($libraryVersion + 1, $data['version']); // Collection timestamp shouldn't change, but numItems should $xml = API::getCollectionXML($collectionKey2); $data = API::parseDataFromAtomEntry($xml); $this->assertEquals(1, (int) array_shift($xml->xpath('//atom:entry/zapi:numItems'))); $this->assertEquals($collectionData2['version'], $data['version']); // Check collections arrays and numItems $xml = API::getItemXML($itemKey1); $data = API::parseDataFromAtomEntry($xml); $json = json_decode($data['content']); $this->assertCount(2, $json->collections); $this->assertContains($collectionKey1, $json->collections); $this->assertContains($collectionKey2, $json->collections); $xml = API::getItemXML($itemKey2); $data = API::parseDataFromAtomEntry($xml); $json = json_decode($data['content']); $this->assertCount(0, $json->collections); $xml = API::getCollectionXML($collectionKey1); $this->assertEquals(1, (int) array_shift($xml->xpath('//atom:entry/zapi:numItems'))); $xml = API::getCollectionXML($collectionKey2); $this->assertEquals(1, (int) array_shift($xml->xpath('//atom:entry/zapi:numItems'))); }