Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorVincent Petry <pvince81@owncloud.com>2016-07-20 17:48:54 +0300
committerThomas Müller <thomas.mueller@tmit.eu>2016-08-13 18:10:13 +0300
commitfd0f40383f4334ad5f9fb2ebc8893a7fdd653708 (patch)
tree513f265a21974101cf88ecadce13a077ae38faba /tests
parentc3e7cf5030f96fb733eeb3bac985a49d55f6995a (diff)
Add repair step for unmerged shares
Diffstat (limited to 'tests')
-rw-r--r--tests/lib/repair/repairunmergedsharestest.php409
1 files changed, 409 insertions, 0 deletions
diff --git a/tests/lib/repair/repairunmergedsharestest.php b/tests/lib/repair/repairunmergedsharestest.php
new file mode 100644
index 00000000000..20dabac2e6b
--- /dev/null
+++ b/tests/lib/repair/repairunmergedsharestest.php
@@ -0,0 +1,409 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace Test\Repair;
+
+
+use OC\Repair\RepairUnmergedShares;
+use OC\Share\Constants;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+use Test\TestCase;
+use OC\Share20\DefaultShareProvider;
+
+/**
+ * Tests for repairing invalid shares
+ *
+ * @group DB
+ *
+ * @see \OC\Repair\RepairUnmergedShares
+ */
+class RepairUnmergedSharesTest extends TestCase {
+
+ /** @var IRepairStep */
+ private $repair;
+
+ /** @var \OCP\IDBConnection */
+ private $connection;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $config = $this->getMockBuilder('OCP\IConfig')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $config->expects($this->any())
+ ->method('getSystemValue')
+ ->with('version')
+ ->will($this->returnValue('9.0.3.0'));
+
+ $this->connection = \OC::$server->getDatabaseConnection();
+ $this->deleteAllShares();
+
+ $user1 = $this->getMock('\OCP\IUser');
+ $user1->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('user1'));
+
+ $user2 = $this->getMock('\OCP\IUser');
+ $user2->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('user2'));
+
+ $users = [$user1, $user2];
+
+ $groupManager = $this->getMock('\OCP\IGroupManager');
+ $groupManager->expects($this->any())
+ ->method('getUserGroupIds')
+ ->will($this->returnValueMap([
+ // owner
+ [$user1, ['samegroup1', 'samegroup2']],
+ // recipient
+ [$user2, ['recipientgroup1', 'recipientgroup2']],
+ ]));
+
+ $userManager = $this->getMock('\OCP\IUserManager');
+ $userManager->expects($this->once())
+ ->method('countUsers')
+ ->will($this->returnValue([2]));
+ $userManager->expects($this->once())
+ ->method('callForAllUsers')
+ ->will($this->returnCallback(function(\Closure $closure) use ($users) {
+ foreach ($users as $user) {
+ $closure($user);
+ }
+ }));
+
+ /** @var \OCP\IConfig $config */
+ $this->repair = new RepairUnmergedShares($config, $this->connection, $userManager, $groupManager);
+ }
+
+ protected function tearDown() {
+ $this->deleteAllShares();
+
+ parent::tearDown();
+ }
+
+ protected function deleteAllShares() {
+ $qb = $this->connection->getQueryBuilder();
+ $qb->delete('share')->execute();
+ }
+
+ private function createShare($type, $sourceId, $recipient, $targetName, $permissions, $parentId = null) {
+ $qb = $this->connection->getQueryBuilder();
+ $values = [
+ 'share_type' => $qb->expr()->literal($type),
+ 'share_with' => $qb->expr()->literal($recipient),
+ 'uid_owner' => $qb->expr()->literal('user1'),
+ 'item_type' => $qb->expr()->literal('folder'),
+ 'item_source' => $qb->expr()->literal($sourceId),
+ 'item_target' => $qb->expr()->literal('/' . $sourceId),
+ 'file_source' => $qb->expr()->literal($sourceId),
+ 'file_target' => $qb->expr()->literal($targetName),
+ 'permissions' => $qb->expr()->literal($permissions),
+ 'stime' => $qb->expr()->literal(time()),
+ ];
+ if ($parentId !== null) {
+ $values['parent'] = $qb->expr()->literal($parentId);
+ }
+ $qb->insert('share')
+ ->values($values)
+ ->execute();
+
+ return $this->connection->lastInsertId('*PREFIX*share');
+ }
+
+ private function getShareById($id) {
+ $query = $this->connection->getQueryBuilder();
+ $results = $query
+ ->select('*')
+ ->from('share')
+ ->where($query->expr()->eq('id', $query->expr()->literal($id)))
+ ->execute()
+ ->fetchAll();
+
+ if (!empty($results)) {
+ return $results[0];
+ }
+ return null;
+ }
+
+ public function sharesDataProvider() {
+ /**
+ * For all these test cases we have the following situation:
+ *
+ * - "user1" is the share owner
+ * - "user2" is the recipient, and member of "recipientgroup1" and "recipientgroup2"
+ * - "user1" is member of "samegroup1", "samegroup2" for same group tests
+ */
+ return [
+ [
+ // #0 legitimate share:
+ // - outsider shares with group1, group2
+ // - recipient renamed, resulting in subshares
+ // - one subshare for each group share
+ // - targets of subshare all match
+ [
+ [Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 31],
+ [Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup2', '/test', 31],
+ // child of the previous ones
+ [DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test renamed', 31, 0],
+ // child of the previous ones
+ [DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test renamed', 31, 1],
+ // different unrelated share
+ [Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
+ ],
+ [
+ ['/test', 31],
+ ['/test', 31],
+ // leave them alone
+ ['/test renamed', 31],
+ ['/test renamed', 31],
+ // leave unrelated alone
+ ['/test (4)', 31],
+ ]
+ ],
+ [
+ // #1 broken share:
+ // - outsider shares with group1, group2
+ // - only one subshare for two group shares
+ [
+ [Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 31],
+ [Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup2', '/test', 31],
+ // child of the previous one
+ [DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (2)', 31, 1],
+ // different unrelated share
+ [Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
+ ],
+ [
+ ['/test', 31],
+ ['/test', 31],
+ ['/test', 31],
+ // leave unrelated alone
+ ['/test (4)', 31],
+ ]
+ ],
+ [
+ // #2 bogus share
+ // - outsider shares with group1, group2
+ // - one subshare for each group share
+ // - but the targets do not match when grouped
+ [
+ [Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 31],
+ [Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup2', '/test', 31],
+ // child of the previous ones
+ [DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (2)', 31, 0],
+ [DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (3)', 31, 1],
+ // different unrelated share
+ [Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
+ ],
+ [
+ ['/test', 31],
+ ['/test', 31],
+ // reset to original name
+ ['/test', 31],
+ ['/test', 31],
+ // leave unrelated alone
+ ['/test (4)', 31],
+ ]
+ ],
+ [
+ // #3 bogus share
+ // - outsider shares with group1, group2
+ // - one subshare for each group share
+ // - first subshare not renamed (as in real world scenario)
+ // - but the targets do not match when grouped
+ [
+ [Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 31],
+ [Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup2', '/test', 31],
+ // child of the previous ones
+ [DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test', 31, 0],
+ [DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (2)', 31, 1],
+ // different unrelated share
+ [Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
+ ],
+ [
+ ['/test', 31],
+ ['/test', 31],
+ // reset to original name
+ ['/test', 31],
+ ['/test', 31],
+ // leave unrelated alone
+ ['/test (4)', 31],
+ ]
+ ],
+ [
+ // #4 bogus share:
+ // - outsider shares with group1, group2
+ // - one subshare for each group share
+ // - non-matching targets
+ // - recipient deletes one duplicate (unshare from self, permissions 0)
+ [
+ [Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 31],
+ [Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup2', '/test', 15],
+ // child of the previous ones
+ [DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (2)', 0, 0],
+ [DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (3)', 15, 1],
+ // different unrelated share
+ [Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
+ ],
+ [
+ ['/test', 31],
+ ['/test', 15],
+ // subshares repaired and permissions restored to the max allowed
+ ['/test', 31],
+ ['/test', 15],
+ // leave unrelated alone
+ ['/test (4)', 31],
+ ]
+ ],
+ [
+ // #5 bogus share:
+ // - outsider shares with group1, group2
+ // - one subshare for each group share
+ // - non-matching targets
+ // - recipient deletes ALL duplicates (unshare from self, permissions 0)
+ [
+ [Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 31],
+ [Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup2', '/test', 15],
+ // child of the previous ones
+ [DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (2)', 0, 0],
+ [DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (3)', 0, 1],
+ // different unrelated share
+ [Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
+ ],
+ [
+ ['/test', 31],
+ ['/test', 15],
+ // subshares target repaired but left "deleted" as it was the user's choice
+ ['/test', 0],
+ ['/test', 0],
+ // leave unrelated alone
+ ['/test (4)', 31],
+ ]
+ ],
+ [
+ // #6 bogus share:
+ // - outsider shares with group1, group2 and also user2
+ // - one subshare for each group share
+ // - one extra share entry for direct share to user2
+ // - non-matching targets
+ // - user share has more permissions
+ [
+ [Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 1],
+ [Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup2', '/test', 15],
+ // child of the previous ones
+ [DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (2)', 1, 0],
+ [DefaultShareProvider::SHARE_TYPE_USERGROUP, 123, 'user2', '/test (3)', 15, 1],
+ [Constants::SHARE_TYPE_USER, 123, 'user2', '/test (4)', 31],
+ // different unrelated share
+ [Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (5)', 31],
+ ],
+ [
+ ['/test', 1],
+ ['/test', 15],
+ // subshares repaired
+ ['/test', 1],
+ ['/test', 15],
+ ['/test', 31],
+ // leave unrelated alone
+ ['/test (5)', 31],
+ ]
+ ],
+ [
+ // #7 legitimate share with own group:
+ // - insider shares with both groups the user is already in
+ // - no subshares in this case
+ [
+ [Constants::SHARE_TYPE_GROUP, 123, 'samegroup1', '/test', 31],
+ [Constants::SHARE_TYPE_GROUP, 123, 'samegroup2', '/test', 31],
+ // different unrelated share
+ [Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
+ ],
+ [
+ // leave all alone
+ ['/test', 31],
+ ['/test', 31],
+ // leave unrelated alone
+ ['/test (4)', 31],
+ ]
+ ],
+ [
+ // #7 legitimate shares:
+ // - group share with same group
+ // - group share with other group
+ // - user share where recipient renamed
+ // - user share where recipient did not rename
+ [
+ [Constants::SHARE_TYPE_GROUP, 123, 'samegroup1', '/test', 31],
+ [Constants::SHARE_TYPE_GROUP, 123, 'recipientgroup1', '/test', 31],
+ [Constants::SHARE_TYPE_USER, 123, 'user3', '/test legit rename', 31],
+ [Constants::SHARE_TYPE_USER, 123, 'user4', '/test', 31],
+ // different unrelated share
+ [Constants::SHARE_TYPE_GROUP, 456, 'recipientgroup1', '/test (4)', 31],
+ ],
+ [
+ // leave all alone
+ ['/test', 31],
+ ['/test', 31],
+ ['/test legit rename', 31],
+ ['/test', 31],
+ // leave unrelated alone
+ ['/test (4)', 31],
+ ]
+ ],
+ ];
+ }
+
+ /**
+ * Test merge shares from group shares
+ *
+ * @dataProvider sharesDataProvider
+ */
+ public function testMergeGroupShares($shares, $expectedShares) {
+ $shareIds = [];
+
+ foreach ($shares as $share) {
+ // if parent
+ if (isset($share[5])) {
+ // adjust to real id
+ $share[5] = $shareIds[$share[5]];
+ } else {
+ $share[5] = null;
+ }
+ $shareIds[] = $this->createShare($share[0], $share[1], $share[2], $share[3], $share[4], $share[5]);
+ }
+
+ /** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */
+ $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->repair->run($outputMock);
+
+ foreach ($expectedShares as $index => $expectedShare) {
+ $share = $this->getShareById($shareIds[$index]);
+ $this->assertEquals($expectedShare[0], $share['file_target']);
+ $this->assertEquals($expectedShare[1], $share['permissions']);
+ }
+ }
+}
+