* This file is licensed under the Affero General Public License version 3 or * later. * See the COPYING-README file. */ namespace Test\Files\Node; use OC\Files\Cache\Cache; use OC\Files\Cache\CacheEntry; use OC\Files\Config\CachedMountInfo; use OC\Files\FileInfo; use OC\Files\Mount\Manager; use OC\Files\Mount\MountPoint; use OC\Files\Node\Folder; use OC\Files\Node\Node; use OC\Files\Node\Root; use OC\Files\Search\SearchComparison; use OC\Files\Search\SearchOrder; use OC\Files\Search\SearchQuery; use OC\Files\Storage\Temporary; use OC\Files\Storage\Wrapper\Jail; use OC\Files\View; use OCP\Files\Cache\ICacheEntry; use OCP\Files\Mount\IMountPoint; use OCP\Files\NotFoundException; use OCP\Files\Search\ISearchComparison; use OCP\Files\Search\ISearchOrder; use OCP\Files\Storage; /** * Class FolderTest * * @group DB * * @package Test\Files\Node */ class FolderTest extends NodeTest { protected function createTestNode($root, $view, $path) { return new Folder($root, $view, $path); } protected function getNodeClass() { return '\OC\Files\Node\Folder'; } protected function getNonExistingNodeClass() { return '\OC\Files\Node\NonExistingFolder'; } protected function getViewDeleteMethod() { return 'rmdir'; } public function testGetDirectoryContent() { $manager = $this->createMock(Manager::class); /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $root->expects($this->any()) ->method('getUser') ->willReturn($this->user); $view->expects($this->any()) ->method('getDirectoryContent') ->with('/bar/foo') ->willReturn([ new FileInfo('/bar/foo/asd', null, 'foo/asd', ['fileid' => 2, 'path' => '/bar/foo/asd', 'name' => 'asd', 'size' => 100, 'mtime' => 50, 'mimetype' => 'text/plain'], null), new FileInfo('/bar/foo/qwerty', null, 'foo/qwerty', ['fileid' => 3, 'path' => '/bar/foo/qwerty', 'name' => 'qwerty', 'size' => 200, 'mtime' => 55, 'mimetype' => 'httpd/unix-directory'], null), ]); $node = new Folder($root, $view, '/bar/foo'); $children = $node->getDirectoryListing(); $this->assertEquals(2, count($children)); $this->assertInstanceOf('\OC\Files\Node\File', $children[0]); $this->assertInstanceOf('\OC\Files\Node\Folder', $children[1]); $this->assertEquals('asd', $children[0]->getName()); $this->assertEquals('qwerty', $children[1]->getName()); $this->assertEquals(2, $children[0]->getId()); $this->assertEquals(3, $children[1]->getId()); } public function testGet() { $manager = $this->createMock(Manager::class); /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $root->expects($this->any()) ->method('getUser') ->willReturn($this->user); $root->method('get') ->with('/bar/foo/asd'); $node = new Folder($root, $view, '/bar/foo'); $node->get('asd'); } public function testNodeExists() { $manager = $this->createMock(Manager::class); /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $root->expects($this->any()) ->method('getUser') ->willReturn($this->user); $child = new Folder($root, $view, '/bar/foo/asd'); $root->method('get') ->with('/bar/foo/asd') ->willReturn($child); $node = new Folder($root, $view, '/bar/foo'); $this->assertTrue($node->nodeExists('asd')); } public function testNodeExistsNotExists() { $manager = $this->createMock(Manager::class); /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $root->expects($this->any()) ->method('getUser') ->willReturn($this->user); $root->method('get') ->with('/bar/foo/asd') ->will($this->throwException(new NotFoundException())); $node = new Folder($root, $view, '/bar/foo'); $this->assertFalse($node->nodeExists('asd')); } public function testNewFolder() { $manager = $this->createMock(Manager::class); /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $root->expects($this->any()) ->method('getUser') ->willReturn($this->user); $view->method('getFileInfo') ->with('/bar/foo') ->willReturn($this->getFileInfo(['permissions' => \OCP\Constants::PERMISSION_ALL])); $view->method('mkdir') ->with('/bar/foo/asd') ->willReturn(true); $node = new Folder($root, $view, '/bar/foo'); $child = new Folder($root, $view, '/bar/foo/asd'); $result = $node->newFolder('asd'); $this->assertEquals($child, $result); } public function testNewFolderNotPermitted() { $this->expectException(\OCP\Files\NotPermittedException::class); $manager = $this->createMock(Manager::class); /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $root->method('getUser') ->willReturn($this->user); $view->method('getFileInfo') ->with('/bar/foo') ->willReturn($this->getFileInfo(['permissions' => \OCP\Constants::PERMISSION_READ])); $node = new Folder($root, $view, '/bar/foo'); $node->newFolder('asd'); } public function testNewFile() { $manager = $this->createMock(Manager::class); /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $root->expects($this->any()) ->method('getUser') ->willReturn($this->user); $view->method('getFileInfo') ->with('/bar/foo') ->willReturn($this->getFileInfo(['permissions' => \OCP\Constants::PERMISSION_ALL])); $view->method('touch') ->with('/bar/foo/asd') ->willReturn(true); $node = new Folder($root, $view, '/bar/foo'); $child = new \OC\Files\Node\File($root, $view, '/bar/foo/asd'); $result = $node->newFile('asd'); $this->assertEquals($child, $result); } public function testNewFileNotPermitted() { $this->expectException(\OCP\Files\NotPermittedException::class); $manager = $this->createMock(Manager::class); /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $root->method('getUser') ->willReturn($this->user); $view->method('getFileInfo') ->with('/bar/foo') ->willReturn($this->getFileInfo(['permissions' => \OCP\Constants::PERMISSION_READ])); $node = new Folder($root, $view, '/bar/foo'); $node->newFile('asd'); } public function testGetFreeSpace() { $manager = $this->createMock(Manager::class); /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $root->method('getUser') ->willReturn($this->user); $view->method('free_space') ->with('/bar/foo') ->willReturn(100); $node = new Folder($root, $view, '/bar/foo'); $this->assertEquals(100, $node->getFreeSpace()); } public function testSearch() { $manager = $this->createMock(Manager::class); /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $root->method('getUser') ->willReturn($this->user); /** @var Storage\IStorage $storage */ $storage = $this->createMock(Storage\IStorage::class); $storage->method('getId')->willReturn('test::1'); $cache = new Cache($storage); $storage->method('getCache') ->willReturn($cache); $mount = $this->createMock(IMountPoint::class); $mount->method('getStorage') ->willReturn($storage); $mount->method('getInternalPath') ->willReturn('foo'); $cache->insert('foo', ['size' => 200, 'mtime' => 55, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]); $cache->insert('foo/qwerty', ['size' => 200, 'mtime' => 55, 'mimetype' => 'text/plain']); $root->method('getMountsIn') ->with('/bar/foo') ->willReturn([]); $root->method('getMount') ->with('/bar/foo') ->willReturn($mount); $node = new Folder($root, $view, '/bar/foo'); $result = $node->search('qw'); $cache->clear(); $this->assertEquals(1, count($result)); $this->assertEquals('/bar/foo/qwerty', $result[0]->getPath()); } public function testSearchInRoot() { $manager = $this->createMock(Manager::class); /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setMethods(['getUser', 'getMountsIn', 'getMount']) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $root->expects($this->any()) ->method('getUser') ->willReturn($this->user); /** @var \PHPUnit\Framework\MockObject\MockObject|Storage $storage */ $storage = $this->createMock(Storage::class); $storage->method('getId')->willReturn('test::2'); $cache = new Cache($storage); $mount = $this->createMock(IMountPoint::class); $mount->method('getStorage') ->willReturn($storage); $mount->method('getInternalPath') ->willReturn('files'); $storage->method('getCache') ->willReturn($cache); $cache->insert('files', ['size' => 200, 'mtime' => 55, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]); $cache->insert('files/foo', ['size' => 200, 'mtime' => 55, 'mimetype' => 'text/plain']); $root->method('getMountsIn') ->with('') ->willReturn([]); $root->method('getMount') ->with('') ->willReturn($mount); $result = $root->search('foo'); $cache->clear(); $this->assertEquals(1, count($result)); $this->assertEquals('/foo', $result[0]->getPath()); } public function testSearchInStorageRoot() { $manager = $this->createMock(Manager::class); /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $root->method('getUser') ->willReturn($this->user); $storage = $this->createMock(Storage::class); $storage->method('getId')->willReturn('test::1'); $cache = new Cache($storage); $mount = $this->createMock(IMountPoint::class); $mount->method('getStorage') ->willReturn($storage); $mount->method('getInternalPath') ->willReturn(''); $storage->method('getCache') ->willReturn($cache); $cache->insert('foo', ['size' => 200, 'mtime' => 55, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]); $cache->insert('foo/qwerty', ['size' => 200, 'mtime' => 55, 'mimetype' => 'text/plain']); $root->method('getMountsIn') ->with('/bar') ->willReturn([]); $root->method('getMount') ->with('/bar') ->willReturn($mount); $node = new Folder($root, $view, '/bar'); $result = $node->search('qw'); $cache->clear(); $this->assertEquals(1, count($result)); $this->assertEquals('/bar/foo/qwerty', $result[0]->getPath()); } public function testSearchSubStorages() { $manager = $this->createMock(Manager::class); /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $root->expects($this->any()) ->method('getUser') ->willReturn($this->user); $storage = $this->createMock(Storage::class); $storage->method('getId')->willReturn('test::1'); $cache = new Cache($storage); $subStorage = $this->createMock(Storage::class); $subStorage->method('getId')->willReturn('test::2'); $subCache = new Cache($subStorage); $subMount = $this->getMockBuilder(MountPoint::class)->setConstructorArgs([Temporary::class, ''])->getMock(); $mount = $this->createMock(IMountPoint::class); $mount->method('getStorage') ->willReturn($storage); $mount->method('getInternalPath') ->willReturn('foo'); $subMount->method('getStorage') ->willReturn($subStorage); $subMount->method('getMountPoint') ->willReturn('/bar/foo/bar/'); $storage->method('getCache') ->willReturn($cache); $subStorage->method('getCache') ->willReturn($subCache); $cache->insert('foo', ['size' => 200, 'mtime' => 55, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]); $cache->insert('foo/qwerty', ['size' => 200, 'mtime' => 55, 'mimetype' => 'text/plain']); $subCache->insert('asd', ['size' => 200, 'mtime' => 55, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]); $subCache->insert('asd/qwerty', ['size' => 200, 'mtime' => 55, 'mimetype' => 'text/plain']); $root->method('getMountsIn') ->with('/bar/foo') ->willReturn([$subMount]); $root->method('getMount') ->with('/bar/foo') ->willReturn($mount); $node = new Folder($root, $view, '/bar/foo'); $result = $node->search('qw'); $cache->clear(); $subCache->clear(); $this->assertEquals(2, count($result)); } public function testIsSubNode() { $file = new Node(null, null, '/foo/bar'); $folder = new Folder(null, null, '/foo'); $this->assertTrue($folder->isSubNode($file)); $this->assertFalse($folder->isSubNode($folder)); $file = new Node(null, null, '/foobar'); $this->assertFalse($folder->isSubNode($file)); } public function testGetById() { $manager = $this->createMock(Manager::class); /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setMethods(['getMountsIn', 'getMount']) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $storage = $this->createMock(\OC\Files\Storage\Storage::class); $mount = new MountPoint($storage, '/bar'); $storage->method('getId')->willReturn(''); $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([$storage])->getMock(); $fileInfo = new CacheEntry(['path' => 'foo/qwerty', 'mimetype' => 'text/plain'], null); $storage->method('getCache') ->willReturn($cache); $this->userMountCache->expects($this->any()) ->method('getMountsForFileId') ->with(1) ->willReturn([new CachedMountInfo( $this->user, 1, 0, '/bar/', 1, '' )]); $cache->method('get') ->with(1) ->willReturn($fileInfo); $root->method('getMountsIn') ->with('/bar/foo') ->willReturn([]); $root->method('getMount') ->with('/bar/foo') ->willReturn($mount); $node = new Folder($root, $view, '/bar/foo'); $result = $node->getById(1); $this->assertEquals(1, count($result)); $this->assertEquals('/bar/foo/qwerty', $result[0]->getPath()); } public function testGetByIdMountRoot() { $manager = $this->createMock(Manager::class); /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setMethods(['getMountsIn', 'getMount']) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $storage = $this->createMock(\OC\Files\Storage\Storage::class); $mount = new MountPoint($storage, '/bar'); $storage->method('getId')->willReturn(''); $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([$storage])->getMock(); $fileInfo = new CacheEntry(['path' => '', 'mimetype' => 'text/plain'], null); $storage->method('getCache') ->willReturn($cache); $this->userMountCache->expects($this->any()) ->method('getMountsForFileId') ->with(1) ->willReturn([new CachedMountInfo( $this->user, 1, 0, '/bar/', 1, '' )]); $cache->method('get') ->with(1) ->willReturn($fileInfo); $root->method('getMount') ->with('/bar') ->willReturn($mount); $node = new Folder($root, $view, '/bar'); $result = $node->getById(1); $this->assertEquals(1, count($result)); $this->assertEquals('/bar', $result[0]->getPath()); } public function testGetByIdOutsideFolder() { $manager = $this->createMock(Manager::class); /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setMethods(['getMountsIn', 'getMount']) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $storage = $this->createMock(\OC\Files\Storage\Storage::class); $mount = new MountPoint($storage, '/bar'); $storage->method('getId')->willReturn(''); $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([$storage])->getMock(); $fileInfo = new CacheEntry(['path' => 'foobar', 'mimetype' => 'text/plain'], null); $storage->method('getCache') ->willReturn($cache); $this->userMountCache->expects($this->any()) ->method('getMountsForFileId') ->with(1) ->willReturn([new CachedMountInfo( $this->user, 1, 0, '/bar/', 1, '' )]); $cache->method('get') ->with(1) ->willReturn($fileInfo); $root->method('getMountsIn') ->with('/bar/foo') ->willReturn([]); $root->method('getMount') ->with('/bar/foo') ->willReturn($mount); $node = new Folder($root, $view, '/bar/foo'); $result = $node->getById(1); $this->assertEquals(0, count($result)); } public function testGetByIdMultipleStorages() { $manager = $this->createMock(Manager::class); /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setMethods(['getMountsIn', 'getMount']) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $storage = $this->createMock(\OC\Files\Storage\Storage::class); $mount1 = new MountPoint($storage, '/bar'); $mount2 = new MountPoint($storage, '/bar/foo/asd'); $storage->method('getId')->willReturn(''); $cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([$storage])->getMock(); $fileInfo = new CacheEntry(['path' => 'foo/qwerty', 'mimetype' => 'text/plain'], null); $storage->method('getCache') ->willReturn($cache); $this->userMountCache->method('getMountsForFileId') ->with(1) ->willReturn([ new CachedMountInfo( $this->user, 1, 0, '/bar/', 1, '' ), ]); $storage->method('getCache') ->willReturn($cache); $cache->method('get') ->with(1) ->willReturn($fileInfo); $root->method('getMountsIn') ->with('/bar/foo') ->willReturn([$mount2]); $root->method('getMount') ->with('/bar/foo') ->willReturn($mount1); $node = new Folder($root, $view, '/bar/foo'); $result = $node->getById(1); $this->assertEquals(2, count($result)); $this->assertEquals('/bar/foo/qwerty', $result[0]->getPath()); $this->assertEquals('/bar/foo/asd/foo/qwerty', $result[1]->getPath()); } public function uniqueNameProvider() { return [ // input, existing, expected ['foo', [], 'foo'], ['foo', ['foo'], 'foo (2)'], ['foo', ['foo', 'foo (2)'], 'foo (3)'], ]; } /** * @dataProvider uniqueNameProvider */ public function testGetUniqueName($name, $existingFiles, $expected) { $manager = $this->createMock(Manager::class); $folderPath = '/bar/foo'; /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setMethods(['getUser', 'getMountsIn', 'getMount']) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $view->expects($this->any()) ->method('file_exists') ->willReturnCallback(function ($path) use ($existingFiles, $folderPath) { foreach ($existingFiles as $existing) { if ($folderPath . '/' . $existing === $path) { return true; } } return false; }); $node = new Folder($root, $view, $folderPath); $this->assertEquals($expected, $node->getNonExistingName($name)); } public function testRecent() { $manager = $this->createMock(Manager::class); $folderPath = '/bar/foo'; /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); /** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\Node\Root $root */ $root = $this->getMockBuilder(Root::class) ->setMethods(['getUser', 'getMountsIn', 'getMount']) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); /** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\FileInfo $folderInfo */ $folderInfo = $this->getMockBuilder(FileInfo::class) ->disableOriginalConstructor()->getMock(); $baseTime = 1000; $storage = new Temporary(); $mount = new MountPoint($storage, ''); $folderInfo->expects($this->any()) ->method('getMountPoint') ->willReturn($mount); $root->method('getMount') ->willReturn($mount); $root->method('getMountsIn') ->willReturn([]); $cache = $storage->getCache(); $id1 = $cache->put('bar/foo/inside.txt', [ 'storage_mtime' => $baseTime, 'mtime' => $baseTime, 'mimetype' => 'text/plain', 'size' => 3, 'permissions' => \OCP\Constants::PERMISSION_ALL, ]); $id2 = $cache->put('bar/foo/old.txt', [ 'storage_mtime' => $baseTime - 100, 'mtime' => $baseTime - 100, 'mimetype' => 'text/plain', 'size' => 3, 'permissions' => \OCP\Constants::PERMISSION_READ, ]); $cache->put('bar/asd/outside.txt', [ 'storage_mtime' => $baseTime, 'mtime' => $baseTime, 'mimetype' => 'text/plain', 'size' => 3, ]); $id3 = $cache->put('bar/foo/older.txt', [ 'storage_mtime' => $baseTime - 600, 'mtime' => $baseTime - 600, 'mimetype' => 'text/plain', 'size' => 3, 'permissions' => \OCP\Constants::PERMISSION_ALL, ]); $node = new Folder($root, $view, $folderPath, $folderInfo); $nodes = $node->getRecent(5); $ids = array_map(function (Node $node) { return (int)$node->getId(); }, $nodes); $this->assertEquals([$id1, $id2, $id3], $ids); } public function testRecentFolder() { $manager = $this->createMock(Manager::class); $folderPath = '/bar/foo'; /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); /** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\Node\Root $root */ $root = $this->getMockBuilder(Root::class) ->setMethods(['getUser', 'getMountsIn', 'getMount']) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); /** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\FileInfo $folderInfo */ $folderInfo = $this->getMockBuilder(FileInfo::class) ->disableOriginalConstructor()->getMock(); $baseTime = 1000; $storage = new Temporary(); $mount = new MountPoint($storage, ''); $folderInfo->expects($this->any()) ->method('getMountPoint') ->willReturn($mount); $root->method('getMount') ->willReturn($mount); $root->method('getMountsIn') ->willReturn([]); $cache = $storage->getCache(); $id1 = $cache->put('bar/foo/folder', [ 'storage_mtime' => $baseTime, 'mtime' => $baseTime, 'mimetype' => \OCP\Files\FileInfo::MIMETYPE_FOLDER, 'size' => 3, 'permissions' => 0, ]); $id2 = $cache->put('bar/foo/folder/bar.txt', [ 'storage_mtime' => $baseTime, 'mtime' => $baseTime, 'mimetype' => 'text/plain', 'size' => 3, 'parent' => $id1, 'permissions' => \OCP\Constants::PERMISSION_ALL, ]); $id3 = $cache->put('bar/foo/folder/asd.txt', [ 'storage_mtime' => $baseTime - 100, 'mtime' => $baseTime - 100, 'mimetype' => 'text/plain', 'size' => 3, 'parent' => $id1, 'permissions' => \OCP\Constants::PERMISSION_ALL, ]); $node = new Folder($root, $view, $folderPath, $folderInfo); $nodes = $node->getRecent(5); $ids = array_map(function (Node $node) { return (int)$node->getId(); }, $nodes); $this->assertEquals([$id2, $id3], $ids); $this->assertEquals($baseTime, $nodes[0]->getMTime()); $this->assertEquals($baseTime - 100, $nodes[1]->getMTime()); } public function testRecentJail() { $manager = $this->createMock(Manager::class); $folderPath = '/bar/foo'; /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); /** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\Node\Root $root */ $root = $this->getMockBuilder(Root::class) ->setMethods(['getUser', 'getMountsIn', 'getMount']) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); /** @var \PHPUnit\Framework\MockObject\MockObject|\OC\Files\FileInfo $folderInfo */ $folderInfo = $this->getMockBuilder(FileInfo::class) ->disableOriginalConstructor()->getMock(); $baseTime = 1000; $storage = new Temporary(); $jail = new Jail([ 'storage' => $storage, 'root' => 'folder', ]); $mount = new MountPoint($jail, '/bar/foo'); $folderInfo->expects($this->any()) ->method('getMountPoint') ->willReturn($mount); $root->method('getMount') ->willReturn($mount); $root->method('getMountsIn') ->willReturn([]); $cache = $storage->getCache(); $id1 = $cache->put('folder/inside.txt', [ 'storage_mtime' => $baseTime, 'mtime' => $baseTime, 'mimetype' => 'text/plain', 'size' => 3, 'permissions' => \OCP\Constants::PERMISSION_ALL, ]); $cache->put('outside.txt', [ 'storage_mtime' => $baseTime - 100, 'mtime' => $baseTime - 100, 'mimetype' => 'text/plain', 'size' => 3, ]); $node = new Folder($root, $view, $folderPath, $folderInfo); $nodes = $node->getRecent(5); $ids = array_map(function (Node $node) { return (int)$node->getId(); }, $nodes); $this->assertEquals([$id1], $ids); } public function offsetLimitProvider() { return [ [0, 10, ['/bar/foo/foo1', '/bar/foo/foo2', '/bar/foo/foo3', '/bar/foo/foo4', '/bar/foo/sub1/foo5', '/bar/foo/sub1/foo6', '/bar/foo/sub2/foo7', '/bar/foo/sub2/foo8'], []], [0, 5, ['/bar/foo/foo1', '/bar/foo/foo2', '/bar/foo/foo3', '/bar/foo/foo4', '/bar/foo/sub1/foo5'], []], [0, 2, ['/bar/foo/foo1', '/bar/foo/foo2'], []], [3, 2, ['/bar/foo/foo4', '/bar/foo/sub1/foo5'], []], [3, 5, ['/bar/foo/foo4', '/bar/foo/sub1/foo5', '/bar/foo/sub1/foo6', '/bar/foo/sub2/foo7', '/bar/foo/sub2/foo8'], []], [5, 2, ['/bar/foo/sub1/foo6', '/bar/foo/sub2/foo7'], []], [6, 2, ['/bar/foo/sub2/foo7', '/bar/foo/sub2/foo8'], []], [7, 2, ['/bar/foo/sub2/foo8'], []], [10, 2, [], []], [0, 5, ['/bar/foo/sub2/foo7', '/bar/foo/foo1', '/bar/foo/sub1/foo5', '/bar/foo/foo2', '/bar/foo/foo3'], [new SearchOrder(ISearchOrder::DIRECTION_ASCENDING, 'mtime')]], [3, 2, ['/bar/foo/foo2', '/bar/foo/foo3'], [new SearchOrder(ISearchOrder::DIRECTION_ASCENDING, 'mtime')]], [0, 5, ['/bar/foo/sub1/foo5', '/bar/foo/sub1/foo6', '/bar/foo/sub2/foo7', '/bar/foo/foo1', '/bar/foo/foo2'], [ new SearchOrder(ISearchOrder::DIRECTION_DESCENDING, 'size'), new SearchOrder(ISearchOrder::DIRECTION_ASCENDING, 'mtime') ]], ]; } /** * @dataProvider offsetLimitProvider * @param int $offset * @param int $limit * @param string[] $expectedPaths * @param ISearchOrder[] $ordering * @throws NotFoundException * @throws \OCP\Files\InvalidPathException */ public function testSearchSubStoragesLimitOffset(int $offset, int $limit, array $expectedPaths, array $ordering) { if (!$ordering) { $ordering = [new SearchOrder(ISearchOrder::DIRECTION_ASCENDING, 'fileid')]; } $manager = $this->createMock(Manager::class); /** * @var \OC\Files\View | \PHPUnit\Framework\MockObject\MockObject $view */ $view = $this->createMock(View::class); $root = $this->getMockBuilder(Root::class) ->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache, $this->logger, $this->userManager]) ->getMock(); $root->expects($this->any()) ->method('getUser') ->willReturn($this->user); $storage = $this->createMock(Storage::class); $storage->method('getId')->willReturn('test::1'); $cache = new Cache($storage); $subStorage1 = $this->createMock(Storage::class); $subStorage1->method('getId')->willReturn('test::2'); $subCache1 = new Cache($subStorage1); $subMount1 = $this->getMockBuilder(MountPoint::class)->setConstructorArgs([Temporary::class, ''])->getMock(); $subStorage2 = $this->createMock(Storage::class); $subStorage2->method('getId')->willReturn('test::3'); $subCache2 = new Cache($subStorage2); $subMount2 = $this->getMockBuilder(MountPoint::class)->setConstructorArgs([Temporary::class, ''])->getMock(); $mount = $this->createMock(IMountPoint::class); $mount->method('getStorage') ->willReturn($storage); $mount->method('getInternalPath') ->willReturn('foo'); $subMount1->method('getStorage') ->willReturn($subStorage1); $subMount1->method('getMountPoint') ->willReturn('/bar/foo/sub1/'); $storage->method('getCache') ->willReturn($cache); $subStorage1->method('getCache') ->willReturn($subCache1); $subMount2->method('getStorage') ->willReturn($subStorage2); $subMount2->method('getMountPoint') ->willReturn('/bar/foo/sub2/'); $subStorage2->method('getCache') ->willReturn($subCache2); $cache->insert('foo/foo1', ['size' => 200, 'mtime' => 10, 'mimetype' => 'text/plain']); $cache->insert('foo/foo2', ['size' => 200, 'mtime' => 20, 'mimetype' => 'text/plain']); $cache->insert('foo/foo3', ['size' => 200, 'mtime' => 30, 'mimetype' => 'text/plain']); $cache->insert('foo/foo4', ['size' => 200, 'mtime' => 40, 'mimetype' => 'text/plain']); $subCache1->insert('foo5', ['size' => 300, 'mtime' => 15, 'mimetype' => 'text/plain']); $subCache1->insert('foo6', ['size' => 300, 'mtime' => 50, 'mimetype' => 'text/plain']); $subCache2->insert('foo7', ['size' => 200, 'mtime' => 5, 'mimetype' => 'text/plain']); $subCache2->insert('foo8', ['size' => 200, 'mtime' => 60, 'mimetype' => 'text/plain']); $root->method('getMountsIn') ->with('/bar/foo') ->willReturn([$subMount1, $subMount2]); $root->method('getMount') ->with('/bar/foo') ->willReturn($mount); $node = new Folder($root, $view, '/bar/foo'); $comparison = new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', '%foo%'); $query = new SearchQuery($comparison, $limit, $offset, $ordering); $result = $node->search($query); $cache->clear(); $subCache1->clear(); $subCache2->clear(); $ids = array_map(function (Node $info) { return $info->getPath(); }, $result); $this->assertEquals($expectedPaths, $ids); } } >backport/48142/stable28 Nextcloud server, a safe home for all your data: https://github.com/nextcloud/serverwww-data
aboutsummaryrefslogtreecommitdiffstats
path: root/tests/lib/SubAdminTest.php
blob: 4cda08a2945159a690c6bb64694cbfbfe2a43777 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
<?php
/**
 * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
 * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
 * SPDX-License-Identifier: AGPL-3.0-only
 */

namespace Test;

use OCP\EventDispatcher\IEventDispatcher;
use OCP\Group\Events\SubAdminAddedEvent;
use OCP\Group\Events\SubAdminRemovedEvent;

/**
 * @group DB
 */
class SubAdminTest extends \Test\TestCase {
	/** @var \OCP\IUserManager */
	private $userManager;

	/** @var \OCP\IGroupManager */
	private $groupManager;

	/** @var \OCP\IDBConnection */
	private $dbConn;

	/** @var IEventDispatcher */
	private $eventDispatcher;

	/** @var \OCP\IUser[] */
	private $users;

	/** @var \OCP\IGroup[] */
	private $groups;

	protected function setUp(): void {
		parent::setUp();

		$this->users = [];
		$this->groups = [];

		$this->userManager = \OC::$server->getUserManager();
		$this->groupManager = \OC::$server->getGroupManager();
		$this->dbConn = \OC::$server->getDatabaseConnection();
		$this->eventDispatcher = \OC::$server->get(IEventDispatcher::class);

		// Create 3 users and 3 groups
		for ($i = 0; $i < 3; $i++) {
			$this->users[] = $this->userManager->createUser('user' . $i, 'user');
			$this->groups[] = $this->groupManager->createGroup('group' . $i);
		}

		// Create admin group
		if (!$this->groupManager->groupExists('admin')) {
			$this->groupManager->createGroup('admin');
		}

		// Create "orphaned" users and groups (scenario: temporarily disabled
		// backend)
		$qb = $this->dbConn->getQueryBuilder();
		$qb->insert('group_admin')
			->values([
				'gid' => $qb->createNamedParameter($this->groups[0]->getGID()),
				'uid' => $qb->createNamedParameter('orphanedUser')
			])
			->execute();
		$qb->insert('group_admin')
			->values([
				'gid' => $qb->createNamedParameter('orphanedGroup'),
				'uid' => $qb->createNamedParameter('orphanedUser')
			])
			->execute();
		$qb->insert('group_admin')
			->values([
				'gid' => $qb->createNamedParameter('orphanedGroup'),
				'uid' => $qb->createNamedParameter($this->users[0]->getUID())
			])
			->execute();
	}

	protected function tearDown(): void {
		foreach ($this->users as $user) {
			$user->delete();
		}

		foreach ($this->groups as $group) {
			$group->delete();
		}

		$qb = $this->dbConn->getQueryBuilder();
		$qb->delete('group_admin')
			->where($qb->expr()->eq('uid', $qb->createNamedParameter('orphanedUser')))
			->orWhere($qb->expr()->eq('gid', $qb->createNamedParameter('orphanedGroup')))
			->execute();
	}

	public function testCreateSubAdmin(): void {
		$subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn, $this->eventDispatcher);
		$subAdmin->createSubAdmin($this->users[0], $this->groups[0]);

		// Look for subadmin in the database
		$qb = $this->dbConn->getQueryBuilder();
		$result = $qb->select(['gid', 'uid'])
			->from('group_admin')
			->where($qb->expr()->eq('gid', $qb->createNamedParameter($this->groups[0]->getGID())))
			->andWHere($qb->expr()->eq('uid', $qb->createNamedParameter($this->users[0]->getUID())))
			->execute()
			->fetch();
		$this->assertEquals(
			[
				'gid' => $this->groups[0]->getGID(),
				'uid' => $this->users[0]->getUID()
			], $result);

		// Delete subadmin
		$result = $qb->delete('*PREFIX*group_admin')
			->where($qb->expr()->eq('gid', $qb->createNamedParameter($this->groups[0]->getGID())))
			->andWHere($qb->expr()->eq('uid', $qb->createNamedParameter($this->users[0]->getUID())))
			->execute();
	}

	public function testDeleteSubAdmin(): void {
		$subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn, $this->eventDispatcher);
		$subAdmin->createSubAdmin($this->users[0], $this->groups[0]);
		$subAdmin->deleteSubAdmin($this->users[0], $this->groups[0]);

		// DB query should be empty
		$qb = $this->dbConn->getQueryBuilder();
		$result = $qb->select(['gid', 'uid'])
			->from('group_admin')
			->where($qb->expr()->eq('gid', $qb->createNamedParameter($this->groups[0]->getGID())))
			->andWHere($qb->expr()->eq('uid', $qb->createNamedParameter($this->users[0]->getUID())))
			->execute()
			->fetch();
		$this->assertEmpty($result);
	}

	public function testGetSubAdminsGroups(): void {
		$subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn, $this->eventDispatcher);
		$subAdmin->createSubAdmin($this->users[0], $this->groups[0]);
		$subAdmin->createSubAdmin($this->users[0], $this->groups[1]);

		$result = $subAdmin->getSubAdminsGroups($this->users[0]);

		$this->assertContains($this->groups[0], $result);
		$this->assertContains($this->groups[1], $result);
		$this->assertNotContains($this->groups[2], $result);
		$this->assertNotContains(null, $result);

		$subAdmin->deleteSubAdmin($this->users[0], $this->groups[0]);
		$subAdmin->deleteSubAdmin($this->users[0], $this->groups[1]);
	}

	public function testGetGroupsSubAdmins(): void {
		$subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn, $this->eventDispatcher);
		$subAdmin->createSubAdmin($this->users[0], $this->groups[0]);
		$subAdmin->createSubAdmin($this->users[1], $this->groups[0]);

		$result = $subAdmin->getGroupsSubAdmins($this->groups[0]);

		$this->assertContains($this->users[0], $result);
		$this->assertContains($this->users[1], $result);
		$this->assertNotContains($this->users[2], $result);
		$this->assertNotContains(null, $result);

		$subAdmin->deleteSubAdmin($this->users[0], $this->groups[0]);
		$subAdmin->deleteSubAdmin($this->users[1], $this->groups[0]);
	}

	public function testGetAllSubAdmin(): void {
		$subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn, $this->eventDispatcher);

		$subAdmin->createSubAdmin($this->users[0], $this->groups[0]);
		$subAdmin->createSubAdmin($this->users[1], $this->groups[1]);
		$subAdmin->createSubAdmin($this->users[2], $this->groups[1]);

		$result = $subAdmin->getAllSubAdmins();

		$this->assertContains(['user' => $this->users[0], 'group' => $this->groups[0]], $result);
		$this->assertContains(['user' => $this->users[1], 'group' => $this->groups[1]], $result);
		$this->assertContains(['user' => $this->users[2], 'group' => $this->groups[1]], $result);
		$this->assertNotContains(['user' => null, 'group' => null], $result);
	}

	public function testIsSubAdminofGroup(): void {
		$subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn, $this->eventDispatcher);
		$subAdmin->createSubAdmin($this->users[0], $this->groups[0]);

		$this->assertTrue($subAdmin->isSubAdminOfGroup($this->users[0], $this->groups[0]));
		$this->assertFalse($subAdmin->isSubAdminOfGroup($this->users[0], $this->groups[1]));
		$this->assertFalse($subAdmin->isSubAdminOfGroup($this->users[1], $this->groups[0]));

		$subAdmin->deleteSubAdmin($this->users[0], $this->groups[0]);
	}

	public function testIsSubAdmin(): void {
		$subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn, $this->eventDispatcher);
		$subAdmin->createSubAdmin($this->users[0], $this->groups[0]);

		$this->assertTrue($subAdmin->isSubAdmin($this->users[0]));
		$this->assertFalse($subAdmin->isSubAdmin($this->users[1]));

		$subAdmin->deleteSubAdmin($this->users[0], $this->groups[0]);
	}

	public function testIsSubAdminAsAdmin(): void {
		$subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn, $this->eventDispatcher);
		$this->groupManager->get('admin')->addUser($this->users[0]);

		$this->assertTrue($subAdmin->isSubAdmin($this->users[0]));
	}

	public function testIsUserAccessible(): void {
		$subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn, $this->eventDispatcher);
		$this->groups[0]->addUser($this->users[1]);
		$this->groups[1]->addUser($this->users[1]);
		$this->groups[1]->addUser($this->users[2]);
		$subAdmin->createSubAdmin($this->users[0], $this->groups[0]);
		$subAdmin->createSubAdmin($this->users[2], $this->groups[2]);

		$this->assertTrue($subAdmin->isUserAccessible($this->users[0], $this->users[1]));
		$this->assertFalse($subAdmin->isUserAccessible($this->users[0], $this->users[2]));
		$this->assertFalse($subAdmin->isUserAccessible($this->users[2], $this->users[0]));

		$subAdmin->deleteSubAdmin($this->users[0], $this->groups[0]);
		$subAdmin->deleteSubAdmin($this->users[2], $this->groups[2]);
	}

	public function testIsUserAccessibleAsUser(): void {
		$subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn, $this->eventDispatcher);
		$this->assertFalse($subAdmin->isUserAccessible($this->users[0], $this->users[1]));
	}

	public function testIsUserAccessibleAdmin(): void {
		$subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn, $this->eventDispatcher);
		$subAdmin->createSubAdmin($this->users[0], $this->groups[0]);
		$this->groupManager->get('admin')->addUser($this->users[1]);

		$this->assertFalse($subAdmin->isUserAccessible($this->users[0], $this->users[1]));
	}

	public function testPostDeleteUser(): void {
		$subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn, $this->eventDispatcher);

		$user = array_shift($this->users);
		foreach ($this->groups as $group) {
			$subAdmin->createSubAdmin($user, $group);
		}

		$user->delete();
		$this->assertEmpty($subAdmin->getAllSubAdmins());
	}

	public function testPostDeleteGroup(): void {
		$subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn, $this->eventDispatcher);

		$group = array_shift($this->groups);
		foreach ($this->users as $user) {
			$subAdmin->createSubAdmin($user, $group);
		}

		$group->delete();
		$this->assertEmpty($subAdmin->getAllSubAdmins());
	}

	public function testHooks(): void {
		$subAdmin = new \OC\SubAdmin($this->userManager, $this->groupManager, $this->dbConn, $this->eventDispatcher);

		$test = $this;
		$u = $this->users[0];
		$g = $this->groups[0];
		$count = 0;

		$this->eventDispatcher->addListener(SubAdminAddedEvent::class, function (SubAdminAddedEvent $event) use ($test, $u, $g, &$count) {
			$test->assertEquals($u->getUID(), $event->getUser()->getUID());
			$test->assertEquals($g->getGID(), $event->getGroup()->getGID());
			$count++;
		});

		$this->eventDispatcher->addListener(SubAdminRemovedEvent::class, function ($event) use ($test, $u, $g, &$count) {
			$test->assertEquals($u->getUID(), $event->getUser()->getUID());
			$test->assertEquals($g->getGID(), $event->getGroup()->getGID());
			$count++;
		});

		$subAdmin->createSubAdmin($u, $g);
		$this->assertEquals(1, $count);

		$subAdmin->deleteSubAdmin($u, $g);
		$this->assertEquals(2, $count);
	}
}