diff options
Diffstat (limited to 'tests/lib/Files/Storage')
-rw-r--r-- | tests/lib/Files/Storage/CommonTest.php | 48 | ||||
-rw-r--r-- | tests/lib/Files/Storage/CopyDirectoryTest.php | 53 | ||||
-rw-r--r-- | tests/lib/Files/Storage/HomeStorageQuotaTest.php | 81 | ||||
-rw-r--r-- | tests/lib/Files/Storage/HomeTest.php | 109 | ||||
-rw-r--r-- | tests/lib/Files/Storage/LocalTest.php | 88 | ||||
-rw-r--r-- | tests/lib/Files/Storage/Storage.php | 617 | ||||
-rw-r--r-- | tests/lib/Files/Storage/StorageFactoryTest.php | 72 | ||||
-rw-r--r-- | tests/lib/Files/Storage/Wrapper/AvailabilityTest.php | 153 | ||||
-rw-r--r-- | tests/lib/Files/Storage/Wrapper/EncryptionTest.php | 926 | ||||
-rw-r--r-- | tests/lib/Files/Storage/Wrapper/JailTest.php | 51 | ||||
-rw-r--r-- | tests/lib/Files/Storage/Wrapper/PermissionsMaskTest.php | 105 | ||||
-rw-r--r-- | tests/lib/Files/Storage/Wrapper/QuotaTest.php | 211 | ||||
-rw-r--r-- | tests/lib/Files/Storage/Wrapper/WrapperTest.php | 34 |
13 files changed, 2548 insertions, 0 deletions
diff --git a/tests/lib/Files/Storage/CommonTest.php b/tests/lib/Files/Storage/CommonTest.php new file mode 100644 index 00000000000..38faa9b0b21 --- /dev/null +++ b/tests/lib/Files/Storage/CommonTest.php @@ -0,0 +1,48 @@ +<?php +/** +* ownCloud +* +* @author Robin Appelman +* @copyright 2012 Robin Appelman icewind@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\Storage; + +/** + * Class CommonTest + * + * @group DB + * + * @package Test\Files\Storage + */ +class CommonTest extends Storage { + /** + * @var string tmpDir + */ + private $tmpDir; + protected function setUp() { + parent::setUp(); + + $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder(); + $this->instance=new \OC\Files\Storage\CommonTest(array('datadir'=>$this->tmpDir)); + } + + protected function tearDown() { + \OC_Helper::rmdirr($this->tmpDir); + parent::tearDown(); + } +} diff --git a/tests/lib/Files/Storage/CopyDirectoryTest.php b/tests/lib/Files/Storage/CopyDirectoryTest.php new file mode 100644 index 00000000000..74b8148aa36 --- /dev/null +++ b/tests/lib/Files/Storage/CopyDirectoryTest.php @@ -0,0 +1,53 @@ +<?php +/** + * @author Robin Appelman <icewind@owncloud.com> + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace Test\Files\Storage; + +use OC\Files\Storage\Temporary; + +class StorageNoRecursiveCopy extends Temporary { + public function copy($path1, $path2) { + if ($this->is_dir($path1)) { + return false; + } + return copy($this->getSourcePath($path1), $this->getSourcePath($path2)); + } +} + +class CopyDirectoryStorage extends StorageNoRecursiveCopy { + use \OC\Files\Storage\PolyFill\CopyDirectory; +} + +/** + * Class CopyDirectoryTest + * + * @group DB + * + * @package Test\Files\Storage + */ +class CopyDirectoryTest extends Storage { + + protected function setUp() { + parent::setUp(); + $this->instance = new CopyDirectoryStorage([]); + } +} + diff --git a/tests/lib/Files/Storage/HomeStorageQuotaTest.php b/tests/lib/Files/Storage/HomeStorageQuotaTest.php new file mode 100644 index 00000000000..68fa4bb0bbb --- /dev/null +++ b/tests/lib/Files/Storage/HomeStorageQuotaTest.php @@ -0,0 +1,81 @@ +<?php +/** + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace Test\Files\Storage; + +/** + * Class HomeStorageQuotaTest + * + * @group DB + */ +class HomeStorageQuotaTest extends \Test\TestCase { + /** + * Tests that the home storage is not wrapped when no quota exists. + */ + function testHomeStorageWrapperWithoutQuota() { + $user1 = $this->getUniqueID(); + \OC::$server->getUserManager()->createUser($user1, 'test'); + \OC::$server->getConfig()->setUserValue($user1, 'files', 'quota', 'none'); + \OC_User::setUserId($user1); + + \OC_Util::setupFS($user1); + + $userMount = \OC\Files\Filesystem::getMountManager()->find('/' . $user1 . '/'); + $this->assertNotNull($userMount); + $this->assertNotInstanceOf('\OC\Files\Storage\Wrapper\Quota', $userMount->getStorage()); + + // clean up + \OC_User::setUserId(''); + $user = \OC::$server->getUserManager()->get($user1); + if ($user !== null) { $user->delete(); } + \OC::$server->getConfig()->deleteAllUserValues($user1); + \OC_Util::tearDownFS(); + } + + /** + * Tests that the home storage is not wrapped when no quota exists. + */ + function testHomeStorageWrapperWithQuota() { + $user1 = $this->getUniqueID(); + \OC::$server->getUserManager()->createUser($user1, 'test'); + \OC::$server->getConfig()->setUserValue($user1, 'files', 'quota', '1024'); + \OC_User::setUserId($user1); + + \OC_Util::setupFS($user1); + + $userMount = \OC\Files\Filesystem::getMountManager()->find('/' . $user1 . '/'); + $this->assertNotNull($userMount); + $this->assertTrue($userMount->getStorage()->instanceOfStorage('\OC\Files\Storage\Wrapper\Quota')); + + // ensure that root wasn't wrapped + $rootMount = \OC\Files\Filesystem::getMountManager()->find('/'); + $this->assertNotNull($rootMount); + $this->assertNotInstanceOf('\OC\Files\Storage\Wrapper\Quota', $rootMount->getStorage()); + + // clean up + \OC_User::setUserId(''); + $user = \OC::$server->getUserManager()->get($user1); + if ($user !== null) { $user->delete(); } + \OC::$server->getConfig()->deleteAllUserValues($user1); + \OC_Util::tearDownFS(); + } + +} diff --git a/tests/lib/Files/Storage/HomeTest.php b/tests/lib/Files/Storage/HomeTest.php new file mode 100644 index 00000000000..d9a1b11849e --- /dev/null +++ b/tests/lib/Files/Storage/HomeTest.php @@ -0,0 +1,109 @@ +<?php +/** + * ownCloud + * + * @author Robin Appelman + * @copyright 2012 Robin Appelman icewind@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\Storage; + +use OC\User\User; + +class DummyUser extends User { + private $home; + + private $uid; + + /** + * @param string $uid + * @param string $home + */ + public function __construct($uid, $home) { + $this->uid = $uid; + $this->home = $home; + } + + public function getHome() { + return $this->home; + } + + public function getUID() { + return $this->uid; + } +} + +/** + * Class Home + * + * @group DB + * + * @package Test\Files\Storage + */ +class HomeTest extends Storage { + /** + * @var string tmpDir + */ + private $tmpDir; + + private $userId; + + /** + * @var \OC\User\User $user + */ + private $user; + + protected function setUp() { + parent::setUp(); + + $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder(); + $this->userId = $this->getUniqueID('user_'); + $this->user = new DummyUser($this->userId, $this->tmpDir); + $this->instance = new \OC\Files\Storage\Home(array('user' => $this->user)); + } + + protected function tearDown() { + \OC_Helper::rmdirr($this->tmpDir); + parent::tearDown(); + } + + /** + * Tests that the home id is in the format home::user1 + */ + public function testId() { + $this->assertEquals('home::' . $this->userId, $this->instance->getId()); + } + + /** + * Tests that the legacy home id is in the format local::/path/to/datadir/user1/ + */ + public function testLegacyId() { + $this->instance = new \OC\Files\Storage\Home(array('user' => $this->user, 'legacy' => true)); + $this->assertEquals('local::' . $this->tmpDir . '/', $this->instance->getId()); + } + + /** + * Tests that getCache() returns an instance of HomeCache + */ + public function testGetCacheReturnsHomeCache() { + $this->assertInstanceOf('\OC\Files\Cache\HomeCache', $this->instance->getCache()); + } + + public function testGetOwner() { + $this->assertEquals($this->userId, $this->instance->getOwner('')); + } +} diff --git a/tests/lib/Files/Storage/LocalTest.php b/tests/lib/Files/Storage/LocalTest.php new file mode 100644 index 00000000000..7b8ae6a24b2 --- /dev/null +++ b/tests/lib/Files/Storage/LocalTest.php @@ -0,0 +1,88 @@ +<?php +/** + * ownCloud + * + * @author Robin Appelman + * @copyright 2012 Robin Appelman icewind@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\Storage; + +/** + * Class LocalTest + * + * @group DB + * + * @package Test\Files\Storage + */ +class LocalTest extends Storage { + /** + * @var string tmpDir + */ + private $tmpDir; + + protected function setUp() { + parent::setUp(); + + $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder(); + $this->instance = new \OC\Files\Storage\Local(array('datadir' => $this->tmpDir)); + } + + protected function tearDown() { + \OC_Helper::rmdirr($this->tmpDir); + parent::tearDown(); + } + + public function testStableEtag() { + if (\OC_Util::runningOnWindows()) { + $this->markTestSkipped('[Windows] On Windows platform we have no stable etag generation - yet'); + } + + $this->instance->file_put_contents('test.txt', 'foobar'); + $etag1 = $this->instance->getETag('test.txt'); + $etag2 = $this->instance->getETag('test.txt'); + $this->assertEquals($etag1, $etag2); + } + + public function testEtagChange() { + if (\OC_Util::runningOnWindows()) { + $this->markTestSkipped('[Windows] On Windows platform we have no stable etag generation - yet'); + } + + $this->instance->file_put_contents('test.txt', 'foo'); + $this->instance->touch('test.txt', time() - 2); + $etag1 = $this->instance->getETag('test.txt'); + $this->instance->file_put_contents('test.txt', 'bar'); + $etag2 = $this->instance->getETag('test.txt'); + $this->assertNotEquals($etag1, $etag2); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testInvalidArgumentsEmptyArray() { + new \OC\Files\Storage\Local([]); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testInvalidArgumentsNoArray() { + new \OC\Files\Storage\Local(null); + } +} + diff --git a/tests/lib/Files/Storage/Storage.php b/tests/lib/Files/Storage/Storage.php new file mode 100644 index 00000000000..ed2ea87f9d9 --- /dev/null +++ b/tests/lib/Files/Storage/Storage.php @@ -0,0 +1,617 @@ +<?php +/** + * ownCloud + * + * @author Robin Appelman + * @copyright 2012 Robin Appelman icewind@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\Storage; + +use OC\Files\Cache\Watcher; + +abstract class Storage extends \Test\TestCase { + /** + * @var \OC\Files\Storage\Storage instance + */ + protected $instance; + protected $waitDelay = 0; + + /** + * Sleep for the number of seconds specified in the + * $waitDelay attribute + */ + protected function wait() { + if ($this->waitDelay > 0) { + sleep($this->waitDelay); + } + } + + /** + * the root folder of the storage should always exist, be readable and be recognized as a directory + */ + public function testRoot() { + $this->assertTrue($this->instance->file_exists('/'), 'Root folder does not exist'); + $this->assertTrue($this->instance->isReadable('/'), 'Root folder is not readable'); + $this->assertTrue($this->instance->is_dir('/'), 'Root folder is not a directory'); + $this->assertFalse($this->instance->is_file('/'), 'Root folder is a file'); + $this->assertEquals('dir', $this->instance->filetype('/')); + + //without this, any further testing would be useless, not an actual requirement for filestorage though + $this->assertTrue($this->instance->isUpdatable('/'), 'Root folder is not writable'); + } + + /** + * Check that the test() function works + */ + public function testTestFunction() { + $this->assertTrue($this->instance->test()); + } + + /** + * @dataProvider directoryProvider + */ + public function testDirectories($directory) { + $this->assertFalse($this->instance->file_exists('/' . $directory)); + + $this->assertTrue($this->instance->mkdir('/' . $directory)); + + $this->assertTrue($this->instance->file_exists('/' . $directory)); + $this->assertTrue($this->instance->is_dir('/' . $directory)); + $this->assertFalse($this->instance->is_file('/' . $directory)); + $this->assertEquals('dir', $this->instance->filetype('/' . $directory)); + $this->assertEquals(0, $this->instance->filesize('/' . $directory)); + $this->assertTrue($this->instance->isReadable('/' . $directory)); + $this->assertTrue($this->instance->isUpdatable('/' . $directory)); + + $dh = $this->instance->opendir('/'); + $content = array(); + while ($file = readdir($dh)) { + if ($file != '.' and $file != '..') { + $content[] = $file; + } + } + $this->assertEquals(array($directory), $content); + + $this->assertFalse($this->instance->mkdir('/' . $directory)); //can't create existing folders + $this->assertTrue($this->instance->rmdir('/' . $directory)); + + $this->wait(); + $this->assertFalse($this->instance->file_exists('/' . $directory)); + + $this->assertFalse($this->instance->rmdir('/' . $directory)); //can't remove non existing folders + + $dh = $this->instance->opendir('/'); + $content = array(); + while ($file = readdir($dh)) { + if ($file != '.' and $file != '..') { + $content[] = $file; + } + } + $this->assertEquals(array(), $content); + } + + public function directoryProvider() { + return [ + ['folder'], + [' folder'], + ['folder '], + ['folder with space'], + ['spéciäl földer'], + ['test single\'quote'], + ]; + } + + function loremFileProvider() { + $root = \OC::$SERVERROOT . '/tests/data/'; + return array( + // small file + array($root . 'lorem.txt'), + // bigger file (> 8 KB which is the standard PHP block size) + array($root . 'lorem-big.txt') + ); + } + + /** + * test the various uses of file_get_contents and file_put_contents + * + * @dataProvider loremFileProvider + */ + public function testGetPutContents($sourceFile) { + $sourceText = file_get_contents($sourceFile); + + //fill a file with string data + $this->instance->file_put_contents('/lorem.txt', $sourceText); + $this->assertFalse($this->instance->is_dir('/lorem.txt')); + $this->assertEquals($sourceText, $this->instance->file_get_contents('/lorem.txt'), 'data returned from file_get_contents is not equal to the source data'); + + //empty the file + $this->instance->file_put_contents('/lorem.txt', ''); + $this->assertEquals('', $this->instance->file_get_contents('/lorem.txt'), 'file not emptied'); + } + + /** + * test various known mimetypes + */ + public function testMimeType() { + $this->assertEquals('httpd/unix-directory', $this->instance->getMimeType('/')); + $this->assertEquals(false, $this->instance->getMimeType('/non/existing/file')); + + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile, 'r')); + $this->assertEquals('text/plain', $this->instance->getMimeType('/lorem.txt')); + + $pngFile = \OC::$SERVERROOT . '/tests/data/desktopapp.png'; + $this->instance->file_put_contents('/desktopapp.png', file_get_contents($pngFile, 'r')); + $this->assertEquals('image/png', $this->instance->getMimeType('/desktopapp.png')); + + $svgFile = \OC::$SERVERROOT . '/tests/data/desktopapp.svg'; + $this->instance->file_put_contents('/desktopapp.svg', file_get_contents($svgFile, 'r')); + $this->assertEquals('image/svg+xml', $this->instance->getMimeType('/desktopapp.svg')); + } + + + public function copyAndMoveProvider() { + return [ + ['/source.txt', '/target.txt'], + ['/source.txt', '/target with space.txt'], + ['/source with space.txt', '/target.txt'], + ['/source with space.txt', '/target with space.txt'], + ['/source.txt', '/tärgét.txt'], + ['/sòurcē.txt', '/target.txt'], + ['/sòurcē.txt', '/tärgét.txt'], + ['/single \' quote.txt', '/tar\'get.txt'], + ]; + } + + public function initSourceAndTarget($source, $target = null) { + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + $this->instance->file_put_contents($source, file_get_contents($textFile)); + if ($target) { + $testContents = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $this->instance->file_put_contents($target, $testContents); + } + } + + public function assertSameAsLorem($file) { + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + $this->assertEquals( + file_get_contents($textFile), + $this->instance->file_get_contents($file), + 'Expected ' . $file . ' to be a copy of ' . $textFile + ); + } + + /** + * @dataProvider copyAndMoveProvider + */ + public function testCopy($source, $target) { + $this->initSourceAndTarget($source); + + $this->instance->copy($source, $target); + + $this->assertTrue($this->instance->file_exists($target), $target . ' was not created'); + $this->assertSameAsLorem($target); + $this->assertTrue($this->instance->file_exists($source), $source . ' was deleted'); + } + + /** + * @dataProvider copyAndMoveProvider + */ + public function testMove($source, $target) { + $this->initSourceAndTarget($source); + + $this->instance->rename($source, $target); + + $this->wait(); + $this->assertTrue($this->instance->file_exists($target), $target . ' was not created'); + $this->assertFalse($this->instance->file_exists($source), $source . ' still exists'); + $this->assertSameAsLorem($target); + } + + /** + * @dataProvider copyAndMoveProvider + */ + public function testCopyOverwrite($source, $target) { + $this->initSourceAndTarget($source, $target); + + $this->instance->copy($source, $target); + + $this->assertTrue($this->instance->file_exists($target), $target . ' was not created'); + $this->assertTrue($this->instance->file_exists($source), $source . ' was deleted'); + $this->assertSameAsLorem($target); + $this->assertSameAsLorem($source); + } + + /** + * @dataProvider copyAndMoveProvider + */ + public function testMoveOverwrite($source, $target) { + $this->initSourceAndTarget($source, $target); + + $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); + } + + public function testLocal() { + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile)); + $localFile = $this->instance->getLocalFile('/lorem.txt'); + $this->assertTrue(file_exists($localFile)); + $this->assertEquals(file_get_contents($textFile), file_get_contents($localFile)); + + $this->instance->mkdir('/folder'); + $this->instance->file_put_contents('/folder/lorem.txt', file_get_contents($textFile)); + $this->instance->file_put_contents('/folder/bar.txt', 'asd'); + $this->instance->mkdir('/folder/recursive'); + $this->instance->file_put_contents('/folder/recursive/file.txt', 'foo'); + + // test below require to use instance->getLocalFile because the physical storage might be different + $localFile = $this->instance->getLocalFile('/folder/lorem.txt'); + $this->assertTrue(file_exists($localFile)); + $this->assertEquals(file_get_contents($localFile), file_get_contents($textFile)); + + $localFile = $this->instance->getLocalFile('/folder/bar.txt'); + $this->assertTrue(file_exists($localFile)); + $this->assertEquals(file_get_contents($localFile), 'asd'); + + $localFile = $this->instance->getLocalFile('/folder/recursive/file.txt'); + $this->assertTrue(file_exists($localFile)); + $this->assertEquals(file_get_contents($localFile), 'foo'); + } + + 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'); + $this->assertTrue($this->instance->hasUpdated('/lorem.txt', $ctimeStart - 5)); + $this->assertTrue($this->instance->hasUpdated('/', $ctimeStart - 5)); + + // 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); + } + + $mtimeStart = time(); + + $this->instance->unlink('/lorem.txt'); + $this->assertTrue($this->instance->hasUpdated('/', $mtimeStart - 5)); + } + + /** + * Test whether checkUpdate properly returns false when there was + * no change. + */ + public function testCheckUpdate() { + if ($this->instance instanceof \OC\Files\Storage\Wrapper\Wrapper) { + $this->markTestSkipped('Cannot test update check on wrappers'); + } + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + $watcher = $this->instance->getWatcher(); + $watcher->setPolicy(Watcher::CHECK_ALWAYS); + $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile)); + $this->assertTrue($watcher->checkUpdate('/lorem.txt'), 'Update detected'); + $this->assertFalse($watcher->checkUpdate('/lorem.txt'), 'No update'); + } + + public function testUnlink() { + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + $this->instance->file_put_contents('/lorem.txt', file_get_contents($textFile)); + + $this->assertTrue($this->instance->file_exists('/lorem.txt')); + + $this->assertTrue($this->instance->unlink('/lorem.txt')); + $this->wait(); + + $this->assertFalse($this->instance->file_exists('/lorem.txt')); + } + + public function testFOpen() { + $textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt'; + + $fh = @$this->instance->fopen('foo', 'r'); + if ($fh) { + fclose($fh); + } + $this->assertFalse($fh); + $this->assertFalse($this->instance->file_exists('foo')); + + $fh = $this->instance->fopen('foo', 'w'); + fwrite($fh, file_get_contents($textFile)); + fclose($fh); + $this->assertTrue($this->instance->file_exists('foo')); + + $fh = $this->instance->fopen('foo', 'r'); + $content = stream_get_contents($fh); + $this->assertEquals(file_get_contents($textFile), $content); + } + + public function testTouchCreateFile() { + $this->assertFalse($this->instance->file_exists('touch')); + // returns true on success + $this->assertTrue($this->instance->touch('touch')); + $this->assertTrue($this->instance->file_exists('touch')); + } + + public function testRecursiveRmdir() { + $this->instance->mkdir('folder'); + $this->instance->mkdir('folder/bar'); + $this->wait(); + $this->instance->file_put_contents('folder/asd.txt', 'foobar'); + $this->instance->file_put_contents('folder/bar/foo.txt', 'asd'); + $this->assertTrue($this->instance->rmdir('folder')); + $this->wait(); + $this->assertFalse($this->instance->file_exists('folder/asd.txt')); + $this->assertFalse($this->instance->file_exists('folder/bar/foo.txt')); + $this->assertFalse($this->instance->file_exists('folder/bar')); + $this->assertFalse($this->instance->file_exists('folder')); + } + + public function testRmdirEmptyFolder() { + $this->assertTrue($this->instance->mkdir('empty')); + $this->wait(); + $this->assertTrue($this->instance->rmdir('empty')); + $this->assertFalse($this->instance->file_exists('empty')); + } + + public function testRecursiveUnlink() { + $this->instance->mkdir('folder'); + $this->instance->mkdir('folder/bar'); + $this->instance->file_put_contents('folder/asd.txt', 'foobar'); + $this->instance->file_put_contents('folder/bar/foo.txt', 'asd'); + $this->assertTrue($this->instance->unlink('folder')); + $this->wait(); + $this->assertFalse($this->instance->file_exists('folder/asd.txt')); + $this->assertFalse($this->instance->file_exists('folder/bar/foo.txt')); + $this->assertFalse($this->instance->file_exists('folder/bar')); + $this->assertFalse($this->instance->file_exists('folder')); + } + + public function hashProvider() { + return array( + array('Foobar', 'md5'), + array('Foobar', 'sha1'), + array('Foobar', 'sha256'), + ); + } + + /** + * @dataProvider hashProvider + */ + public function testHash($data, $type) { + $this->instance->file_put_contents('hash.txt', $data); + $this->assertEquals(hash($type, $data), $this->instance->hash($type, 'hash.txt')); + $this->assertEquals(hash($type, $data, true), $this->instance->hash($type, 'hash.txt', true)); + } + + public function testHashInFileName() { + $this->instance->file_put_contents('#test.txt', 'data'); + $this->assertEquals('data', $this->instance->file_get_contents('#test.txt')); + + $this->instance->mkdir('#foo'); + $this->instance->file_put_contents('#foo/test.txt', 'data'); + $this->assertEquals('data', $this->instance->file_get_contents('#foo/test.txt')); + + $dh = $this->instance->opendir('#foo'); + $content = array(); + while ($file = readdir($dh)) { + if ($file != '.' and $file != '..') { + $content[] = $file; + } + } + + $this->assertEquals(array('test.txt'), $content); + } + + public function testCopyOverWriteFile() { + $this->instance->file_put_contents('target.txt', 'foo'); + $this->instance->file_put_contents('source.txt', 'bar'); + $this->instance->copy('source.txt', 'target.txt'); + $this->assertEquals('bar', $this->instance->file_get_contents('target.txt')); + } + + public function testRenameOverWriteFile() { + $this->instance->file_put_contents('target.txt', 'foo'); + $this->instance->file_put_contents('source.txt', 'bar'); + $this->instance->rename('source.txt', 'target.txt'); + $this->assertEquals('bar', $this->instance->file_get_contents('target.txt')); + $this->assertFalse($this->instance->file_exists('source.txt')); + } + + 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'); + $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')); + } + + public function testRenameOverWriteDirectory() { + $this->instance->mkdir('source'); + $this->instance->file_put_contents('source/test1.txt', 'foo'); + + $this->instance->mkdir('target'); + $this->instance->file_put_contents('target/test1.txt', 'bar'); + $this->instance->file_put_contents('target/test2.txt', 'bar'); + + $this->assertTrue($this->instance->rename('source', 'target'), 'rename must return true on success'); + + $this->assertFalse($this->instance->file_exists('source'), 'source has not been removed'); + $this->assertFalse($this->instance->file_exists('source/test1.txt'), 'source/test1.txt has not been removed'); + $this->assertFalse($this->instance->file_exists('target/test2.txt'), 'target/test2.txt has not been removed'); + $this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt'), 'target/test1.txt has not been overwritten'); + } + + public function testRenameOverWriteDirectoryOverFile() { + $this->instance->mkdir('source'); + $this->instance->file_put_contents('source/test1.txt', 'foo'); + + $this->instance->file_put_contents('target', 'bar'); + + $this->assertTrue($this->instance->rename('source', 'target'), 'rename must return true on success'); + + $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')); + } + + public function testCopyDirectory() { + $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'); + $this->instance->copy('source', 'target'); + + $this->assertTrue($this->instance->file_exists('source')); + $this->assertTrue($this->instance->file_exists('source/test1.txt')); + $this->assertTrue($this->instance->file_exists('source/test2.txt')); + $this->assertTrue($this->instance->file_exists('source/subfolder')); + $this->assertTrue($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')); + } + + public function testCopyOverWriteDirectory() { + $this->instance->mkdir('source'); + $this->instance->file_put_contents('source/test1.txt', 'foo'); + + $this->instance->mkdir('target'); + $this->instance->file_put_contents('target/test1.txt', 'bar'); + $this->instance->file_put_contents('target/test2.txt', 'bar'); + + $this->instance->copy('source', 'target'); + + $this->assertFalse($this->instance->file_exists('target/test2.txt')); + $this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt')); + } + + public function testCopyOverWriteDirectoryOverFile() { + $this->instance->mkdir('source'); + $this->instance->file_put_contents('source/test1.txt', 'foo'); + + $this->instance->file_put_contents('target', 'bar'); + + $this->instance->copy('source', 'target'); + + $this->assertEquals('foo', $this->instance->file_get_contents('target/test1.txt')); + } + + public function testInstanceOfStorage() { + $this->assertTrue($this->instance->instanceOfStorage('\OCP\Files\Storage')); + $this->assertTrue($this->instance->instanceOfStorage(get_class($this->instance))); + $this->assertFalse($this->instance->instanceOfStorage('\OC')); + } + + /** + * @dataProvider copyAndMoveProvider + */ + public function testCopyFromSameStorage($source, $target) { + $this->initSourceAndTarget($source); + + $this->instance->copyFromStorage($this->instance, $source, $target); + + $this->assertTrue($this->instance->file_exists($target), $target . ' was not created'); + $this->assertSameAsLorem($target); + $this->assertTrue($this->instance->file_exists($source), $source . ' was deleted'); + } + + public function testIsCreatable() { + $this->instance->mkdir('source'); + $this->assertTrue($this->instance->isCreatable('source')); + } + + public function testIsReadable() { + $this->instance->mkdir('source'); + $this->assertTrue($this->instance->isReadable('source')); + } + + public function testIsUpdatable() { + $this->instance->mkdir('source'); + $this->assertTrue($this->instance->isUpdatable('source')); + } + + public function testIsDeletable() { + $this->instance->mkdir('source'); + $this->assertTrue($this->instance->isDeletable('source')); + } + + public function testIsShareable() { + $this->instance->mkdir('source'); + $this->assertTrue($this->instance->isSharable('source')); + } + + public function testStatAfterWrite() { + $this->instance->file_put_contents('foo.txt', 'bar'); + $stat = $this->instance->stat('foo.txt'); + $this->assertEquals(3, $stat['size']); + + $fh = $this->instance->fopen('foo.txt', 'w'); + fwrite($fh, 'qwerty'); + fclose($fh); + + $stat = $this->instance->stat('foo.txt'); + $this->assertEquals(6, $stat['size']); + } + + public function testPartFile() { + $this->instance->file_put_contents('bar.txt.part', 'bar'); + $this->instance->rename('bar.txt.part', 'bar.txt'); + $this->assertEquals('bar', $this->instance->file_get_contents('bar.txt')); + } +} diff --git a/tests/lib/Files/Storage/StorageFactoryTest.php b/tests/lib/Files/Storage/StorageFactoryTest.php new file mode 100644 index 00000000000..d3dc036ab42 --- /dev/null +++ b/tests/lib/Files/Storage/StorageFactoryTest.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright (c) 2015 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Files\Storage; + +use OC\Files\Mount\MountPoint; +use OCP\Files\Mount\IMountPoint; +use OCP\Files\Storage as IStorage; +use Test\TestCase; +use OC\Files\Storage\Wrapper\Wrapper; + +class DummyWrapper extends Wrapper { + public $data; + + public function __construct($arguments) { + parent::__construct($arguments); + if (isset($arguments['data'])) { + $this->data = $arguments['data']; + } + } +} + +class StorageFactoryTest extends TestCase { + public function testSimpleWrapper() { + $instance = new \OC\Files\Storage\StorageFactory(); + $mount = new MountPoint('\OC\Files\Storage\Temporary', '/foo', [[]], $instance); + $instance->addStorageWrapper('dummy', function ($mountPoint, IStorage $storage, IMountPoint $mount) { + $this->assertInstanceOf('\OC\Files\Storage\Temporary', $storage); + $this->assertEquals('/foo/', $mount->getMountPoint()); + $this->assertEquals('/foo/', $mountPoint); + return new DummyWrapper(['storage' => $storage]); + }); + $wrapped = $mount->getStorage(); + $this->assertInstanceOf('\Test\Files\Storage\DummyWrapper', $wrapped); + } + + public function testRemoveWrapper() { + $instance = new \OC\Files\Storage\StorageFactory(); + $mount = new MountPoint('\OC\Files\Storage\Temporary', '/foo', [[]], $instance); + $instance->addStorageWrapper('dummy', function ($mountPoint, IStorage $storage) { + return new DummyWrapper(['storage' => $storage]); + }); + $instance->removeStorageWrapper('dummy'); + $wrapped = $mount->getStorage(); + $this->assertInstanceOf('\OC\Files\Storage\Temporary', $wrapped); + } + + public function testWrapperPriority() { + $instance = new \OC\Files\Storage\StorageFactory(); + $mount = new MountPoint('\OC\Files\Storage\Temporary', '/foo', [[]], $instance); + $instance->addStorageWrapper('dummy1', function ($mountPoint, IStorage $storage) { + return new DummyWrapper(['storage' => $storage, 'data' => 1]); + }, 1); + $instance->addStorageWrapper('dummy2', function ($mountPoint, IStorage $storage) { + return new DummyWrapper(['storage' => $storage, 'data' => 100]); + }, 100); + $instance->addStorageWrapper('dummy3', function ($mountPoint, IStorage $storage) { + return new DummyWrapper(['storage' => $storage, 'data' => 50]); + }, 50); + /** @var \Test\Files\Storage\DummyWrapper $wrapped */ + $wrapped = $mount->getStorage(); + $this->assertInstanceOf('\Test\Files\Storage\DummyWrapper', $wrapped); + $this->assertEquals(1, $wrapped->data);// lowest priority is applied last, called first + $this->assertEquals(50, $wrapped->getWrapperStorage()->data); + $this->assertEquals(100, $wrapped->getWrapperStorage()->getWrapperStorage()->data); + } +} diff --git a/tests/lib/Files/Storage/Wrapper/AvailabilityTest.php b/tests/lib/Files/Storage/Wrapper/AvailabilityTest.php new file mode 100644 index 00000000000..5ea7f8403ce --- /dev/null +++ b/tests/lib/Files/Storage/Wrapper/AvailabilityTest.php @@ -0,0 +1,153 @@ +<?php +/** + * @author Robin McCorkell <rmccorkell@karoshi.org.uk> + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace Test\Files\Storage\Wrapper; + +class AvailabilityTest extends \Test\TestCase { + protected function getWrapperInstance() { + $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary') + ->disableOriginalConstructor() + ->getMock(); + $wrapper = new \OC\Files\Storage\Wrapper\Availability(['storage' => $storage]); + return [$storage, $wrapper]; + } + + /** + * Storage is available + */ + public function testAvailable() { + list($storage, $wrapper) = $this->getWrapperInstance(); + $storage->expects($this->once()) + ->method('getAvailability') + ->willReturn(['available' => true, 'last_checked' => 0]); + $storage->expects($this->never()) + ->method('test'); + $storage->expects($this->once()) + ->method('mkdir'); + + $wrapper->mkdir('foobar'); + } + + /** + * Storage marked unavailable, TTL not expired + * + * @expectedException \OCP\Files\StorageNotAvailableException + */ + public function testUnavailable() { + list($storage, $wrapper) = $this->getWrapperInstance(); + $storage->expects($this->once()) + ->method('getAvailability') + ->willReturn(['available' => false, 'last_checked' => time()]); + $storage->expects($this->never()) + ->method('test'); + $storage->expects($this->never()) + ->method('mkdir'); + + $wrapper->mkdir('foobar'); + } + + /** + * Storage marked unavailable, TTL expired + */ + public function testUnavailableRecheck() { + list($storage, $wrapper) = $this->getWrapperInstance(); + $storage->expects($this->once()) + ->method('getAvailability') + ->willReturn(['available' => false, 'last_checked' => 0]); + $storage->expects($this->once()) + ->method('test') + ->willReturn(true); + $storage->expects($this->exactly(2)) + ->method('setAvailability') + ->withConsecutive( + [$this->equalTo(false)], // prevents concurrent rechecks + [$this->equalTo(true)] // sets correct availability + ); + $storage->expects($this->once()) + ->method('mkdir'); + + $wrapper->mkdir('foobar'); + } + + /** + * Storage marked available, but throws StorageNotAvailableException + * + * @expectedException \OCP\Files\StorageNotAvailableException + */ + public function testAvailableThrowStorageNotAvailable() { + list($storage, $wrapper) = $this->getWrapperInstance(); + $storage->expects($this->once()) + ->method('getAvailability') + ->willReturn(['available' => true, 'last_checked' => 0]); + $storage->expects($this->never()) + ->method('test'); + $storage->expects($this->once()) + ->method('mkdir') + ->will($this->throwException(new \OCP\Files\StorageNotAvailableException())); + $storage->expects($this->once()) + ->method('setAvailability') + ->with($this->equalTo(false)); + + $wrapper->mkdir('foobar'); + } + + /** + * Storage available, but call fails + * Method failure does not indicate storage unavailability + */ + public function testAvailableFailure() { + list($storage, $wrapper) = $this->getWrapperInstance(); + $storage->expects($this->once()) + ->method('getAvailability') + ->willReturn(['available' => true, 'last_checked' => 0]); + $storage->expects($this->never()) + ->method('test'); + $storage->expects($this->once()) + ->method('mkdir') + ->willReturn(false); + $storage->expects($this->never()) + ->method('setAvailability'); + + $wrapper->mkdir('foobar'); + } + + /** + * Storage available, but throws exception + * Standard exception does not indicate storage unavailability + * + * @expectedException \Exception + */ + public function testAvailableThrow() { + list($storage, $wrapper) = $this->getWrapperInstance(); + $storage->expects($this->once()) + ->method('getAvailability') + ->willReturn(['available' => true, 'last_checked' => 0]); + $storage->expects($this->never()) + ->method('test'); + $storage->expects($this->once()) + ->method('mkdir') + ->will($this->throwException(new \Exception())); + $storage->expects($this->never()) + ->method('setAvailability'); + + $wrapper->mkdir('foobar'); + } +} diff --git a/tests/lib/Files/Storage/Wrapper/EncryptionTest.php b/tests/lib/Files/Storage/Wrapper/EncryptionTest.php new file mode 100644 index 00000000000..e9ebf2f3bdf --- /dev/null +++ b/tests/lib/Files/Storage/Wrapper/EncryptionTest.php @@ -0,0 +1,926 @@ +<?php + +namespace Test\Files\Storage\Wrapper; + +use OC\Encryption\Util; +use OC\Files\Storage\Temporary; +use OC\Files\View; +use OC\User\Manager; +use Test\Files\Storage\Storage; + +class EncryptionTest extends Storage { + + /** + * block size will always be 8192 for a PHP stream + * @see https://bugs.php.net/bug.php?id=21641 + * @var integer + */ + protected $headerSize = 8192; + + /** + * @var Temporary + */ + private $sourceStorage; + + /** + * @var \OC\Files\Storage\Wrapper\Encryption | \PHPUnit_Framework_MockObject_MockObject + */ + protected $instance; + + /** + * @var \OC\Encryption\Keys\Storage | \PHPUnit_Framework_MockObject_MockObject + */ + private $keyStore; + + /** + * @var \OC\Encryption\Util | \PHPUnit_Framework_MockObject_MockObject + */ + private $util; + + /** + * @var \OC\Encryption\Manager | \PHPUnit_Framework_MockObject_MockObject + */ + private $encryptionManager; + + /** + * @var \OCP\Encryption\IEncryptionModule | \PHPUnit_Framework_MockObject_MockObject + */ + private $encryptionModule; + + /** + * @var \OC\Encryption\Update | \PHPUnit_Framework_MockObject_MockObject + */ + private $update; + + /** + * @var \OC\Files\Cache\Cache | \PHPUnit_Framework_MockObject_MockObject + */ + private $cache; + + /** + * @var \OC\Log | \PHPUnit_Framework_MockObject_MockObject + */ + private $logger; + + /** + * @var \OC\Encryption\File | \PHPUnit_Framework_MockObject_MockObject + */ + private $file; + + + /** + * @var \OC\Files\Mount\MountPoint | \PHPUnit_Framework_MockObject_MockObject + */ + private $mount; + + /** + * @var \OC\Files\Mount\Manager | \PHPUnit_Framework_MockObject_MockObject + */ + private $mountManager; + + /** + * @var \OC\Group\Manager | \PHPUnit_Framework_MockObject_MockObject + */ + private $groupManager; + + /** + * @var \OCP\IConfig | \PHPUnit_Framework_MockObject_MockObject + */ + private $config; + + /** @var \OC\Memcache\ArrayCache | \PHPUnit_Framework_MockObject_MockObject */ + private $arrayCache; + + + /** @var integer dummy unencrypted size */ + private $dummySize = -1; + + protected function setUp() { + + parent::setUp(); + + $mockModule = $this->buildMockModule(); + $this->encryptionManager = $this->getMockBuilder('\OC\Encryption\Manager') + ->disableOriginalConstructor() + ->setMethods(['getEncryptionModule', 'isEnabled']) + ->getMock(); + $this->encryptionManager->expects($this->any()) + ->method('getEncryptionModule') + ->willReturn($mockModule); + + $this->arrayCache = $this->getMock('OC\Memcache\ArrayCache'); + $this->config = $this->getMockBuilder('\OCP\IConfig') + ->disableOriginalConstructor() + ->getMock(); + $this->groupManager = $this->getMockBuilder('\OC\Group\Manager') + ->disableOriginalConstructor() + ->getMock(); + + $this->util = $this->getMock( + '\OC\Encryption\Util', + ['getUidAndFilename', 'isFile', 'isExcluded'], + [new View(), new Manager(), $this->groupManager, $this->config, $this->arrayCache]); + $this->util->expects($this->any()) + ->method('getUidAndFilename') + ->willReturnCallback(function ($path) { + return ['user1', $path]; + }); + + $this->file = $this->getMockBuilder('\OC\Encryption\File') + ->disableOriginalConstructor() + ->setMethods(['getAccessList']) + ->getMock(); + $this->file->expects($this->any())->method('getAccessList')->willReturn([]); + + $this->logger = $this->getMock('\OC\Log'); + + $this->sourceStorage = new Temporary(array()); + + $this->keyStore = $this->getMockBuilder('\OC\Encryption\Keys\Storage') + ->disableOriginalConstructor()->getMock(); + + $this->update = $this->getMockBuilder('\OC\Encryption\Update') + ->disableOriginalConstructor()->getMock(); + + $this->mount = $this->getMockBuilder('\OC\Files\Mount\MountPoint') + ->disableOriginalConstructor() + ->setMethods(['getOption']) + ->getMock(); + $this->mount->expects($this->any())->method('getOption')->willReturnCallback(function ($option, $default) { + if ($option === 'encrypt' && $default === true) { + global $mockedMountPointEncryptionEnabled; + if ($mockedMountPointEncryptionEnabled !== null) { + return $mockedMountPointEncryptionEnabled; + } + } + return true; + }); + + $this->cache = $this->getMockBuilder('\OC\Files\Cache\Cache') + ->disableOriginalConstructor()->getMock(); + $this->cache->expects($this->any()) + ->method('get') + ->willReturnCallback(function($path) {return ['encrypted' => false, 'path' => $path];}); + + $this->mountManager = $this->getMockBuilder('\OC\Files\Mount\Manager') + ->disableOriginalConstructor()->getMock(); + + $this->instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption') + ->setConstructorArgs( + [ + [ + 'storage' => $this->sourceStorage, + 'root' => 'foo', + 'mountPoint' => '/', + 'mount' => $this->mount + ], + $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache + ] + ) + ->setMethods(['getMetaData', 'getCache', 'getEncryptionModule']) + ->getMock(); + + $this->instance->expects($this->any()) + ->method('getMetaData') + ->willReturnCallback(function ($path) { + return ['encrypted' => true, 'size' => $this->dummySize, 'path' => $path]; + }); + + $this->instance->expects($this->any()) + ->method('getCache') + ->willReturn($this->cache); + + $this->instance->expects($this->any()) + ->method('getEncryptionModule') + ->willReturn($mockModule); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject + */ + protected function buildMockModule() { + $this->encryptionModule = $this->getMockBuilder('\OCP\Encryption\IEncryptionModule') + ->disableOriginalConstructor() + ->setMethods(['getId', 'getDisplayName', 'begin', 'end', 'encrypt', 'decrypt', 'update', 'shouldEncrypt', 'getUnencryptedBlockSize', 'isReadable', 'encryptAll', 'prepareDecryptAll', 'isReadyForUser']) + ->getMock(); + + $this->encryptionModule->expects($this->any())->method('getId')->willReturn('UNIT_TEST_MODULE'); + $this->encryptionModule->expects($this->any())->method('getDisplayName')->willReturn('Unit test module'); + $this->encryptionModule->expects($this->any())->method('begin')->willReturn([]); + $this->encryptionModule->expects($this->any())->method('end')->willReturn(''); + $this->encryptionModule->expects($this->any())->method('encrypt')->willReturnArgument(0); + $this->encryptionModule->expects($this->any())->method('decrypt')->willReturnArgument(0); + $this->encryptionModule->expects($this->any())->method('update')->willReturn(true); + $this->encryptionModule->expects($this->any())->method('shouldEncrypt')->willReturn(true); + $this->encryptionModule->expects($this->any())->method('getUnencryptedBlockSize')->willReturn(8192); + $this->encryptionModule->expects($this->any())->method('isReadable')->willReturn(true); + return $this->encryptionModule; + } + + /** + * @dataProvider dataTestGetMetaData + * + * @param string $path + * @param array $metaData + * @param bool $encrypted + * @param bool $unencryptedSizeSet + * @param int $storedUnencryptedSize + * @param array $expected + */ + public function testGetMetaData($path, $metaData, $encrypted, $unencryptedSizeSet, $storedUnencryptedSize, $expected) { + + $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage') + ->disableOriginalConstructor()->getMock(); + + $cache = $this->getMockBuilder('\OC\Files\Cache\Cache') + ->disableOriginalConstructor()->getMock(); + $cache->expects($this->any()) + ->method('get') + ->willReturnCallback( + function($path) use ($encrypted) { + return ['encrypted' => $encrypted, 'path' => $path, 'size' => 0, 'fileid' => 1]; + } + ); + + $this->instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption') + ->setConstructorArgs( + [ + [ + 'storage' => $sourceStorage, + 'root' => 'foo', + 'mountPoint' => '/', + 'mount' => $this->mount + ], + $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache + ] + ) + ->setMethods(['getCache', 'verifyUnencryptedSize']) + ->getMock(); + + if($unencryptedSizeSet) { + $this->invokePrivate($this->instance, 'unencryptedSize', [[$path => $storedUnencryptedSize]]); + } + + $fileEntry = $this->getMockBuilder('\OC\Files\Cache\Cache') + ->disableOriginalConstructor()->getMock(); + $sourceStorage->expects($this->once())->method('getMetaData')->with($path) + ->willReturn($metaData); + $sourceStorage->expects($this->any()) + ->method('getCache') + ->with($path) + ->willReturn($fileEntry); + $fileEntry->expects($this->any()) + ->method('get') + ->with($metaData['fileid']); + + $this->instance->expects($this->any())->method('getCache')->willReturn($cache); + $this->instance->expects($this->any())->method('verifyUnencryptedSize') + ->with($path, 0)->willReturn($expected['size']); + + $result = $this->instance->getMetaData($path); + if(isset($expected['encrypted'])) { + $this->assertSame($expected['encrypted'], (bool)$result['encrypted']); + + if(isset($expected['encryptedVersion'])) { + $this->assertSame($expected['encryptedVersion'], $result['encryptedVersion']); + } + } + $this->assertSame($expected['size'], $result['size']); + } + + public function dataTestGetMetaData() { + return [ + ['/test.txt', ['size' => 42, 'encrypted' => 2, 'encryptedVersion' => 2, 'fileid' => 1], true, true, 12, ['size' => 12, 'encrypted' => true, 'encryptedVersion' => 2]], + ['/test.txt', null, true, true, 12, null], + ['/test.txt', ['size' => 42, 'encrypted' => 0, 'fileid' => 1], false, false, 12, ['size' => 42, 'encrypted' => false]], + ['/test.txt', ['size' => 42, 'encrypted' => false, 'fileid' => 1], true, false, 12, ['size' => 12, 'encrypted' => true]] + ]; + } + + public function testFilesize() { + $cache = $this->getMockBuilder('\OC\Files\Cache\Cache') + ->disableOriginalConstructor()->getMock(); + $cache->expects($this->any()) + ->method('get') + ->willReturn(['encrypted' => true, 'path' => '/test.txt', 'size' => 0, 'fileid' => 1]); + + $this->instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption') + ->setConstructorArgs( + [ + [ + 'storage' => $this->sourceStorage, + 'root' => 'foo', + 'mountPoint' => '/', + 'mount' => $this->mount + ], + $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache + ] + ) + ->setMethods(['getCache', 'verifyUnencryptedSize']) + ->getMock(); + + $this->instance->expects($this->any())->method('getCache')->willReturn($cache); + $this->instance->expects($this->any())->method('verifyUnencryptedSize') + ->willReturn(42); + + + $this->assertSame(42, + $this->instance->filesize('/test.txt') + ); + + } + + /** + * @dataProvider dataTestVerifyUnencryptedSize + * + * @param int $encryptedSize + * @param int $unencryptedSize + * @param bool $failure + * @param int $expected + */ + public function testVerifyUnencryptedSize($encryptedSize, $unencryptedSize, $failure, $expected) { + $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage') + ->disableOriginalConstructor()->getMock(); + + $this->instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption') + ->setConstructorArgs( + [ + [ + 'storage' => $sourceStorage, + 'root' => 'foo', + 'mountPoint' => '/', + 'mount' => $this->mount + ], + $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache + ] + ) + ->setMethods(['fixUnencryptedSize']) + ->getMock(); + + $sourceStorage->expects($this->once())->method('filesize')->willReturn($encryptedSize); + + $this->instance->expects($this->any())->method('fixUnencryptedSize') + ->with('/test.txt', $encryptedSize, $unencryptedSize) + ->willReturnCallback( + function() use ($failure, $expected) { + if ($failure) { + throw new \Exception(); + } else { + return $expected; + } + } + ); + + $this->assertSame( + $expected, + $this->invokePrivate($this->instance, 'verifyUnencryptedSize', ['/test.txt', $unencryptedSize]) + ); + } + + public function dataTestVerifyUnencryptedSize() { + return [ + [120, 80, false, 80], + [120, 120, false, 80], + [120, -1, false, 80], + [120, -1, true, -1] + ]; + } + + /** + * @dataProvider dataTestCopyAndRename + * + * @param string $source + * @param string $target + * @param $encryptionEnabled + * @param boolean $renameKeysReturn + */ + public function testRename($source, + $target, + $encryptionEnabled, + $renameKeysReturn) { + if ($encryptionEnabled) { + $this->keyStore + ->expects($this->once()) + ->method('renameKeys') + ->willReturn($renameKeysReturn); + } else { + $this->keyStore + ->expects($this->never())->method('renameKeys'); + } + $this->util->expects($this->any()) + ->method('isFile')->willReturn(true); + $this->encryptionManager->expects($this->once()) + ->method('isEnabled')->willReturn($encryptionEnabled); + + $this->instance->mkdir($source); + $this->instance->mkdir(dirname($target)); + $this->instance->rename($source, $target); + } + + public function testCopyEncryption() { + $this->instance->file_put_contents('source.txt', 'bar'); + $this->instance->copy('source.txt', 'target.txt'); + $this->assertSame('bar', $this->instance->file_get_contents('target.txt')); + $targetMeta = $this->instance->getMetaData('target.txt'); + $sourceMeta = $this->instance->getMetaData('source.txt'); + $this->assertSame($sourceMeta['encrypted'], $targetMeta['encrypted']); + $this->assertSame($sourceMeta['size'], $targetMeta['size']); + } + + /** + * data provider for testCopyTesting() and dataTestCopyAndRename() + * + * @return array + */ + public function dataTestCopyAndRename() { + return array( + array('source', 'target', true, false, false), + array('source', 'target', true, true, false), + array('source', '/subFolder/target', true, false, false), + array('source', '/subFolder/target', true, true, true), + array('source', '/subFolder/target', false, true, false), + ); + } + + public function testIsLocal() { + $this->encryptionManager->expects($this->once()) + ->method('isEnabled')->willReturn(true); + $this->assertFalse($this->instance->isLocal()); + } + + /** + * @dataProvider dataTestRmdir + * + * @param string $path + * @param boolean $rmdirResult + * @param boolean $isExcluded + * @param boolean $encryptionEnabled + */ + public function testRmdir($path, $rmdirResult, $isExcluded, $encryptionEnabled) { + $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage') + ->disableOriginalConstructor()->getMock(); + + $util = $this->getMockBuilder('\OC\Encryption\Util')->disableOriginalConstructor()->getMock(); + + $sourceStorage->expects($this->once())->method('rmdir')->willReturn($rmdirResult); + $util->expects($this->any())->method('isExcluded')-> willReturn($isExcluded); + $this->encryptionManager->expects($this->any())->method('isEnabled')->willReturn($encryptionEnabled); + + $encryptionStorage = new \OC\Files\Storage\Wrapper\Encryption( + [ + 'storage' => $sourceStorage, + 'root' => 'foo', + 'mountPoint' => '/mountPoint', + 'mount' => $this->mount + ], + $this->encryptionManager, $util, $this->logger, $this->file, null, $this->keyStore, $this->update + ); + + + if ($rmdirResult === true && $isExcluded === false && $encryptionEnabled === true) { + $this->keyStore->expects($this->once())->method('deleteAllFileKeys')->with('/mountPoint' . $path); + } else { + $this->keyStore->expects($this->never())->method('deleteAllFileKeys'); + } + + $encryptionStorage->rmdir($path); + } + + public function dataTestRmdir() { + return array( + array('/file.txt', true, true, true), + array('/file.txt', false, true, true), + array('/file.txt', true, false, true), + array('/file.txt', false, false, true), + array('/file.txt', true, true, false), + array('/file.txt', false, true, false), + array('/file.txt', true, false, false), + array('/file.txt', false, false, false), + ); + } + + /** + * @dataProvider dataTestCopyKeys + * + * @param boolean $excluded + * @param boolean $expected + */ + public function testCopyKeys($excluded, $expected) { + $this->util->expects($this->once()) + ->method('isExcluded') + ->willReturn($excluded); + + if ($excluded) { + $this->keyStore->expects($this->never())->method('copyKeys'); + } else { + $this->keyStore->expects($this->once())->method('copyKeys')->willReturn(true); + } + + $this->assertSame($expected, + self::invokePrivate($this->instance, 'copyKeys', ['/source', '/target']) + ); + } + + public function dataTestCopyKeys() { + return array( + array(true, false), + array(false, true), + ); + } + + /** + * @dataProvider dataTestGetHeader + * + * @param string $path + * @param bool $strippedPathExists + * @param string $strippedPath + */ + public function testGetHeader($path, $strippedPathExists, $strippedPath) { + + $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage') + ->disableOriginalConstructor()->getMock(); + + $util = $this->getMockBuilder('\OC\Encryption\Util') + ->setConstructorArgs( + [ + new View(), + new Manager(), + $this->groupManager, + $this->config, + $this->arrayCache + ] + )->getMock(); + + $instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption') + ->setConstructorArgs( + [ + [ + 'storage' => $sourceStorage, + 'root' => 'foo', + 'mountPoint' => '/', + 'mount' => $this->mount + ], + $this->encryptionManager, $util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache + ] + ) + ->setMethods(['readFirstBlock', 'parseRawHeader']) + ->getMock(); + + $instance->expects($this->once())->method(('parseRawHeader')) + ->willReturn([Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']); + + if ($strippedPathExists) { + $instance->expects($this->once())->method('readFirstBlock') + ->with($strippedPath)->willReturn(''); + } else { + $instance->expects($this->once())->method('readFirstBlock') + ->with($path)->willReturn(''); + } + + $util->expects($this->once())->method('stripPartialFileExtension') + ->with($path)->willReturn($strippedPath); + $sourceStorage->expects($this->once()) + ->method('file_exists') + ->with($strippedPath) + ->willReturn($strippedPathExists); + + $this->invokePrivate($instance, 'getHeader', [$path]); + } + + public function dataTestGetHeader() { + return array( + array('/foo/bar.txt', false, '/foo/bar.txt'), + array('/foo/bar.txt.part', false, '/foo/bar.txt'), + array('/foo/bar.txt.ocTransferId7437493.part', false, '/foo/bar.txt'), + array('/foo/bar.txt.part', true, '/foo/bar.txt'), + array('/foo/bar.txt.ocTransferId7437493.part', true, '/foo/bar.txt'), + ); + } + + /** + * test if getHeader adds the default module correctly to the header for + * legacy files + * + * @dataProvider dataTestGetHeaderAddLegacyModule + */ + public function testGetHeaderAddLegacyModule($header, $isEncrypted, $expected) { + + $sourceStorage = $this->getMockBuilder('\OC\Files\Storage\Storage') + ->disableOriginalConstructor()->getMock(); + + $util = $this->getMockBuilder('\OC\Encryption\Util') + ->setConstructorArgs([new View(), new Manager(), $this->groupManager, $this->config, $this->arrayCache]) + ->getMock(); + + $cache = $this->getMockBuilder('\OC\Files\Cache\Cache') + ->disableOriginalConstructor()->getMock(); + $cache->expects($this->any()) + ->method('get') + ->willReturnCallback(function($path) use ($isEncrypted) {return ['encrypted' => $isEncrypted, 'path' => $path];}); + + $instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption') + ->setConstructorArgs( + [ + [ + 'storage' => $sourceStorage, + 'root' => 'foo', + 'mountPoint' => '/', + 'mount' => $this->mount + ], + $this->encryptionManager, $util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache + ] + ) + ->setMethods(['readFirstBlock', 'parseRawHeader', 'getCache']) + ->getMock(); + + $instance->expects($this->once())->method(('parseRawHeader'))->willReturn($header); + $instance->expects($this->any())->method('getCache')->willReturn($cache); + + $result = $this->invokePrivate($instance, 'getHeader', ['test.txt']); + $this->assertSameSize($expected, $result); + foreach ($result as $key => $value) { + $this->assertArrayHasKey($key, $expected); + $this->assertSame($expected[$key], $value); + } + } + + public function dataTestGetHeaderAddLegacyModule() { + return [ + [['cipher' => 'AES-128'], true, ['cipher' => 'AES-128', Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']], + [[], true, [Util::HEADER_ENCRYPTION_MODULE_KEY => 'OC_DEFAULT_MODULE']], + [[], false, []], + ]; + } + + /** + * @dataProvider dataTestParseRawHeader + */ + public function testParseRawHeader($rawHeader, $expected) { + $instance = new \OC\Files\Storage\Wrapper\Encryption( + [ + 'storage' => $this->sourceStorage, + 'root' => 'foo', + 'mountPoint' => '/', + 'mount' => $this->mount + ], + $this->encryptionManager, $this->util, $this->logger, $this->file, null, $this->keyStore, $this->update, $this->mountManager, $this->arrayCache + + ); + + $result = $this->invokePrivate($instance, 'parseRawHeader', [$rawHeader]); + $this->assertSameSize($expected, $result); + foreach ($result as $key => $value) { + $this->assertArrayHasKey($key, $expected); + $this->assertSame($expected[$key], $value); + } + } + + public function dataTestParseRawHeader() { + return [ + [str_pad('HBEGIN:oc_encryption_module:0:HEND', $this->headerSize, '-', STR_PAD_RIGHT) + , [Util::HEADER_ENCRYPTION_MODULE_KEY => '0']], + [str_pad('HBEGIN:oc_encryption_module:0:custom_header:foo:HEND', $this->headerSize, '-', STR_PAD_RIGHT) + , ['custom_header' => 'foo', Util::HEADER_ENCRYPTION_MODULE_KEY => '0']], + [str_pad('HelloWorld', $this->headerSize, '-', STR_PAD_RIGHT), []], + ['', []], + [str_pad('HBEGIN:oc_encryption_module:0', $this->headerSize, '-', STR_PAD_RIGHT) + , []], + [str_pad('oc_encryption_module:0:HEND', $this->headerSize, '-', STR_PAD_RIGHT) + , []], + ]; + } + + public function dataCopyBetweenStorage() { + return [ + [true, true, true], + [true, false, false], + [false, true, false], + [false, false, false], + ]; + } + + public function testCopyBetweenStorageMinimumEncryptedVersion() { + $storage2 = $this->getMockBuilder('OCP\Files\Storage') + ->disableOriginalConstructor() + ->getMock(); + + $sourceInternalPath = $targetInternalPath = 'file.txt'; + $preserveMtime = $isRename = false; + + $storage2->expects($this->any()) + ->method('fopen') + ->willReturnCallback(function($path, $mode) { + $temp = \OC::$server->getTempManager(); + return fopen($temp->getTemporaryFile(), $mode); + }); + $cache = $this->getMock('\OCP\Files\Cache\ICache'); + $cache->expects($this->once()) + ->method('get') + ->with($sourceInternalPath) + ->willReturn(['encryptedVersion' => 0]); + $storage2->expects($this->once()) + ->method('getCache') + ->willReturn($cache); + $this->encryptionManager->expects($this->any()) + ->method('isEnabled') + ->willReturn(true); + global $mockedMountPointEncryptionEnabled; + $mockedMountPointEncryptionEnabled = true; + + $expectedCachePut = [ + 'encrypted' => true, + ]; + $expectedCachePut['encryptedVersion'] = 1; + + $this->cache->expects($this->once()) + ->method('put') + ->with($sourceInternalPath, $expectedCachePut); + + $this->invokePrivate($this->instance, 'copyBetweenStorage', [$storage2, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename]); + + $this->assertFalse(false); + } + + /** + * @dataProvider dataCopyBetweenStorage + * + * @param bool $encryptionEnabled + * @param bool $mountPointEncryptionEnabled + * @param bool $expectedEncrypted + */ + public function testCopyBetweenStorage($encryptionEnabled, $mountPointEncryptionEnabled, $expectedEncrypted) { + $storage2 = $this->getMockBuilder('OCP\Files\Storage') + ->disableOriginalConstructor() + ->getMock(); + + $sourceInternalPath = $targetInternalPath = 'file.txt'; + $preserveMtime = $isRename = false; + + $storage2->expects($this->any()) + ->method('fopen') + ->willReturnCallback(function($path, $mode) { + $temp = \OC::$server->getTempManager(); + return fopen($temp->getTemporaryFile(), $mode); + }); + if($expectedEncrypted) { + $cache = $this->getMock('\OCP\Files\Cache\ICache'); + $cache->expects($this->once()) + ->method('get') + ->with($sourceInternalPath) + ->willReturn(['encryptedVersion' => 12345]); + $storage2->expects($this->once()) + ->method('getCache') + ->willReturn($cache); + } + $this->encryptionManager->expects($this->any()) + ->method('isEnabled') + ->willReturn($encryptionEnabled); + // FIXME can not overwrite the return after definition +// $this->mount->expects($this->at(0)) +// ->method('getOption') +// ->with('encrypt', true) +// ->willReturn($mountPointEncryptionEnabled); + global $mockedMountPointEncryptionEnabled; + $mockedMountPointEncryptionEnabled = $mountPointEncryptionEnabled; + + $expectedCachePut = [ + 'encrypted' => $expectedEncrypted, + ]; + if($expectedEncrypted === true) { + $expectedCachePut['encryptedVersion'] = 12345; + } + + $this->arrayCache->expects($this->never())->method('set'); + + $this->cache->expects($this->once()) + ->method('put') + ->with($sourceInternalPath, $expectedCachePut); + + $this->invokePrivate($this->instance, 'copyBetweenStorage', [$storage2, $sourceInternalPath, $targetInternalPath, $preserveMtime, $isRename]); + + $this->assertFalse(false); + } + + /** + * @dataProvider dataTestCopyBetweenStorageVersions + * + * @param string $sourceInternalPath + * @param string $targetInternalPath + * @param bool $copyResult + * @param bool $encrypted + */ + public function testCopyBetweenStorageVersions($sourceInternalPath, $targetInternalPath, $copyResult, $encrypted) { + + $sourceStorage = $this->getMockBuilder('OCP\Files\Storage') + ->disableOriginalConstructor() + ->getMock(); + + $targetStorage = $this->getMockBuilder('OCP\Files\Storage') + ->disableOriginalConstructor() + ->getMock(); + + $cache = $this->getMockBuilder('\OC\Files\Cache\Cache') + ->disableOriginalConstructor()->getMock(); + + $mountPoint = '/mountPoint'; + + /** @var \OC\Files\Storage\Wrapper\Encryption |\PHPUnit_Framework_MockObject_MockObject $instance */ + $instance = $this->getMockBuilder('\OC\Files\Storage\Wrapper\Encryption') + ->setConstructorArgs( + [ + [ + 'storage' => $targetStorage, + 'root' => 'foo', + 'mountPoint' => $mountPoint, + 'mount' => $this->mount + ], + $this->encryptionManager, + $this->util, + $this->logger, + $this->file, + null, + $this->keyStore, + $this->update, + $this->mountManager, + $this->arrayCache + ] + ) + ->setMethods(['updateUnencryptedSize', 'getCache']) + ->getMock(); + + $targetStorage->expects($this->once())->method('copyFromStorage') + ->with($sourceStorage, $sourceInternalPath, $targetInternalPath) + ->willReturn($copyResult); + + $instance->expects($this->any())->method('getCache') + ->willReturn($cache); + + $this->arrayCache->expects($this->once())->method('set') + ->with('encryption_copy_version_' . $sourceInternalPath, true); + + if ($copyResult) { + $cache->expects($this->once())->method('get') + ->with($sourceInternalPath) + ->willReturn(['encrypted' => $encrypted, 'size' => 42]); + if ($encrypted) { + $instance->expects($this->once())->method('updateUnencryptedSize') + ->with($mountPoint . $targetInternalPath, 42); + } else { + $instance->expects($this->never())->method('updateUnencryptedSize'); + } + } else { + $instance->expects($this->never())->method('updateUnencryptedSize'); + } + + $result = $this->invokePrivate( + $instance, + 'copyBetweenStorage', + [ + $sourceStorage, + $sourceInternalPath, + $targetInternalPath, + false, + false + ] + ); + + $this->assertSame($copyResult, $result); + } + + public function dataTestCopyBetweenStorageVersions() { + return [ + ['/files/foo.txt', '/files_versions/foo.txt.768743', true, true], + ['/files/foo.txt', '/files_versions/foo.txt.768743', true, false], + ['/files/foo.txt', '/files_versions/foo.txt.768743', false, true], + ['/files/foo.txt', '/files_versions/foo.txt.768743', false, false], + ['/files_versions/foo.txt.6487634', '/files/foo.txt', true, true], + ['/files_versions/foo.txt.6487634', '/files/foo.txt', true, false], + ['/files_versions/foo.txt.6487634', '/files/foo.txt', false, true], + ['/files_versions/foo.txt.6487634', '/files/foo.txt', false, false], + + ]; + } + + /** + * @dataProvider dataTestIsVersion + * @param string $path + * @param bool $expected + */ + public function testIsVersion($path, $expected) { + $this->assertSame($expected, + $this->invokePrivate($this->instance, 'isVersion', [$path]) + ); + } + + public function dataTestIsVersion() { + return [ + ['files_versions/foo', true], + ['/files_versions/foo', true], + ['//files_versions/foo', true], + ['files/versions/foo', false], + ['files/files_versions/foo', false], + ['files_versions_test/foo', false], + ]; + } + +} diff --git a/tests/lib/Files/Storage/Wrapper/JailTest.php b/tests/lib/Files/Storage/Wrapper/JailTest.php new file mode 100644 index 00000000000..b03eb0bcc63 --- /dev/null +++ b/tests/lib/Files/Storage/Wrapper/JailTest.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Files\Storage\Wrapper; + +class JailTest extends \Test\Files\Storage\Storage { + + /** + * @var \OC\Files\Storage\Temporary + */ + private $sourceStorage; + + public function setUp() { + parent::setUp(); + $this->sourceStorage = new \OC\Files\Storage\Temporary(array()); + $this->sourceStorage->mkdir('foo'); + $this->instance = new \OC\Files\Storage\Wrapper\Jail(array( + 'storage' => $this->sourceStorage, + 'root' => 'foo' + )); + } + + public function tearDown() { + // test that nothing outside our jail is touched + $contents = array(); + $dh = $this->sourceStorage->opendir(''); + while ($file = readdir($dh)) { + if (!\OC\Files\Filesystem::isIgnoredDir($file)) { + $contents[] = $file; + } + } + $this->assertEquals(array('foo'), $contents); + $this->sourceStorage->cleanUp(); + parent::tearDown(); + } + + public function testMkDirRooted() { + $this->instance->mkdir('bar'); + $this->assertTrue($this->sourceStorage->is_dir('foo/bar')); + } + + public function testFilePutContentsRooted() { + $this->instance->file_put_contents('bar', 'asd'); + $this->assertEquals('asd', $this->sourceStorage->file_get_contents('foo/bar')); + } +} diff --git a/tests/lib/Files/Storage/Wrapper/PermissionsMaskTest.php b/tests/lib/Files/Storage/Wrapper/PermissionsMaskTest.php new file mode 100644 index 00000000000..c3421553643 --- /dev/null +++ b/tests/lib/Files/Storage/Wrapper/PermissionsMaskTest.php @@ -0,0 +1,105 @@ +<?php +/** + * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Files\Storage\Wrapper; + +use OCP\Constants; + +class PermissionsMaskTest extends \Test\Files\Storage\Storage { + + /** + * @var \OC\Files\Storage\Temporary + */ + private $sourceStorage; + + public function setUp() { + parent::setUp(); + $this->sourceStorage = new \OC\Files\Storage\Temporary(array()); + $this->instance = $this->getMaskedStorage(Constants::PERMISSION_ALL); + } + + public function tearDown() { + $this->sourceStorage->cleanUp(); + parent::tearDown(); + } + + protected function getMaskedStorage($mask) { + return new \OC\Files\Storage\Wrapper\PermissionsMask(array( + 'storage' => $this->sourceStorage, + 'mask' => $mask + )); + } + + public function testMkdirNoCreate() { + $storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE); + $this->assertFalse($storage->mkdir('foo')); + $this->assertFalse($storage->file_exists('foo')); + } + + public function testRmdirNoDelete() { + $storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_DELETE); + $this->assertTrue($storage->mkdir('foo')); + $this->assertTrue($storage->file_exists('foo')); + $this->assertFalse($storage->rmdir('foo')); + $this->assertTrue($storage->file_exists('foo')); + } + + public function testTouchNewFileNoCreate() { + $storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE); + $this->assertFalse($storage->touch('foo')); + $this->assertFalse($storage->file_exists('foo')); + } + + public function testTouchNewFileNoUpdate() { + $storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_UPDATE); + $this->assertTrue($storage->touch('foo')); + $this->assertTrue($storage->file_exists('foo')); + } + + public function testTouchExistingFileNoUpdate() { + $this->sourceStorage->touch('foo'); + $storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_UPDATE); + $this->assertFalse($storage->touch('foo')); + } + + public function testUnlinkNoDelete() { + $storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_DELETE); + $this->assertTrue($storage->touch('foo')); + $this->assertTrue($storage->file_exists('foo')); + $this->assertFalse($storage->unlink('foo')); + $this->assertTrue($storage->file_exists('foo')); + } + + public function testPutContentsNewFileNoUpdate() { + $storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_UPDATE); + $this->assertTrue($storage->file_put_contents('foo', 'bar')); + $this->assertEquals('bar', $storage->file_get_contents('foo')); + } + + public function testPutContentsNewFileNoCreate() { + $storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE); + $this->assertFalse($storage->file_put_contents('foo', 'bar')); + } + + public function testPutContentsExistingFileNoUpdate() { + $this->sourceStorage->touch('foo'); + $storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_UPDATE); + $this->assertFalse($storage->file_put_contents('foo', 'bar')); + } + + public function testFopenExistingFileNoUpdate() { + $this->sourceStorage->touch('foo'); + $storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_UPDATE); + $this->assertFalse($storage->fopen('foo', 'w')); + } + + public function testFopenNewFileNoCreate() { + $storage = $this->getMaskedStorage(Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE); + $this->assertFalse($storage->fopen('foo', 'w')); + } +} diff --git a/tests/lib/Files/Storage/Wrapper/QuotaTest.php b/tests/lib/Files/Storage/Wrapper/QuotaTest.php new file mode 100644 index 00000000000..2e9f68b3c56 --- /dev/null +++ b/tests/lib/Files/Storage/Wrapper/QuotaTest.php @@ -0,0 +1,211 @@ +<?php +/** + * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Files\Storage\Wrapper; + +//ensure the constants are loaded +use OC\Files\Cache\CacheEntry; + +\OC::$loader->load('\OC\Files\Filesystem'); + +/** + * Class QuotaTest + * + * @group DB + * + * @package Test\Files\Storage\Wrapper + */ +class QuotaTest extends \Test\Files\Storage\Storage { + /** + * @var string tmpDir + */ + private $tmpDir; + + protected function setUp() { + parent::setUp(); + + $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder(); + $storage = new \OC\Files\Storage\Local(array('datadir' => $this->tmpDir)); + $this->instance = new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => 10000000)); + } + + protected function tearDown() { + \OC_Helper::rmdirr($this->tmpDir); + parent::tearDown(); + } + + /** + * @param integer $limit + */ + protected function getLimitedStorage($limit) { + $storage = new \OC\Files\Storage\Local(array('datadir' => $this->tmpDir)); + $storage->mkdir('files'); + $storage->getScanner()->scan(''); + return new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => $limit)); + } + + public function testFilePutContentsNotEnoughSpace() { + $instance = $this->getLimitedStorage(3); + $this->assertFalse($instance->file_put_contents('files/foo', 'foobar')); + } + + public function testCopyNotEnoughSpace() { + $instance = $this->getLimitedStorage(9); + $this->assertEquals(6, $instance->file_put_contents('files/foo', 'foobar')); + $instance->getScanner()->scan(''); + $this->assertFalse($instance->copy('files/foo', 'files/bar')); + } + + public function testFreeSpace() { + $instance = $this->getLimitedStorage(9); + $this->assertEquals(9, $instance->free_space('')); + } + + public function testFreeSpaceWithUsedSpace() { + $instance = $this->getLimitedStorage(9); + $instance->getCache()->put( + '', array('size' => 3) + ); + $this->assertEquals(6, $instance->free_space('')); + } + + public function testFreeSpaceWithUnknownDiskSpace() { + $storage = $this->getMock( + '\OC\Files\Storage\Local', + array('free_space'), + array(array('datadir' => $this->tmpDir)) + ); + $storage->expects($this->any()) + ->method('free_space') + ->will($this->returnValue(-2)); + $storage->getScanner()->scan(''); + + $instance = new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => 9)); + $instance->getCache()->put( + '', array('size' => 3) + ); + $this->assertEquals(6, $instance->free_space('')); + } + + public function testFreeSpaceWithUsedSpaceAndEncryption() { + $instance = $this->getLimitedStorage(9); + $instance->getCache()->put( + '', array('size' => 7) + ); + $this->assertEquals(2, $instance->free_space('')); + } + + public function testFWriteNotEnoughSpace() { + $instance = $this->getLimitedStorage(9); + $stream = $instance->fopen('files/foo', 'w+'); + $this->assertEquals(6, fwrite($stream, 'foobar')); + $this->assertEquals(3, fwrite($stream, 'qwerty')); + fclose($stream); + $this->assertEquals('foobarqwe', $instance->file_get_contents('files/foo')); + } + + public function testStreamCopyWithEnoughSpace() { + $instance = $this->getLimitedStorage(16); + $inputStream = fopen('data://text/plain,foobarqwerty', 'r'); + $outputStream = $instance->fopen('files/foo', 'w+'); + list($count, $result) = \OC_Helper::streamCopy($inputStream, $outputStream); + $this->assertEquals(12, $count); + $this->assertTrue($result); + fclose($inputStream); + fclose($outputStream); + } + + public function testStreamCopyNotEnoughSpace() { + $instance = $this->getLimitedStorage(9); + $inputStream = fopen('data://text/plain,foobarqwerty', 'r'); + $outputStream = $instance->fopen('files/foo', 'w+'); + list($count, $result) = \OC_Helper::streamCopy($inputStream, $outputStream); + $this->assertEquals(9, $count); + $this->assertFalse($result); + fclose($inputStream); + fclose($outputStream); + } + + public function testReturnFalseWhenFopenFailed() { + $failStorage = $this->getMock( + '\OC\Files\Storage\Local', + array('fopen'), + array(array('datadir' => $this->tmpDir))); + $failStorage->expects($this->any()) + ->method('fopen') + ->will($this->returnValue(false)); + + $instance = new \OC\Files\Storage\Wrapper\Quota(array('storage' => $failStorage, 'quota' => 1000)); + + $this->assertFalse($instance->fopen('failedfopen', 'r')); + } + + public function testReturnRegularStreamOnRead() { + $instance = $this->getLimitedStorage(9); + + // create test file first + $stream = $instance->fopen('files/foo', 'w+'); + fwrite($stream, 'blablacontent'); + fclose($stream); + + $stream = $instance->fopen('files/foo', 'r'); + $meta = stream_get_meta_data($stream); + $this->assertEquals('plainfile', $meta['wrapper_type']); + fclose($stream); + + $stream = $instance->fopen('files/foo', 'rb'); + $meta = stream_get_meta_data($stream); + $this->assertEquals('plainfile', $meta['wrapper_type']); + fclose($stream); + } + + public function testReturnRegularStreamWhenOutsideFiles() { + $instance = $this->getLimitedStorage(9); + $instance->mkdir('files_other'); + + // create test file first + $stream = $instance->fopen('files_other/foo', 'w+'); + $meta = stream_get_meta_data($stream); + $this->assertEquals('plainfile', $meta['wrapper_type']); + fclose($stream); + } + + public function testReturnQuotaStreamOnWrite() { + $instance = $this->getLimitedStorage(9); + $stream = $instance->fopen('files/foo', 'w+'); + $meta = stream_get_meta_data($stream); + $expected_type = defined('HHVM_VERSION') ? 'File' : 'user-space'; + $this->assertEquals($expected_type, $meta['wrapper_type']); + fclose($stream); + } + + public function testSpaceRoot() { + $storage = $this->getMockBuilder('\OC\Files\Storage\Local')->disableOriginalConstructor()->getMock(); + $cache = $this->getMockBuilder('\OC\Files\Cache\Cache')->disableOriginalConstructor()->getMock(); + $storage->expects($this->once()) + ->method('getCache') + ->will($this->returnValue($cache)); + $storage->expects($this->once()) + ->method('free_space') + ->will($this->returnValue(2048)); + $cache->expects($this->once()) + ->method('get') + ->with('files') + ->will($this->returnValue(new CacheEntry(['size' => 50]))); + + $instance = new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => 1024, 'root' => 'files')); + + $this->assertEquals(1024 - 50, $instance->free_space('')); + } + + public function testInstanceOfStorageWrapper() { + $this->assertTrue($this->instance->instanceOfStorage('\OC\Files\Storage\Local')); + $this->assertTrue($this->instance->instanceOfStorage('\OC\Files\Storage\Wrapper\Wrapper')); + $this->assertTrue($this->instance->instanceOfStorage('\OC\Files\Storage\Wrapper\Quota')); + } +} diff --git a/tests/lib/Files/Storage/Wrapper/WrapperTest.php b/tests/lib/Files/Storage/Wrapper/WrapperTest.php new file mode 100644 index 00000000000..942ff27fc35 --- /dev/null +++ b/tests/lib/Files/Storage/Wrapper/WrapperTest.php @@ -0,0 +1,34 @@ +<?php +/** + * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Files\Storage\Wrapper; + +class WrapperTest extends \Test\Files\Storage\Storage { + /** + * @var string tmpDir + */ + private $tmpDir; + + protected function setUp() { + parent::setUp(); + + $this->tmpDir = \OC::$server->getTempManager()->getTemporaryFolder(); + $storage = new \OC\Files\Storage\Local(array('datadir' => $this->tmpDir)); + $this->instance = new \OC\Files\Storage\Wrapper\Wrapper(array('storage' => $storage)); + } + + protected function tearDown() { + \OC_Helper::rmdirr($this->tmpDir); + parent::tearDown(); + } + + public function testInstanceOfStorageWrapper() { + $this->assertTrue($this->instance->instanceOfStorage('\OC\Files\Storage\Local')); + $this->assertTrue($this->instance->instanceOfStorage('\OC\Files\Storage\Wrapper\Wrapper')); + } +} |