diff options
Diffstat (limited to 'tests/lib/Repair')
-rw-r--r-- | tests/lib/Repair/CleanTagsTest.php | 181 | ||||
-rw-r--r-- | tests/lib/Repair/DropOldJobsTest.php | 48 | ||||
-rw-r--r-- | tests/lib/Repair/DropOldTablesTest.php | 46 | ||||
-rw-r--r-- | tests/lib/Repair/OldGroupMembershipSharesTest.php | 136 | ||||
-rw-r--r-- | tests/lib/Repair/RemoveGetETagEntriesTest.php | 90 | ||||
-rw-r--r-- | tests/lib/Repair/RepairCollationTest.php | 88 | ||||
-rw-r--r-- | tests/lib/Repair/RepairInnoDBTest.php | 78 | ||||
-rw-r--r-- | tests/lib/Repair/RepairInvalidSharesTest.php | 201 | ||||
-rw-r--r-- | tests/lib/Repair/RepairLegacyStoragesTest.php | 335 | ||||
-rw-r--r-- | tests/lib/Repair/RepairMimeTypesTest.php | 582 | ||||
-rw-r--r-- | tests/lib/Repair/RepairSharePropagationTest.php | 57 | ||||
-rw-r--r-- | tests/lib/Repair/RepairSqliteAutoincrementTest.php | 89 | ||||
-rw-r--r-- | tests/lib/Repair/UpdateOutdatedOcsIdsTest.php | 80 | ||||
-rw-r--r-- | tests/lib/Repair/fixtures/dropoldtables.xml | 24 |
14 files changed, 2035 insertions, 0 deletions
diff --git a/tests/lib/Repair/CleanTagsTest.php b/tests/lib/Repair/CleanTagsTest.php new file mode 100644 index 00000000000..804fa4f66c9 --- /dev/null +++ b/tests/lib/Repair/CleanTagsTest.php @@ -0,0 +1,181 @@ +<?php +/** + * Copyright (c) 2015 Joas Schilling <nickvergessen@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Repair; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\Migration\IOutput; + +/** + * Tests for the cleaning the tags tables + * + * @group DB + * + * @see \OC\Repair\CleanTags + */ +class CleanTagsTest extends \Test\TestCase { + + /** @var \OC\Repair\CleanTags */ + protected $repair; + + /** @var \OCP\IDBConnection */ + protected $connection; + + /** @var int */ + protected $createdFile; + + /** @var IOutput */ + private $outputMock; + + protected function setUp() { + parent::setUp(); + + $this->outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + ->disableOriginalConstructor() + ->getMock(); + + $this->connection = \OC::$server->getDatabaseConnection(); + $this->repair = new \OC\Repair\CleanTags($this->connection); + $this->cleanUpTables(); + } + + protected function tearDown() { + $this->cleanUpTables(); + + parent::tearDown(); + } + + protected function cleanUpTables() { + $qb = $this->connection->getQueryBuilder(); + $qb->delete('vcategory') + ->execute(); + + $qb->delete('vcategory_to_object') + ->execute(); + + $qb->delete('filecache') + ->execute(); + } + + public function testRun() { + $cat1 = $this->addTagCategory('TestRepairCleanTags', 'files'); // Retained + $cat2 = $this->addTagCategory('TestRepairCleanTags2', 'files'); // Deleted: Category will be empty + $this->addTagCategory('TestRepairCleanTags3', 'files'); // Deleted: Category is empty + $cat3 = $this->addTagCategory('TestRepairCleanTags', 'contacts'); // Retained + + $this->addTagEntry($this->getFileID(), $cat2, 'files'); // Retained + $this->addTagEntry($this->getFileID() + 1, $cat1, 'files'); // Deleted: File is NULL + $this->addTagEntry(9999999, $cat3, 'contacts'); // Retained + $this->addTagEntry($this->getFileID(), $cat3 + 1, 'files'); // Deleted: Category is NULL + + $this->assertEntryCount('vcategory_to_object', 4, 'Assert tag entries count before repair step'); + $this->assertEntryCount('vcategory', 4, 'Assert tag categories count before repair step'); + + self::invokePrivate($this->repair, 'deleteOrphanFileEntries', [$this->outputMock]); + $this->assertEntryCount('vcategory_to_object', 3, 'Assert tag entries count after cleaning file entries'); + $this->assertEntryCount('vcategory', 4, 'Assert tag categories count after cleaning file entries'); + + self::invokePrivate($this->repair, 'deleteOrphanTagEntries', [$this->outputMock]); + $this->assertEntryCount('vcategory_to_object', 2, 'Assert tag entries count after cleaning tag entries'); + $this->assertEntryCount('vcategory', 4, 'Assert tag categories count after cleaning tag entries'); + + self::invokePrivate($this->repair, 'deleteOrphanCategoryEntries', [$this->outputMock]); + $this->assertEntryCount('vcategory_to_object', 2, 'Assert tag entries count after cleaning category entries'); + $this->assertEntryCount('vcategory', 2, 'Assert tag categories count after cleaning category entries'); + } + + /** + * @param string $tableName + * @param int $expected + * @param string $message + */ + protected function assertEntryCount($tableName, $expected, $message = '') { + $qb = $this->connection->getQueryBuilder(); + $result = $qb->select($qb->createFunction('COUNT(*)')) + ->from($tableName) + ->execute(); + + $this->assertEquals($expected, $result->fetchColumn(), $message); + } + + /** + * Adds a new tag category to the database + * + * @param string $category + * @param string $type + * @return int + */ + protected function addTagCategory($category, $type) { + $qb = $this->connection->getQueryBuilder(); + $qb->insert('vcategory') + ->values([ + 'uid' => $qb->createNamedParameter('TestRepairCleanTags'), + 'category' => $qb->createNamedParameter($category), + 'type' => $qb->createNamedParameter($type), + ]) + ->execute(); + + return (int) $this->getLastInsertID('vcategory', 'id'); + } + + /** + * Adds a new tag entry to the database + * @param int $objectId + * @param int $category + * @param string $type + */ + protected function addTagEntry($objectId, $category, $type) { + $qb = $this->connection->getQueryBuilder(); + $qb->insert('vcategory_to_object') + ->values([ + 'objid' => $qb->createNamedParameter($objectId, IQueryBuilder::PARAM_INT), + 'categoryid' => $qb->createNamedParameter($category, IQueryBuilder::PARAM_INT), + 'type' => $qb->createNamedParameter($type), + ]) + ->execute(); + } + + /** + * Gets the last fileid from the file cache + * @return int + */ + protected function getFileID() { + if ($this->createdFile) { + return $this->createdFile; + } + + $qb = $this->connection->getQueryBuilder(); + + // We create a new file entry and delete it after the test again + $fileName = $this->getUniqueID('TestRepairCleanTags', 12); + $qb->insert('filecache') + ->values([ + 'path' => $qb->createNamedParameter($fileName), + 'path_hash' => $qb->createNamedParameter(md5($fileName)), + ]) + ->execute(); + $fileName = $this->getUniqueID('TestRepairCleanTags', 12); + $qb->insert('filecache') + ->values([ + 'path' => $qb->createNamedParameter($fileName), + 'path_hash' => $qb->createNamedParameter(md5($fileName)), + ]) + ->execute(); + + $this->createdFile = (int) $this->getLastInsertID('filecache', 'fileid'); + return $this->createdFile; + } + + /** + * @param $tableName + * @param $idName + * @return int + */ + protected function getLastInsertID($tableName, $idName) { + return $this->connection->lastInsertId("*PREFIX*$tableName"); + } +} diff --git a/tests/lib/Repair/DropOldJobsTest.php b/tests/lib/Repair/DropOldJobsTest.php new file mode 100644 index 00000000000..d83ecbe59c4 --- /dev/null +++ b/tests/lib/Repair/DropOldJobsTest.php @@ -0,0 +1,48 @@ +<?php +/** + * Copyright (c) 2015 Arthur Schiwon <blizzz@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Repair; + +use OCP\BackgroundJob\IJobList; +use OCP\Migration\IOutput; + +/** + * Tests for the dropping old tables + * + * @group DB + * + * @see \OC\Repair\DropOldTables + */ +class DropOldJobsTest extends \Test\TestCase { + /** @var IJobList */ + protected $jobList; + + protected function setUp() { + parent::setUp(); + + $this->jobList = \OC::$server->getJobList(); + $this->jobList->add('OC\Cache\FileGlobalGC'); + $this->jobList->add('OC_Cache_FileGlobalGC'); + } + + public function testRun() { + $this->assertTrue($this->jobList->has('OC\Cache\FileGlobalGC', null), 'Asserting that the job OC\Cache\FileGlobalGC exists before repairing'); + $this->assertTrue($this->jobList->has('OC_Cache_FileGlobalGC', null), 'Asserting that the job OC_Cache_FileGlobalGC exists before repairing'); + + /** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */ + $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + ->disableOriginalConstructor() + ->getMock(); + + $repair = new \OC\Repair\DropOldJobs($this->jobList); + $repair->run($outputMock); + + $this->assertFalse($this->jobList->has('OC\Cache\FileGlobalGC', null), 'Asserting that the job OC\Cache\FileGlobalGC does not exist after repairing'); + $this->assertFalse($this->jobList->has('OC_Cache_FileGlobalGC', null), 'Asserting that the job OC_Cache_FileGlobalGC does not exist after repairing'); + } +} diff --git a/tests/lib/Repair/DropOldTablesTest.php b/tests/lib/Repair/DropOldTablesTest.php new file mode 100644 index 00000000000..1f5a4c15295 --- /dev/null +++ b/tests/lib/Repair/DropOldTablesTest.php @@ -0,0 +1,46 @@ +<?php +/** + * Copyright (c) 2015 Joas Schilling <nickvergessen@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Repair; +use OCP\Migration\IOutput; + +/** + * Tests for the dropping old tables + * + * @group DB + * + * @see \OC\Repair\DropOldTables + */ +class DropOldTablesTest extends \Test\TestCase { + /** @var \OCP\IDBConnection */ + protected $connection; + + protected function setUp() { + parent::setUp(); + + $this->connection = \OC::$server->getDatabaseConnection(); + $manager = new \OC\DB\MDB2SchemaManager($this->connection); + $manager->createDbFromStructure(__DIR__ . '/fixtures/dropoldtables.xml'); + } + + public function testRun() { + $this->assertFalse($this->connection->tableExists('sharing'), 'Asserting that the table oc_sharing does not exist before repairing'); + $this->assertTrue($this->connection->tableExists('permissions'), 'Asserting that the table oc_permissions does exist before repairing'); + + /** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */ + $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + ->disableOriginalConstructor() + ->getMock(); + + $repair = new \OC\Repair\DropOldTables($this->connection); + $repair->run($outputMock); + + $this->assertFalse($this->connection->tableExists('sharing'), 'Asserting that the table oc_sharing does not exist after repairing'); + $this->assertFalse($this->connection->tableExists('permissions'), 'Asserting that the table oc_permissions does not exist after repairing'); + } +} diff --git a/tests/lib/Repair/OldGroupMembershipSharesTest.php b/tests/lib/Repair/OldGroupMembershipSharesTest.php new file mode 100644 index 00000000000..cc04a80eef9 --- /dev/null +++ b/tests/lib/Repair/OldGroupMembershipSharesTest.php @@ -0,0 +1,136 @@ +<?php +/** + * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Repair; + +use OC\Repair\OldGroupMembershipShares; +use OC\Share\Constants; +use OCP\Migration\IOutput; + +/** + * Class OldGroupMembershipSharesTest + * + * @group DB + * + * @package Test\Repair + */ +class OldGroupMembershipSharesTest extends \Test\TestCase { + + /** @var OldGroupMembershipShares */ + protected $repair; + + /** @var \OCP\IDBConnection */ + protected $connection; + + /** @var \OCP\IGroupManager|\PHPUnit_Framework_MockObject_MockObject */ + protected $groupManager; + + protected function setUp() { + parent::setUp(); + + /** \OCP\IGroupManager|\PHPUnit_Framework_MockObject_MockObject */ + $this->groupManager = $this->getMockBuilder('OCP\IGroupManager') + ->disableOriginalConstructor() + ->getMock(); + $this->connection = \OC::$server->getDatabaseConnection(); + + $this->deleteAllShares(); + } + + protected function tearDown() { + $this->deleteAllShares(); + + parent::tearDown(); + } + + protected function deleteAllShares() { + $qb = $this->connection->getQueryBuilder(); + $qb->delete('share')->execute(); + } + + public function testRun() { + $repair = new OldGroupMembershipShares( + $this->connection, + $this->groupManager + ); + + $this->groupManager->expects($this->exactly(2)) + ->method('isInGroup') + ->willReturnMap([ + ['member', 'group', true], + ['not-a-member', 'group', false], + ]); + + $parent = $this->createShare(Constants::SHARE_TYPE_GROUP, 'group', null); + $group2 = $this->createShare(Constants::SHARE_TYPE_GROUP, 'group2', $parent); + $user1 = $this->createShare(Constants::SHARE_TYPE_USER, 'user1', $parent); + + // \OC\Share\Constant::$shareTypeGroupUserUnique === 2 + $member = $this->createShare(2, 'member', $parent); + $notAMember = $this->createShare(2, 'not-a-member', $parent); + + $query = $this->connection->getQueryBuilder(); + $result = $query->select('id') + ->from('share') + ->orderBy('id', 'ASC') + ->execute(); + $rows = $result->fetchAll(); + $this->assertEquals([['id' => $parent], ['id' => $group2], ['id' => $user1], ['id' => $member], ['id' => $notAMember]], $rows); + $result->closeCursor(); + + /** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */ + $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + ->disableOriginalConstructor() + ->getMock(); + + $repair->run($outputMock); + + $query = $this->connection->getQueryBuilder(); + $result = $query->select('id') + ->from('share') + ->orderBy('id', 'ASC') + ->execute(); + $rows = $result->fetchAll(); + $this->assertEquals([['id' => $parent], ['id' => $group2], ['id' => $user1], ['id' => $member]], $rows); + $result->closeCursor(); + } + + /** + * @param string $shareType + * @param string $shareWith + * @param null|int $parent + * @return int + */ + protected function createShare($shareType, $shareWith, $parent) { + $qb = $this->connection->getQueryBuilder(); + $shareValues = [ + 'share_type' => $qb->expr()->literal($shareType), + 'share_with' => $qb->expr()->literal($shareWith), + 'uid_owner' => $qb->expr()->literal('user1'), + 'item_type' => $qb->expr()->literal('folder'), + 'item_source' => $qb->expr()->literal(123), + 'item_target' => $qb->expr()->literal('/123'), + 'file_source' => $qb->expr()->literal(123), + 'file_target' => $qb->expr()->literal('/test'), + 'permissions' => $qb->expr()->literal(1), + 'stime' => $qb->expr()->literal(time()), + 'expiration' => $qb->expr()->literal('2015-09-25 00:00:00'), + ]; + + if ($parent) { + $shareValues['parent'] = $qb->expr()->literal($parent); + } + + $qb = $this->connection->getQueryBuilder(); + $qb->insert('share') + ->values($shareValues) + ->execute(); + + return $this->connection->lastInsertId('*PREFIX*share'); + } +} diff --git a/tests/lib/Repair/RemoveGetETagEntriesTest.php b/tests/lib/Repair/RemoveGetETagEntriesTest.php new file mode 100644 index 00000000000..c00923228d0 --- /dev/null +++ b/tests/lib/Repair/RemoveGetETagEntriesTest.php @@ -0,0 +1,90 @@ +<?php +/** + * @author Morris Jobke <hey@morrisjobke.de> + * + * @copyright Copyright (c) 2015, 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\RemoveGetETagEntries; +use OCP\Migration\IOutput; +use Test\TestCase; + +/** + * Class RemoveGetETagEntriesTest + * + * @group DB + * + * @package Test\Repair + */ +class RemoveGetETagEntriesTest extends TestCase { + /** @var \OCP\IDBConnection */ + protected $connection; + + protected function setUp() { + parent::setUp(); + + $this->connection = \OC::$server->getDatabaseConnection(); + } + + public function testRun() { + + $userName = 'removePropertiesUser'; + $data = [ + [$userName, '/abc.def.txt', '{DAV:}getetag', 'abcdef'], + [$userName, '/abc.def.txt', '{DAV:}anotherRandomProperty', 'ghi'], + ]; + + // insert test data + $sqlToInsertProperties = 'INSERT INTO `*PREFIX*properties` (`userid`, `propertypath`, `propertyname`, `propertyvalue`) VALUES (?, ?, ? ,?)'; + foreach ($data as $entry) { + $this->connection->executeUpdate($sqlToInsertProperties, $entry); + } + + // check if test data is written to DB + $sqlToFetchProperties = 'SELECT `userid`, `propertypath`, `propertyname`, `propertyvalue` FROM `*PREFIX*properties` WHERE `userid` = ?'; + $stmt = $this->connection->executeQuery($sqlToFetchProperties, [$userName]); + $entries = $stmt->fetchAll(\PDO::FETCH_NUM); + + $this->assertCount(2, $entries, 'Asserts that two entries are returned as we have inserted two'); + foreach($entries as $entry) { + $this->assertTrue(in_array($entry, $data), 'Asserts that the entries are the ones from the test data set'); + } + + /** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */ + $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + ->disableOriginalConstructor() + ->getMock(); + + // run repair step + $repair = new RemoveGetETagEntries($this->connection); + $repair->run($outputMock); + + // check if test data is correctly modified in DB + $stmt = $this->connection->executeQuery($sqlToFetchProperties, [$userName]); + $entries = $stmt->fetchAll(\PDO::FETCH_NUM); + + $this->assertCount(1, $entries, 'Asserts that only one entry is returned after the repair step - the other one has to be removed'); + $this->assertSame($data[1], $entries[0], 'Asserts that the returned entry is the correct one from the test data set'); + + // remove test data + $sqlToRemoveProperties = 'DELETE FROM `*PREFIX*properties` WHERE `userid` = ?'; + $this->connection->executeUpdate($sqlToRemoveProperties, [$userName]); + } + +} diff --git a/tests/lib/Repair/RepairCollationTest.php b/tests/lib/Repair/RepairCollationTest.php new file mode 100644 index 00000000000..2e304a74abc --- /dev/null +++ b/tests/lib/Repair/RepairCollationTest.php @@ -0,0 +1,88 @@ +<?php + +namespace Test\Repair; + +use OCP\Migration\IOutput; + +/** + * Copyright (c) 2014 Thomas Müller <deepdiver@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +class TestCollationRepair extends \OC\Repair\Collation { + /** + * @param \Doctrine\DBAL\Connection $connection + * @return string[] + */ + public function getAllNonUTF8BinTables($connection) { + return parent::getAllNonUTF8BinTables($connection); + } +} + +/** + * Tests for the converting of MySQL tables to InnoDB engine + * + * @group DB + * + * @see \OC\Repair\RepairMimeTypes + */ +class RepairCollationTest extends \Test\TestCase { + + /** + * @var TestCollationRepair + */ + private $repair; + + /** + * @var \Doctrine\DBAL\Connection + */ + private $connection; + + /** + * @var string + */ + private $tableName; + + /** + * @var \OCP\IConfig + */ + private $config; + + protected function setUp() { + parent::setUp(); + + $this->connection = \OC::$server->getDatabaseConnection(); + $this->config = \OC::$server->getConfig(); + if (!$this->connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\MySqlPlatform) { + $this->markTestSkipped("Test only relevant on MySql"); + } + + $dbPrefix = $this->config->getSystemValue("dbtableprefix"); + $this->tableName = $this->getUniqueID($dbPrefix . "_collation_test"); + $this->connection->exec("CREATE TABLE $this->tableName(text VARCHAR(16)) COLLATE utf8_unicode_ci"); + + $this->repair = new TestCollationRepair($this->config, $this->connection); + } + + protected function tearDown() { + $this->connection->getSchemaManager()->dropTable($this->tableName); + parent::tearDown(); + } + + public function testCollationConvert() { + $tables = $this->repair->getAllNonUTF8BinTables($this->connection); + $this->assertGreaterThanOrEqual(1, count($tables)); + + /** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */ + $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + ->disableOriginalConstructor() + ->getMock(); + + $this->repair->run($outputMock); + + $tables = $this->repair->getAllNonUTF8BinTables($this->connection); + $this->assertCount(0, $tables); + } +} diff --git a/tests/lib/Repair/RepairInnoDBTest.php b/tests/lib/Repair/RepairInnoDBTest.php new file mode 100644 index 00000000000..1258dad73f5 --- /dev/null +++ b/tests/lib/Repair/RepairInnoDBTest.php @@ -0,0 +1,78 @@ +<?php +/** + * Copyright (c) 2014 Thomas Müller <deepdiver@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +namespace Test\Repair; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +/** + * Tests for the converting of MySQL tables to InnoDB engine + * + * @group DB + * + * @see \OC\Repair\RepairMimeTypes + */ +class RepairInnoDBTest extends \Test\TestCase { + + /** @var IRepairStep */ + private $repair; + + /** @var \Doctrine\DBAL\Connection */ + private $connection; + + /** @var string */ + private $tableName; + + protected function setUp() { + parent::setUp(); + + $this->connection = \OC::$server->getDatabaseConnection(); + if (!$this->connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\MySqlPlatform) { + $this->markTestSkipped("Test only relevant on MySql"); + } + + $dbPrefix = \OC::$server->getConfig()->getSystemValue("dbtableprefix"); + $this->tableName = $this->getUniqueID($dbPrefix . "_innodb_test"); + $this->connection->exec("CREATE TABLE $this->tableName(id INT) ENGINE MyISAM"); + + $this->repair = new \OC\Repair\InnoDB(); + } + + protected function tearDown() { + $this->connection->getSchemaManager()->dropTable($this->tableName); + parent::tearDown(); + } + + public function testInnoDBConvert() { + $result = $this->countMyIsamTables(); + $this->assertEquals(1, $result); + + /** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */ + $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + ->disableOriginalConstructor() + ->getMock(); + + $this->repair->run($outputMock); + + $result = $this->countMyIsamTables(); + $this->assertEquals(0, $result); + } + + /** + * @param $dbName + * @return mixed + */ + private function countMyIsamTables() { + $dbName = \OC::$server->getConfig()->getSystemValue("dbname"); + + $result = $this->connection->fetchColumn( + "SELECT count(*) FROM information_schema.tables WHERE table_schema = ? and table_name = ? AND engine = 'MyISAM'", + array($dbName, $this->tableName) + ); + return $result; + } +} diff --git a/tests/lib/Repair/RepairInvalidSharesTest.php b/tests/lib/Repair/RepairInvalidSharesTest.php new file mode 100644 index 00000000000..a1e871bcc80 --- /dev/null +++ b/tests/lib/Repair/RepairInvalidSharesTest.php @@ -0,0 +1,201 @@ +<?php +/** + * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Repair; + + +use OC\Repair\RepairInvalidShares; +use OC\Share\Constants; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; +use Test\TestCase; + +/** + * Tests for repairing invalid shares + * + * @group DB + * + * @see \OC\Repair\RepairInvalidShares + */ +class RepairInvalidSharesTest 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('8.0.0.0')); + + $this->connection = \OC::$server->getDatabaseConnection(); + $this->deleteAllShares(); + + /** @var \OCP\IConfig $config */ + $this->repair = new RepairInvalidShares($config, $this->connection); + } + + protected function tearDown() { + $this->deleteAllShares(); + + parent::tearDown(); + } + + protected function deleteAllShares() { + $qb = $this->connection->getQueryBuilder(); + $qb->delete('share')->execute(); + } + + /** + * Test remove expiration date for non-link shares + */ + public function testRemoveExpirationDateForNonLinkShares() { + // user share with bogus expiration date + $qb = $this->connection->getQueryBuilder(); + $qb->insert('share') + ->values([ + 'share_type' => $qb->expr()->literal(Constants::SHARE_TYPE_USER), + 'share_with' => $qb->expr()->literal('recipientuser1'), + 'uid_owner' => $qb->expr()->literal('user1'), + 'item_type' => $qb->expr()->literal('folder'), + 'item_source' => $qb->expr()->literal(123), + 'item_target' => $qb->expr()->literal('/123'), + 'file_source' => $qb->expr()->literal(123), + 'file_target' => $qb->expr()->literal('/test'), + 'permissions' => $qb->expr()->literal(1), + 'stime' => $qb->expr()->literal(time()), + 'expiration' => $qb->expr()->literal('2015-09-25 00:00:00') + ]) + ->execute(); + + $bogusShareId = $this->getLastShareId(); + + // link share with expiration date + $qb = $this->connection->getQueryBuilder(); + $qb->insert('share') + ->values([ + 'share_type' => $qb->expr()->literal(Constants::SHARE_TYPE_LINK), + 'uid_owner' => $qb->expr()->literal('user1'), + 'item_type' => $qb->expr()->literal('folder'), + 'item_source' => $qb->expr()->literal(123), + 'item_target' => $qb->expr()->literal('/123'), + 'file_source' => $qb->expr()->literal(123), + 'file_target' => $qb->expr()->literal('/test'), + 'permissions' => $qb->expr()->literal(1), + 'stime' => $qb->expr()->literal(time()), + 'expiration' => $qb->expr()->literal('2015-09-25 00:00:00'), + 'token' => $qb->expr()->literal('abcdefg') + ])->execute(); + + /** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */ + $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + ->disableOriginalConstructor() + ->getMock(); + + $this->repair->run($outputMock); + + $results = $this->connection->getQueryBuilder() + ->select('*') + ->from('share') + ->orderBy('share_type', 'ASC') + ->execute() + ->fetchAll(); + + $this->assertCount(2, $results); + + $userShare = $results[0]; + $linkShare = $results[1]; + $this->assertEquals($bogusShareId, $userShare['id'], 'sanity check'); + $this->assertNull($userShare['expiration'], 'bogus expiration date was removed'); + $this->assertNotNull($linkShare['expiration'], 'valid link share expiration date still there'); + } + + /** + * Test remove shares where the parent share does not exist anymore + */ + public function testSharesNonExistingParent() { + $qb = $this->connection->getQueryBuilder(); + $shareValues = [ + 'share_type' => $qb->expr()->literal(Constants::SHARE_TYPE_USER), + 'share_with' => $qb->expr()->literal('recipientuser1'), + 'uid_owner' => $qb->expr()->literal('user1'), + 'item_type' => $qb->expr()->literal('folder'), + 'item_source' => $qb->expr()->literal(123), + 'item_target' => $qb->expr()->literal('/123'), + 'file_source' => $qb->expr()->literal(123), + 'file_target' => $qb->expr()->literal('/test'), + 'permissions' => $qb->expr()->literal(1), + 'stime' => $qb->expr()->literal(time()), + 'expiration' => $qb->expr()->literal('2015-09-25 00:00:00') + ]; + + // valid share + $qb = $this->connection->getQueryBuilder(); + $qb->insert('share') + ->values($shareValues) + ->execute(); + $parent = $this->getLastShareId(); + + // share with existing parent + $qb = $this->connection->getQueryBuilder(); + $qb->insert('share') + ->values(array_merge($shareValues, [ + 'parent' => $qb->expr()->literal($parent), + ]))->execute(); + $validChild = $this->getLastShareId(); + + // share with non-existing parent + $qb = $this->connection->getQueryBuilder(); + $qb->insert('share') + ->values(array_merge($shareValues, [ + 'parent' => $qb->expr()->literal($parent + 100), + ]))->execute(); + $invalidChild = $this->getLastShareId(); + + $query = $this->connection->getQueryBuilder(); + $result = $query->select('id') + ->from('share') + ->orderBy('id', 'ASC') + ->execute(); + $rows = $result->fetchAll(); + $this->assertEquals([['id' => $parent], ['id' => $validChild], ['id' => $invalidChild]], $rows); + $result->closeCursor(); + + /** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */ + $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + ->disableOriginalConstructor() + ->getMock(); + + $this->repair->run($outputMock); + + $query = $this->connection->getQueryBuilder(); + $result = $query->select('id') + ->from('share') + ->orderBy('id', 'ASC') + ->execute(); + $rows = $result->fetchAll(); + $this->assertEquals([['id' => $parent], ['id' => $validChild]], $rows); + $result->closeCursor(); + } + + /** + * @return int + */ + protected function getLastShareId() { + return $this->connection->lastInsertId('*PREFIX*share'); + } +} + diff --git a/tests/lib/Repair/RepairLegacyStoragesTest.php b/tests/lib/Repair/RepairLegacyStoragesTest.php new file mode 100644 index 00000000000..aa51fe06a35 --- /dev/null +++ b/tests/lib/Repair/RepairLegacyStoragesTest.php @@ -0,0 +1,335 @@ +<?php +/** + * Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Repair; + +use OC\Files\Cache\Cache; +use OC\Files\Cache\Storage; +use OCP\Migration\IOutput; +use PHPUnit_Framework_MockObject_MockObject; +use Test\TestCase; + +/** + * Tests for the converting of legacy storages to home storages. + * + * @group DB + * + * @see \OC\Repair\RepairLegacyStorages + */ +class RepairLegacyStoragesTest extends TestCase { + /** @var \OCP\IDBConnection */ + private $connection; + /** @var \OCP\IConfig */ + private $config; + private $user; + /** @var \OC\Repair\RepairLegacyStorages */ + private $repair; + + private $dataDir; + private $oldDataDir; + + private $legacyStorageId; + private $newStorageId; + + /** @var IOutput | PHPUnit_Framework_MockObject_MockObject */ + private $outputMock; + + protected function setUp() { + parent::setUp(); + + $this->config = \OC::$server->getConfig(); + $this->connection = \OC::$server->getDatabaseConnection(); + $this->oldDataDir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data/'); + + $this->repair = new \OC\Repair\RepairLegacyStorages($this->config, $this->connection); + + $this->outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + ->disableOriginalConstructor() + ->getMock(); + } + + protected function tearDown() { + $user = \OC::$server->getUserManager()->get($this->user); + if ($user) { + $user->delete(); + } + + $sql = 'DELETE FROM `*PREFIX*storages`'; + $this->connection->executeQuery($sql); + $sql = 'DELETE FROM `*PREFIX*filecache`'; + $this->connection->executeQuery($sql); + $this->config->setSystemValue('datadirectory', $this->oldDataDir); + $this->config->setAppValue('core', 'repairlegacystoragesdone', 'no'); + + parent::tearDown(); + } + + /** + * @param string $dataDir + * @param string $userId + * @throws \Exception + */ + function prepareSettings($dataDir, $userId) { + // hard-coded string as we want a predictable fixed length + // no data will be written there + $this->dataDir = $dataDir; + $this->config->setSystemValue('datadirectory', $this->dataDir); + + $this->user = $userId; + $this->legacyStorageId = 'local::' . $this->dataDir . $this->user . '/'; + $this->newStorageId = 'home::' . $this->user; + \OC::$server->getUserManager()->createUser($this->user, $this->user); + } + + /** + * Create a storage entry + * + * @param string $storageId + * @return int + */ + private function createStorage($storageId) { + $sql = 'INSERT INTO `*PREFIX*storages` (`id`)' + . ' VALUES (?)'; + + $storageId = Storage::adjustStorageId($storageId); + $numRows = $this->connection->executeUpdate($sql, array($storageId)); + $this->assertEquals(1, $numRows); + + return \OC::$server->getDatabaseConnection()->lastInsertId('*PREFIX*storages'); + } + + /** + * Returns the storage id based on the numeric id + * + * @param int $storageId numeric id of the storage + * @return string storage id or null if not found + */ + private function getStorageId($storageId) { + $numericId = Storage::getNumericStorageId($storageId); + if (!is_null($numericId)) { + return (int)$numericId; + } + return null; + } + + /** + * Create dummy data in the filecache for the given storage numeric id + * + * @param string $storageId storage id + */ + private function createData($storageId) { + $cache = new Cache($storageId); + $cache->put( + 'dummyfile.txt', + array('size' => 5, 'mtime' => 12, 'mimetype' => 'text/plain') + ); + } + + /** + * Test that existing home storages are left alone when valid. + * + * @dataProvider settingsProvider + * + * @param string $dataDir + * @param string $userId + */ + public function testNoopWithExistingHomeStorage($dataDir, $userId) { + $this->prepareSettings($dataDir, $userId); + $newStorageNumId = $this->createStorage($this->newStorageId); + + $this->repair->run($this->outputMock); + + $this->assertNull($this->getStorageId($this->legacyStorageId)); + $this->assertEquals($newStorageNumId, $this->getStorageId($this->newStorageId)); + } + + /** + * Test that legacy storages are converted to home storages when + * the latter does not exist. + * + * @dataProvider settingsProvider + * + * @param string $dataDir + * @param string $userId + */ + public function testConvertLegacyToHomeStorage($dataDir, $userId) { + $this->prepareSettings($dataDir, $userId); + $legacyStorageNumId = $this->createStorage($this->legacyStorageId); + + $this->repair->run($this->outputMock); + + $this->assertNull($this->getStorageId($this->legacyStorageId)); + $this->assertEquals($legacyStorageNumId, $this->getStorageId($this->newStorageId)); + } + + /** + * Test that legacy storages are converted to home storages + * when home storage already exists but has no data. + * + * @dataProvider settingsProvider + * + * @param string $dataDir + * @param string $userId + */ + public function testConvertLegacyToExistingEmptyHomeStorage($dataDir, $userId) { + $this->prepareSettings($dataDir, $userId); + $legacyStorageNumId = $this->createStorage($this->legacyStorageId); + $this->createStorage($this->newStorageId); + + $this->createData($this->legacyStorageId); + + $this->repair->run($this->outputMock); + + $this->assertNull($this->getStorageId($this->legacyStorageId)); + $this->assertEquals($legacyStorageNumId, $this->getStorageId($this->newStorageId)); + } + + /** + * Test that legacy storages are converted to home storages + * when home storage already exists and the legacy storage + * has no data. + * + * @dataProvider settingsProvider + * + * @param string $dataDir + * @param string $userId + */ + public function testConvertEmptyLegacyToHomeStorage($dataDir, $userId) { + $this->prepareSettings($dataDir, $userId); + $this->createStorage($this->legacyStorageId); + $newStorageNumId = $this->createStorage($this->newStorageId); + + $this->createData($this->newStorageId); + + $this->repair->run($this->outputMock); + + $this->assertNull($this->getStorageId($this->legacyStorageId)); + $this->assertEquals($newStorageNumId, $this->getStorageId($this->newStorageId)); + } + + /** + * Test that nothing is done when both conflicting legacy + * and home storage have data. + * + * @dataProvider settingsProvider + * + * @param string $dataDir + * @param string $userId + */ + public function testConflictNoop($dataDir, $userId) { + $this->prepareSettings($dataDir, $userId); + $legacyStorageNumId = $this->createStorage($this->legacyStorageId); + $newStorageNumId = $this->createStorage($this->newStorageId); + + $this->createData($this->legacyStorageId); + $this->createData($this->newStorageId); + + $this->outputMock->expects($this->exactly(2))->method('warning'); + $this->repair->run($this->outputMock); + + // storages left alone + $this->assertEquals($legacyStorageNumId, $this->getStorageId($this->legacyStorageId)); + $this->assertEquals($newStorageNumId, $this->getStorageId($this->newStorageId)); + + // do not set the done flag + $this->assertNotEquals('yes', $this->config->getAppValue('core', 'repairlegacystoragesdone')); + } + + /** + * Test that the data dir local entry is left alone + * + * @dataProvider settingsProvider + * + * @param string $dataDir + * @param string $userId + */ + public function testDataDirEntryNoop($dataDir, $userId) { + $this->prepareSettings($dataDir, $userId); + $storageId = 'local::' . $this->dataDir; + $numId = $this->createStorage($storageId); + + $this->repair->run($this->outputMock); + + $this->assertEquals($numId, $this->getStorageId($storageId)); + } + + /** + * Test that external local storages are left alone + * + * @dataProvider settingsProvider + * + * @param string $dataDir + * @param string $userId + */ + public function testLocalExtStorageNoop($dataDir, $userId) { + $this->prepareSettings($dataDir, $userId); + $storageId = 'local::/tmp/somedir/' . $this->user; + $numId = $this->createStorage($storageId); + + $this->repair->run($this->outputMock); + + $this->assertEquals($numId, $this->getStorageId($storageId)); + } + + /** + * Test that other external storages are left alone + * + * @dataProvider settingsProvider + * + * @param string $dataDir + * @param string $userId + */ + public function testExtStorageNoop($dataDir, $userId) { + $this->prepareSettings($dataDir, $userId); + $storageId = 'smb::user@password/tmp/somedir/' . $this->user; + $numId = $this->createStorage($storageId); + + $this->repair->run($this->outputMock); + + $this->assertEquals($numId, $this->getStorageId($storageId)); + } + + /** + * Provides data dir and user name + */ + function settingsProvider() { + return array( + // regular data dir + array( + '/tmp/oc-autotest/datadir/', + $this->getUniqueID('user_'), + ), + // long datadir / short user + array( + '/tmp/oc-autotest/datadir01234567890123456789012345678901234567890123456789END/', + $this->getUniqueID('user_'), + ), + // short datadir / long user + array( + '/tmp/oc-autotest/datadir/', + 'u123456789012345678901234567890123456789012345678901234567890END', // 64 chars + ), + ); + } + + /** + * Only run the repair once + */ + public function testOnlyRunOnce() { + $this->outputMock->expects($this->exactly(1))->method('info'); + + $this->prepareSettings('/tmp/oc-autotest/datadir', $this->getUniqueID('user_')); + $this->assertNotEquals('yes', $this->config->getAppValue('core', 'repairlegacystoragesdone')); + $this->repair->run($this->outputMock); + $this->assertEquals('yes', $this->config->getAppValue('core', 'repairlegacystoragesdone')); + + $this->outputMock->expects($this->never())->method('info'); + $this->repair->run($this->outputMock); + $this->assertEquals('yes', $this->config->getAppValue('core', 'repairlegacystoragesdone')); + } +} diff --git a/tests/lib/Repair/RepairMimeTypesTest.php b/tests/lib/Repair/RepairMimeTypesTest.php new file mode 100644 index 00000000000..6a42b016938 --- /dev/null +++ b/tests/lib/Repair/RepairMimeTypesTest.php @@ -0,0 +1,582 @@ +<?php +/** + * Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com> + * Copyright (c) 2014-2015 Olivier Paroz owncloud@oparoz.com + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +namespace Test\Repair; + +use OC\Files\Storage\Temporary; +use OCP\Files\IMimeTypeLoader; +use OCP\IConfig; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +/** + * Tests for the converting of legacy storages to home storages. + * + * @group DB + * + * @see \OC\Repair\RepairMimeTypes + */ +class RepairMimeTypesTest extends \Test\TestCase { + + /** @var IRepairStep */ + private $repair; + + /** @var Temporary */ + private $storage; + + /** @var IMimeTypeLoader */ + private $mimetypeLoader; + + protected function setUp() { + parent::setUp(); + + $this->savedMimetypeLoader = \OC::$server->getMimeTypeLoader(); + $this->mimetypeLoader = \OC::$server->getMimeTypeLoader(); + + /** @var IConfig | \PHPUnit_Framework_MockObject_MockObject $config */ + $config = $this->getMockBuilder('OCP\IConfig') + ->disableOriginalConstructor() + ->getMock(); + $config->expects($this->any()) + ->method('getSystemValue') + ->with('version') + ->will($this->returnValue('8.0.0.0')); + + $this->storage = new \OC\Files\Storage\Temporary([]); + + $this->repair = new \OC\Repair\RepairMimeTypes($config); + } + + protected function tearDown() { + $this->storage->getCache()->clear(); + $sql = 'DELETE FROM `*PREFIX*storages` WHERE `id` = ?'; + \OC_DB::executeAudited($sql, [$this->storage->getId()]); + $this->clearMimeTypes(); + + parent::tearDown(); + } + + private function clearMimeTypes() { + $sql = 'DELETE FROM `*PREFIX*mimetypes`'; + \OC_DB::executeAudited($sql); + $this->mimetypeLoader->reset(); + } + + private function addEntries($entries) { + // create files for the different extensions, this + // will also automatically create the corresponding mime types + foreach ($entries as $entry) { + $this->storage->getCache()->put( + $entry[0], + [ + 'size' => 0, + 'mtime' => 0, + 'mimetype' => $entry[1] + ] + ); + } + + } + + private function checkEntries($entries) { + foreach ($entries as $entry) { + $data = $this->storage->getCache()->get($entry[0]); + $this->assertEquals($entry[1], $data['mimetype']); + } + } + + /** + * Returns the id of a given mime type or null + * if it does not exist. + */ + private function getMimeTypeIdFromDB($mimeType) { + $sql = 'SELECT `id` FROM `*PREFIX*mimetypes` WHERE `mimetype` = ?'; + $results = \OC_DB::executeAudited($sql, [$mimeType]); + $result = $results->fetchOne(); + if ($result) { + return $result['id']; + } + return null; + } + + private function renameMimeTypes($currentMimeTypes, $fixedMimeTypes) { + $this->addEntries($currentMimeTypes); + + /** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */ + $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + ->disableOriginalConstructor() + ->getMock(); + + $this->repair->run($outputMock); + + // force mimetype reload + $this->mimetypeLoader->reset(); + + $this->checkEntries($fixedMimeTypes); + } + + /** + * Test renaming and splitting old office mime types + */ + public function testRenameOfficeMimeTypes() { + $currentMimeTypes = [ + ['test.doc', 'application/msword'], + ['test.docx', 'application/msword'], + ['test.xls', 'application/msexcel'], + ['test.xlsx', 'application/msexcel'], + ['test.ppt', 'application/mspowerpoint'], + ['test.pptx', 'application/mspowerpoint'], + ]; + + $fixedMimeTypes = [ + ['test.doc', 'application/msword'], + ['test.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'], + ['test.xls', 'application/vnd.ms-excel'], + ['test.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'], + ['test.ppt', 'application/vnd.ms-powerpoint'], + ['test.pptx', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'], + ]; + + $this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes); + } + + /** + * Test renaming old fonts mime types + */ + public function testRenameFontsMimeTypes() { + $currentMimeTypes = [ + ['test.ttf', 'application/x-font-ttf'], + ['test.otf', 'font/opentype'], + ['test.pfb', 'application/octet-stream'], + ]; + + $fixedMimeTypes = [ + ['test.ttf', 'application/font-sfnt'], + ['test.otf', 'application/font-sfnt'], + ['test.pfb', 'application/x-font'], + ]; + + $this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes); + } + + /** + * Test renaming the APK mime type + */ + public function testRenameAPKMimeType() { + $currentMimeTypes = [ + ['test.apk', 'application/octet-stream'], + ['bogus.apk', 'application/vnd.android.package-archive'], + ['bogus2.apk', 'application/wrong'], + ]; + + $fixedMimeTypes = [ + ['test.apk', 'application/vnd.android.package-archive'], + ['bogus.apk', 'application/vnd.android.package-archive'], + ['bogus2.apk', 'application/vnd.android.package-archive'], + ]; + + $this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes); + } + + /** + * Test renaming the postscript mime types + */ + public function testRenamePostscriptMimeType() { + $currentMimeTypes = [ + ['test.eps', 'application/octet-stream'], + ['test.ps', 'application/octet-stream'], + ]; + + $fixedMimeTypes = [ + ['test.eps', 'application/postscript'], + ['test.ps', 'application/postscript'], + ]; + + $this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes); + } + + /** + * Test renaming the Raw mime types + */ + public function testRenameRawMimeType() { + $currentMimeTypes = [ + ['test.arw', 'application/octet-stream'], + ['test.cr2', 'application/octet-stream'], + ['test.dcr', 'application/octet-stream'], + ['test.dng', 'application/octet-stream'], + ['test.erf', 'application/octet-stream'], + ['test.iiq', 'application/octet-stream'], + ['test.k25', 'application/octet-stream'], + ['test.kdc', 'application/octet-stream'], + ['test.mef', 'application/octet-stream'], + ['test.nef', 'application/octet-stream'], + ['test.orf', 'application/octet-stream'], + ['test.pef', 'application/octet-stream'], + ['test.raf', 'application/octet-stream'], + ['test.rw2', 'application/octet-stream'], + ['test.srf', 'application/octet-stream'], + ['test.sr2', 'application/octet-stream'], + ['test.xrf', 'application/octet-stream'], + ['CapitalExtension.DNG', 'application/octet-stream'], + ]; + + $fixedMimeTypes = [ + ['test.arw', 'image/x-dcraw'], + ['test.cr2', 'image/x-dcraw'], + ['test.dcr', 'image/x-dcraw'], + ['test.dng', 'image/x-dcraw'], + ['test.erf', 'image/x-dcraw'], + ['test.iiq', 'image/x-dcraw'], + ['test.k25', 'image/x-dcraw'], + ['test.kdc', 'image/x-dcraw'], + ['test.mef', 'image/x-dcraw'], + ['test.nef', 'image/x-dcraw'], + ['test.orf', 'image/x-dcraw'], + ['test.pef', 'image/x-dcraw'], + ['test.raf', 'image/x-dcraw'], + ['test.rw2', 'image/x-dcraw'], + ['test.srf', 'image/x-dcraw'], + ['test.sr2', 'image/x-dcraw'], + ['test.xrf', 'image/x-dcraw'], + ['CapitalExtension.DNG', 'image/x-dcraw'], + ]; + + $this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes); + } + + /** + * Test renaming the 3D image media type + */ + public function testRename3dImagesMimeType() { + $currentMimeTypes = [ + ['test.jps', 'application/octet-stream'], + ['test.mpo', 'application/octet-stream'], + ]; + + $fixedMimeTypes = [ + ['test.jps', 'image/jpeg'], + ['test.mpo', 'image/jpeg'], + ]; + + $this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes); + } + + /** + * Test renaming the conf/cnf media type + */ + public function testRenameConfMimeType() { + $currentMimeTypes = [ + ['test.conf', 'application/octet-stream'], + ['test.cnf', 'application/octet-stream'], + ]; + + $fixedMimeTypes = [ + ['test.conf', 'text/plain'], + ['test.cnf', 'text/plain'], + ]; + + $this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes); + } + + /** + * Test renaming the yaml media type + */ + public function testRenameYamlMimeType() { + $currentMimeTypes = [ + ['test.yaml', 'application/octet-stream'], + ['test.yml', 'application/octet-stream'], + ]; + + $fixedMimeTypes = [ + ['test.yaml', 'application/yaml'], + ['test.yml', 'application/yaml'], + ]; + + $this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes); + } + + /** + * Test renaming the java mime types + */ + public function testRenameJavaMimeType() { + $currentMimeTypes = [ + ['test.java', 'application/octet-stream'], + ['test.class', 'application/octet-stream'], + ]; + + $fixedMimeTypes = [ + ['test.java', 'text/x-java-source'], + ['test.class', 'application/java'], + ]; + + $this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes); + } + + /** + * Test renaming the hpp mime type + */ + public function testRenameHppMimeType() { + $currentMimeTypes = [ + ['test.hpp', 'application/octet-stream'], + ]; + + $fixedMimeTypes = [ + ['test.hpp', 'text/x-h'], + ]; + + $this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes); + } + + /** + * Test renaming the rss mime type + */ + public function testRenameRssMimeType() { + $currentMimeTypes = [ + ['test.rss', 'application/octet-stream'], + ]; + + $fixedMimeTypes = [ + ['test.rss', 'application/rss+xml'], + ]; + + $this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes); + } + + /** + * Test renaming the hpp mime type + */ + public function testRenameRtfMimeType() { + $currentMimeTypes = [ + ['test.rtf', 'application/octet-stream'], + ]; + + $fixedMimeTypes = [ + ['test.rtf', 'text/rtf'], + ]; + + $this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes); + } + + /** + * Test renaming the richdocuments additional office mime types + */ + public function testRenameRichDocumentsMimeTypes() { + $currentMimeTypes = [ + ['test.lwp', 'application/octet-stream'], + ['test.one', 'application/octet-stream'], + ['test.vsd', 'application/octet-stream'], + ['test.wpd', 'application/octet-stream'], + ]; + + $fixedMimeTypes = [ + ['test.lwp', 'application/vnd.lotus-wordpro'], + ['test.one', 'application/msonenote'], + ['test.vsd', 'application/vnd.visio'], + ['test.wpd', 'application/vnd.wordperfect'], + ]; + + $this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes); + } + + /** + * Test renaming and splitting old office mime types when + * new ones already exist + */ + public function testRenameOfficeMimeTypesWhenExist() { + $currentMimeTypes = [ + ['test.doc', 'application/msword'], + ['test.docx', 'application/msword'], + ['test.xls', 'application/msexcel'], + ['test.xlsx', 'application/msexcel'], + ['test.ppt', 'application/mspowerpoint'], + ['test.pptx', 'application/mspowerpoint'], + // make it so that the new mimetypes already exist + ['bogus.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'], + ['bogus.xlsx', 'application/vnd.ms-excel'], + ['bogus.pptx', 'application/vnd.ms-powerpoint'], + ['bogus2.docx', 'application/wrong'], + ['bogus2.xlsx', 'application/wrong'], + ['bogus2.pptx', 'application/wrong'], + ]; + + $fixedMimeTypes = [ + ['test.doc', 'application/msword'], + ['test.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'], + ['test.xls', 'application/vnd.ms-excel'], + ['test.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'], + ['test.ppt', 'application/vnd.ms-powerpoint'], + ['test.pptx', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'], + ['bogus.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'], + ['bogus.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'], + ['bogus.pptx', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'], + ['bogus2.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'], + ['bogus2.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'], + ['bogus2.pptx', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'], + ]; + + $this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes); + + // wrong mimetypes are gone + $this->assertNull($this->getMimeTypeIdFromDB('application/msexcel')); + $this->assertNull($this->getMimeTypeIdFromDB('application/mspowerpoint')); + } + + /** + * Test renaming old fonts mime types when + * new ones already exist + */ + public function testRenameFontsMimeTypesWhenExist() { + $currentMimeTypes = [ + ['test.ttf', 'application/x-font-ttf'], + ['test.otf', 'font/opentype'], + // make it so that the new mimetypes already exist + ['bogus.ttf', 'application/font-sfnt'], + ['bogus.otf', 'application/font-sfnt'], + ['bogus2.ttf', 'application/wrong'], + ['bogus2.otf', 'application/wrong'], + ]; + + $fixedMimeTypes = [ + ['test.ttf', 'application/font-sfnt'], + ['test.otf', 'application/font-sfnt'], + ['bogus.ttf', 'application/font-sfnt'], + ['bogus.otf', 'application/font-sfnt'], + ['bogus2.ttf', 'application/font-sfnt'], + ['bogus2.otf', 'application/font-sfnt'], + ]; + + $this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes); + + // wrong mimetypes are gone + $this->assertNull($this->getMimeTypeIdFromDB('application/x-font-ttf')); + $this->assertNull($this->getMimeTypeIdFromDB('font')); + $this->assertNull($this->getMimeTypeIdFromDB('font/opentype')); + } + + /** + * Test that nothing happens and no error happens when all mimetypes are + * already correct and no old ones exist.. + */ + public function testDoNothingWhenOnlyNewFiles() { + $currentMimeTypes = [ + ['test.doc', 'application/msword'], + ['test.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'], + ['test.xls', 'application/vnd.ms-excel'], + ['test.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'], + ['test.ppt', 'application/vnd.ms-powerpoint'], + ['test.pptx', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'], + ['test.apk', 'application/vnd.android.package-archive'], + ['test.ttf', 'application/font-sfnt'], + ['test.otf', 'application/font-sfnt'], + ['test.pfb', 'application/x-font'], + ['test.eps', 'application/postscript'], + ['test.ps', 'application/postscript'], + ['test.arw', 'image/x-dcraw'], + ['test.cr2', 'image/x-dcraw'], + ['test.dcr', 'image/x-dcraw'], + ['test.dng', 'image/x-dcraw'], + ['test.erf', 'image/x-dcraw'], + ['test.iiq', 'image/x-dcraw'], + ['test.k25', 'image/x-dcraw'], + ['test.kdc', 'image/x-dcraw'], + ['test.mef', 'image/x-dcraw'], + ['test.nef', 'image/x-dcraw'], + ['test.orf', 'image/x-dcraw'], + ['test.pef', 'image/x-dcraw'], + ['test.raf', 'image/x-dcraw'], + ['test.rw2', 'image/x-dcraw'], + ['test.srf', 'image/x-dcraw'], + ['test.sr2', 'image/x-dcraw'], + ['test.xrf', 'image/x-dcraw'], + ['test.DNG', 'image/x-dcraw'], + ['test.jps', 'image/jpeg'], + ['test.MPO', 'image/jpeg'], + ['test.conf', 'text/plain'], + ['test.cnf', 'text/plain'], + ['test.yaml', 'application/yaml'], + ['test.yml', 'application/yaml'], + ['test.java', 'text/x-java-source'], + ['test.class', 'application/java'], + ['test.hpp', 'text/x-h'], + ['test.rss', 'application/rss+xml'], + ['test.rtf', 'text/rtf'], + ['test.lwp', 'application/vnd.lotus-wordpro'], + ['test.one', 'application/msonenote'], + ['test.vsd', 'application/vnd.visio'], + ['test.wpd', 'application/vnd.wordperfect'], + ]; + + $fixedMimeTypes = [ + ['test.doc', 'application/msword'], + ['test.docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'], + ['test.xls', 'application/vnd.ms-excel'], + ['test.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'], + ['test.ppt', 'application/vnd.ms-powerpoint'], + ['test.pptx', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'], + ['test.apk', 'application/vnd.android.package-archive'], + ['test.ttf', 'application/font-sfnt'], + ['test.otf', 'application/font-sfnt'], + ['test.pfb', 'application/x-font'], + ['test.eps', 'application/postscript'], + ['test.ps', 'application/postscript'], + ['test.arw', 'image/x-dcraw'], + ['test.cr2', 'image/x-dcraw'], + ['test.dcr', 'image/x-dcraw'], + ['test.dng', 'image/x-dcraw'], + ['test.erf', 'image/x-dcraw'], + ['test.iiq', 'image/x-dcraw'], + ['test.k25', 'image/x-dcraw'], + ['test.kdc', 'image/x-dcraw'], + ['test.mef', 'image/x-dcraw'], + ['test.nef', 'image/x-dcraw'], + ['test.orf', 'image/x-dcraw'], + ['test.pef', 'image/x-dcraw'], + ['test.raf', 'image/x-dcraw'], + ['test.rw2', 'image/x-dcraw'], + ['test.srf', 'image/x-dcraw'], + ['test.sr2', 'image/x-dcraw'], + ['test.xrf', 'image/x-dcraw'], + ['test.DNG', 'image/x-dcraw'], + ['test.jps', 'image/jpeg'], + ['test.MPO', 'image/jpeg'], + ['test.conf', 'text/plain'], + ['test.cnf', 'text/plain'], + ['test.yaml', 'application/yaml'], + ['test.yml', 'application/yaml'], + ['test.java', 'text/x-java-source'], + ['test.class', 'application/java'], + ['test.hpp', 'text/x-h'], + ['test.rss', 'application/rss+xml'], + ['test.rtf', 'text/rtf'], + ['test.lwp', 'application/vnd.lotus-wordpro'], + ['test.one', 'application/msonenote'], + ['test.vsd', 'application/vnd.visio'], + ['test.wpd', 'application/vnd.wordperfect'], + ]; + + $this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes); + } + + /** + * Test that mime type renaming does not affect folders + */ + public function testDoNotChangeFolderMimeType() { + $currentMimeTypes = [ + ['test.conf', 'httpd/unix-directory'], + ['test.cnf', 'httpd/unix-directory'], + ]; + + $fixedMimeTypes = [ + ['test.conf', 'httpd/unix-directory'], + ['test.cnf', 'httpd/unix-directory'], + ]; + + $this->renameMimeTypes($currentMimeTypes, $fixedMimeTypes); + } +} + diff --git a/tests/lib/Repair/RepairSharePropagationTest.php b/tests/lib/Repair/RepairSharePropagationTest.php new file mode 100644 index 00000000000..07db3c84f28 --- /dev/null +++ b/tests/lib/Repair/RepairSharePropagationTest.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright (c) 2016 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Repair; + +use OC\Repair\SharePropagation; +use OCP\Migration\IOutput; + +class RepairSharePropagationTest extends \Test\TestCase { + public function keyProvider() { + return [ + [['1', '2'], ['1', '2']], + [['1', '2', 'foo'], ['1', '2']], + [['foo'], []], + ]; + } + + /** + * @dataProvider keyProvider + * @param array $startKeys + * @param array $expectedRemovedKeys + */ + public function testRemovePropagationEntries(array $startKeys, array $expectedRemovedKeys) { + /** @var \PHPUnit_Framework_MockObject_MockObject|\OCP\IConfig $config */ + $config = $this->getMock('\OCP\IConfig'); + $config->expects($this->once()) + ->method('getAppKeys') + ->with('files_sharing') + ->will($this->returnValue($startKeys)); + + $removedKeys = []; + + $config->expects($this->any()) + ->method('deleteAppValue') + ->will($this->returnCallback(function ($app, $key) use (&$removedKeys) { + $removedKeys[] = $key; + })); + + /** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */ + $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + ->disableOriginalConstructor() + ->getMock(); + + $step = new SharePropagation($config); + $step->run($outputMock); + + sort($expectedRemovedKeys); + sort($removedKeys); + + $this->assertEquals($expectedRemovedKeys, $removedKeys); + } +} diff --git a/tests/lib/Repair/RepairSqliteAutoincrementTest.php b/tests/lib/Repair/RepairSqliteAutoincrementTest.php new file mode 100644 index 00000000000..22186283779 --- /dev/null +++ b/tests/lib/Repair/RepairSqliteAutoincrementTest.php @@ -0,0 +1,89 @@ +<?php +/** + * Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Repair; +use OCP\Migration\IOutput; + +/** + * Tests for fixing the SQLite id recycling + * + * @group DB + */ +class RepairSqliteAutoincrementTest extends \Test\TestCase { + + /** + * @var \OC\Repair\SqliteAutoincrement + */ + private $repair; + + /** + * @var \Doctrine\DBAL\Connection + */ + private $connection; + + /** + * @var string + */ + private $tableName; + + /** + * @var \OCP\IConfig + */ + private $config; + + protected function setUp() { + parent::setUp(); + + $this->connection = \OC::$server->getDatabaseConnection(); + $this->config = \OC::$server->getConfig(); + if (!$this->connection->getDatabasePlatform() instanceof \Doctrine\DBAL\Platforms\SqlitePlatform) { + $this->markTestSkipped("Test only relevant on Sqlite"); + } + + $dbPrefix = $this->config->getSystemValue('dbtableprefix', 'oc_'); + $this->tableName = $this->getUniqueID($dbPrefix . 'autoinc_test'); + $this->connection->exec('CREATE TABLE ' . $this->tableName . '("someid" INTEGER NOT NULL, "text" VARCHAR(16), PRIMARY KEY("someid"))'); + + $this->repair = new \OC\Repair\SqliteAutoincrement($this->connection); + } + + protected function tearDown() { + $this->connection->getSchemaManager()->dropTable($this->tableName); + parent::tearDown(); + } + + /** + * Tests whether autoincrement works + * + * @return boolean true if autoincrement works, false otherwise + */ + protected function checkAutoincrement() { + $this->connection->executeUpdate('INSERT INTO ' . $this->tableName . ' ("text") VALUES ("test")'); + $insertId = $this->connection->lastInsertId(); + $this->connection->executeUpdate('DELETE FROM ' . $this->tableName . ' WHERE "someid" = ?', array($insertId)); + + // insert again + $this->connection->executeUpdate('INSERT INTO ' . $this->tableName . ' ("text") VALUES ("test2")'); + $newInsertId = $this->connection->lastInsertId(); + + return ($insertId !== $newInsertId); + } + + public function testConvertIdColumn() { + $this->assertFalse($this->checkAutoincrement()); + + /** @var IOutput | \PHPUnit_Framework_MockObject_MockObject $outputMock */ + $outputMock = $this->getMockBuilder('\OCP\Migration\IOutput') + ->disableOriginalConstructor() + ->getMock(); + + $this->repair->run($outputMock); + + $this->assertTrue($this->checkAutoincrement()); + } +} diff --git a/tests/lib/Repair/UpdateOutdatedOcsIdsTest.php b/tests/lib/Repair/UpdateOutdatedOcsIdsTest.php new file mode 100644 index 00000000000..eb80e63a202 --- /dev/null +++ b/tests/lib/Repair/UpdateOutdatedOcsIdsTest.php @@ -0,0 +1,80 @@ +<?php +/** + * @author Lukas Reschke <l8kas@owncloud.com> + * + * @copyright Copyright (c) 2015, 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 OCP\IConfig; +use Test\TestCase; + +/** + * Class UpdateOutdatedOcsIds + * + * @package Test\Repair + */ +class UpdateOutdatedOcsIdsTest extends TestCase { + /** @var IConfig | \PHPUnit_Framework_MockObject_MockObject */ + private $config; + /** @var \OC\Repair\UpdateOutdatedOcsIds */ + private $updateOutdatedOcsIds; + + public function setUp() { + parent::setUp(); + $this->config = $this->getMockBuilder('\\OCP\\IConfig')->getMock(); + $this->updateOutdatedOcsIds = new \OC\Repair\UpdateOutdatedOcsIds($this->config); + } + + public function testGetName() { + $this->assertSame('Repair outdated OCS IDs', $this->updateOutdatedOcsIds->getName()); + } + + public function testFixOcsIdNoOcsId() { + $this->config + ->expects($this->once()) + ->method('getAppValue') + ->with('MyNotInstalledApp', 'ocsid') + ->will($this->returnValue('')); + $this->assertFalse($this->updateOutdatedOcsIds->fixOcsId('MyNotInstalledApp', '1337', '0815')); + } + + public function testFixOcsIdUpdateOcsId() { + $this->config + ->expects($this->at(0)) + ->method('getAppValue') + ->with('MyInstalledApp', 'ocsid') + ->will($this->returnValue('1337')); + $this->config + ->expects($this->at(1)) + ->method('setAppValue') + ->with('MyInstalledApp', 'ocsid', '0815'); + + $this->assertTrue($this->updateOutdatedOcsIds->fixOcsId('MyInstalledApp', '1337', '0815')); + } + + public function testFixOcsIdAlreadyFixed() { + $this->config + ->expects($this->once()) + ->method('getAppValue') + ->with('MyAlreadyFixedAppId', 'ocsid') + ->will($this->returnValue('0815')); + + $this->assertFalse($this->updateOutdatedOcsIds->fixOcsId('MyAlreadyFixedAppId', '1337', '0815')); + } +} diff --git a/tests/lib/Repair/fixtures/dropoldtables.xml b/tests/lib/Repair/fixtures/dropoldtables.xml new file mode 100644 index 00000000000..6c42a8f90a7 --- /dev/null +++ b/tests/lib/Repair/fixtures/dropoldtables.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8" ?> +<database> + + <name>*dbname*</name> + <create>true</create> + <overwrite>false</overwrite> + + <charset>utf8</charset> + + <table> + + <name>*dbprefix*permissions</name> + + <declaration> + <field> + <name>textfield</name> + <type>text</type> + <default>foo</default> + <notnull>true</notnull> + <length>32</length> + </field> + </declaration> + </table> +</database> |