From 7934eb2b73a06abb1e972d9e12169b84215cf09a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Thu, 25 Oct 2018 15:13:20 +0200 Subject: [PATCH 1/2] do not iterate over all storages when you only need a single node anyway MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jörn Friedrich Dreyer --- apps/comments/appinfo/app.php | 2 +- apps/comments/lib/Activity/Listener.php | 7 +-- .../lib/Connector/Sabre/FilesReportPlugin.php | 4 +- apps/dav/lib/RootCollection.php | 4 +- .../SystemTagsObjectTypeCollection.php | 2 +- .../lib/FederatedShareProvider.php | 2 +- apps/files/lib/ActivityHelper.php | 7 +-- .../lib/Controller/Share20OcsController.php | 16 +++-- apps/files_sharing/lib/SharedMount.php | 6 +- apps/systemtags/lib/Activity/Listener.php | 7 +-- lib/private/Files/Config/CachedMountInfo.php | 8 +-- lib/private/Files/Meta/MetaFileIdNode.php | 19 +++--- lib/private/Files/Meta/MetaRootNode.php | 8 +-- .../Files/Meta/MetaVersionCollection.php | 41 ++++++------ lib/private/Files/Node/AbstractFolder.php | 2 +- lib/private/Files/Node/Folder.php | 7 ++- lib/private/Files/Node/LazyRoot.php | 2 +- lib/private/Files/Node/NonExistingFolder.php | 2 +- lib/private/Files/Storage/Wrapper/Jail.php | 62 ++++++++++++++++++- lib/private/Share20/Share.php | 2 +- lib/public/Files/Folder.php | 3 +- 21 files changed, 134 insertions(+), 79 deletions(-) diff --git a/apps/comments/appinfo/app.php b/apps/comments/appinfo/app.php index b491b1d4d3f0..bbc292dc4a1f 100644 --- a/apps/comments/appinfo/app.php +++ b/apps/comments/appinfo/app.php @@ -54,7 +54,7 @@ function () { $eventDispatcher->addListener(\OCP\Comments\CommentsEntityEvent::EVENT_ENTITY, function (\OCP\Comments\CommentsEntityEvent $event) { $event->addEntityCollection('files', function ($name) { - $nodes = \OC::$server->getUserFolder()->getById(\intval($name)); + $nodes = \OC::$server->getUserFolder()->getById((int)$name, true); return !empty($nodes); }); }); diff --git a/apps/comments/lib/Activity/Listener.php b/apps/comments/lib/Activity/Listener.php index a4ca3b4aa463..1781286713d9 100644 --- a/apps/comments/lib/Activity/Listener.php +++ b/apps/comments/lib/Activity/Listener.php @@ -86,10 +86,9 @@ public function commentEvent(CommentsEvent $event) { foreach ($mounts as $mount) { $owner = $mount->getUser()->getUID(); $ownerFolder = $this->rootFolder->getUserFolder($owner); - $nodes = $ownerFolder->getById($event->getComment()->getObjectId()); - if (!empty($nodes)) { - /** @var Node $node */ - $node = \array_shift($nodes); + $nodes = $ownerFolder->getById($event->getComment()->getObjectId(), true); + $node = $nodes[0] ?? null; + if ($node) { $path = $node->getPath(); if (\strpos($path, '/' . $owner . '/files/') === 0) { $path = \substr($path, \strlen('/' . $owner . '/files')); diff --git a/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php b/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php index 3ea18fabfb0d..e6512b376aaf 100644 --- a/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php +++ b/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php @@ -360,9 +360,9 @@ public function findNodesByFileIds($rootNode, $fileIds) { $results = []; foreach ($fileIds as $fileId) { - $entry = $folder->getById($fileId); + $entries = $folder->getById($fileId, true); + $entry = $entries[0] ?? null; if ($entry) { - $entry = \current($entry); $node = $this->makeSabreNode($entry); if ($node) { $results[] = $node; diff --git a/apps/dav/lib/RootCollection.php b/apps/dav/lib/RootCollection.php index faa8e3fba63d..43eb9b178c03 100644 --- a/apps/dav/lib/RootCollection.php +++ b/apps/dav/lib/RootCollection.php @@ -74,7 +74,7 @@ public function __construct() { \OC::$server->getSystemTagObjectMapper(), \OC::$server->getUserSession(), \OC::$server->getGroupManager(), - \OC::$server->getRootFolder() + \OC::$server->getLazyRootFolder() ); $usersCardDavBackend = new CardDavBackend($db, $userPrincipalBackend, $groupPrincipalBackend, $dispatcher); @@ -109,7 +109,7 @@ public function __construct() { $systemTagRelationsCollection, $uploadCollection, $avatarCollection, - new \OCA\DAV\Meta\RootCollection(\OC::$server->getRootFolder()), + new \OCA\DAV\Meta\RootCollection(\OC::$server->getLazyRootFolder()), $queueCollection ]; diff --git a/apps/dav/lib/SystemTag/SystemTagsObjectTypeCollection.php b/apps/dav/lib/SystemTag/SystemTagsObjectTypeCollection.php index fa44c0b2f47b..4ffd4aa20d14 100644 --- a/apps/dav/lib/SystemTag/SystemTagsObjectTypeCollection.php +++ b/apps/dav/lib/SystemTag/SystemTagsObjectTypeCollection.php @@ -139,7 +139,7 @@ public function childExists($name) { if ($this->objectType === 'files') { // make sure the object is reachable for the current user $userId = $this->userSession->getUser()->getUID(); - $nodes = $this->fileRoot->getUserFolder($userId)->getById(\intval($name)); + $nodes = $this->fileRoot->getUserFolder($userId)->getById((int)$name, true); return !empty($nodes); } return true; diff --git a/apps/federatedfilesharing/lib/FederatedShareProvider.php b/apps/federatedfilesharing/lib/FederatedShareProvider.php index c6bea791e61a..01606ce5097a 100644 --- a/apps/federatedfilesharing/lib/FederatedShareProvider.php +++ b/apps/federatedfilesharing/lib/FederatedShareProvider.php @@ -886,7 +886,7 @@ private function getNode($userId, $id) { throw new InvalidShare(); } - $nodes = $userFolder->getById($id); + $nodes = $userFolder->getById($id, true); if (empty($nodes)) { throw new InvalidShare(); diff --git a/apps/files/lib/ActivityHelper.php b/apps/files/lib/ActivityHelper.php index 20ac77cbc75a..c198c10353cb 100644 --- a/apps/files/lib/ActivityHelper.php +++ b/apps/files/lib/ActivityHelper.php @@ -59,10 +59,9 @@ public function getFavoriteFilePaths($user) { $rootFolder = \OC::$server->getUserFolder($user); $folders = $items = []; foreach ($favorites as $favorite) { - $nodes = $rootFolder->getById($favorite); - if (!empty($nodes)) { - /** @var \OCP\Files\Node $node */ - $node = \array_shift($nodes); + $nodes = $rootFolder->getById($favorite, true); + $node = $nodes[0] ?? null; + if ($node) { $path = \substr($node->getPath(), \strlen($user . '/files/')); $items[] = $path; diff --git a/apps/files_sharing/lib/Controller/Share20OcsController.php b/apps/files_sharing/lib/Controller/Share20OcsController.php index bde1320991ef..8d1ee1c7645a 100644 --- a/apps/files_sharing/lib/Controller/Share20OcsController.php +++ b/apps/files_sharing/lib/Controller/Share20OcsController.php @@ -166,14 +166,12 @@ protected function formatShare(IShare $share, $received = false) { $userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID()); } - $nodes = $userFolder->getById($share->getNodeId()); - - if (empty($nodes)) { + $nodes = $userFolder->getById($share->getNodeId(), true); + $node = $nodes[0] ?? null; + if ($node === null) { throw new NotFoundException(); } - $node = $nodes[0]; - $result['path'] = $userFolder->getRelativePath($node->getPath()); if ($node instanceof \OCP\Files\Folder) { $result['item_type'] = 'folder'; @@ -912,8 +910,8 @@ public function notifyRecipients($itemSource, $shareType, $recipient) { ); $userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID()); - $nodes = $userFolder->getById($itemSource); - $node = $nodes[0]; + $nodes = $userFolder->getById($itemSource, true); + $node = $nodes[0] ?? null; $result = $mailNotification->sendInternalShareMail($node, $shareType, $recipientList); // if we were able to send to at least one recipient, mark as sent @@ -950,8 +948,8 @@ public function notifyRecipients($itemSource, $shareType, $recipient) { */ public function notifyRecipientsDisabled($itemSource, $shareType, $recipient) { $userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID()); - $nodes = $userFolder->getById($itemSource); - $node = $nodes[0]; + $nodes = $userFolder->getById($itemSource, true); + $node = $nodes[0] ?? null; $items = $this->shareManager->getSharedWith($recipient, $shareType, $node); if (\count($items) > 0) { diff --git a/apps/files_sharing/lib/SharedMount.php b/apps/files_sharing/lib/SharedMount.php index 3923c58da4e1..059687095d97 100644 --- a/apps/files_sharing/lib/SharedMount.php +++ b/apps/files_sharing/lib/SharedMount.php @@ -193,13 +193,13 @@ public function isTargetAllowed($target) { $fileId = (int)$targetStorage->getCache()->getId(\dirname($targetInternalPath)); } - $targetNodes = \OC::$server->getRootFolder()->getById($fileId); - if (empty($targetNodes)) { + $targetNodes = \OC::$server->getRootFolder()->getById($fileId, true); + $targetNode = $targetNodes[0] ?? null; + if ($targetNode === null) { return false; } $shareManager = \OC::$server->getShareManager(); - $targetNode = $targetNodes[0]; // FIXME: make it stop earlier in '/$userId/files' while ($targetNode !== null && $targetNode->getPath() !== '/') { $shares = $shareManager->getSharesByPath($targetNode); diff --git a/apps/systemtags/lib/Activity/Listener.php b/apps/systemtags/lib/Activity/Listener.php index 112ab4a8fcf9..f8983d33337e 100644 --- a/apps/systemtags/lib/Activity/Listener.php +++ b/apps/systemtags/lib/Activity/Listener.php @@ -159,10 +159,9 @@ public function mapperEvent(MapperEvent $event) { foreach ($mounts as $mount) { $owner = $mount->getUser()->getUID(); $ownerFolder = $this->rootFolder->getUserFolder($owner); - $nodes = $ownerFolder->getById($event->getObjectId()); - if (!empty($nodes)) { - /** @var Node $node */ - $node = \array_shift($nodes); + $nodes = $ownerFolder->getById($event->getObjectId(), true); + $node = $nodes[0] ?? null; + if ($node) { $path = $node->getPath(); if (\strpos($path, '/' . $owner . '/files/') === 0) { $path = \substr($path, \strlen('/' . $owner . '/files')); diff --git a/lib/private/Files/Config/CachedMountInfo.php b/lib/private/Files/Config/CachedMountInfo.php index d2b3c78f393a..cc3074150142 100644 --- a/lib/private/Files/Config/CachedMountInfo.php +++ b/lib/private/Files/Config/CachedMountInfo.php @@ -91,12 +91,8 @@ public function getMountPointNode() { // TODO injection etc Filesystem::initMountPoints($this->getUser()->getUID()); $userNode = \OC::$server->getUserFolder($this->getUser()->getUID()); - $nodes = $userNode->getParent()->getById($this->getRootId()); - if (\count($nodes) > 0) { - return $nodes[0]; - } else { - return null; - } + $nodes = $userNode->getParent()->getById($this->getRootId(), true); + return $nodes[0] ?? null; } /** diff --git a/lib/private/Files/Meta/MetaFileIdNode.php b/lib/private/Files/Meta/MetaFileIdNode.php index b04d344b247e..2f8407ea9fb5 100644 --- a/lib/private/Files/Meta/MetaFileIdNode.php +++ b/lib/private/Files/Meta/MetaFileIdNode.php @@ -34,8 +34,8 @@ */ class MetaFileIdNode extends AbstractFolder { - /** @var int */ - private $fileId; + /** @var \OCP\Files\Node */ + private $node; /** @var MetaRootNode */ private $parentNode; /** @var IRootFolder */ @@ -45,12 +45,13 @@ class MetaFileIdNode extends AbstractFolder { * MetaFileIdNode constructor. * * @param MetaRootNode $parentNode - * @param int $fileId + * @param IRootFolder $root + * @param \OCP\Files\Node $node */ - public function __construct(MetaRootNode $parentNode, IRootFolder $root, $fileId) { + public function __construct(MetaRootNode $parentNode, IRootFolder $root, \OCP\Files\Node $node) { $this->parentNode = $parentNode; - $this->fileId = $fileId; $this->root = $root; + $this->node = $node; } /** @@ -79,7 +80,7 @@ public function isMounted() { */ public function getDirectoryListing() { return [ - new MetaVersionCollection($this->fileId, $this->root) + new MetaVersionCollection($this->root, $this->node) ]; } @@ -90,7 +91,7 @@ public function get($path) { $pieces = \explode('/', $path); if ($pieces[0] === 'v') { \array_shift($pieces); - $node = new MetaVersionCollection($this->fileId, $this->root); + $node = new MetaVersionCollection($this->root, $this->node); if (empty($pieces)) { return $node; } @@ -117,7 +118,7 @@ public function getPath() { * @inheritdoc */ public function getInternalPath() { - return "/meta/{$this->fileId}"; + return "/meta/{$this->node->getId()}"; } /** @@ -166,6 +167,6 @@ public function getParent() { * @inheritdoc */ public function getName() { - return "{$this->fileId}"; + return "{$this->node->getId()}"; } } diff --git a/lib/private/Files/Meta/MetaRootNode.php b/lib/private/Files/Meta/MetaRootNode.php index 6a893652c115..930180f5d714 100644 --- a/lib/private/Files/Meta/MetaRootNode.php +++ b/lib/private/Files/Meta/MetaRootNode.php @@ -76,13 +76,13 @@ public function get($path) { $pieces = \explode('/', $path); $fileId = (int)$pieces[0]; - // check if file exists - if (empty($this->rootFolder->getById($fileId))) { + $nodes = $this->rootFolder->getById($fileId, true); + if (empty($nodes)) { throw new NotFoundException(); } \array_shift($pieces); - $node = new MetaFileIdNode($this, $this->rootFolder, $fileId); + $node = new MetaFileIdNode($this, $this->rootFolder, $nodes[0]); if (empty($pieces)) { return $node; } @@ -92,7 +92,7 @@ public function get($path) { /** * @inheritdoc */ - public function getById($id) { + public function getById($id, $first = false) { return [ $this->get("$id") ]; diff --git a/lib/private/Files/Meta/MetaVersionCollection.php b/lib/private/Files/Meta/MetaVersionCollection.php index 5e63c7d0f43e..fd3a238efa64 100644 --- a/lib/private/Files/Meta/MetaVersionCollection.php +++ b/lib/private/Files/Meta/MetaVersionCollection.php @@ -1,5 +1,6 @@ * @author Thomas Müller * * @copyright Copyright (c) 2018, ownCloud GmbH @@ -24,7 +25,6 @@ use OC\Files\Node\AbstractFolder; use OCP\Files\IRootFolder; use OCP\Files\Storage\IVersionedStorage; -use OC\Files\View; use OCP\Files\NotFoundException; use OCP\Files\Storage; @@ -36,20 +36,20 @@ */ class MetaVersionCollection extends AbstractFolder { - /** @var int */ - private $fileId; /** @var IRootFolder */ private $root; + /** @var \OCP\Files\Node */ + private $node; /** * MetaVersionCollection constructor. * - * @param int $fileId * @param IRootFolder $root + * @param \OCP\Files\Node $node */ - public function __construct($fileId, IRootFolder $root) { - $this->fileId = $fileId; + public function __construct(IRootFolder $root, \OCP\Files\Node $node) { $this->root = $root; + $this->node = $node; } /** @@ -66,22 +66,19 @@ public function isShared() { return false; } - /** - * @inheritdoc - */ public function getDirectoryListing() { - $view = new View(); - $path = $view->getPath($this->fileId, false); - /** @var Storage $storage */ - list($storage, $internalPath) = $view->resolvePath($path); + $node = $this->node; + $storage = $node->getStorage(); + $internalPath = $node->getInternalPath(); + if (!$storage->instanceOfStorage(IVersionedStorage::class)) { return []; } /** @var IVersionedStorage | Storage $storage */ $versions = $storage->getVersions($internalPath); - return \array_values(\array_map(function ($version) use ($storage, $internalPath, $view, $path) { + return \array_values(\array_map(function ($version) use ($storage, $node, $internalPath) { if (!isset($version['mimetype'])) { - $version['mimetype'] = $view->getMimeType($path); + $version['mimetype'] = $node->getMimetype(); } return new MetaFileVersionNode($this, $this->root, $version, $storage, $internalPath); @@ -97,10 +94,10 @@ public function get($path) { throw new NotFoundException(); } $versionId = $pieces[0]; - $view = new View(); - $path = $view->getPath($this->fileId); - /** @var Storage $storage */ - list($storage, $internalPath) = $view->resolvePath($path); + + $storage = $this->node->getStorage(); + $internalPath = $this->node->getInternalPath(); + if (!$storage->instanceOfStorage(IVersionedStorage::class)) { throw new NotFoundException(); } @@ -110,7 +107,7 @@ public function get($path) { throw new NotFoundException(); } if (!isset($version['mimetype'])) { - $version['mimetype'] = $view->getMimeType($path); + $version['mimetype'] = $this->node->getMimetype(); } return new MetaFileVersionNode($this, $this->root, $version, $storage, $internalPath); } @@ -119,7 +116,7 @@ public function get($path) { * @inheritdoc */ public function getId() { - return $this->fileId; + return $this->node->getId(); } public function getName() { @@ -127,6 +124,6 @@ public function getName() { } public function getPath() { - return "/meta/{$this->fileId}/v"; + return "/meta/{$this->getId()}/v"; } } diff --git a/lib/private/Files/Node/AbstractFolder.php b/lib/private/Files/Node/AbstractFolder.php index fb6c3feea3a4..d652c026a2f6 100644 --- a/lib/private/Files/Node/AbstractFolder.php +++ b/lib/private/Files/Node/AbstractFolder.php @@ -112,7 +112,7 @@ public function searchByTag($tag, $userId) { /** * @inheritdoc */ - public function getById($id) { + public function getById($id, $first = false) { throw new NotPermittedException(); } diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php index adb9e56a1b4c..ca559a1f7e86 100644 --- a/lib/private/Files/Node/Folder.php +++ b/lib/private/Files/Node/Folder.php @@ -269,9 +269,11 @@ private function searchCommon($method, $args) { /** * @param int $id + * @param boolean $first only return the first node that is found * @return \OC\Files\Node\Node[] + * @throws NotFoundException */ - public function getById($id) { + public function getById($id, $first = false) { $mounts = $this->root->getMountsIn($this->path); $mounts[] = $this->root->getMount($this->path); // reverse the array so we start with the storage this view is in @@ -290,6 +292,9 @@ public function getById($id) { $fullPath = $mount->getMountPoint() . $internalPath; if (($path = $this->getRelativePath($fullPath)) !== null) { $nodes[] = $this->get($path); + if ($first) { + break; + } } } } diff --git a/lib/private/Files/Node/LazyRoot.php b/lib/private/Files/Node/LazyRoot.php index 9e43f7e09b47..c9bf01f71525 100644 --- a/lib/private/Files/Node/LazyRoot.php +++ b/lib/private/Files/Node/LazyRoot.php @@ -417,7 +417,7 @@ public function searchByTag($tag, $userId) { /** * @inheritDoc */ - public function getById($id) { + public function getById($id, $first = false) { return $this->__call(__FUNCTION__, \func_get_args()); } diff --git a/lib/private/Files/Node/NonExistingFolder.php b/lib/private/Files/Node/NonExistingFolder.php index c3634403fea6..032e5764312c 100644 --- a/lib/private/Files/Node/NonExistingFolder.php +++ b/lib/private/Files/Node/NonExistingFolder.php @@ -154,7 +154,7 @@ public function searchByTag($tag, $userId) { throw new NotFoundException(); } - public function getById($id) { + public function getById($id, $first = false) { throw new NotFoundException(); } diff --git a/lib/private/Files/Storage/Wrapper/Jail.php b/lib/private/Files/Storage/Wrapper/Jail.php index f533cd8330f1..24d12774d8a0 100644 --- a/lib/private/Files/Storage/Wrapper/Jail.php +++ b/lib/private/Files/Storage/Wrapper/Jail.php @@ -26,6 +26,7 @@ use OC\Files\Cache\Wrapper\CacheJail; use OCP\Files\Storage\IStorage; +use OCP\Files\Storage\IVersionedStorage; use OCP\Lock\ILockingProvider; /** @@ -33,7 +34,8 @@ * * This restricts access to a subfolder of the wrapped storage with the subfolder becoming the root folder new storage */ -class Jail extends Wrapper { +class Jail extends Wrapper /* implements IVersionedStorage */ +{ /** * @var string */ @@ -497,4 +499,62 @@ public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceIntern } return $this->getWrapperStorage()->moveFromStorage($sourceStorage, $sourceInternalPath, $this->getSourcePath($targetInternalPath)); } + + /** + * Get the content of a given version of a given file as stream resource + * + * @param string $internalPath + * @param string $versionId + * @return resource + * @since 10.0.9 + */ + public function getContentOfVersion($internalPath, $versionId) { + return $this->getWrapperStorage()->getContentOfVersion($this->getSourcePath($internalPath), $versionId); + } + + /** + * Restore the given version of a given file + * + * @param string $internalPath + * @param string $versionId + * @return boolean + * @since 10.0.9 + */ + public function restoreVersion($internalPath, $versionId) { + return $this->getWrapperStorage()->restoreVersion($this->getSourcePath($internalPath), $versionId); + } + + /** + * Tells the storage to explicitly create a version of a given file + * + * @param string $internalPath + * @return bool + * @since 10.0.9 + */ + public function saveVersion($internalPath) { + return $this->getWrapperStorage()->saveVersion($this->getSourcePath($internalPath)); + } + + /** + * List all versions for the given file + * + * @param string $internalPath + * @return array + * @since 10.0.9 + */ + public function getVersions($internalPath) { + return $this->getWrapperStorage()->getVersions($this->getSourcePath($internalPath)); + } + + /** + * Get one explicit version for the given file + * + * @param string $internalPath + * @param string $versionId + * @return array + * @since 10.0.9 + */ + public function getVersion($internalPath, $versionId) { + return $this->getWrapperStorage()->getVersion($this->getSourcePath($internalPath), $versionId); + } } diff --git a/lib/private/Share20/Share.php b/lib/private/Share20/Share.php index 6f774f08f653..4fa7e4ccfe93 100644 --- a/lib/private/Share20/Share.php +++ b/lib/private/Share20/Share.php @@ -164,7 +164,7 @@ public function getNode() { $userFolder = $this->rootFolder->getUserFolder($this->sharedBy); } - $nodes = $userFolder->getById($this->fileId); + $nodes = $userFolder->getById($this->fileId, true); if (empty($nodes)) { throw new NotFoundException(); } diff --git a/lib/public/Files/Folder.php b/lib/public/Files/Folder.php index 2dfa83a409ed..55f5211bc22d 100644 --- a/lib/public/Files/Folder.php +++ b/lib/public/Files/Folder.php @@ -145,10 +145,11 @@ public function searchByTag($tag, $userId); * get a file or folder inside the folder by it's internal id * * @param int $id + * @param boolean $first only return the first node that is found * @return \OCP\Files\Node[] * @since 6.0.0 */ - public function getById($id); + public function getById($id, $first = false); /** * Get the amount of free space inside the folder From 15f00cc2b1ed5919a8de99589b26b48da7a81845 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Mon, 10 Dec 2018 20:40:42 +0100 Subject: [PATCH 2/2] Increase test coverage, including meta version nodes Added more tests for meta node collection Add tests for comments activity listener Add activity listener test for system tags Add test coverage for files' ActivityHelper Test for legacy shares in fed share provider --- .../tests/unit/ActivityListenerTest.php | 151 ++++++++++++ .../tests/FederatedShareProviderTest.php | 86 +++++++ apps/files/tests/ActivityHelperTest.php | 137 +++++++++++ apps/systemtags/lib/Activity/Listener.php | 6 +- apps/systemtags/tests/ListenerTest.php | 84 ------- .../{ => unit/activity}/ExtensionTest.php | 0 .../tests/unit/activity/ListenerTest.php | 218 ++++++++++++++++++ tests/lib/Files/MetaFilesTest.php | 56 ++++- tests/lib/Files/MetaVersionCollectionTest.php | 166 +++++++++++++ tests/lib/Files/Storage/Wrapper/JailTest.php | 36 +++ 10 files changed, 847 insertions(+), 93 deletions(-) create mode 100644 apps/comments/tests/unit/ActivityListenerTest.php create mode 100644 apps/files/tests/ActivityHelperTest.php delete mode 100644 apps/systemtags/tests/ListenerTest.php rename apps/systemtags/tests/{ => unit/activity}/ExtensionTest.php (100%) create mode 100644 apps/systemtags/tests/unit/activity/ListenerTest.php create mode 100644 tests/lib/Files/MetaVersionCollectionTest.php diff --git a/apps/comments/tests/unit/ActivityListenerTest.php b/apps/comments/tests/unit/ActivityListenerTest.php new file mode 100644 index 000000000000..6f81cc1da7d6 --- /dev/null +++ b/apps/comments/tests/unit/ActivityListenerTest.php @@ -0,0 +1,151 @@ + + * + * @copyright Copyright (c) 2018, ownCloud GmbH + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OCA\Comments\Tests\unit; + +use OCA\Comments\Activity\Listener; +use OCP\Comments\CommentsEntityEvent; +use Test\Traits\UserTrait; +use OCP\IUserSession; +use OCP\Activity\IManager; +use OCP\App\IAppManager; +use OCP\Files\Config\IMountProviderCollection; +use OCP\Files\IRootFolder; +use OCP\Files\Config\IUserMountCache; +use OCP\Files\Config\ICachedMountInfo; +use OCP\IUser; +use OCP\Files\Folder; +use OCP\Activity\IEvent; +use OCA\Comments\Activity\Extension; +use OCP\Comments\IComment; +use OCP\Comments\CommentsEvent; + +/** + * Tests for the activity listener + * + * @group DB + */ +class ActivityListenerTest extends \Test\TestCase { + use UserTrait; + + /** + * @var Listener + */ + private $listener; + + /** + * @var IUserMountCache + */ + private $userMountCache; + + /** + * @var IRootFolder + */ + private $rootFolder; + + /** + * @var IUserSession + */ + private $userSession; + + /** + * @var IManager + */ + private $activityManager; + + protected function setUp() { + parent::setUp(); + + $this->activityManager = $this->createMock(IManager::class); + $this->userSession = $this->createMock(IUserSession::class); + $appManager = $this->createMock(IAppManager::class); + $appManager->method('isInstalled')->with('activity')->willReturn(true); + + $this->userMountCache = $this->createMock(IUserMountCache::class); + + $mountProviderCollection = $this->createMock(IMountProviderCollection::class); + $mountProviderCollection->method('getMountCache')->willReturn($this->userMountCache); + + $this->rootFolder = $this->createMock(IRootFolder::class); + + // needed for the one unmockable static method "Share::getUsersSharingFile"... + $this->createUser('user1'); + $this->createUser('actor1'); + + $this->listener = new Listener( + $this->activityManager, + $this->userSession, + $appManager, + $mountProviderCollection, + $this->rootFolder + ); + } + + public function testActivityOnFilesComment() { + $user = $this->createMock(IUser::class); + $user->method('getUID')->willReturn('user1'); + + $actor = $this->createMock(IUser::class); + $actor->method('getUID')->willReturn('actor1'); + + $this->userSession->method('getUser')->willReturn($actor); + + $cachedMountInfo = $this->createMock(ICachedMountInfo::class); + $cachedMountInfo->method('getUser')->willReturn($user); + + $node = $this->createMock(Folder::class); + $node->method('getPath')->willReturn('/user1/files/folder'); + + $ownerFolder = $this->createMock(Folder::class); + $ownerFolder->method('getById') + ->with(123, true) + ->willReturn([$node]); + + $this->rootFolder->method('getUserFolder') + ->with('user1') + ->willReturn($ownerFolder); + + $this->userMountCache->method('getMountsForFileId') + ->with(123) + ->willReturn([$cachedMountInfo]); + + $activityEvent = $this->createMock(IEvent::class); + $activityEvent->expects($this->once())->method('setApp')->with('comments')->willReturn($activityEvent); + $activityEvent->expects($this->once())->method('setType')->with('comments')->willReturn($activityEvent); + $activityEvent->expects($this->once())->method('setAuthor')->with('actor1')->willReturn($activityEvent); + $activityEvent->expects($this->once())->method('setObject')->with('files', 123)->willReturn($activityEvent); + $activityEvent->expects($this->once())->method('setMessage')->with(Extension::ADD_COMMENT_MESSAGE, [111])->willReturn($activityEvent); + + $this->activityManager->method('generateEvent') + ->willReturn($activityEvent); + $this->activityManager->expects($this->once()) + ->method('publish') + ->with($activityEvent); + + $comment = $this->createMock(IComment::class); + $comment->method('getObjectType')->willReturn('files'); + $comment->method('getObjectId')->willReturn(123); + $comment->method('getId')->willReturn(111); + + $commentsEvent = new CommentsEvent(CommentsEvent::EVENT_ADD, $comment); + $this->listener->commentEvent($commentsEvent); + } +} diff --git a/apps/federatedfilesharing/tests/FederatedShareProviderTest.php b/apps/federatedfilesharing/tests/FederatedShareProviderTest.php index 8b0189c4be0c..ffb0fbd6574c 100644 --- a/apps/federatedfilesharing/tests/FederatedShareProviderTest.php +++ b/apps/federatedfilesharing/tests/FederatedShareProviderTest.php @@ -37,6 +37,8 @@ use OCP\IUserManager; use OCP\Share\IManager; use OCP\Share\IShare; +use OCP\Files\Folder; +use OCP\IUser; /** * Class FederatedShareProviderTest @@ -188,6 +190,90 @@ public function testCreate() { $this->assertEquals('token', $share->getToken()); } + public function testCreateLegacy() { + $share = $this->shareManager->newShare(); + + $node = $this->createMock('\OCP\Files\File'); + $node->method('getId')->willReturn(42); + $node->method('getName')->willReturn('myFile'); + + $share->setSharedWith('user@server.com') + ->setShareOwner('shareOwner') + ->setPermissions(19) + ->setNode($node); + + $this->tokenHandler->method('generateToken')->willReturn('token'); + + $shareWithAddress = new Address('user@server.com'); + $ownerAddress = new Address('shareOwner@http://localhost/'); + $sharedByAddress = new Address('sharedBy@http://localhost/'); + $this->addressHandler->expects($this->any())->method('getLocalUserFederatedAddress') + ->will($this->onConsecutiveCalls($ownerAddress, $sharedByAddress, $ownerAddress)); + + $this->addressHandler->expects($this->any())->method('splitUserRemote') + ->willReturn(['user', 'server.com']); + + $this->notifications->expects($this->once()) + ->method('sendRemoteShare') + ->with( + $this->equalTo($shareWithAddress), + $this->equalTo($ownerAddress), + $this->equalTo($sharedByAddress), + $this->equalTo('token'), + $this->equalTo('myFile'), + $this->anything() + )->willReturn(true); + + $folderOwner = $this->createMock(IUser::class); + $folderOwner->method('getUID')->willReturn('folderOwner'); + $node = $this->createMock(Folder::class); + $node->method('getOwner')->willReturn($folderOwner); + + $userFolder = $this->createMock(Folder::class); + $userFolder->method('getById') + ->with(42, true) + ->willReturn([$node]); + $this->rootFolder->expects($this->once()) + ->method('getUserFolder') + ->with('shareOwner') + ->willReturn($userFolder); + + $share = $this->provider->create($share); + + $qb = $this->connection->getQueryBuilder(); + $stmt = $qb->select('*') + ->from('share') + ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) + ->execute(); + + $data = $stmt->fetch(); + $stmt->closeCursor(); + + $expected = [ + 'share_type' => \OCP\Share::SHARE_TYPE_REMOTE, + 'share_with' => 'user@server.com', + 'uid_owner' => 'shareOwner', + 'uid_initiator' => null, + 'item_type' => 'file', + 'item_source' => 42, + 'file_source' => 42, + 'permissions' => 19, + 'accepted' => 0, + 'token' => 'token', + ]; + $this->assertArraySubset($expected, $data); + + $this->assertEquals($data['id'], $share->getId()); + $this->assertEquals(\OCP\Share::SHARE_TYPE_REMOTE, $share->getShareType()); + $this->assertEquals('user@server.com', $share->getSharedWith()); + $this->assertEquals('shareOwner', $share->getSharedBy()); + $this->assertEquals('folderOwner', $share->getShareOwner()); + $this->assertEquals('file', $share->getNodeType()); + $this->assertEquals(42, $share->getNodeId()); + $this->assertEquals(19, $share->getPermissions()); + $this->assertEquals('token', $share->getToken()); + } + public function testCreateCouldNotFindServer() { $share = $this->shareManager->newShare(); diff --git a/apps/files/tests/ActivityHelperTest.php b/apps/files/tests/ActivityHelperTest.php new file mode 100644 index 000000000000..e2c04ea276e8 --- /dev/null +++ b/apps/files/tests/ActivityHelperTest.php @@ -0,0 +1,137 @@ + + * + * @copyright Copyright (c) 2018, ownCloud GmbH + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +use OCA\Files\ActivityHelper; +use OCP\ITagManager; +use OCP\ITags; +use Test\Traits\UserTrait; + +/** + * Class ActivityHelperTest + * + * @group DB + */ +class ActivityHelperTest extends \Test\TestCase { + use UserTrait; + + /** + * @var ITagManager + */ + private $tagManager; + + /** + * @var ITags + */ + private $tags; + + /** + * @var ActivityHelper + */ + private $helper; + + /** + * @var string + */ + private $user; + + protected function setUp() { + parent::setUp(); + + $this->tags = $this->createMock(ITags::class); + + $this->user = $this->getUniqueID('files_activityhelpertest_user_'); + + // because \OC::$server->getUserFolder() + $this->createUser($this->user); + $this->loginAsUser($this->user); + + $this->tagManager = $this->createMock(ITagManager::class); + $this->tagManager->expects($this->once()) + ->method('load') + ->with('files', [], false, $this->user) + ->willReturn($this->tags); + + $this->helper = new ActivityHelper($this->tagManager); + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage No favorites + */ + public function testGetFavoriteFilePathsNoFavorites() { + $this->tags->method('getFavorites')->willReturn([]); + $this->helper->getFavoriteFilePaths($this->user); + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage Too many favorites + */ + public function testGetFavoriteFilePathsTooManyFavorites() { + $tooManyFavorites = []; + for ($i = 0; $i < ActivityHelper::FAVORITE_LIMIT + 1; $i++) { + $tooManyFavorites[] = []; + } + + $this->tags->method('getFavorites')->willReturn($tooManyFavorites); + + $this->helper->getFavoriteFilePaths($this->user); + } + + public function testGetFavoriteFilePaths() { + $userFolder = \OC::$server->getUserFolder(); + $fav1 = $userFolder->newFolder('fav1'); + $fav2 = $userFolder->newFile('fav2.txt'); + $userFolder->newFolder('nonfav1'); + $userFolder->newFolder('nonfav2'); + + $favorites = [ + $fav1->getId(), + $fav2->getId(), + $fav2->getId() + 999, // non-existing + ]; + + $this->tags->method('getFavorites')->willReturn($favorites); + + $result = $this->helper->getFavoriteFilePaths($this->user); + + $this->assertEquals(['/fav1', '/fav2.txt'], $result['items']); + $this->assertEquals(['/fav1'], $result['folders']); + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage No favorites + */ + public function testGetFavoriteFilePathsMissingFolder() { + $userFolder = \OC::$server->getUserFolder(); + $aFolder = $userFolder->newFolder('x'); + + $favorites = [ + // non-existing + $aFolder->getId() + 999, + ]; + + $this->tags->method('getFavorites')->willReturn($favorites); + + $result = $this->helper->getFavoriteFilePaths($this->user); + } +} diff --git a/apps/systemtags/lib/Activity/Listener.php b/apps/systemtags/lib/Activity/Listener.php index f8983d33337e..3cbd9223235a 100644 --- a/apps/systemtags/lib/Activity/Listener.php +++ b/apps/systemtags/lib/Activity/Listener.php @@ -167,7 +167,7 @@ public function mapperEvent(MapperEvent $event) { $path = \substr($path, \strlen('/' . $owner . '/files')); } // Get all users that have access to the mount point - $users = \array_merge($users, Share::getUsersSharingFile($path, $owner, true, true)); + $users = \array_merge($users, $this->getUsersSharingFile($path, $owner)); } } @@ -226,4 +226,8 @@ protected function prepareTagAsParameter(ISystemTag $tag) { return '{{{' . $tag->getName() . '|||assignable}}}'; } } + + public function getUsersSharingFile($path, $owner) { + return Share::getUsersSharingFile($path, $owner, true, true); + } } diff --git a/apps/systemtags/tests/ListenerTest.php b/apps/systemtags/tests/ListenerTest.php deleted file mode 100644 index aad3e3c4c2b7..000000000000 --- a/apps/systemtags/tests/ListenerTest.php +++ /dev/null @@ -1,84 +0,0 @@ - - * - * @copyright Copyright (c) 2018, ownCloud GmbH - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OCA\SystemTags\Tests; - -use OC\SystemTag\SystemTag; -use OCA\SystemTags\Activity\Listener; -use OCP\Activity\IManager; -use OCP\App\IAppManager; -use OCP\Files\Config\IMountProviderCollection; -use OCP\Files\IRootFolder; -use OCP\IGroupManager; -use OCP\IUserSession; -use OCP\SystemTag\ISystemTagManager; -use Test\TestCase; - -class ListenerTest extends TestCase { - /** @var IGroupManager | \PHPUnit_Framework_MockObject_MockObject */ - private $groupManager; - /** @var IManager | \PHPUnit_Framework_MockObject_MockObject */ - private $activityManager; - /** @var IUserSession | \PHPUnit_Framework_MockObject_MockObject */ - private $userSession; - /** @var ISystemTagManager | \PHPUnit_Framework_MockObject_MockObject */ - private $tagManager; - /** @var IAppManager | \PHPUnit_Framework_MockObject_MockObject */ - private $appManager; - /** @var IMountProviderCollection | \PHPUnit_Framework_MockObject_MockObject */ - private $mountCollection; - /** @var IRootFolder | \PHPUnit_Framework_MockObject_MockObject */ - private $rootFolder; - /** @var Listener */ - private $listener; - - public function setUp() { - parent::setUp(); - - $this->groupManager = $this->createMock(IGroupManager::class); - $this->activityManager = $this->createMock(IManager::class); - $this->userSession = $this->createMock(IUserSession::class); - $this->tagManager = $this->createMock(ISystemTagManager::class); - $this->appManager = $this->createMock(IAppManager::class); - $this->mountCollection = $this->createMock(IMountProviderCollection::class); - $this->rootFolder = $this->createMock(IRootFolder::class); - $this->listener = new Listener($this->groupManager, $this->activityManager, - $this->userSession, $this->tagManager, $this->appManager, - $this->mountCollection, $this->rootFolder); - } - - public function prepareTagAsParameterProvider() { - return [ - [new SystemTag('1', 'visibleTag', true, true, true), "{{{visibleTag|||assignable}}}"], - [new SystemTag('2', 'invisibleTag', false, false, false), "{{{invisibleTag|||invisible}}}"], - [new SystemTag('3', 'restrictTag', true, false, false), "{{{restrictTag|||not-assignable}}}"], - [new SystemTag('3', 'staticTag', true, true, false), "{{{staticTag|||not-editable}}}"], - ]; - } - - /** - * @dataProvider prepareTagAsParameterProvider - */ - public function testPrepareTagAsParameter(SystemTag $tag, $expectedResult) { - $result = $this->invokePrivate($this->listener, 'prepareTagAsParameter', [$tag]); - $this->assertEquals($expectedResult, $result); - } -} diff --git a/apps/systemtags/tests/ExtensionTest.php b/apps/systemtags/tests/unit/activity/ExtensionTest.php similarity index 100% rename from apps/systemtags/tests/ExtensionTest.php rename to apps/systemtags/tests/unit/activity/ExtensionTest.php diff --git a/apps/systemtags/tests/unit/activity/ListenerTest.php b/apps/systemtags/tests/unit/activity/ListenerTest.php new file mode 100644 index 000000000000..1ecc2df62897 --- /dev/null +++ b/apps/systemtags/tests/unit/activity/ListenerTest.php @@ -0,0 +1,218 @@ + + * + * @copyright Copyright (c) 2018, ownCloud GmbH + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OCA\SystemTags\Tests\unit; + +use Test\Traits\UserTrait; +use OCA\SystemTags\Activity\Listener; +use OCA\SystemTags\Activity\Extension; +use OCP\IUserSession; +use OCP\Activity\IManager; +use OCP\App\IAppManager; +use OCP\Files\Config\IMountProviderCollection; +use OCP\Files\IRootFolder; +use OCP\Files\Config\IUserMountCache; +use OCP\Files\Config\ICachedMountInfo; +use OCP\IUser; +use OCP\Files\Folder; +use OCP\Activity\IEvent; +use OCP\SystemTag\MapperEvent; +use OCP\IGroupManager; +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\ISystemTag; +use OC\SystemTag\SystemTag; + +/** + * Tests for the activity listener + * + * @group DB + */ +class ActivityListenerTest extends \Test\TestCase { + use UserTrait; + + /** + * @var IGroupManager + */ + private $groupManager; + + /** + * @var ISystemTagManager + */ + private $tagManager; + + /** + * @var Listener + */ + private $listener; + + /** + * @var IUserMountCache + */ + private $userMountCache; + + /** + * @var IRootFolder + */ + private $rootFolder; + + /** + * @var IUserSession + */ + private $userSession; + + /** + * @var IManager + */ + private $activityManager; + + protected function setUp() { + parent::setUp(); + + $this->groupManager = $this->createMock(IGroupManager::class); + + $this->tagManager = $this->createMock(ISystemTagManager::class); + $this->activityManager = $this->createMock(IManager::class); + $this->userSession = $this->createMock(IUserSession::class); + + $appManager = $this->createMock(IAppManager::class); + $appManager->method('isInstalled')->with('activity')->willReturn(true); + + $this->userMountCache = $this->createMock(IUserMountCache::class); + + $mountProviderCollection = $this->createMock(IMountProviderCollection::class); + $mountProviderCollection->method('getMountCache')->willReturn($this->userMountCache); + + $this->rootFolder = $this->createMock(IRootFolder::class); + + $this->listener = $this->getMockBuilder(Listener::class) + ->setConstructorArgs([ + $this->groupManager, + $this->activityManager, + $this->userSession, + $this->tagManager, + $appManager, + $mountProviderCollection, + $this->rootFolder + ]) + ->setMethods(['getUsersSharingFile']) + ->getMock(); + } + + public function providesEventTypes() { + return [ + [MapperEvent::EVENT_ASSIGN, Extension::ASSIGN_TAG], + [MapperEvent::EVENT_UNASSIGN, Extension::UNASSIGN_TAG], + ]; + } + + /** + * @dataProvider providesEventTypes + */ + public function testActivityOnMapperEvent($eventType, $extensionEvent) { + $user = $this->createMock(IUser::class); + $user->method('getUID')->willReturn('user1'); + + $actor = $this->createMock(IUser::class); + $actor->method('getUID')->willReturn('actor1'); + + $this->userSession->method('getUser')->willReturn($actor); + + $tag1 = $this->createMock(ISystemTag::class); + $tag1->method('isUserVisible')->willReturn(true); + $tag1->method('isUserAssignable')->willReturn(true); + $tag1->method('isUserEditable')->willReturn(true); + $tag1->method('getName')->willReturn('tag1'); + + $tag2 = $this->createMock(ISystemTag::class); + $tag2->method('isUserVisible')->willReturn(true); + $tag2->method('isUserAssignable')->willReturn(false); + $tag2->method('isUserEditable')->willReturn(false); + $tag2->method('getName')->willReturn('tag2'); + + $invisibleTag = $this->createMock(ISystemTag::class); + $invisibleTag->method('isUserVisible')->willReturn(false); + + $this->groupManager->method('isAdmin')->willReturn(false); + + $this->tagManager->method('getTagsByIds') + ->with([111, 222, 333]) + ->willReturn([$tag1, $tag2, $invisibleTag]); + + $cachedMountInfo = $this->createMock(ICachedMountInfo::class); + $cachedMountInfo->method('getUser')->willReturn($user); + + $node = $this->createMock(Folder::class); + $node->method('getPath')->willReturn('/user1/files/folder'); + + $ownerFolder = $this->createMock(Folder::class); + $ownerFolder->method('getById') + ->with(123, true) + ->willReturn([$node]); + + $this->rootFolder->method('getUserFolder') + ->with('user1') + ->willReturn($ownerFolder); + + $this->userMountCache->method('getMountsForFileId') + ->with(123) + ->willReturn([$cachedMountInfo]); + + $this->listener->method('getUsersSharingFile')->willReturn(['user1' => '/folder']); + + $activityEvent = $this->createMock(IEvent::class); + $activityEvent->expects($this->once())->method('setApp')->with('systemtags')->willReturn($activityEvent); + $activityEvent->expects($this->once())->method('setType')->with('systemtags')->willReturn($activityEvent); + $activityEvent->expects($this->once())->method('setAuthor')->with('actor1')->willReturn($activityEvent); + $activityEvent->expects($this->once())->method('setObject')->with('files', 123)->willReturn($activityEvent); + $activityEvent->expects($this->exactly(2))->method('setSubject') + ->withConsecutive( + [$extensionEvent, ['actor1', '/folder', '{{{tag1|||assignable}}}']], + [$extensionEvent, ['actor1', '/folder', '{{{tag2|||not-assignable}}}']] + ) + ->willReturn($activityEvent); + + $this->activityManager->method('generateEvent') + ->willReturn($activityEvent); + $this->activityManager->expects($this->exactly(2)) + ->method('publish') + ->with($activityEvent); + + $event = new MapperEvent($eventType, 'files', 123, [111, 222, 333]); + $this->listener->mapperEvent($event); + } + + public function prepareTagAsParameterProvider() { + return [ + [new SystemTag('1', 'visibleTag', true, true, true), "{{{visibleTag|||assignable}}}"], + [new SystemTag('2', 'invisibleTag', false, false, false), "{{{invisibleTag|||invisible}}}"], + [new SystemTag('3', 'restrictTag', true, false, false), "{{{restrictTag|||not-assignable}}}"], + [new SystemTag('3', 'staticTag', true, true, false), "{{{staticTag|||not-editable}}}"], + ]; + } + + /** + * @dataProvider prepareTagAsParameterProvider + */ + public function testPrepareTagAsParameter(SystemTag $tag, $expectedResult) { + $result = $this->invokePrivate($this->listener, 'prepareTagAsParameter', [$tag]); + $this->assertEquals($expectedResult, $result); + } +} diff --git a/tests/lib/Files/MetaFilesTest.php b/tests/lib/Files/MetaFilesTest.php index 28bac72710ff..9db1638234dd 100644 --- a/tests/lib/Files/MetaFilesTest.php +++ b/tests/lib/Files/MetaFilesTest.php @@ -43,11 +43,36 @@ class MetaFilesTest extends TestCase { use UserTrait; + /** + * @var string + */ + private $userId; + + protected function setUp() { + parent::setUp(); + + // workaround: re-setup versions hooks + Hooks::connectHooks(); + + $this->userId = $this->getUniqueID('meta-data-user-'); + $this->createUser($this->userId); + $this->loginAsUser($this->userId); + } + protected function tearDown() { self::logout(); parent::tearDown(); } + private function createFile() { + // create file + $file = $this->getUniqueID('file') . '.txt'; + $fileName = "{$this->userId}/files/$file"; + $view = new View(); + $view->file_put_contents($fileName, '1234'); + return $view->getFileInfo($fileName); + } + /** * @throws \Exception * @throws \OCP\Files\ForbiddenException @@ -55,17 +80,11 @@ protected function tearDown() { * @throws \OCP\Files\NotPermittedException */ public function testMetaInNodeAPI() { - // workaround: re-setup versions hooks - Hooks::connectHooks(); - - // create user - $userId = 'meta-data-user'; - $this->createUser($userId); - $this->loginAsUser($userId); + $userId = $this->userId; // create file $file = $this->getUniqueID('file') . '.txt'; - $fileName = "$userId/files/$file"; + $fileName = "{$this->userId}/files/$file"; $view = new View(); $view->file_put_contents($fileName, '1234'); $info = $view->getFileInfo($fileName); @@ -124,4 +143,25 @@ public function testMetaInNodeAPI() { $metaNodeOfFile->copy($fileName); $this->assertEquals('1234', $target->getContent()); } + + public function testMetaRootGetById() { + $info = $this->createFile(); + + $metaRoot = \OC::$server->getRootFolder(); + $info2 = $metaRoot->getById($info->getId()); + + $this->assertEquals($info->getId(), $info2[0]->getId()); + $this->assertEquals($info->getPath(), $info2[0]->getPath()); + } + + /** + * @expectedException OCP\Files\NotFoundException + */ + public function testMetaRootGetNotFound() { + $info = $this->createFile(); + + $metaRoot = \OC::$server->getRootFolder(); + // get non-existing + $metaRoot->get($info->getId() + 100); + } } diff --git a/tests/lib/Files/MetaVersionCollectionTest.php b/tests/lib/Files/MetaVersionCollectionTest.php new file mode 100644 index 000000000000..0659d6057361 --- /dev/null +++ b/tests/lib/Files/MetaVersionCollectionTest.php @@ -0,0 +1,166 @@ + + * + * @copyright Copyright (c) 2018, ownCloud GmbH + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace Test\Files; + +use Test\TestCase; +use OCP\Files\Node; +use OC\Files\Meta\MetaVersionCollection; +use OCP\Files\IRootFolder; +use OCP\Files\Storage\IStorage; +use OCA\Files_Sharing\External\Storage; +use OCP\Files\Storage\IVersionedStorage; +use OC\Files\Meta\MetaFileVersionNode; + +/** + * Class MetaFilesTest + * + * @package Test\Files + */ +class MetaVersionCollectionTest extends TestCase { + + /** + * @var Node + */ + private $node; + + /** + * @var IRootFolder + */ + private $rootFolder; + + /** + * @var MetaVersionCollection + */ + private $collection; + + /** + * @var IStorage|IVersionedStorage + */ + private $storage; + + protected function setUp() { + parent::setUp(); + + $this->rootFolder = $this->createMock(IRootFolder::class); + $this->node = $this->createMock(Node::class); + $this->storage = $this->createMock([IStorage::class, IVersionedStorage::class]); + $this->node->method('getStorage')->willReturn($this->storage); + $this->collection = new MetaVersionCollection($this->rootFolder, $this->node); + } + + protected function tearDown() { + parent::tearDown(); + } + + public function testGetDirectoryListing() { + $this->node->method('getInternalPath')->willReturn('/abc'); + $this->node->method('getMimetype')->willReturn('application/json'); + + $this->storage->method('instanceOfStorage') + ->with(IVersionedStorage::class) + ->willReturn(true); + + $this->storage->expects($this->once()) + ->method('getVersions') + ->with('/abc') + ->willReturn([ + ['version' => '1014', 'timestamp' => 12345678], + ['version' => '1015', 'mimetype' => 'text/plain', 'timestamp' => 12345679], + ]); + + $children = $this->collection->getDirectoryListing(); + + $this->assertCount(2, $children); + $this->assertInstanceOf(MetaFileVersionNode::class, $children[0]); + $this->assertEquals('1014', $children[0]->getName()); + $this->assertEquals('application/json', $children[0]->getMimetype()); + $this->assertEquals(12345678, $children[0]->getMtime()); + $this->assertInstanceOf(MetaFileVersionNode::class, $children[1]); + $this->assertEquals('1015', $children[1]->getName()); + $this->assertEquals('text/plain', $children[1]->getMimetype()); + $this->assertEquals(12345679, $children[1]->getMtime()); + } + + public function testGetDirectoryListingNonVersionedStorage() { + $this->node->method('getInternalPath')->willReturn('/abc'); + $this->node->method('getMimetype')->willReturn('application/json'); + + $this->storage->method('instanceOfStorage') + ->with(IVersionedStorage::class) + ->willReturn(false); + + $this->storage->expects($this->never()) + ->method('getVersions'); + + $children = $this->collection->getDirectoryListing(); + + $this->assertCount(0, $children); + } + + public function testGet() { + $this->node->method('getInternalPath')->willReturn('/abc'); + $this->node->method('getMimetype')->willReturn('application/json'); + + $this->storage->method('instanceOfStorage') + ->with(IVersionedStorage::class) + ->willReturn(true); + + $this->storage->expects($this->once()) + ->method('getVersion') + ->with('/abc', '1014') + ->willReturn(['version' => '1014', 'timestamp' => 12345678]); + + $result = $this->collection->get('1014'); + + $this->assertInstanceOf(MetaFileVersionNode::class, $result); + $this->assertEquals('1014', $result->getName()); + $this->assertEquals('application/json', $result->getMimetype()); + $this->assertEquals(12345678, $result->getMtime()); + } + + /** + * @expectedException OCP\Files\NotFoundException + */ + public function testGetNonVersionedStorageFails() { + $this->node->method('getInternalPath')->willReturn('/abc'); + $this->node->method('getMimetype')->willReturn('application/json'); + + $this->storage->method('instanceOfStorage') + ->with(IVersionedStorage::class) + ->willReturn(false); + + $this->storage->expects($this->never()) + ->method('getVersion'); + + $this->collection->get('1014'); + } + + /** + * @expectedException OCP\Files\NotFoundException + */ + public function testGetSubEntryFails() { + $this->storage->expects($this->never()) + ->method('instanceOfStorage'); + + $this->collection->get('1014/1'); + } +} diff --git a/tests/lib/Files/Storage/Wrapper/JailTest.php b/tests/lib/Files/Storage/Wrapper/JailTest.php index 122953e9e54d..1b8f708155a5 100644 --- a/tests/lib/Files/Storage/Wrapper/JailTest.php +++ b/tests/lib/Files/Storage/Wrapper/JailTest.php @@ -8,6 +8,9 @@ namespace Test\Files\Storage\Wrapper; +use OCP\Files\Storage\IStorage; +use OCP\Files\Storage\IVersionedStorage; + class JailTest extends \Test\Files\Storage\Storage { /** @@ -48,4 +51,37 @@ public function testFilePutContentsRooted() { $this->instance->file_put_contents('bar', 'asd'); $this->assertEquals('asd', $this->sourceStorage->file_get_contents('foo/bar')); } + + public function providesVersionMethods() { + return [ + ['getContentOfVersion', 1014], + ['restoreVersion', 1014], + ['saveVersion'], + ['getVersions'], + ['getVersion', 1014], + ]; + } + + /** + * @dataProvider providesVersionMethods + */ + public function testCallsSourceVersionMethods($method, $extraArg = null) { + $sourceStorage = $this->createMock([IStorage::class, IVersionedStorage::class]); + $instance = new \OC\Files\Storage\Wrapper\Jail([ + 'storage' => $sourceStorage, + 'root' => 'foo' + ]); + + $matcher = $sourceStorage->expects($this->once()) + ->method($method); + // FIXME: normalize path... + if ($extraArg !== null) { + $matcher = $matcher->with('foo//bar', $extraArg); + } else { + $matcher = $matcher->with('foo//bar'); + } + $matcher->willReturn('returnValue'); + + $this->assertEquals('returnValue', $instance->$method('/bar', $extraArg)); + } }