summaryrefslogtreecommitdiffstats
path: root/tests/lib/Files/Storage
diff options
context:
space:
mode:
Diffstat (limited to 'tests/lib/Files/Storage')
-rw-r--r--tests/lib/Files/Storage/CommonTest.php48
-rw-r--r--tests/lib/Files/Storage/CopyDirectoryTest.php53
-rw-r--r--tests/lib/Files/Storage/HomeStorageQuotaTest.php81
-rw-r--r--tests/lib/Files/Storage/HomeTest.php109
-rw-r--r--tests/lib/Files/Storage/LocalTest.php88
-rw-r--r--tests/lib/Files/Storage/Storage.php617
-rw-r--r--tests/lib/Files/Storage/StorageFactoryTest.php72
-rw-r--r--tests/lib/Files/Storage/Wrapper/AvailabilityTest.php153
-rw-r--r--tests/lib/Files/Storage/Wrapper/EncryptionTest.php926
-rw-r--r--tests/lib/Files/Storage/Wrapper/JailTest.php51
-rw-r--r--tests/lib/Files/Storage/Wrapper/PermissionsMaskTest.php105
-rw-r--r--tests/lib/Files/Storage/Wrapper/QuotaTest.php211
-rw-r--r--tests/lib/Files/Storage/Wrapper/WrapperTest.php34
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'));
+ }
+}