diff options
author | Vincent Petry <pvince81@owncloud.com> | 2016-07-12 13:38:49 +0200 |
---|---|---|
committer | Roeland Jago Douma <roeland@famdouma.nl> | 2016-08-03 10:16:28 +0200 |
commit | 67fa6bf9bce6d237684ebd3f60625ff98abc71c0 (patch) | |
tree | b83d18579d72a5f51387e5621774baf5bbba4b0a /tests | |
parent | 714d7ec9368c7afc2a73cc49ba1342413ba9d90d (diff) | |
download | nextcloud-server-67fa6bf9bce6d237684ebd3f60625ff98abc71c0.tar.gz nextcloud-server-67fa6bf9bce6d237684ebd3f60625ff98abc71c0.zip |
Add repair step for unmerged shares (WIP)
Diffstat (limited to 'tests')
-rw-r--r-- | tests/lib/Repair/RepairUnmergedSharesTest.php | 409 |
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']); + } + } +} + |