diff options
author | Joas Schilling <nickvergessen@gmx.de> | 2016-05-20 15:38:20 +0200 |
---|---|---|
committer | Thomas Müller <DeepDiver1975@users.noreply.github.com> | 2016-05-20 15:38:20 +0200 |
commit | 94ad54ec9b96d41a614fbbad4a97b34c41a6901f (patch) | |
tree | f3eb7cdda2704aaf0cd59d58efe66bcbd34cb67d /tests/lib/files/view.php | |
parent | 2ef751b1ec28f7b5c7113af60ec8c9fa0ae1cf87 (diff) | |
download | nextcloud-server-94ad54ec9b96d41a614fbbad4a97b34c41a6901f.tar.gz nextcloud-server-94ad54ec9b96d41a614fbbad4a97b34c41a6901f.zip |
Move tests/ to PSR-4 (#24731)
* Move a-b to PSR-4
* Move c-d to PSR-4
* Move e+g to PSR-4
* Move h-l to PSR-4
* Move m-r to PSR-4
* Move s-u to PSR-4
* Move files/ to PSR-4
* Move remaining tests to PSR-4
* Remove Test\ from old autoloader
Diffstat (limited to 'tests/lib/files/view.php')
-rw-r--r-- | tests/lib/files/view.php | 2447 |
1 files changed, 0 insertions, 2447 deletions
diff --git a/tests/lib/files/view.php b/tests/lib/files/view.php deleted file mode 100644 index d33c9f31503..00000000000 --- a/tests/lib/files/view.php +++ /dev/null @@ -1,2447 +0,0 @@ -<?php -/** - * Copyright (c) 2012 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; - -use OC\Files\Cache\Watcher; -use OC\Files\Storage\Common; -use OC\Files\Mount\MountPoint; -use OC\Files\Storage\Temporary; -use OCP\Files\FileInfo; -use OCP\Lock\ILockingProvider; - -class TemporaryNoTouch extends \OC\Files\Storage\Temporary { - public function touch($path, $mtime = null) { - return false; - } -} - -class TemporaryNoCross extends \OC\Files\Storage\Temporary { - public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { - return Common::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); - } - - public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { - return Common::moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); - } -} - -class TemporaryNoLocal extends \OC\Files\Storage\Temporary { - public function instanceOfStorage($className) { - if ($className === '\OC\Files\Storage\Local') { - return false; - } else { - return parent::instanceOfStorage($className); - } - } -} - -/** - * Class View - * - * @group DB - * - * @package Test\Files - */ -class View extends \Test\TestCase { - /** - * @var \OC\Files\Storage\Storage[] $storages - */ - private $storages = array(); - - /** - * @var string - */ - private $user; - - /** - * @var \OCP\IUser - */ - private $userObject; - - /** - * @var \OCP\IGroup - */ - private $groupObject; - - /** @var \OC\Files\Storage\Storage */ - private $tempStorage; - - protected function setUp() { - parent::setUp(); - \OC_Hook::clear(); - - \OC_User::clearBackends(); - \OC_User::useBackend(new \Test\Util\User\Dummy()); - - //login - $userManager = \OC::$server->getUserManager(); - $groupManager = \OC::$server->getGroupManager(); - $this->user = 'test'; - $this->userObject = $userManager->createUser('test', 'test'); - - $this->groupObject = $groupManager->createGroup('group1'); - $this->groupObject->addUser($this->userObject); - - $this->loginAsUser($this->user); - // clear mounts but somehow keep the root storage - // that was initialized above... - \OC\Files\Filesystem::clearMounts(); - - $this->tempStorage = null; - } - - protected function tearDown() { - \OC_User::setUserId($this->user); - foreach ($this->storages as $storage) { - $cache = $storage->getCache(); - $ids = $cache->getAll(); - $cache->clear(); - } - - if ($this->tempStorage && !\OC_Util::runningOnWindows()) { - system('rm -rf ' . escapeshellarg($this->tempStorage->getDataDir())); - } - - $this->logout(); - - $this->userObject->delete(); - $this->groupObject->delete(); - - $mountProviderCollection = \OC::$server->getMountProviderCollection(); - \Test\TestCase::invokePrivate($mountProviderCollection, 'providers', [[]]); - - parent::tearDown(); - } - - /** - * @medium - */ - public function testCacheAPI() { - $storage1 = $this->getTestStorage(); - $storage2 = $this->getTestStorage(); - $storage3 = $this->getTestStorage(); - $root = $this->getUniqueID('/'); - \OC\Files\Filesystem::mount($storage1, array(), $root . '/'); - \OC\Files\Filesystem::mount($storage2, array(), $root . '/substorage'); - \OC\Files\Filesystem::mount($storage3, array(), $root . '/folder/anotherstorage'); - $textSize = strlen("dummy file data\n"); - $imageSize = filesize(\OC::$SERVERROOT . '/core/img/logo.png'); - $storageSize = $textSize * 2 + $imageSize; - - $storageInfo = $storage3->getCache()->get(''); - $this->assertEquals($storageSize, $storageInfo['size']); - - $rootView = new \OC\Files\View($root); - - $cachedData = $rootView->getFileInfo('/foo.txt'); - $this->assertEquals($textSize, $cachedData['size']); - $this->assertEquals('text/plain', $cachedData['mimetype']); - $this->assertNotEquals(-1, $cachedData['permissions']); - - $cachedData = $rootView->getFileInfo('/'); - $this->assertEquals($storageSize * 3, $cachedData['size']); - $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']); - - // get cached data excluding mount points - $cachedData = $rootView->getFileInfo('/', false); - $this->assertEquals($storageSize, $cachedData['size']); - $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']); - - $cachedData = $rootView->getFileInfo('/folder'); - $this->assertEquals($storageSize + $textSize, $cachedData['size']); - $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']); - - $folderData = $rootView->getDirectoryContent('/'); - /** - * expected entries: - * folder - * foo.png - * foo.txt - * substorage - */ - $this->assertEquals(4, count($folderData)); - $this->assertEquals('folder', $folderData[0]['name']); - $this->assertEquals('foo.png', $folderData[1]['name']); - $this->assertEquals('foo.txt', $folderData[2]['name']); - $this->assertEquals('substorage', $folderData[3]['name']); - - $this->assertEquals($storageSize + $textSize, $folderData[0]['size']); - $this->assertEquals($imageSize, $folderData[1]['size']); - $this->assertEquals($textSize, $folderData[2]['size']); - $this->assertEquals($storageSize, $folderData[3]['size']); - - $folderData = $rootView->getDirectoryContent('/substorage'); - /** - * expected entries: - * folder - * foo.png - * foo.txt - */ - $this->assertEquals(3, count($folderData)); - $this->assertEquals('folder', $folderData[0]['name']); - $this->assertEquals('foo.png', $folderData[1]['name']); - $this->assertEquals('foo.txt', $folderData[2]['name']); - - $folderView = new \OC\Files\View($root . '/folder'); - $this->assertEquals($rootView->getFileInfo('/folder'), $folderView->getFileInfo('/')); - - $cachedData = $rootView->getFileInfo('/foo.txt'); - $this->assertFalse($cachedData['encrypted']); - $id = $rootView->putFileInfo('/foo.txt', array('encrypted' => true)); - $cachedData = $rootView->getFileInfo('/foo.txt'); - $this->assertTrue($cachedData['encrypted']); - $this->assertEquals($cachedData['fileid'], $id); - - $this->assertFalse($rootView->getFileInfo('/non/existing')); - $this->assertEquals(array(), $rootView->getDirectoryContent('/non/existing')); - } - - /** - * @medium - */ - public function testGetPath() { - $storage1 = $this->getTestStorage(); - $storage2 = $this->getTestStorage(); - $storage3 = $this->getTestStorage(); - \OC\Files\Filesystem::mount($storage1, array(), '/'); - \OC\Files\Filesystem::mount($storage2, array(), '/substorage'); - \OC\Files\Filesystem::mount($storage3, array(), '/folder/anotherstorage'); - - $rootView = new \OC\Files\View(''); - - $cachedData = $rootView->getFileInfo('/foo.txt'); - /** @var int $id1 */ - $id1 = $cachedData['fileid']; - $this->assertEquals('/foo.txt', $rootView->getPath($id1)); - - $cachedData = $rootView->getFileInfo('/substorage/foo.txt'); - /** @var int $id2 */ - $id2 = $cachedData['fileid']; - $this->assertEquals('/substorage/foo.txt', $rootView->getPath($id2)); - - $folderView = new \OC\Files\View('/substorage'); - $this->assertEquals('/foo.txt', $folderView->getPath($id2)); - } - - /** - * @expectedException \OCP\Files\NotFoundException - */ - function testGetPathNotExisting() { - $storage1 = $this->getTestStorage(); - \OC\Files\Filesystem::mount($storage1, [], '/'); - - $rootView = new \OC\Files\View(''); - $cachedData = $rootView->getFileInfo('/foo.txt'); - /** @var int $id1 */ - $id1 = $cachedData['fileid']; - $folderView = new \OC\Files\View('/substorage'); - $this->assertNull($folderView->getPath($id1)); - } - - /** - * @medium - */ - public function testMountPointOverwrite() { - $storage1 = $this->getTestStorage(false); - $storage2 = $this->getTestStorage(); - $storage1->mkdir('substorage'); - \OC\Files\Filesystem::mount($storage1, array(), '/'); - \OC\Files\Filesystem::mount($storage2, array(), '/substorage'); - - $rootView = new \OC\Files\View(''); - $folderContent = $rootView->getDirectoryContent('/'); - $this->assertEquals(4, count($folderContent)); - } - - public function sharingDisabledPermissionProvider() { - return [ - ['no', '', true], - ['yes', 'group1', false], - ]; - } - - /** - * @dataProvider sharingDisabledPermissionProvider - */ - public function testRemoveSharePermissionWhenSharingDisabledForUser($excludeGroups, $excludeGroupsList, $expectedShareable) { - $appConfig = \OC::$server->getAppConfig(); - $oldExcludeGroupsFlag = $appConfig->getValue('core', 'shareapi_exclude_groups', 'no'); - $oldExcludeGroupsList = $appConfig->getValue('core', 'shareapi_exclude_groups_list', ''); - $appConfig->setValue('core', 'shareapi_exclude_groups', $excludeGroups); - $appConfig->setValue('core', 'shareapi_exclude_groups_list', $excludeGroupsList); - - $storage1 = $this->getTestStorage(); - $storage2 = $this->getTestStorage(); - \OC\Files\Filesystem::mount($storage1, array(), '/'); - \OC\Files\Filesystem::mount($storage2, array(), '/mount'); - - $view = new \OC\Files\View('/'); - - $folderContent = $view->getDirectoryContent(''); - $this->assertEquals($expectedShareable, $folderContent[0]->isShareable()); - - $folderContent = $view->getDirectoryContent('mount'); - $this->assertEquals($expectedShareable, $folderContent[0]->isShareable()); - - $appConfig->setValue('core', 'shareapi_exclude_groups', $oldExcludeGroupsFlag); - $appConfig->setValue('core', 'shareapi_exclude_groups_list', $oldExcludeGroupsList); - } - - public function testCacheIncompleteFolder() { - $storage1 = $this->getTestStorage(false); - \OC\Files\Filesystem::clearMounts(); - \OC\Files\Filesystem::mount($storage1, array(), '/incomplete'); - $rootView = new \OC\Files\View('/incomplete'); - - $entries = $rootView->getDirectoryContent('/'); - $this->assertEquals(3, count($entries)); - - // /folder will already be in the cache but not scanned - $entries = $rootView->getDirectoryContent('/folder'); - $this->assertEquals(1, count($entries)); - } - - public function testAutoScan() { - $storage1 = $this->getTestStorage(false); - $storage2 = $this->getTestStorage(false); - \OC\Files\Filesystem::mount($storage1, array(), '/'); - \OC\Files\Filesystem::mount($storage2, array(), '/substorage'); - $textSize = strlen("dummy file data\n"); - - $rootView = new \OC\Files\View(''); - - $cachedData = $rootView->getFileInfo('/'); - $this->assertEquals('httpd/unix-directory', $cachedData['mimetype']); - $this->assertEquals(-1, $cachedData['size']); - - $folderData = $rootView->getDirectoryContent('/substorage/folder'); - $this->assertEquals('text/plain', $folderData[0]['mimetype']); - $this->assertEquals($textSize, $folderData[0]['size']); - } - - /** - * @medium - */ - public function testSearch() { - $storage1 = $this->getTestStorage(); - $storage2 = $this->getTestStorage(); - $storage3 = $this->getTestStorage(); - \OC\Files\Filesystem::mount($storage1, array(), '/'); - \OC\Files\Filesystem::mount($storage2, array(), '/substorage'); - \OC\Files\Filesystem::mount($storage3, array(), '/folder/anotherstorage'); - - $rootView = new \OC\Files\View(''); - - $results = $rootView->search('foo'); - $this->assertEquals(6, count($results)); - $paths = array(); - foreach ($results as $result) { - $this->assertEquals($result['path'], \OC\Files\Filesystem::normalizePath($result['path'])); - $paths[] = $result['path']; - } - $this->assertContains('/foo.txt', $paths); - $this->assertContains('/foo.png', $paths); - $this->assertContains('/substorage/foo.txt', $paths); - $this->assertContains('/substorage/foo.png', $paths); - $this->assertContains('/folder/anotherstorage/foo.txt', $paths); - $this->assertContains('/folder/anotherstorage/foo.png', $paths); - - $folderView = new \OC\Files\View('/folder'); - $results = $folderView->search('bar'); - $this->assertEquals(2, count($results)); - $paths = array(); - foreach ($results as $result) { - $paths[] = $result['path']; - } - $this->assertContains('/anotherstorage/folder/bar.txt', $paths); - $this->assertContains('/bar.txt', $paths); - - $results = $folderView->search('foo'); - $this->assertEquals(2, count($results)); - $paths = array(); - foreach ($results as $result) { - $paths[] = $result['path']; - } - $this->assertContains('/anotherstorage/foo.txt', $paths); - $this->assertContains('/anotherstorage/foo.png', $paths); - - $this->assertEquals(6, count($rootView->searchByMime('text'))); - $this->assertEquals(3, count($folderView->searchByMime('text'))); - } - - /** - * @medium - */ - public function testWatcher() { - $storage1 = $this->getTestStorage(); - \OC\Files\Filesystem::mount($storage1, array(), '/'); - $storage1->getWatcher()->setPolicy(Watcher::CHECK_ALWAYS); - - $rootView = new \OC\Files\View(''); - - $cachedData = $rootView->getFileInfo('foo.txt'); - $this->assertEquals(16, $cachedData['size']); - - $rootView->putFileInfo('foo.txt', array('storage_mtime' => 10)); - $storage1->file_put_contents('foo.txt', 'foo'); - clearstatcache(); - - $cachedData = $rootView->getFileInfo('foo.txt'); - $this->assertEquals(3, $cachedData['size']); - } - - /** - * @medium - */ - public function testCopyBetweenStorageNoCross() { - $storage1 = $this->getTestStorage(true, '\Test\Files\TemporaryNoCross'); - $storage2 = $this->getTestStorage(true, '\Test\Files\TemporaryNoCross'); - $this->copyBetweenStorages($storage1, $storage2); - } - - /** - * @medium - */ - public function testCopyBetweenStorageCross() { - $storage1 = $this->getTestStorage(); - $storage2 = $this->getTestStorage(); - $this->copyBetweenStorages($storage1, $storage2); - } - - /** - * @medium - */ - public function testCopyBetweenStorageCrossNonLocal() { - $storage1 = $this->getTestStorage(true, '\Test\Files\TemporaryNoLocal'); - $storage2 = $this->getTestStorage(true, '\Test\Files\TemporaryNoLocal'); - $this->copyBetweenStorages($storage1, $storage2); - } - - function copyBetweenStorages($storage1, $storage2) { - \OC\Files\Filesystem::mount($storage1, array(), '/'); - \OC\Files\Filesystem::mount($storage2, array(), '/substorage'); - - $rootView = new \OC\Files\View(''); - $rootView->mkdir('substorage/emptyfolder'); - $rootView->copy('substorage', 'anotherfolder'); - $this->assertTrue($rootView->is_dir('/anotherfolder')); - $this->assertTrue($rootView->is_dir('/substorage')); - $this->assertTrue($rootView->is_dir('/anotherfolder/emptyfolder')); - $this->assertTrue($rootView->is_dir('/substorage/emptyfolder')); - $this->assertTrue($rootView->file_exists('/anotherfolder/foo.txt')); - $this->assertTrue($rootView->file_exists('/anotherfolder/foo.png')); - $this->assertTrue($rootView->file_exists('/anotherfolder/folder/bar.txt')); - $this->assertTrue($rootView->file_exists('/substorage/foo.txt')); - $this->assertTrue($rootView->file_exists('/substorage/foo.png')); - $this->assertTrue($rootView->file_exists('/substorage/folder/bar.txt')); - } - - /** - * @medium - */ - public function testMoveBetweenStorageNoCross() { - $storage1 = $this->getTestStorage(true, '\Test\Files\TemporaryNoCross'); - $storage2 = $this->getTestStorage(true, '\Test\Files\TemporaryNoCross'); - $this->moveBetweenStorages($storage1, $storage2); - } - - /** - * @medium - */ - public function testMoveBetweenStorageCross() { - $storage1 = $this->getTestStorage(); - $storage2 = $this->getTestStorage(); - $this->moveBetweenStorages($storage1, $storage2); - } - - /** - * @medium - */ - public function testMoveBetweenStorageCrossNonLocal() { - $storage1 = $this->getTestStorage(true, '\Test\Files\TemporaryNoLocal'); - $storage2 = $this->getTestStorage(true, '\Test\Files\TemporaryNoLocal'); - $this->moveBetweenStorages($storage1, $storage2); - } - - function moveBetweenStorages($storage1, $storage2) { - \OC\Files\Filesystem::mount($storage1, array(), '/'); - \OC\Files\Filesystem::mount($storage2, array(), '/substorage'); - - $rootView = new \OC\Files\View(''); - $rootView->rename('foo.txt', 'substorage/folder/foo.txt'); - $this->assertFalse($rootView->file_exists('foo.txt')); - $this->assertTrue($rootView->file_exists('substorage/folder/foo.txt')); - $rootView->rename('substorage/folder', 'anotherfolder'); - $this->assertFalse($rootView->is_dir('substorage/folder')); - $this->assertTrue($rootView->file_exists('anotherfolder/foo.txt')); - $this->assertTrue($rootView->file_exists('anotherfolder/bar.txt')); - } - - /** - * @medium - */ - public function testUnlink() { - $storage1 = $this->getTestStorage(); - $storage2 = $this->getTestStorage(); - \OC\Files\Filesystem::mount($storage1, array(), '/'); - \OC\Files\Filesystem::mount($storage2, array(), '/substorage'); - - $rootView = new \OC\Files\View(''); - $rootView->file_put_contents('/foo.txt', 'asd'); - $rootView->file_put_contents('/substorage/bar.txt', 'asd'); - - $this->assertTrue($rootView->file_exists('foo.txt')); - $this->assertTrue($rootView->file_exists('substorage/bar.txt')); - - $this->assertTrue($rootView->unlink('foo.txt')); - $this->assertTrue($rootView->unlink('substorage/bar.txt')); - - $this->assertFalse($rootView->file_exists('foo.txt')); - $this->assertFalse($rootView->file_exists('substorage/bar.txt')); - } - - /** - * @medium - */ - public function testUnlinkRootMustFail() { - $storage1 = $this->getTestStorage(); - $storage2 = $this->getTestStorage(); - \OC\Files\Filesystem::mount($storage1, array(), '/'); - \OC\Files\Filesystem::mount($storage2, array(), '/substorage'); - - $rootView = new \OC\Files\View(''); - $rootView->file_put_contents('/foo.txt', 'asd'); - $rootView->file_put_contents('/substorage/bar.txt', 'asd'); - - $this->assertFalse($rootView->unlink('')); - $this->assertFalse($rootView->unlink('/')); - $this->assertFalse($rootView->unlink('substorage')); - $this->assertFalse($rootView->unlink('/substorage')); - } - - /** - * @medium - */ - public function testTouch() { - $storage = $this->getTestStorage(true, '\Test\Files\TemporaryNoTouch'); - - \OC\Files\Filesystem::mount($storage, array(), '/'); - - $rootView = new \OC\Files\View(''); - $oldCachedData = $rootView->getFileInfo('foo.txt'); - - $rootView->touch('foo.txt', 500); - - $cachedData = $rootView->getFileInfo('foo.txt'); - $this->assertEquals(500, $cachedData['mtime']); - $this->assertEquals($oldCachedData['storage_mtime'], $cachedData['storage_mtime']); - - $rootView->putFileInfo('foo.txt', array('storage_mtime' => 1000)); //make sure the watcher detects the change - $rootView->file_put_contents('foo.txt', 'asd'); - $cachedData = $rootView->getFileInfo('foo.txt'); - $this->assertGreaterThanOrEqual($oldCachedData['mtime'], $cachedData['mtime']); - $this->assertEquals($cachedData['storage_mtime'], $cachedData['mtime']); - } - - /** - * @medium - */ - public function testViewHooks() { - $storage1 = $this->getTestStorage(); - $storage2 = $this->getTestStorage(); - $defaultRoot = \OC\Files\Filesystem::getRoot(); - \OC\Files\Filesystem::mount($storage1, array(), '/'); - \OC\Files\Filesystem::mount($storage2, array(), $defaultRoot . '/substorage'); - \OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook'); - - $rootView = new \OC\Files\View(''); - $subView = new \OC\Files\View($defaultRoot . '/substorage'); - $this->hookPath = null; - - $rootView->file_put_contents('/foo.txt', 'asd'); - $this->assertNull($this->hookPath); - - $subView->file_put_contents('/foo.txt', 'asd'); - $this->assertEquals('/substorage/foo.txt', $this->hookPath); - } - - private $hookPath; - - public function dummyHook($params) { - $this->hookPath = $params['path']; - } - - public function testSearchNotOutsideView() { - $storage1 = $this->getTestStorage(); - \OC\Files\Filesystem::mount($storage1, array(), '/'); - $storage1->rename('folder', 'foo'); - $scanner = $storage1->getScanner(); - $scanner->scan(''); - - $view = new \OC\Files\View('/foo'); - - $result = $view->search('.txt'); - $this->assertCount(1, $result); - } - - /** - * @param bool $scan - * @param string $class - * @return \OC\Files\Storage\Storage - */ - private function getTestStorage($scan = true, $class = '\OC\Files\Storage\Temporary') { - /** - * @var \OC\Files\Storage\Storage $storage - */ - $storage = new $class(array()); - $textData = "dummy file data\n"; - $imgData = file_get_contents(\OC::$SERVERROOT . '/core/img/logo.png'); - $storage->mkdir('folder'); - $storage->file_put_contents('foo.txt', $textData); - $storage->file_put_contents('foo.png', $imgData); - $storage->file_put_contents('folder/bar.txt', $textData); - - if ($scan) { - $scanner = $storage->getScanner(); - $scanner->scan(''); - } - $this->storages[] = $storage; - return $storage; - } - - /** - * @medium - */ - public function testViewHooksIfRootStartsTheSame() { - $storage1 = $this->getTestStorage(); - $storage2 = $this->getTestStorage(); - $defaultRoot = \OC\Files\Filesystem::getRoot(); - \OC\Files\Filesystem::mount($storage1, array(), '/'); - \OC\Files\Filesystem::mount($storage2, array(), $defaultRoot . '_substorage'); - \OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHook'); - - $subView = new \OC\Files\View($defaultRoot . '_substorage'); - $this->hookPath = null; - - $subView->file_put_contents('/foo.txt', 'asd'); - $this->assertNull($this->hookPath); - } - - private $hookWritePath; - private $hookCreatePath; - private $hookUpdatePath; - - public function dummyHookWrite($params) { - $this->hookWritePath = $params['path']; - } - - public function dummyHookUpdate($params) { - $this->hookUpdatePath = $params['path']; - } - - public function dummyHookCreate($params) { - $this->hookCreatePath = $params['path']; - } - - public function testEditNoCreateHook() { - $storage1 = $this->getTestStorage(); - $storage2 = $this->getTestStorage(); - $defaultRoot = \OC\Files\Filesystem::getRoot(); - \OC\Files\Filesystem::mount($storage1, array(), '/'); - \OC\Files\Filesystem::mount($storage2, array(), $defaultRoot); - \OC_Hook::connect('OC_Filesystem', 'post_create', $this, 'dummyHookCreate'); - \OC_Hook::connect('OC_Filesystem', 'post_update', $this, 'dummyHookUpdate'); - \OC_Hook::connect('OC_Filesystem', 'post_write', $this, 'dummyHookWrite'); - - $view = new \OC\Files\View($defaultRoot); - $this->hookWritePath = $this->hookUpdatePath = $this->hookCreatePath = null; - - $view->file_put_contents('/asd.txt', 'foo'); - $this->assertEquals('/asd.txt', $this->hookCreatePath); - $this->assertNull($this->hookUpdatePath); - $this->assertEquals('/asd.txt', $this->hookWritePath); - - $this->hookWritePath = $this->hookUpdatePath = $this->hookCreatePath = null; - - $view->file_put_contents('/asd.txt', 'foo'); - $this->assertNull($this->hookCreatePath); - $this->assertEquals('/asd.txt', $this->hookUpdatePath); - $this->assertEquals('/asd.txt', $this->hookWritePath); - - \OC_Hook::clear('OC_Filesystem', 'post_create'); - \OC_Hook::clear('OC_Filesystem', 'post_update'); - \OC_Hook::clear('OC_Filesystem', 'post_write'); - } - - /** - * @dataProvider resolvePathTestProvider - */ - public function testResolvePath($expected, $pathToTest) { - $storage1 = $this->getTestStorage(); - \OC\Files\Filesystem::mount($storage1, array(), '/'); - - $view = new \OC\Files\View(''); - - $result = $view->resolvePath($pathToTest); - $this->assertEquals($expected, $result[1]); - - $exists = $view->file_exists($pathToTest); - $this->assertTrue($exists); - - $exists = $view->file_exists($result[1]); - $this->assertTrue($exists); - } - - function resolvePathTestProvider() { - return array( - array('foo.txt', 'foo.txt'), - array('foo.txt', '/foo.txt'), - array('folder', 'folder'), - array('folder', '/folder'), - array('folder', 'folder/'), - array('folder', '/folder/'), - array('folder/bar.txt', 'folder/bar.txt'), - array('folder/bar.txt', '/folder/bar.txt'), - array('', ''), - array('', '/'), - ); - } - - public function testUTF8Names() { - $names = array('虚', '和知しゃ和で', 'regular ascii', 'sɨˈrɪlɪk', 'ѨѬ', 'أنا أحب القراءة كثيرا'); - - $storage = new \OC\Files\Storage\Temporary(array()); - \OC\Files\Filesystem::mount($storage, array(), '/'); - - $rootView = new \OC\Files\View(''); - foreach ($names as $name) { - $rootView->file_put_contents('/' . $name, 'dummy content'); - } - - $list = $rootView->getDirectoryContent('/'); - - $this->assertCount(count($names), $list); - foreach ($list as $item) { - $this->assertContains($item['name'], $names); - } - - $cache = $storage->getCache(); - $scanner = $storage->getScanner(); - $scanner->scan(''); - - $list = $cache->getFolderContents(''); - - $this->assertCount(count($names), $list); - foreach ($list as $item) { - $this->assertContains($item['name'], $names); - } - } - - public function xtestLongPath() { - - $storage = new \OC\Files\Storage\Temporary(array()); - \OC\Files\Filesystem::mount($storage, array(), '/'); - - $rootView = new \OC\Files\View(''); - - $longPath = ''; - $ds = DIRECTORY_SEPARATOR; - /* - * 4096 is the maximum path length in file_cache.path in *nix - * 1024 is the max path length in mac - * 228 is the max path length in windows - */ - $folderName = 'abcdefghijklmnopqrstuvwxyz012345678901234567890123456789'; - $tmpdirLength = strlen(\OC::$server->getTempManager()->getTemporaryFolder()); - if (\OC_Util::runningOnWindows()) { - $this->markTestSkipped('[Windows] '); - $depth = ((260 - $tmpdirLength) / 57); - } elseif (\OC_Util::runningOnMac()) { - $depth = ((1024 - $tmpdirLength) / 57); - } else { - $depth = ((4000 - $tmpdirLength) / 57); - } - foreach (range(0, $depth - 1) as $i) { - $longPath .= $ds . $folderName; - $result = $rootView->mkdir($longPath); - $this->assertTrue($result, "mkdir failed on $i - path length: " . strlen($longPath)); - - $result = $rootView->file_put_contents($longPath . "{$ds}test.txt", 'lorem'); - $this->assertEquals(5, $result, "file_put_contents failed on $i"); - - $this->assertTrue($rootView->file_exists($longPath)); - $this->assertTrue($rootView->file_exists($longPath . "{$ds}test.txt")); - } - - $cache = $storage->getCache(); - $scanner = $storage->getScanner(); - $scanner->scan(''); - - $longPath = $folderName; - foreach (range(0, $depth - 1) as $i) { - $cachedFolder = $cache->get($longPath); - $this->assertTrue(is_array($cachedFolder), "No cache entry for folder at $i"); - $this->assertEquals($folderName, $cachedFolder['name'], "Wrong cache entry for folder at $i"); - - $cachedFile = $cache->get($longPath . '/test.txt'); - $this->assertTrue(is_array($cachedFile), "No cache entry for file at $i"); - $this->assertEquals('test.txt', $cachedFile['name'], "Wrong cache entry for file at $i"); - - $longPath .= $ds . $folderName; - } - } - - public function testTouchNotSupported() { - $storage = new TemporaryNoTouch(array()); - $scanner = $storage->getScanner(); - \OC\Files\Filesystem::mount($storage, array(), '/test/'); - $past = time() - 100; - $storage->file_put_contents('test', 'foobar'); - $scanner->scan(''); - $view = new \OC\Files\View(''); - $info = $view->getFileInfo('/test/test'); - - $view->touch('/test/test', $past); - $scanner->scanFile('test', \OC\Files\Cache\Scanner::REUSE_ETAG); - - $info2 = $view->getFileInfo('/test/test'); - $this->assertSame($info['etag'], $info2['etag']); - } - - public function testWatcherEtagCrossStorage() { - $storage1 = new Temporary(array()); - $storage2 = new Temporary(array()); - $scanner1 = $storage1->getScanner(); - $scanner2 = $storage2->getScanner(); - $storage1->mkdir('sub'); - \OC\Files\Filesystem::mount($storage1, array(), '/test/'); - \OC\Files\Filesystem::mount($storage2, array(), '/test/sub/storage'); - - $past = time() - 100; - $storage2->file_put_contents('test.txt', 'foobar'); - $scanner1->scan(''); - $scanner2->scan(''); - $view = new \OC\Files\View(''); - - $storage2->getWatcher('')->setPolicy(Watcher::CHECK_ALWAYS); - - $oldFileInfo = $view->getFileInfo('/test/sub/storage/test.txt'); - $oldFolderInfo = $view->getFileInfo('/test'); - - $storage2->getCache()->update($oldFileInfo->getId(), array( - 'storage_mtime' => $past - )); - - $view->getFileInfo('/test/sub/storage/test.txt'); - $newFolderInfo = $view->getFileInfo('/test'); - - $this->assertNotEquals($newFolderInfo->getEtag(), $oldFolderInfo->getEtag()); - } - - /** - * @dataProvider absolutePathProvider - */ - public function testGetAbsolutePath($expectedPath, $relativePath) { - $view = new \OC\Files\View('/files'); - $this->assertEquals($expectedPath, $view->getAbsolutePath($relativePath)); - } - - public function testPartFileInfo() { - $storage = new Temporary(array()); - $scanner = $storage->getScanner(); - \OC\Files\Filesystem::mount($storage, array(), '/test/'); - $storage->file_put_contents('test.part', 'foobar'); - $scanner->scan(''); - $view = new \OC\Files\View('/test'); - $info = $view->getFileInfo('test.part'); - - $this->assertInstanceOf('\OCP\Files\FileInfo', $info); - $this->assertNull($info->getId()); - $this->assertEquals(6, $info->getSize()); - } - - function absolutePathProvider() { - return array( - array('/files/', ''), - array('/files/0', '0'), - array('/files/false', 'false'), - array('/files/true', 'true'), - array('/files/', '/'), - array('/files/test', 'test'), - array('/files/test', '/test'), - ); - } - - /** - * @dataProvider chrootRelativePathProvider - */ - function testChrootGetRelativePath($root, $absolutePath, $expectedPath) { - $view = new \OC\Files\View('/files'); - $view->chroot($root); - $this->assertEquals($expectedPath, $view->getRelativePath($absolutePath)); - } - - public function chrootRelativePathProvider() { - return $this->relativePathProvider('/'); - } - - /** - * @dataProvider initRelativePathProvider - */ - public function testInitGetRelativePath($root, $absolutePath, $expectedPath) { - $view = new \OC\Files\View($root); - $this->assertEquals($expectedPath, $view->getRelativePath($absolutePath)); - } - - public function initRelativePathProvider() { - return $this->relativePathProvider(null); - } - - public function relativePathProvider($missingRootExpectedPath) { - return array( - // No root - returns the path - array('', '/files', '/files'), - array('', '/files/', '/files/'), - - // Root equals path - / - array('/files/', '/files/', '/'), - array('/files/', '/files', '/'), - array('/files', '/files/', '/'), - array('/files', '/files', '/'), - - // False negatives: chroot fixes those by adding the leading slash. - // But setting them up with this root (instead of chroot($root)) - // will fail them, although they should be the same. - // TODO init should be fixed, so it also adds the leading slash - array('files/', '/files/', $missingRootExpectedPath), - array('files', '/files/', $missingRootExpectedPath), - array('files/', '/files', $missingRootExpectedPath), - array('files', '/files', $missingRootExpectedPath), - - // False negatives: Paths provided to the method should have a leading slash - // TODO input should be checked to have a leading slash - array('/files/', 'files/', null), - array('/files', 'files/', null), - array('/files/', 'files', null), - array('/files', 'files', null), - - // with trailing slashes - array('/files/', '/files/0', '0'), - array('/files/', '/files/false', 'false'), - array('/files/', '/files/true', 'true'), - array('/files/', '/files/test', 'test'), - array('/files/', '/files/test/foo', 'test/foo'), - - // without trailing slashes - // TODO false expectation: Should match "with trailing slashes" - array('/files', '/files/0', '/0'), - array('/files', '/files/false', '/false'), - array('/files', '/files/true', '/true'), - array('/files', '/files/test', '/test'), - array('/files', '/files/test/foo', '/test/foo'), - - // leading slashes - array('/files/', '/files_trashbin/', null), - array('/files', '/files_trashbin/', null), - array('/files/', '/files_trashbin', null), - array('/files', '/files_trashbin', null), - - // no leading slashes - array('files/', 'files_trashbin/', null), - array('files', 'files_trashbin/', null), - array('files/', 'files_trashbin', null), - array('files', 'files_trashbin', null), - - // mixed leading slashes - array('files/', '/files_trashbin/', null), - array('/files/', 'files_trashbin/', null), - array('files', '/files_trashbin/', null), - array('/files', 'files_trashbin/', null), - array('files/', '/files_trashbin', null), - array('/files/', 'files_trashbin', null), - array('files', '/files_trashbin', null), - array('/files', 'files_trashbin', null), - - array('files', 'files_trashbin/test', null), - array('/files', '/files_trashbin/test', null), - array('/files', 'files_trashbin/test', null), - ); - } - - public function testFileView() { - $storage = new Temporary(array()); - $scanner = $storage->getScanner(); - $storage->file_put_contents('foo.txt', 'bar'); - \OC\Files\Filesystem::mount($storage, array(), '/test/'); - $scanner->scan(''); - $view = new \OC\Files\View('/test/foo.txt'); - - $this->assertEquals('bar', $view->file_get_contents('')); - $fh = tmpfile(); - fwrite($fh, 'foo'); - rewind($fh); - $view->file_put_contents('', $fh); - $this->assertEquals('foo', $view->file_get_contents('')); - } - - /** - * @dataProvider tooLongPathDataProvider - * @expectedException \OCP\Files\InvalidPathException - */ - public function testTooLongPath($operation, $param0 = null) { - - $longPath = ''; - // 4000 is the maximum path length in file_cache.path - $folderName = 'abcdefghijklmnopqrstuvwxyz012345678901234567890123456789'; - $depth = (4000 / 57); - foreach (range(0, $depth + 1) as $i) { - $longPath .= '/' . $folderName; - } - - $storage = new \OC\Files\Storage\Temporary(array()); - $this->tempStorage = $storage; // for later hard cleanup - \OC\Files\Filesystem::mount($storage, array(), '/'); - - $rootView = new \OC\Files\View(''); - - if ($param0 === '@0') { - $param0 = $longPath; - } - - if ($operation === 'hash') { - $param0 = $longPath; - $longPath = 'md5'; - } - - call_user_func(array($rootView, $operation), $longPath, $param0); - } - - public function tooLongPathDataProvider() { - return array( - array('getAbsolutePath'), - array('getRelativePath'), - array('getMountPoint'), - array('resolvePath'), - array('getLocalFile'), - array('getLocalFolder'), - array('mkdir'), - array('rmdir'), - array('opendir'), - array('is_dir'), - array('is_file'), - array('stat'), - array('filetype'), - array('filesize'), - array('readfile'), - array('isCreatable'), - array('isReadable'), - array('isUpdatable'), - array('isDeletable'), - array('isSharable'), - array('file_exists'), - array('filemtime'), - array('touch'), - array('file_get_contents'), - array('unlink'), - array('deleteAll'), - array('toTmpFile'), - array('getMimeType'), - array('free_space'), - array('getFileInfo'), - array('getDirectoryContent'), - array('getOwner'), - array('getETag'), - array('file_put_contents', 'ipsum'), - array('rename', '@0'), - array('copy', '@0'), - array('fopen', 'r'), - array('fromTmpFile', '@0'), - array('hash'), - array('hasUpdated', 0), - array('putFileInfo', array()), - ); - } - - public function testRenameCrossStoragePreserveMtime() { - $storage1 = new Temporary(array()); - $storage2 = new Temporary(array()); - $scanner1 = $storage1->getScanner(); - $scanner2 = $storage2->getScanner(); - $storage1->mkdir('sub'); - $storage1->mkdir('foo'); - $storage1->file_put_contents('foo.txt', 'asd'); - $storage1->file_put_contents('foo/bar.txt', 'asd'); - \OC\Files\Filesystem::mount($storage1, array(), '/test/'); - \OC\Files\Filesystem::mount($storage2, array(), '/test/sub/storage'); - - $view = new \OC\Files\View(''); - $time = time() - 200; - $view->touch('/test/foo.txt', $time); - $view->touch('/test/foo', $time); - $view->touch('/test/foo/bar.txt', $time); - - $view->rename('/test/foo.txt', '/test/sub/storage/foo.txt'); - - $this->assertEquals($time, $view->filemtime('/test/sub/storage/foo.txt')); - - $view->rename('/test/foo', '/test/sub/storage/foo'); - - $this->assertEquals($time, $view->filemtime('/test/sub/storage/foo/bar.txt')); - } - - public function testRenameFailDeleteTargetKeepSource() { - $this->doTestCopyRenameFail('rename'); - } - - public function testCopyFailDeleteTargetKeepSource() { - $this->doTestCopyRenameFail('copy'); - } - - private function doTestCopyRenameFail($operation) { - $storage1 = new Temporary(array()); - /** @var \PHPUnit_Framework_MockObject_MockObject | \OC\Files\Storage\Temporary $storage2 */ - $storage2 = $this->getMockBuilder('\Test\Files\TemporaryNoCross') - ->setConstructorArgs([[]]) - ->setMethods(['fopen']) - ->getMock(); - - $storage2->expects($this->any()) - ->method('fopen') - ->will($this->returnCallback(function ($path, $mode) use ($storage2) { - /** @var \PHPUnit_Framework_MockObject_MockObject | \OC\Files\Storage\Temporary $storage2 */ - $source = fopen($storage2->getSourcePath($path), $mode); - return \OC\Files\Stream\Quota::wrap($source, 9); - })); - - $storage1->mkdir('sub'); - $storage1->file_put_contents('foo.txt', '0123456789ABCDEFGH'); - $storage1->mkdir('dirtomove'); - $storage1->file_put_contents('dirtomove/indir1.txt', '0123456'); // fits - $storage1->file_put_contents('dirtomove/indir2.txt', '0123456789ABCDEFGH'); // doesn't fit - $storage2->file_put_contents('existing.txt', '0123'); - $storage1->getScanner()->scan(''); - $storage2->getScanner()->scan(''); - \OC\Files\Filesystem::mount($storage1, array(), '/test/'); - \OC\Files\Filesystem::mount($storage2, array(), '/test/sub/storage'); - - // move file - $view = new \OC\Files\View(''); - $this->assertTrue($storage1->file_exists('foo.txt')); - $this->assertFalse($storage2->file_exists('foo.txt')); - $this->assertFalse($view->$operation('/test/foo.txt', '/test/sub/storage/foo.txt')); - $this->assertFalse($storage2->file_exists('foo.txt')); - $this->assertFalse($storage2->getCache()->get('foo.txt')); - $this->assertTrue($storage1->file_exists('foo.txt')); - - // if target exists, it will be deleted too - $this->assertFalse($view->$operation('/test/foo.txt', '/test/sub/storage/existing.txt')); - $this->assertFalse($storage2->file_exists('existing.txt')); - $this->assertFalse($storage2->getCache()->get('existing.txt')); - $this->assertTrue($storage1->file_exists('foo.txt')); - - // move folder - $this->assertFalse($view->$operation('/test/dirtomove/', '/test/sub/storage/dirtomove/')); - // since the move failed, the full source tree is kept - $this->assertTrue($storage1->file_exists('dirtomove/indir1.txt')); - $this->assertTrue($storage1->file_exists('dirtomove/indir2.txt')); - // second file not moved/copied - $this->assertFalse($storage2->file_exists('dirtomove/indir2.txt')); - $this->assertFalse($storage2->getCache()->get('dirtomove/indir2.txt')); - - } - - public function testDeleteFailKeepCache() { - /** - * @var \PHPUnit_Framework_MockObject_MockObject | \OC\Files\Storage\Temporary $storage - */ - $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary') - ->setConstructorArgs(array(array())) - ->setMethods(array('unlink')) - ->getMock(); - $storage->expects($this->once()) - ->method('unlink') - ->will($this->returnValue(false)); - $scanner = $storage->getScanner(); - $cache = $storage->getCache(); - $storage->file_put_contents('foo.txt', 'asd'); - $scanner->scan(''); - \OC\Files\Filesystem::mount($storage, array(), '/test/'); - - $view = new \OC\Files\View('/test'); - - $this->assertFalse($view->unlink('foo.txt')); - $this->assertTrue($cache->inCache('foo.txt')); - } - - function directoryTraversalProvider() { - return [ - ['../test/'], - ['..\\test\\my/../folder'], - ['/test/my/../foo\\'], - ]; - } - - /** - * @dataProvider directoryTraversalProvider - * @expectedException \Exception - * @param string $root - */ - public function testConstructDirectoryTraversalException($root) { - new \OC\Files\View($root); - } - - public function testRenameOverWrite() { - $storage = new Temporary(array()); - $scanner = $storage->getScanner(); - $storage->mkdir('sub'); - $storage->mkdir('foo'); - $storage->file_put_contents('foo.txt', 'asd'); - $storage->file_put_contents('foo/bar.txt', 'asd'); - $scanner->scan(''); - \OC\Files\Filesystem::mount($storage, array(), '/test/'); - $view = new \OC\Files\View(''); - $this->assertTrue($view->rename('/test/foo.txt', '/test/foo/bar.txt')); - } - - public function testSetMountOptionsInStorage() { - $mount = new MountPoint('\OC\Files\Storage\Temporary', '/asd/', [[]], \OC\Files\Filesystem::getLoader(), ['foo' => 'bar']); - \OC\Files\Filesystem::getMountManager()->addMount($mount); - /** @var \OC\Files\Storage\Common $storage */ - $storage = $mount->getStorage(); - $this->assertEquals($storage->getMountOption('foo'), 'bar'); - } - - public function testSetMountOptionsWatcherPolicy() { - $mount = new MountPoint('\OC\Files\Storage\Temporary', '/asd/', [[]], \OC\Files\Filesystem::getLoader(), ['filesystem_check_changes' => Watcher::CHECK_NEVER]); - \OC\Files\Filesystem::getMountManager()->addMount($mount); - /** @var \OC\Files\Storage\Common $storage */ - $storage = $mount->getStorage(); - $watcher = $storage->getWatcher(); - $this->assertEquals(Watcher::CHECK_NEVER, $watcher->getPolicy()); - } - - public function testGetAbsolutePathOnNull() { - $view = new \OC\Files\View(); - $this->assertNull($view->getAbsolutePath(null)); - } - - public function testGetRelativePathOnNull() { - $view = new \OC\Files\View(); - $this->assertNull($view->getRelativePath(null)); - } - - /** - * @expectedException \InvalidArgumentException - */ - public function testNullAsRoot() { - new \OC\Files\View(null); - } - - /** - * e.g. reading from a folder that's being renamed - * - * @expectedException \OCP\Lock\LockedException - * - * @dataProvider dataLockPaths - * - * @param string $rootPath - * @param string $pathPrefix - */ - public function testReadFromWriteLockedPath($rootPath, $pathPrefix) { - $rootPath = str_replace('{folder}', 'files', $rootPath); - $pathPrefix = str_replace('{folder}', 'files', $pathPrefix); - - $view = new \OC\Files\View($rootPath); - $storage = new Temporary(array()); - \OC\Files\Filesystem::mount($storage, [], '/'); - $this->assertTrue($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE)); - $view->lockFile($pathPrefix . '/foo/bar/asd', ILockingProvider::LOCK_SHARED); - } - - /** - * Reading from a files_encryption folder that's being renamed - * - * @dataProvider dataLockPaths - * - * @param string $rootPath - * @param string $pathPrefix - */ - public function testReadFromWriteUnlockablePath($rootPath, $pathPrefix) { - $rootPath = str_replace('{folder}', 'files_encryption', $rootPath); - $pathPrefix = str_replace('{folder}', 'files_encryption', $pathPrefix); - - $view = new \OC\Files\View($rootPath); - $storage = new Temporary(array()); - \OC\Files\Filesystem::mount($storage, [], '/'); - $this->assertFalse($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE)); - $this->assertFalse($view->lockFile($pathPrefix . '/foo/bar/asd', ILockingProvider::LOCK_SHARED)); - } - - /** - * e.g. writing a file that's being downloaded - * - * @expectedException \OCP\Lock\LockedException - * - * @dataProvider dataLockPaths - * - * @param string $rootPath - * @param string $pathPrefix - */ - public function testWriteToReadLockedFile($rootPath, $pathPrefix) { - $rootPath = str_replace('{folder}', 'files', $rootPath); - $pathPrefix = str_replace('{folder}', 'files', $pathPrefix); - - $view = new \OC\Files\View($rootPath); - $storage = new Temporary(array()); - \OC\Files\Filesystem::mount($storage, [], '/'); - $this->assertTrue($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_SHARED)); - $view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE); - } - - /** - * Writing a file that's being downloaded - * - * @dataProvider dataLockPaths - * - * @param string $rootPath - * @param string $pathPrefix - */ - public function testWriteToReadUnlockableFile($rootPath, $pathPrefix) { - $rootPath = str_replace('{folder}', 'files_encryption', $rootPath); - $pathPrefix = str_replace('{folder}', 'files_encryption', $pathPrefix); - - $view = new \OC\Files\View($rootPath); - $storage = new Temporary(array()); - \OC\Files\Filesystem::mount($storage, [], '/'); - $this->assertFalse($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_SHARED)); - $this->assertFalse($view->lockFile($pathPrefix . '/foo/bar', ILockingProvider::LOCK_EXCLUSIVE)); - } - - /** - * Test that locks are on mount point paths instead of mount root - */ - public function testLockLocalMountPointPathInsteadOfStorageRoot() { - $lockingProvider = \OC::$server->getLockingProvider(); - $view = new \OC\Files\View('/testuser/files/'); - $storage = new Temporary([]); - \OC\Files\Filesystem::mount($storage, [], '/'); - $mountedStorage = new Temporary([]); - \OC\Files\Filesystem::mount($mountedStorage, [], '/testuser/files/mountpoint'); - - $this->assertTrue( - $view->lockFile('/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, true), - 'Can lock mount point' - ); - - // no exception here because storage root was not locked - $mountedStorage->acquireLock('', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider); - - $thrown = false; - try { - $storage->acquireLock('/testuser/files/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider); - } catch (\OCP\Lock\LockedException $e) { - $thrown = true; - } - $this->assertTrue($thrown, 'Mount point path was locked on root storage'); - - $lockingProvider->releaseAll(); - } - - /** - * Test that locks are on mount point paths and also mount root when requested - */ - public function testLockStorageRootButNotLocalMountPoint() { - $lockingProvider = \OC::$server->getLockingProvider(); - $view = new \OC\Files\View('/testuser/files/'); - $storage = new Temporary([]); - \OC\Files\Filesystem::mount($storage, [], '/'); - $mountedStorage = new Temporary([]); - \OC\Files\Filesystem::mount($mountedStorage, [], '/testuser/files/mountpoint'); - - $this->assertTrue( - $view->lockFile('/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, false), - 'Can lock mount point' - ); - - $thrown = false; - try { - $mountedStorage->acquireLock('', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider); - } catch (\OCP\Lock\LockedException $e) { - $thrown = true; - } - $this->assertTrue($thrown, 'Mount point storage root was locked on original storage'); - - // local mount point was not locked - $storage->acquireLock('/testuser/files/mountpoint', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider); - - $lockingProvider->releaseAll(); - } - - /** - * Test that locks are on mount point paths and also mount root when requested - */ - public function testLockMountPointPathFailReleasesBoth() { - $lockingProvider = \OC::$server->getLockingProvider(); - $view = new \OC\Files\View('/testuser/files/'); - $storage = new Temporary([]); - \OC\Files\Filesystem::mount($storage, [], '/'); - $mountedStorage = new Temporary([]); - \OC\Files\Filesystem::mount($mountedStorage, [], '/testuser/files/mountpoint.txt'); - - // this would happen if someone is writing on the mount point - $mountedStorage->acquireLock('', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider); - - $thrown = false; - try { - // this actually acquires two locks, one on the mount point and one on the storage root, - // but the one on the storage root will fail - $view->lockFile('/mountpoint.txt', ILockingProvider::LOCK_SHARED); - } catch (\OCP\Lock\LockedException $e) { - $thrown = true; - } - $this->assertTrue($thrown, 'Cannot acquire shared lock because storage root is already locked'); - - // from here we expect that the lock on the local mount point was released properly - // so acquiring an exclusive lock will succeed - $storage->acquireLock('/testuser/files/mountpoint.txt', ILockingProvider::LOCK_EXCLUSIVE, $lockingProvider); - - $lockingProvider->releaseAll(); - } - - public function dataLockPaths() { - return [ - ['/testuser/{folder}', ''], - ['/testuser', '/{folder}'], - ['', '/testuser/{folder}'], - ]; - } - - public function pathRelativeToFilesProvider() { - return [ - ['admin/files', ''], - ['admin/files/x', 'x'], - ['/admin/files', ''], - ['/admin/files/sub', 'sub'], - ['/admin/files/sub/', 'sub'], - ['/admin/files/sub/sub2', 'sub/sub2'], - ['//admin//files/sub//sub2', 'sub/sub2'], - ]; - } - - /** - * @dataProvider pathRelativeToFilesProvider - */ - public function testGetPathRelativeToFiles($path, $expectedPath) { - $view = new \OC\Files\View(); - $this->assertEquals($expectedPath, $view->getPathRelativeToFiles($path)); - } - - public function pathRelativeToFilesProviderExceptionCases() { - return [ - [''], - ['x'], - ['files'], - ['/files'], - ['/admin/files_versions/abc'], - ]; - } - - /** - * @dataProvider pathRelativeToFilesProviderExceptionCases - * @expectedException \InvalidArgumentException - */ - public function testGetPathRelativeToFilesWithInvalidArgument($path) { - $view = new \OC\Files\View(); - $view->getPathRelativeToFiles($path); - } - - public function testChangeLock() { - $view = new \OC\Files\View('/testuser/files/'); - $storage = new Temporary(array()); - \OC\Files\Filesystem::mount($storage, [], '/'); - - $view->lockFile('/test/sub', ILockingProvider::LOCK_SHARED); - $this->assertTrue($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_SHARED)); - $this->assertFalse($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_EXCLUSIVE)); - - $view->changeLock('//test/sub', ILockingProvider::LOCK_EXCLUSIVE); - $this->assertTrue($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_EXCLUSIVE)); - - $view->changeLock('test/sub', ILockingProvider::LOCK_SHARED); - $this->assertTrue($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_SHARED)); - - $view->unlockFile('/test/sub/', ILockingProvider::LOCK_SHARED); - - $this->assertFalse($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_SHARED)); - $this->assertFalse($this->isFileLocked($view, '/test//sub', ILockingProvider::LOCK_EXCLUSIVE)); - - } - - public function hookPathProvider() { - return [ - ['/foo/files', '/foo', true], - ['/foo/files/bar', '/foo', true], - ['/foo', '/foo', false], - ['/foo', '/files/foo', true], - ['/foo', 'filesfoo', false], - ['', '/foo/files', true], - ['', '/foo/files/bar.txt', true] - ]; - } - - /** - * @dataProvider hookPathProvider - * @param $root - * @param $path - * @param $shouldEmit - */ - public function testHookPaths($root, $path, $shouldEmit) { - $filesystemReflection = new \ReflectionClass('\OC\Files\Filesystem'); - $defaultRootValue = $filesystemReflection->getProperty('defaultInstance'); - $defaultRootValue->setAccessible(true); - $oldRoot = $defaultRootValue->getValue(); - $defaultView = new \OC\Files\View('/foo/files'); - $defaultRootValue->setValue($defaultView); - $view = new \OC\Files\View($root); - $result = $this->invokePrivate($view, 'shouldEmitHooks', [$path]); - $defaultRootValue->setValue($oldRoot); - $this->assertEquals($shouldEmit, $result); - } - - /** - * Create test movable mount points - * - * @param array $mountPoints array of mount point locations - * @return array array of MountPoint objects - */ - private function createTestMovableMountPoints($mountPoints) { - $mounts = []; - foreach ($mountPoints as $mountPoint) { - $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary') - ->setMethods([]) - ->getMock(); - - $mounts[] = $this->getMock( - '\Test\TestMoveableMountPoint', - ['moveMount'], - [$storage, $mountPoint] - ); - } - - $mountProvider = $this->getMock('\OCP\Files\Config\IMountProvider'); - $mountProvider->expects($this->any()) - ->method('getMountsForUser') - ->will($this->returnValue($mounts)); - - $mountProviderCollection = \OC::$server->getMountProviderCollection(); - $mountProviderCollection->registerProvider($mountProvider); - - return $mounts; - } - - /** - * Test mount point move - */ - public function testMountPointMove() { - $this->loginAsUser($this->user); - - list($mount1, $mount2) = $this->createTestMovableMountPoints([ - $this->user . '/files/mount1', - $this->user . '/files/mount2', - ]); - $mount1->expects($this->once()) - ->method('moveMount') - ->will($this->returnValue(true)); - - $mount2->expects($this->once()) - ->method('moveMount') - ->will($this->returnValue(true)); - - $view = new \OC\Files\View('/' . $this->user . '/files/'); - $view->mkdir('sub'); - - $this->assertTrue($view->rename('mount1', 'renamed_mount'), 'Can rename mount point'); - $this->assertTrue($view->rename('mount2', 'sub/moved_mount'), 'Can move a mount point into a subdirectory'); - } - - /** - * Test that moving a mount point into another is forbidden - */ - public function testMoveMountPointIntoAnother() { - $this->loginAsUser($this->user); - - list($mount1, $mount2) = $this->createTestMovableMountPoints([ - $this->user . '/files/mount1', - $this->user . '/files/mount2', - ]); - - $mount1->expects($this->never()) - ->method('moveMount'); - - $mount2->expects($this->never()) - ->method('moveMount'); - - $view = new \OC\Files\View('/' . $this->user . '/files/'); - - $this->assertFalse($view->rename('mount1', 'mount2'), 'Cannot overwrite another mount point'); - $this->assertFalse($view->rename('mount1', 'mount2/sub'), 'Cannot move a mount point into another'); - } - - /** - * Test that moving a mount point into a shared folder is forbidden - */ - public function testMoveMountPointIntoSharedFolder() { - $this->loginAsUser($this->user); - - list($mount1) = $this->createTestMovableMountPoints([ - $this->user . '/files/mount1', - ]); - - $mount1->expects($this->never()) - ->method('moveMount'); - - $view = new \OC\Files\View('/' . $this->user . '/files/'); - $view->mkdir('shareddir'); - $view->mkdir('shareddir/sub'); - $view->mkdir('shareddir/sub2'); - - $fileId = $view->getFileInfo('shareddir')->getId(); - $userObject = \OC::$server->getUserManager()->createUser('test2', 'IHateNonMockableStaticClasses'); - $this->assertTrue(\OCP\Share::shareItem('folder', $fileId, \OCP\Share::SHARE_TYPE_USER, 'test2', \OCP\Constants::PERMISSION_READ)); - - $this->assertFalse($view->rename('mount1', 'shareddir'), 'Cannot overwrite shared folder'); - $this->assertFalse($view->rename('mount1', 'shareddir/sub'), 'Cannot move mount point into shared folder'); - $this->assertFalse($view->rename('mount1', 'shareddir/sub/sub2'), 'Cannot move mount point into shared subfolder'); - - $this->assertTrue(\OCP\Share::unshare('folder', $fileId, \OCP\Share::SHARE_TYPE_USER, 'test2')); - $userObject->delete(); - } - - public function basicOperationProviderForLocks() { - return [ - // --- write hook ---- - [ - 'touch', - ['touch-create.txt'], - 'touch-create.txt', - 'create', - ILockingProvider::LOCK_SHARED, - ILockingProvider::LOCK_EXCLUSIVE, - ILockingProvider::LOCK_SHARED, - ], - [ - 'fopen', - ['test-write.txt', 'w'], - 'test-write.txt', - 'write', - ILockingProvider::LOCK_SHARED, - ILockingProvider::LOCK_EXCLUSIVE, - null, - // exclusive lock stays until fclose - ILockingProvider::LOCK_EXCLUSIVE, - ], - [ - 'mkdir', - ['newdir'], - 'newdir', - 'write', - ILockingProvider::LOCK_SHARED, - ILockingProvider::LOCK_EXCLUSIVE, - ILockingProvider::LOCK_SHARED, - ], - [ - 'file_put_contents', - ['file_put_contents.txt', 'blah'], - 'file_put_contents.txt', - 'write', - ILockingProvider::LOCK_SHARED, - ILockingProvider::LOCK_EXCLUSIVE, - ILockingProvider::LOCK_SHARED, - ], - - // ---- delete hook ---- - [ - 'rmdir', - ['dir'], - 'dir', - 'delete', - ILockingProvider::LOCK_SHARED, - ILockingProvider::LOCK_EXCLUSIVE, - ILockingProvider::LOCK_SHARED, - ], - [ - 'unlink', - ['test.txt'], - 'test.txt', - 'delete', - ILockingProvider::LOCK_SHARED, - ILockingProvider::LOCK_EXCLUSIVE, - ILockingProvider::LOCK_SHARED, - ], - - // ---- read hook (no post hooks) ---- - [ - 'file_get_contents', - ['test.txt'], - 'test.txt', - 'read', - ILockingProvider::LOCK_SHARED, - ILockingProvider::LOCK_SHARED, - null, - ], - [ - 'fopen', - ['test.txt', 'r'], - 'test.txt', - 'read', - ILockingProvider::LOCK_SHARED, - ILockingProvider::LOCK_SHARED, - null, - ], - [ - 'opendir', - ['dir'], - 'dir', - 'read', - ILockingProvider::LOCK_SHARED, - ILockingProvider::LOCK_SHARED, - null, - ], - - // ---- no lock, touch hook --- - ['touch', ['test.txt'], 'test.txt', 'touch', null, null, null], - - // ---- no hooks, no locks --- - ['is_dir', ['dir'], 'dir', null], - ['is_file', ['dir'], 'dir', null], - ['stat', ['dir'], 'dir', null], - ['filetype', ['dir'], 'dir', null], - ['filesize', ['dir'], 'dir', null], - ['isCreatable', ['dir'], 'dir', null], - ['isReadable', ['dir'], 'dir', null], - ['isUpdatable', ['dir'], 'dir', null], - ['isDeletable', ['dir'], 'dir', null], - ['isSharable', ['dir'], 'dir', null], - ['file_exists', ['dir'], 'dir', null], - ['filemtime', ['dir'], 'dir', null], - ]; - } - - /** - * Test whether locks are set before and after the operation - * - * @dataProvider basicOperationProviderForLocks - * - * @param string $operation operation name on the view - * @param array $operationArgs arguments for the operation - * @param string $lockedPath path of the locked item to check - * @param string $hookType hook type - * @param int $expectedLockBefore expected lock during pre hooks - * @param int $expectedLockduring expected lock during operation - * @param int $expectedLockAfter expected lock during post hooks - * @param int $expectedStrayLock expected lock after returning, should - * be null (unlock) for most operations - */ - public function testLockBasicOperation( - $operation, - $operationArgs, - $lockedPath, - $hookType, - $expectedLockBefore = ILockingProvider::LOCK_SHARED, - $expectedLockDuring = ILockingProvider::LOCK_SHARED, - $expectedLockAfter = ILockingProvider::LOCK_SHARED, - $expectedStrayLock = null - ) { - $view = new \OC\Files\View('/' . $this->user . '/files/'); - - $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary') - ->setMethods([$operation]) - ->getMock(); - - \OC\Files\Filesystem::mount($storage, array(), $this->user . '/'); - - // work directly on disk because mkdir might be mocked - $realPath = $storage->getSourcePath(''); - mkdir($realPath . '/files'); - mkdir($realPath . '/files/dir'); - file_put_contents($realPath . '/files/test.txt', 'blah'); - $storage->getScanner()->scan('files'); - - $storage->expects($this->once()) - ->method($operation) - ->will($this->returnCallback( - function () use ($view, $lockedPath, &$lockTypeDuring) { - $lockTypeDuring = $this->getFileLockType($view, $lockedPath); - - return true; - } - )); - - $this->assertNull($this->getFileLockType($view, $lockedPath), 'File not locked before operation'); - - $this->connectMockHooks($hookType, $view, $lockedPath, $lockTypePre, $lockTypePost); - - // do operation - call_user_func_array(array($view, $operation), $operationArgs); - - if ($hookType !== null) { - $this->assertEquals($expectedLockBefore, $lockTypePre, 'File locked properly during pre-hook'); - $this->assertEquals($expectedLockAfter, $lockTypePost, 'File locked properly during post-hook'); - $this->assertEquals($expectedLockDuring, $lockTypeDuring, 'File locked properly during operation'); - } else { - $this->assertNull($lockTypeDuring, 'File not locked during operation'); - } - - $this->assertEquals($expectedStrayLock, $this->getFileLockType($view, $lockedPath)); - } - - /** - * Test locks for file_put_content with stream. - * This code path uses $storage->fopen instead - */ - public function testLockFilePutContentWithStream() { - $view = new \OC\Files\View('/' . $this->user . '/files/'); - - $path = 'test_file_put_contents.txt'; - $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary') - ->setMethods(['fopen']) - ->getMock(); - - \OC\Files\Filesystem::mount($storage, array(), $this->user . '/'); - $storage->mkdir('files'); - - $storage->expects($this->once()) - ->method('fopen') - ->will($this->returnCallback( - function () use ($view, $path, &$lockTypeDuring) { - $lockTypeDuring = $this->getFileLockType($view, $path); - - return fopen('php://temp', 'r+'); - } - )); - - $this->connectMockHooks('write', $view, $path, $lockTypePre, $lockTypePost); - - $this->assertNull($this->getFileLockType($view, $path), 'File not locked before operation'); - - // do operation - $view->file_put_contents($path, fopen('php://temp', 'r+')); - - $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypePre, 'File locked properly during pre-hook'); - $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypePost, 'File locked properly during post-hook'); - $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeDuring, 'File locked properly during operation'); - - $this->assertNull($this->getFileLockType($view, $path)); - } - - /** - * Test locks for fopen with fclose at the end - */ - public function testLockFopen() { - $view = new \OC\Files\View('/' . $this->user . '/files/'); - - $path = 'test_file_put_contents.txt'; - $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary') - ->setMethods(['fopen']) - ->getMock(); - - \OC\Files\Filesystem::mount($storage, array(), $this->user . '/'); - $storage->mkdir('files'); - - $storage->expects($this->once()) - ->method('fopen') - ->will($this->returnCallback( - function () use ($view, $path, &$lockTypeDuring) { - $lockTypeDuring = $this->getFileLockType($view, $path); - - return fopen('php://temp', 'r+'); - } - )); - - $this->connectMockHooks('write', $view, $path, $lockTypePre, $lockTypePost); - - $this->assertNull($this->getFileLockType($view, $path), 'File not locked before operation'); - - // do operation - $res = $view->fopen($path, 'w'); - - $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypePre, 'File locked properly during pre-hook'); - $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeDuring, 'File locked properly during operation'); - $this->assertNull($lockTypePost, 'No post hook, no lock check possible'); - - $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeDuring, 'File still locked after fopen'); - - fclose($res); - - $this->assertNull($this->getFileLockType($view, $path), 'File unlocked after fclose'); - } - - /** - * Test locks for fopen with fclose at the end - * - * @dataProvider basicOperationProviderForLocks - * - * @param string $operation operation name on the view - * @param array $operationArgs arguments for the operation - * @param string $path path of the locked item to check - */ - public function testLockBasicOperationUnlocksAfterException( - $operation, - $operationArgs, - $path - ) { - $view = new \OC\Files\View('/' . $this->user . '/files/'); - - $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary') - ->setMethods([$operation]) - ->getMock(); - - \OC\Files\Filesystem::mount($storage, array(), $this->user . '/'); - - // work directly on disk because mkdir might be mocked - $realPath = $storage->getSourcePath(''); - mkdir($realPath . '/files'); - mkdir($realPath . '/files/dir'); - file_put_contents($realPath . '/files/test.txt', 'blah'); - $storage->getScanner()->scan('files'); - - $storage->expects($this->once()) - ->method($operation) - ->will($this->returnCallback( - function () { - throw new \Exception('Simulated exception'); - } - )); - - $thrown = false; - try { - call_user_func_array(array($view, $operation), $operationArgs); - } catch (\Exception $e) { - $thrown = true; - $this->assertEquals('Simulated exception', $e->getMessage()); - } - $this->assertTrue($thrown, 'Exception was rethrown'); - $this->assertNull($this->getFileLockType($view, $path), 'File got unlocked after exception'); - } - - /** - * Test locks for fopen with fclose at the end - * - * @dataProvider basicOperationProviderForLocks - * - * @param string $operation operation name on the view - * @param array $operationArgs arguments for the operation - * @param string $path path of the locked item to check - * @param string $hookType hook type - */ - public function testLockBasicOperationUnlocksAfterCancelledHook( - $operation, - $operationArgs, - $path, - $hookType - ) { - $view = new \OC\Files\View('/' . $this->user . '/files/'); - - $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary') - ->setMethods([$operation]) - ->getMock(); - - \OC\Files\Filesystem::mount($storage, array(), $this->user . '/'); - $storage->mkdir('files'); - - \OCP\Util::connectHook( - \OC\Files\Filesystem::CLASSNAME, - $hookType, - '\Test\HookHelper', - 'cancellingCallback' - ); - - call_user_func_array(array($view, $operation), $operationArgs); - - $this->assertNull($this->getFileLockType($view, $path), 'File got unlocked after exception'); - } - - public function lockFileRenameOrCopyDataProvider() { - return [ - ['rename', ILockingProvider::LOCK_EXCLUSIVE], - ['copy', ILockingProvider::LOCK_SHARED], - ]; - } - - /** - * Test locks for rename or copy operation - * - * @dataProvider lockFileRenameOrCopyDataProvider - * - * @param string $operation operation to be done on the view - * @param int $expectedLockTypeSourceDuring expected lock type on source file during - * the operation - */ - public function testLockFileRename($operation, $expectedLockTypeSourceDuring) { - $view = new \OC\Files\View('/' . $this->user . '/files/'); - - $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary') - ->setMethods([$operation, 'filemtime']) - ->getMock(); - - $storage->expects($this->any()) - ->method('filemtime') - ->will($this->returnValue(123456789)); - - $sourcePath = 'original.txt'; - $targetPath = 'target.txt'; - - \OC\Files\Filesystem::mount($storage, array(), $this->user . '/'); - $storage->mkdir('files'); - $view->file_put_contents($sourcePath, 'meh'); - - $storage->expects($this->once()) - ->method($operation) - ->will($this->returnCallback( - function () use ($view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring) { - $lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath); - $lockTypeTargetDuring = $this->getFileLockType($view, $targetPath); - - return true; - } - )); - - $this->connectMockHooks($operation, $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost); - $this->connectMockHooks($operation, $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost); - - $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation'); - $this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked before operation'); - - $view->$operation($sourcePath, $targetPath); - - $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePre, 'Source file locked properly during pre-hook'); - $this->assertEquals($expectedLockTypeSourceDuring, $lockTypeSourceDuring, 'Source file locked properly during operation'); - $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePost, 'Source file locked properly during post-hook'); - - $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPre, 'Target file locked properly during pre-hook'); - $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeTargetDuring, 'Target file locked properly during operation'); - $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPost, 'Target file locked properly during post-hook'); - - $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation'); - $this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked after operation'); - } - - /** - * simulate a failed copy operation. - * We expect that we catch the exception, free the lock and re-throw it. - * - * @expectedException \Exception - */ - public function testLockFileCopyException() { - $view = new \OC\Files\View('/' . $this->user . '/files/'); - - $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary') - ->setMethods(['copy']) - ->getMock(); - - $sourcePath = 'original.txt'; - $targetPath = 'target.txt'; - - \OC\Files\Filesystem::mount($storage, array(), $this->user . '/'); - $storage->mkdir('files'); - $view->file_put_contents($sourcePath, 'meh'); - - $storage->expects($this->once()) - ->method('copy') - ->will($this->returnCallback( - function () { - throw new \Exception(); - } - )); - - $this->connectMockHooks('copy', $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost); - $this->connectMockHooks('copy', $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost); - - $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation'); - $this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked before operation'); - - try { - $view->copy($sourcePath, $targetPath); - } catch (\Exception $e) { - $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation'); - $this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked after operation'); - throw $e; - } - } - - /** - * Test rename operation: unlock first path when second path was locked - */ - public function testLockFileRenameUnlockOnException() { - $this->loginAsUser('test'); - - $view = new \OC\Files\View('/' . $this->user . '/files/'); - - $sourcePath = 'original.txt'; - $targetPath = 'target.txt'; - $view->file_put_contents($sourcePath, 'meh'); - - // simulate that the target path is already locked - $view->lockFile($targetPath, ILockingProvider::LOCK_EXCLUSIVE); - - $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation'); - $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $this->getFileLockType($view, $targetPath), 'Target file is locked before operation'); - - $thrown = false; - try { - $view->rename($sourcePath, $targetPath); - } catch (\OCP\Lock\LockedException $e) { - $thrown = true; - } - - $this->assertTrue($thrown, 'LockedException thrown'); - - $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation'); - $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $this->getFileLockType($view, $targetPath), 'Target file still locked after operation'); - - $view->unlockFile($targetPath, ILockingProvider::LOCK_EXCLUSIVE); - } - - /** - * Test rename operation: unlock first path when second path was locked - */ - public function testGetOwner() { - $this->loginAsUser('test'); - - $view = new \OC\Files\View('/test/files/'); - - $path = 'foo.txt'; - $view->file_put_contents($path, 'meh'); - - $this->assertEquals('test', $view->getFileInfo($path)->getOwner()->getUID()); - - $folderInfo = $view->getDirectoryContent(''); - $folderInfo = array_values(array_filter($folderInfo, function (FileInfo $info) { - return $info->getName() === 'foo.txt'; - })); - - $this->assertEquals('test', $folderInfo[0]->getOwner()->getUID()); - - $subStorage = new Temporary(); - \OC\Files\Filesystem::mount($subStorage, [], '/test/files/asd'); - - $folderInfo = $view->getDirectoryContent(''); - $folderInfo = array_values(array_filter($folderInfo, function (FileInfo $info) { - return $info->getName() === 'asd'; - })); - - $this->assertEquals('test', $folderInfo[0]->getOwner()->getUID()); - } - - public function lockFileRenameOrCopyCrossStorageDataProvider() { - return [ - ['rename', 'moveFromStorage', ILockingProvider::LOCK_EXCLUSIVE], - ['copy', 'copyFromStorage', ILockingProvider::LOCK_SHARED], - ]; - } - - /** - * Test locks for rename or copy operation cross-storage - * - * @dataProvider lockFileRenameOrCopyCrossStorageDataProvider - * - * @param string $viewOperation operation to be done on the view - * @param string $storageOperation operation to be mocked on the storage - * @param int $expectedLockTypeSourceDuring expected lock type on source file during - * the operation - */ - public function testLockFileRenameCrossStorage($viewOperation, $storageOperation, $expectedLockTypeSourceDuring) { - $view = new \OC\Files\View('/' . $this->user . '/files/'); - - $storage = $this->getMockBuilder('\OC\Files\Storage\Temporary') - ->setMethods([$storageOperation]) - ->getMock(); - $storage2 = $this->getMockBuilder('\OC\Files\Storage\Temporary') - ->setMethods([$storageOperation, 'filemtime']) - ->getMock(); - - $storage2->expects($this->any()) - ->method('filemtime') - ->will($this->returnValue(123456789)); - - $sourcePath = 'original.txt'; - $targetPath = 'substorage/target.txt'; - - \OC\Files\Filesystem::mount($storage, array(), $this->user . '/'); - \OC\Files\Filesystem::mount($storage2, array(), $this->user . '/files/substorage'); - $storage->mkdir('files'); - $view->file_put_contents($sourcePath, 'meh'); - - $storage->expects($this->never()) - ->method($storageOperation); - $storage2->expects($this->once()) - ->method($storageOperation) - ->will($this->returnCallback( - function () use ($view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring) { - $lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath); - $lockTypeTargetDuring = $this->getFileLockType($view, $targetPath); - - return true; - } - )); - - $this->connectMockHooks($viewOperation, $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost); - $this->connectMockHooks($viewOperation, $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost); - - $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked before operation'); - $this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked before operation'); - - $view->$viewOperation($sourcePath, $targetPath); - - $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePre, 'Source file locked properly during pre-hook'); - $this->assertEquals($expectedLockTypeSourceDuring, $lockTypeSourceDuring, 'Source file locked properly during operation'); - $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePost, 'Source file locked properly during post-hook'); - - $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPre, 'Target file locked properly during pre-hook'); - $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeTargetDuring, 'Target file locked properly during operation'); - $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPost, 'Target file locked properly during post-hook'); - - $this->assertNull($this->getFileLockType($view, $sourcePath), 'Source file not locked after operation'); - $this->assertNull($this->getFileLockType($view, $targetPath), 'Target file not locked after operation'); - } - - /** - * Test locks when moving a mount point - */ - public function testLockMoveMountPoint() { - $this->loginAsUser('test'); - - list($mount) = $this->createTestMovableMountPoints([ - $this->user . '/files/substorage', - ]); - - $view = new \OC\Files\View('/' . $this->user . '/files/'); - $view->mkdir('subdir'); - - $sourcePath = 'substorage'; - $targetPath = 'subdir/substorage_moved'; - - $mount->expects($this->once()) - ->method('moveMount') - ->will($this->returnCallback( - function ($target) use ($mount, $view, $sourcePath, $targetPath, &$lockTypeSourceDuring, &$lockTypeTargetDuring, &$lockTypeSharedRootDuring) { - $lockTypeSourceDuring = $this->getFileLockType($view, $sourcePath, true); - $lockTypeTargetDuring = $this->getFileLockType($view, $targetPath, true); - - $lockTypeSharedRootDuring = $this->getFileLockType($view, $sourcePath, false); - - $mount->setMountPoint($target); - - return true; - } - )); - - $this->connectMockHooks('rename', $view, $sourcePath, $lockTypeSourcePre, $lockTypeSourcePost, true); - $this->connectMockHooks('rename', $view, $targetPath, $lockTypeTargetPre, $lockTypeTargetPost, true); - // in pre-hook, mount point is still on $sourcePath - $this->connectMockHooks('rename', $view, $sourcePath, $lockTypeSharedRootPre, $dummy, false); - // in post-hook, mount point is now on $targetPath - $this->connectMockHooks('rename', $view, $targetPath, $dummy, $lockTypeSharedRootPost, false); - - $this->assertNull($this->getFileLockType($view, $sourcePath, false), 'Shared storage root not locked before operation'); - $this->assertNull($this->getFileLockType($view, $sourcePath, true), 'Source path not locked before operation'); - $this->assertNull($this->getFileLockType($view, $targetPath, true), 'Target path not locked before operation'); - - $view->rename($sourcePath, $targetPath); - - $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePre, 'Source path locked properly during pre-hook'); - $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeSourceDuring, 'Source path locked properly during operation'); - $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeSourcePost, 'Source path locked properly during post-hook'); - - $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPre, 'Target path locked properly during pre-hook'); - $this->assertEquals(ILockingProvider::LOCK_EXCLUSIVE, $lockTypeTargetDuring, 'Target path locked properly during operation'); - $this->assertEquals(ILockingProvider::LOCK_SHARED, $lockTypeTargetPost, 'Target path locked properly during post-hook'); - - $this->assertNull($lockTypeSharedRootPre, 'Shared storage root not locked during pre-hook'); - $this->assertNull($lockTypeSharedRootDuring, 'Shared storage root not locked during move'); - $this->assertNull($lockTypeSharedRootPost, 'Shared storage root not locked during post-hook'); - - $this->assertNull($this->getFileLockType($view, $sourcePath, false), 'Shared storage root not locked after operation'); - $this->assertNull($this->getFileLockType($view, $sourcePath, true), 'Source path not locked after operation'); - $this->assertNull($this->getFileLockType($view, $targetPath, true), 'Target path not locked after operation'); - } - - /** - * Connect hook callbacks for hook type - * - * @param string $hookType hook type or null for none - * @param \OC\Files\View $view view to check the lock on - * @param string $path path for which to check the lock - * @param int $lockTypePre variable to receive lock type that was active in the pre-hook - * @param int $lockTypePost variable to receive lock type that was active in the post-hook - * @param bool $onMountPoint true to check the mount point instead of the - * mounted storage - */ - private function connectMockHooks($hookType, $view, $path, &$lockTypePre, &$lockTypePost, $onMountPoint = false) { - if ($hookType === null) { - return; - } - - $eventHandler = $this->getMockBuilder('\stdclass') - ->setMethods(['preCallback', 'postCallback']) - ->getMock(); - - $eventHandler->expects($this->any()) - ->method('preCallback') - ->will($this->returnCallback( - function () use ($view, $path, $onMountPoint, &$lockTypePre) { - $lockTypePre = $this->getFileLockType($view, $path, $onMountPoint); - } - )); - $eventHandler->expects($this->any()) - ->method('postCallback') - ->will($this->returnCallback( - function () use ($view, $path, $onMountPoint, &$lockTypePost) { - $lockTypePost = $this->getFileLockType($view, $path, $onMountPoint); - } - )); - - if ($hookType !== null) { - \OCP\Util::connectHook( - \OC\Files\Filesystem::CLASSNAME, - $hookType, - $eventHandler, - 'preCallback' - ); - \OCP\Util::connectHook( - \OC\Files\Filesystem::CLASSNAME, - 'post_' . $hookType, - $eventHandler, - 'postCallback' - ); - } - } - - /** - * Returns the file lock type - * - * @param \OC\Files\View $view view - * @param string $path path - * @param bool $onMountPoint true to check the mount point instead of the - * mounted storage - * - * @return int lock type or null if file was not locked - */ - private function getFileLockType(\OC\Files\View $view, $path, $onMountPoint = false) { - if ($this->isFileLocked($view, $path, ILockingProvider::LOCK_EXCLUSIVE, $onMountPoint)) { - return ILockingProvider::LOCK_EXCLUSIVE; - } else if ($this->isFileLocked($view, $path, ILockingProvider::LOCK_SHARED, $onMountPoint)) { - return ILockingProvider::LOCK_SHARED; - } - return null; - } - - - public function testRemoveMoveableMountPoint() { - $mountPoint = '/' . $this->user . '/files/mount/'; - - // Mock the mount point - $mount = $this->getMockBuilder('\Test\TestMoveableMountPoint') - ->disableOriginalConstructor() - ->getMock(); - $mount->expects($this->once()) - ->method('getMountPoint') - ->willReturn($mountPoint); - $mount->expects($this->once()) - ->method('removeMount') - ->willReturn('foo'); - $mount->expects($this->any()) - ->method('getInternalPath') - ->willReturn(''); - - // Register mount - \OC\Files\Filesystem::getMountManager()->addMount($mount); - - // Listen for events - $eventHandler = $this->getMockBuilder('\stdclass') - ->setMethods(['umount', 'post_umount']) - ->getMock(); - $eventHandler->expects($this->once()) - ->method('umount') - ->with([\OC\Files\Filesystem::signal_param_path => '/mount']); - $eventHandler->expects($this->once()) - ->method('post_umount') - ->with([\OC\Files\Filesystem::signal_param_path => '/mount']); - \OCP\Util::connectHook( - \OC\Files\Filesystem::CLASSNAME, - 'umount', - $eventHandler, - 'umount' - ); - \OCP\Util::connectHook( - \OC\Files\Filesystem::CLASSNAME, - 'post_umount', - $eventHandler, - 'post_umount' - ); - - //Delete the mountpoint - $view = new \OC\Files\View('/' . $this->user . '/files'); - $this->assertEquals('foo', $view->rmdir('mount')); - } - - public function mimeFilterProvider() { - return [ - [null, ['test1.txt', 'test2.txt', 'test3.md', 'test4.png']], - ['text/plain', ['test1.txt', 'test2.txt']], - ['text/markdown', ['test3.md']], - ['text', ['test1.txt', 'test2.txt', 'test3.md']], - ]; - } - - /** - * @param string $filter - * @param string[] $expected - * @dataProvider mimeFilterProvider - */ - public function testGetDirectoryContentMimeFilter($filter, $expected) { - $storage1 = new Temporary(); - $root = $this->getUniqueID('/'); - \OC\Files\Filesystem::mount($storage1, array(), $root . '/'); - $view = new \OC\Files\View($root); - - $view->file_put_contents('test1.txt', 'asd'); - $view->file_put_contents('test2.txt', 'asd'); - $view->file_put_contents('test3.md', 'asd'); - $view->file_put_contents('test4.png', ''); - - $content = $view->getDirectoryContent('', $filter); - - $files = array_map(function(FileInfo $info) { - return $info->getName(); - }, $content); - sort($files); - - $this->assertEquals($expected, $files); - } - - public function testFilePutContentsClearsChecksum() { - $storage = new Temporary(array()); - $scanner = $storage->getScanner(); - $storage->file_put_contents('foo.txt', 'bar'); - \OC\Files\Filesystem::mount($storage, array(), '/test/'); - $scanner->scan(''); - - $view = new \OC\Files\View('/test/foo.txt'); - $view->putFileInfo('.', ['checksum' => '42']); - - $this->assertEquals('bar', $view->file_get_contents('')); - $fh = tmpfile(); - fwrite($fh, 'fooo'); - rewind($fh); - $view->file_put_contents('', $fh); - $this->assertEquals('fooo', $view->file_get_contents('')); - $data = $view->getFileInfo('.'); - $this->assertEquals('', $data->getChecksum()); - } -} |