Signed-off-by: Robin Appelman <robin@icewind.nl>tags/v11.0RC2
@@ -0,0 +1,90 @@ | |||
<?php | |||
/** | |||
* @copyright Copyright (c) 2016 Robin Appelman <robin@icewind.nl> | |||
* | |||
* @license GNU AGPL version 3 or any later version | |||
* | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License as | |||
* published by the Free Software Foundation, either version 3 of the | |||
* License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public License | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\Files\ObjectStore; | |||
use OCP\Files\ObjectStore\IObjectStore; | |||
use OCP\Files\Storage\IStorage; | |||
/** | |||
* Object store that wraps a storage backend, mostly for testing purposes | |||
*/ | |||
class StorageObjectStore implements IObjectStore { | |||
/** @var IStorage */ | |||
private $storage; | |||
/** | |||
* @param IStorage $storage | |||
*/ | |||
public function __construct(IStorage $storage) { | |||
$this->storage = $storage; | |||
} | |||
/** | |||
* @return string the container or bucket name where objects are stored | |||
* @since 7.0.0 | |||
*/ | |||
function getStorageId() { | |||
$this->storage->getId(); | |||
} | |||
/** | |||
* @param string $urn the unified resource name used to identify the object | |||
* @return resource stream with the read data | |||
* @throws \Exception when something goes wrong, message will be logged | |||
* @since 7.0.0 | |||
*/ | |||
function readObject($urn) { | |||
$handle = $this->storage->fopen($urn, 'r'); | |||
if ($handle) { | |||
return $handle; | |||
} else { | |||
throw new \Exception(); | |||
} | |||
} | |||
/** | |||
* @param string $urn the unified resource name used to identify the object | |||
* @param resource $stream stream with the data to write | |||
* @throws \Exception when something goes wrong, message will be logged | |||
* @since 7.0.0 | |||
*/ | |||
function writeObject($urn, $stream) { | |||
$handle = $this->storage->fopen($urn, 'w'); | |||
if ($handle) { | |||
stream_copy_to_stream($stream, $handle); | |||
fclose($handle); | |||
} else { | |||
throw new \Exception(); | |||
} | |||
} | |||
/** | |||
* @param string $urn the unified resource name used to identify the object | |||
* @return void | |||
* @throws \Exception when something goes wrong, message will be logged | |||
* @since 7.0.0 | |||
*/ | |||
function deleteObject($urn) { | |||
$this->storage->unlink($urn); | |||
} | |||
} |
@@ -0,0 +1,36 @@ | |||
<?php | |||
/** | |||
* @copyright Copyright (c) 2016 Robin Appelman <robin@icewind.nl> | |||
* | |||
* @license GNU AGPL version 3 or any later version | |||
* | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License as | |||
* published by the Free Software Foundation, either version 3 of the | |||
* License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public License | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace Test\Files\ObjectStore; | |||
use OC\Files\ObjectStore\StorageObjectStore; | |||
use OC\Files\Storage\Temporary; | |||
class LocalTest extends ObjectStoreTest { | |||
/** | |||
* @return \OCP\Files\ObjectStore\IObjectStore | |||
*/ | |||
protected function getInstance() { | |||
$storage = new Temporary(); | |||
return new StorageObjectStore($storage); | |||
} | |||
} |
@@ -0,0 +1,169 @@ | |||
<?php | |||
/** | |||
* @author Jörn Friedrich Dreyer | |||
* @copyright (c) 2014 Jörn Friedrich Dreyer <jfd@owncloud.com> | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace Test\Files\ObjectStore; | |||
use OC\Files\ObjectStore\ObjectStoreStorage; | |||
use OC\Files\ObjectStore\StorageObjectStore; | |||
use OC\Files\Storage\Temporary; | |||
use OCP\Files\ObjectStore\IObjectStore; | |||
use Test\Files\Storage\Storage; | |||
/** | |||
* @group DB | |||
*/ | |||
class ObjectStoreStorageTest extends Storage { | |||
/** | |||
* @var IObjectStore | |||
*/ | |||
private $objectStorage; | |||
protected function setUp() { | |||
parent::setUp(); | |||
$baseStorage = new Temporary(); | |||
$this->objectStorage = new StorageObjectStore($baseStorage); | |||
$config['objectstore'] = $this->objectStorage; | |||
$this->instance = new ObjectStoreStorage($config); | |||
} | |||
protected function tearDown() { | |||
if (is_null($this->instance)) { | |||
return; | |||
} | |||
$this->instance->getCache()->clear(); | |||
parent::tearDown(); | |||
} | |||
public function testStat() { | |||
$textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; | |||
$ctimeStart = time(); | |||
$this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile)); | |||
$this->assertTrue($this->instance->isReadable('/lorem.txt')); | |||
$ctimeEnd = time(); | |||
$mTime = $this->instance->filemtime('/lorem.txt'); | |||
// check that ($ctimeStart - 5) <= $mTime <= ($ctimeEnd + 1) | |||
$this->assertGreaterThanOrEqual(($ctimeStart - 5), $mTime); | |||
$this->assertLessThanOrEqual(($ctimeEnd + 1), $mTime); | |||
$this->assertEquals(filesize($textFile), $this->instance->filesize('/lorem.txt')); | |||
$stat = $this->instance->stat('/lorem.txt'); | |||
//only size and mtime are required in the result | |||
$this->assertEquals($stat['size'], $this->instance->filesize('/lorem.txt')); | |||
$this->assertEquals($stat['mtime'], $mTime); | |||
if ($this->instance->touch('/lorem.txt', 100) !== false) { | |||
$mTime = $this->instance->filemtime('/lorem.txt'); | |||
$this->assertEquals($mTime, 100); | |||
} | |||
} | |||
public function testCheckUpdate() { | |||
$this->markTestSkipped('Detecting external changes is not supported on object storages'); | |||
} | |||
/** | |||
* @dataProvider copyAndMoveProvider | |||
*/ | |||
public function testMove($source, $target) { | |||
$this->initSourceAndTarget($source); | |||
$sourceId = $this->instance->getCache()->getId(ltrim('/',$source)); | |||
$this->assertNotEquals(-1, $sourceId); | |||
$this->instance->rename($source, $target); | |||
$this->assertTrue($this->instance->file_exists($target), $target.' was not created'); | |||
$this->assertFalse($this->instance->file_exists($source), $source.' still exists'); | |||
$this->assertSameAsLorem($target); | |||
$targetId = $this->instance->getCache()->getId(ltrim('/',$target)); | |||
$this->assertSame($sourceId, $targetId, 'fileid must be stable on move or shares will break'); | |||
} | |||
public function testRenameDirectory() { | |||
$this->instance->mkdir('source'); | |||
$this->instance->file_put_contents('source/test1.txt', 'foo'); | |||
$this->instance->file_put_contents('source/test2.txt', 'qwerty'); | |||
$this->instance->mkdir('source/subfolder'); | |||
$this->instance->file_put_contents('source/subfolder/test.txt', 'bar'); | |||
$sourceId = $this->instance->getCache()->getId('source'); | |||
$this->assertNotEquals(-1, $sourceId); | |||
$this->instance->rename('source', 'target'); | |||
$this->assertFalse($this->instance->file_exists('source')); | |||
$this->assertFalse($this->instance->file_exists('source/test1.txt')); | |||
$this->assertFalse($this->instance->file_exists('source/test2.txt')); | |||
$this->assertFalse($this->instance->file_exists('source/subfolder')); | |||
$this->assertFalse($this->instance->file_exists('source/subfolder/test.txt')); | |||
$this->assertTrue($this->instance->file_exists('target')); | |||
$this->assertTrue($this->instance->file_exists('target/test1.txt')); | |||
$this->assertTrue($this->instance->file_exists('target/test2.txt')); | |||
$this->assertTrue($this->instance->file_exists('target/subfolder')); | |||
$this->assertTrue($this->instance->file_exists('target/subfolder/test.txt')); | |||
$this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt')); | |||
$this->assertEquals('qwerty', $this->instance->file_get_contents('target/test2.txt')); | |||
$this->assertEquals('bar', $this->instance->file_get_contents('target/subfolder/test.txt')); | |||
$targetId = $this->instance->getCache()->getId('target'); | |||
$this->assertSame($sourceId, $targetId, 'fileid must be stable on move or shares will break'); | |||
} | |||
public function testRenameOverWriteDirectory() { | |||
$this->instance->mkdir('source'); | |||
$this->instance->file_put_contents('source/test1.txt', 'foo'); | |||
$sourceId = $this->instance->getCache()->getId('source'); | |||
$this->assertNotEquals(-1, $sourceId); | |||
$this->instance->mkdir('target'); | |||
$this->instance->file_put_contents('target/test1.txt', 'bar'); | |||
$this->instance->file_put_contents('target/test2.txt', 'bar'); | |||
$this->instance->rename('source', 'target'); | |||
$this->assertFalse($this->instance->file_exists('source')); | |||
$this->assertFalse($this->instance->file_exists('source/test1.txt')); | |||
$this->assertFalse($this->instance->file_exists('target/test2.txt')); | |||
$this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt')); | |||
$targetId = $this->instance->getCache()->getId('target'); | |||
$this->assertSame($sourceId, $targetId, 'fileid must be stable on move or shares will break'); | |||
} | |||
public function testRenameOverWriteDirectoryOverFile() { | |||
$this->instance->mkdir('source'); | |||
$this->instance->file_put_contents('source/test1.txt', 'foo'); | |||
$sourceId = $this->instance->getCache()->getId('source'); | |||
$this->assertNotEquals(-1, $sourceId); | |||
$this->instance->file_put_contents('target', 'bar'); | |||
$this->instance->rename('source', 'target'); | |||
$this->assertFalse($this->instance->file_exists('source')); | |||
$this->assertFalse($this->instance->file_exists('source/test1.txt')); | |||
$this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt')); | |||
$targetId = $this->instance->getCache()->getId('target'); | |||
$this->assertSame($sourceId, $targetId, 'fileid must be stable on move or shares will break'); | |||
} | |||
} |
@@ -0,0 +1,97 @@ | |||
<?php | |||
/** | |||
* @copyright Copyright (c) 2016 Robin Appelman <robin@icewind.nl> | |||
* | |||
* @license GNU AGPL version 3 or any later version | |||
* | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License as | |||
* published by the Free Software Foundation, either version 3 of the | |||
* License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU Affero General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public License | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace Test\Files\ObjectStore; | |||
use Test\TestCase; | |||
abstract class ObjectStoreTest extends TestCase { | |||
/** | |||
* @return \OCP\Files\ObjectStore\IObjectStore | |||
*/ | |||
abstract protected function getInstance(); | |||
private function stringToStream($data) { | |||
$stream = fopen('php://temp', 'w+'); | |||
fwrite($stream, $data); | |||
rewind($stream); | |||
return $stream; | |||
} | |||
public function testWriteRead() { | |||
$stream = $this->stringToStream('foobar'); | |||
$instance = $this->getInstance(); | |||
$instance->writeObject('1', $stream); | |||
$result = $instance->readObject('1'); | |||
$instance->deleteObject('1'); | |||
$this->assertEquals('foobar', stream_get_contents($result)); | |||
} | |||
public function testDelete() { | |||
$stream = $this->stringToStream('foobar'); | |||
$instance = $this->getInstance(); | |||
$instance->writeObject('2', $stream); | |||
$instance->deleteObject('2'); | |||
try { | |||
// to to read to verify that the object no longer exists | |||
$instance->readObject('2'); | |||
$this->fail(); | |||
} catch (\Exception $e) { | |||
// dummy assert to keep phpunit happy | |||
$this->assertEquals(1, 1); | |||
} | |||
} | |||
public function testReadNonExisting() { | |||
$instance = $this->getInstance(); | |||
try { | |||
$instance->readObject('non-existing'); | |||
$this->fail(); | |||
} catch (\Exception $e) { | |||
// dummy assert to keep phpunit happy | |||
$this->assertEquals(1, 1); | |||
} | |||
} | |||
public function testDeleteNonExisting() { | |||
$instance = $this->getInstance(); | |||
try { | |||
$instance->deleteObject('non-existing'); | |||
$this->fail(); | |||
} catch (\Exception $e) { | |||
// dummy assert to keep phpunit happy | |||
$this->assertEquals(1, 1); | |||
} | |||
} | |||
} |
@@ -1,198 +1,38 @@ | |||
<?php | |||
/** | |||
* @author Jörn Friedrich Dreyer | |||
* @copyright (c) 2014 Jörn Friedrich Dreyer <jfd@owncloud.com> | |||
* @copyright Copyright (c) 2016 Robin Appelman <robin@icewind.nl> | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* @license GNU AGPL version 3 or any later version | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* This program is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU Affero General Public License as | |||
* published by the Free Software Foundation, either version 3 of the | |||
* License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* GNU Affero General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* You should have received a copy of the GNU Affero General Public License | |||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace Test\Files\ObjectStore; | |||
use OC\Files\ObjectStore\ObjectStoreStorage; | |||
use OC\Files\ObjectStore\Swift; | |||
/** | |||
* Class SwiftTest | |||
* | |||
* @group DB | |||
* | |||
* @package Test\Files\Cache\ObjectStore | |||
*/ | |||
class SwiftTest extends \Test\Files\Storage\Storage { | |||
class SwiftTest extends ObjectStoreTest { | |||
/** | |||
* @var Swift | |||
* @return \OCP\Files\ObjectStore\IObjectStore | |||
*/ | |||
private $objectStorage; | |||
protected function setUp() { | |||
parent::setUp(); | |||
if (!getenv('RUN_OBJECTSTORE_TESTS')) { | |||
$this->markTestSkipped('objectstore tests are unreliable in some environments'); | |||
} | |||
// reset backend | |||
\OC_User::clearBackends(); | |||
\OC_User::useBackend('database'); | |||
// create users | |||
$users = array('test'); | |||
foreach($users as $userName) { | |||
$user = \OC::$server->getUserManager()->get($userName); | |||
if ($user !== null) { $user->delete(); } | |||
\OC::$server->getUserManager()->createUser($userName, $userName); | |||
} | |||
// main test user | |||
\OC_Util::tearDownFS(); | |||
\OC_User::setUserId(''); | |||
\OC\Files\Filesystem::tearDown(); | |||
\OC_User::setUserId('test'); | |||
protected function getInstance() { | |||
$config = \OC::$server->getConfig()->getSystemValue('objectstore'); | |||
$this->objectStorage = new Swift($config['arguments']); | |||
$config['objectstore'] = $this->objectStorage; | |||
$this->instance = new ObjectStoreStorage($config); | |||
} | |||
protected function tearDown() { | |||
if (is_null($this->instance)) { | |||
return; | |||
} | |||
$this->objectStorage->deleteContainer(true); | |||
$this->instance->getCache()->clear(); | |||
$users = array('test'); | |||
foreach($users as $userName) { | |||
$user = \OC::$server->getUserManager()->get($userName); | |||
if ($user !== null) { $user->delete(); } | |||
} | |||
parent::tearDown(); | |||
} | |||
public function testStat() { | |||
$textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; | |||
$ctimeStart = time(); | |||
$this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile)); | |||
$this->assertTrue($this->instance->isReadable('/lorem.txt')); | |||
$ctimeEnd = time(); | |||
$mTime = $this->instance->filemtime('/lorem.txt'); | |||
// check that ($ctimeStart - 5) <= $mTime <= ($ctimeEnd + 1) | |||
$this->assertGreaterThanOrEqual(($ctimeStart - 5), $mTime); | |||
$this->assertLessThanOrEqual(($ctimeEnd + 1), $mTime); | |||
$this->assertEquals(filesize($textFile), $this->instance->filesize('/lorem.txt')); | |||
$stat = $this->instance->stat('/lorem.txt'); | |||
//only size and mtime are required in the result | |||
$this->assertEquals($stat['size'], $this->instance->filesize('/lorem.txt')); | |||
$this->assertEquals($stat['mtime'], $mTime); | |||
if ($this->instance->touch('/lorem.txt', 100) !== false) { | |||
$mTime = $this->instance->filemtime('/lorem.txt'); | |||
$this->assertEquals($mTime, 100); | |||
if (!is_array($config) || $config['class'] !== 'OC\\Files\\ObjectStore\\Swift') { | |||
$this->markTestSkipped('objectstore not configured for swift'); | |||
} | |||
} | |||
public function testCheckUpdate() { | |||
$this->markTestSkipped('Detecting external changes is not supported on object storages'); | |||
} | |||
/** | |||
* @dataProvider copyAndMoveProvider | |||
*/ | |||
public function testMove($source, $target) { | |||
$this->initSourceAndTarget($source); | |||
$sourceId = $this->instance->getCache()->getId(ltrim('/',$source)); | |||
$this->assertNotEquals(-1, $sourceId); | |||
$this->instance->rename($source, $target); | |||
$this->assertTrue($this->instance->file_exists($target), $target.' was not created'); | |||
$this->assertFalse($this->instance->file_exists($source), $source.' still exists'); | |||
$this->assertSameAsLorem($target); | |||
$targetId = $this->instance->getCache()->getId(ltrim('/',$target)); | |||
$this->assertSame($sourceId, $targetId, 'fileid must be stable on move or shares will break'); | |||
} | |||
public function testRenameDirectory() { | |||
$this->instance->mkdir('source'); | |||
$this->instance->file_put_contents('source/test1.txt', 'foo'); | |||
$this->instance->file_put_contents('source/test2.txt', 'qwerty'); | |||
$this->instance->mkdir('source/subfolder'); | |||
$this->instance->file_put_contents('source/subfolder/test.txt', 'bar'); | |||
$sourceId = $this->instance->getCache()->getId('source'); | |||
$this->assertNotEquals(-1, $sourceId); | |||
$this->instance->rename('source', 'target'); | |||
$this->assertFalse($this->instance->file_exists('source')); | |||
$this->assertFalse($this->instance->file_exists('source/test1.txt')); | |||
$this->assertFalse($this->instance->file_exists('source/test2.txt')); | |||
$this->assertFalse($this->instance->file_exists('source/subfolder')); | |||
$this->assertFalse($this->instance->file_exists('source/subfolder/test.txt')); | |||
$this->assertTrue($this->instance->file_exists('target')); | |||
$this->assertTrue($this->instance->file_exists('target/test1.txt')); | |||
$this->assertTrue($this->instance->file_exists('target/test2.txt')); | |||
$this->assertTrue($this->instance->file_exists('target/subfolder')); | |||
$this->assertTrue($this->instance->file_exists('target/subfolder/test.txt')); | |||
$this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt')); | |||
$this->assertEquals('qwerty', $this->instance->file_get_contents('target/test2.txt')); | |||
$this->assertEquals('bar', $this->instance->file_get_contents('target/subfolder/test.txt')); | |||
$targetId = $this->instance->getCache()->getId('target'); | |||
$this->assertSame($sourceId, $targetId, 'fileid must be stable on move or shares will break'); | |||
} | |||
public function testRenameOverWriteDirectory() { | |||
$this->instance->mkdir('source'); | |||
$this->instance->file_put_contents('source/test1.txt', 'foo'); | |||
$sourceId = $this->instance->getCache()->getId('source'); | |||
$this->assertNotEquals(-1, $sourceId); | |||
$this->instance->mkdir('target'); | |||
$this->instance->file_put_contents('target/test1.txt', 'bar'); | |||
$this->instance->file_put_contents('target/test2.txt', 'bar'); | |||
$this->instance->rename('source', 'target'); | |||
$this->assertFalse($this->instance->file_exists('source')); | |||
$this->assertFalse($this->instance->file_exists('source/test1.txt')); | |||
$this->assertFalse($this->instance->file_exists('target/test2.txt')); | |||
$this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt')); | |||
$targetId = $this->instance->getCache()->getId('target'); | |||
$this->assertSame($sourceId, $targetId, 'fileid must be stable on move or shares will break'); | |||
} | |||
public function testRenameOverWriteDirectoryOverFile() { | |||
$this->instance->mkdir('source'); | |||
$this->instance->file_put_contents('source/test1.txt', 'foo'); | |||
$sourceId = $this->instance->getCache()->getId('source'); | |||
$this->assertNotEquals(-1, $sourceId); | |||
$this->instance->file_put_contents('target', 'bar'); | |||
$this->instance->rename('source', 'target'); | |||
$this->assertFalse($this->instance->file_exists('source')); | |||
$this->assertFalse($this->instance->file_exists('source/test1.txt')); | |||
$this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt')); | |||
$targetId = $this->instance->getCache()->getId('target'); | |||
$this->assertSame($sourceId, $targetId, 'fileid must be stable on move or shares will break'); | |||
return new Swift($config['arguments']); | |||
} | |||
} |