diff options
Diffstat (limited to 'tests/lib/DB')
-rw-r--r-- | tests/lib/DB/AdapterTest.php | 69 | ||||
-rw-r--r-- | tests/lib/DB/ConnectionFactoryTest.php | 11 | ||||
-rw-r--r-- | tests/lib/DB/Exception/DbalExceptionTest.php | 4 | ||||
-rw-r--r-- | tests/lib/DB/MigrationsTest.php | 277 | ||||
-rw-r--r-- | tests/lib/DB/MigratorTest.php | 40 | ||||
-rw-r--r-- | tests/lib/DB/OCPostgreSqlPlatformTest.php | 9 | ||||
-rw-r--r-- | tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php | 48 | ||||
-rw-r--r-- | tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php | 90 | ||||
-rw-r--r-- | tests/lib/DB/QueryBuilder/FunctionBuilderTest.php | 92 | ||||
-rw-r--r-- | tests/lib/DB/QueryBuilder/Partitioned/JoinConditionTest.php | 74 | ||||
-rw-r--r-- | tests/lib/DB/QueryBuilder/Partitioned/PartitionedQueryBuilderTest.php | 223 | ||||
-rw-r--r-- | tests/lib/DB/QueryBuilder/QueryBuilderTest.php | 287 | ||||
-rw-r--r-- | tests/lib/DB/QueryBuilder/QuoteHelperTest.php | 13 | ||||
-rw-r--r-- | tests/lib/DB/QueryBuilder/Sharded/SharedQueryBuilderTest.php | 128 |
14 files changed, 1040 insertions, 325 deletions
diff --git a/tests/lib/DB/AdapterTest.php b/tests/lib/DB/AdapterTest.php new file mode 100644 index 00000000000..394428337f1 --- /dev/null +++ b/tests/lib/DB/AdapterTest.php @@ -0,0 +1,69 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\DB; + +use OCP\IDBConnection; +use OCP\Server; +use Test\TestCase; + +class AdapterTest extends TestCase { + private string $appId; + private $connection; + + public function setUp(): void { + $this->connection = Server::get(IDBConnection::class); + $this->appId = substr(uniqid('test_db_adapter', true), 0, 32); + } + + public function tearDown(): void { + $qb = $this->connection->getQueryBuilder(); + + $qb->delete('appconfig') + ->from('appconfig') + ->where($qb->expr()->eq('appid', $qb->createNamedParameter($this->appId))) + ->execute(); + } + + public function testInsertIgnoreOnConflictDuplicate(): void { + $configKey = uniqid('key', true); + $expected = [ + [ + 'configkey' => $configKey, + 'configvalue' => '1', + ] + ]; + $result = $this->connection->insertIgnoreConflict('appconfig', [ + 'appid' => $this->appId, + 'configkey' => $configKey, + 'configvalue' => '1', + ]); + $this->assertEquals(1, $result); + $rows = $this->getRows($configKey); + $this->assertSame($expected, $rows); + + + $result = $this->connection->insertIgnoreConflict('appconfig', [ + 'appid' => $this->appId, + 'configkey' => $configKey, + 'configvalue' => '2', + ]); + $this->assertEquals(0, $result); + $rows = $this->getRows($configKey); + $this->assertSame($expected, $rows); + } + + private function getRows(string $configKey): array { + $qb = $this->connection->getQueryBuilder(); + return $qb->select(['configkey', 'configvalue']) + ->from('appconfig') + ->where($qb->expr()->eq('appid', $qb->createNamedParameter($this->appId))) + ->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter($configKey))) + ->execute() + ->fetchAll(); + } +} diff --git a/tests/lib/DB/ConnectionFactoryTest.php b/tests/lib/DB/ConnectionFactoryTest.php index 208f78f4512..d09a83ca856 100644 --- a/tests/lib/DB/ConnectionFactoryTest.php +++ b/tests/lib/DB/ConnectionFactoryTest.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -8,10 +9,11 @@ namespace Test\DB; use OC\DB\ConnectionFactory; use OC\SystemConfig; +use OCP\ICacheFactory; use Test\TestCase; class ConnectionFactoryTest extends TestCase { - public function splitHostFromPortAndSocketData() { + public static function splitHostFromPortAndSocketData(): array { return [ ['127.0.0.1', ['host' => '127.0.0.1']], ['db.example.org', ['host' => 'db.example.org']], @@ -26,14 +28,15 @@ class ConnectionFactoryTest extends TestCase { } /** - * @dataProvider splitHostFromPortAndSocketData * @param string $host * @param array $expected */ - public function testSplitHostFromPortAndSocket($host, array $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('splitHostFromPortAndSocketData')] + public function testSplitHostFromPortAndSocket($host, array $expected): void { /** @var SystemConfig $config */ $config = $this->createMock(SystemConfig::class); - $factory = new ConnectionFactory($config); + $cacheFactory = $this->createMock(ICacheFactory::class); + $factory = new ConnectionFactory($config, $cacheFactory); $this->assertEquals($expected, self::invokePrivate($factory, 'splitHostFromPortAndSocket', [$host])); } diff --git a/tests/lib/DB/Exception/DbalExceptionTest.php b/tests/lib/DB/Exception/DbalExceptionTest.php index 470beff9080..eac74291749 100644 --- a/tests/lib/DB/Exception/DbalExceptionTest.php +++ b/tests/lib/DB/Exception/DbalExceptionTest.php @@ -35,16 +35,16 @@ class DbalExceptionTest extends \Test\TestCase { } /** - * @dataProvider dataDriverException * @param string $class * @param int $reason */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataDriverException')] public function testDriverException(string $class, int $reason): void { $result = DbalException::wrap(new $class($this->driverException, null)); $this->assertSame($reason, $result->getReason()); } - public function dataDriverException(): array { + public static function dataDriverException(): array { return [ [LockWaitTimeoutException::class, DbalException::REASON_LOCK_WAIT_TIMEOUT], [ForeignKeyConstraintViolationException::class, DbalException::REASON_FOREIGN_KEY_VIOLATION], diff --git a/tests/lib/DB/MigrationsTest.php b/tests/lib/DB/MigrationsTest.php index 6cd489258bf..2b39b26d852 100644 --- a/tests/lib/DB/MigrationsTest.php +++ b/tests/lib/DB/MigrationsTest.php @@ -8,8 +8,6 @@ namespace Test\DB; -use Doctrine\DBAL\Platforms\OraclePlatform; -use Doctrine\DBAL\Platforms\PostgreSqlPlatform; use Doctrine\DBAL\Schema\Column; use Doctrine\DBAL\Schema\ForeignKeyConstraint; use Doctrine\DBAL\Schema\Index; @@ -21,8 +19,21 @@ use Doctrine\DBAL\Types\Type; use OC\DB\Connection; use OC\DB\MigrationService; use OC\DB\SchemaWrapper; +use OC\Migration\MetadataManager; +use OCP\App\IAppManager; use OCP\IDBConnection; +use OCP\Migration\Attributes\AddColumn; +use OCP\Migration\Attributes\AddIndex; +use OCP\Migration\Attributes\ColumnType; +use OCP\Migration\Attributes\CreateTable; +use OCP\Migration\Attributes\DropColumn; +use OCP\Migration\Attributes\DropIndex; +use OCP\Migration\Attributes\DropTable; +use OCP\Migration\Attributes\IndexType; +use OCP\Migration\Attributes\ModifyColumn; use OCP\Migration\IMigrationStep; +use OCP\Server; +use PHPUnit\Framework\MockObject\MockObject; /** * Class MigrationsTest @@ -30,10 +41,9 @@ use OCP\Migration\IMigrationStep; * @package Test\DB */ class MigrationsTest extends \Test\TestCase { - /** @var MigrationService | \PHPUnit\Framework\MockObject\MockObject */ - private $migrationService; - /** @var \PHPUnit\Framework\MockObject\MockObject | IDBConnection $db */ - private $db; + private MigrationService|MockObject $migrationService; + private MockObject|IDBConnection $db; + private IAppManager $appManager; protected function setUp(): void { parent::setUp(); @@ -41,16 +51,18 @@ class MigrationsTest extends \Test\TestCase { $this->db = $this->createMock(Connection::class); $this->db->expects($this->any())->method('getPrefix')->willReturn('test_oc_'); $this->migrationService = new MigrationService('testing', $this->db); + + $this->appManager = Server::get(IAppManager::class); } - public function testGetters() { + public function testGetters(): void { $this->assertEquals('testing', $this->migrationService->getApp()); $this->assertEquals(\OC::$SERVERROOT . '/apps/testing/lib/Migration', $this->migrationService->getMigrationsDirectory()); $this->assertEquals('OCA\Testing\Migration', $this->migrationService->getMigrationsNamespace()); $this->assertEquals('test_oc_migrations', $this->migrationService->getMigrationsTableName()); } - public function testCore() { + public function testCore(): void { $this->migrationService = new MigrationService('core', $this->db); $this->assertEquals('core', $this->migrationService->getApp()); @@ -60,7 +72,7 @@ class MigrationsTest extends \Test\TestCase { } - public function testExecuteUnknownStep() { + public function testExecuteUnknownStep(): void { $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Version 20170130180000 is unknown.'); @@ -68,7 +80,7 @@ class MigrationsTest extends \Test\TestCase { } - public function testUnknownApp() { + public function testUnknownApp(): void { $this->expectException(\Exception::class); $this->expectExceptionMessage('App not found'); @@ -76,12 +88,12 @@ class MigrationsTest extends \Test\TestCase { } - public function testExecuteStepWithUnknownClass() { + public function testExecuteStepWithUnknownClass(): void { $this->expectException(\Exception::class); $this->expectExceptionMessage('Migration step \'X\' is unknown'); $this->migrationService = $this->getMockBuilder(MigrationService::class) - ->setMethods(['findMigrations']) + ->onlyMethods(['findMigrations']) ->setConstructorArgs(['testing', $this->db]) ->getMock(); $this->migrationService->expects($this->any())->method('findMigrations')->willReturn( @@ -90,7 +102,7 @@ class MigrationsTest extends \Test\TestCase { $this->migrationService->executeStep('20170130180000'); } - public function testExecuteStepWithSchemaChange() { + public function testExecuteStepWithSchemaChange(): void { $schema = $this->createMock(Schema::class); $this->db->expects($this->any()) ->method('createSchema') @@ -122,7 +134,7 @@ class MigrationsTest extends \Test\TestCase { ->method('postSchemaChange'); $this->migrationService = $this->getMockBuilder(MigrationService::class) - ->setMethods(['createInstance']) + ->onlyMethods(['createInstance']) ->setConstructorArgs(['testing', $this->db]) ->getMock(); @@ -133,7 +145,7 @@ class MigrationsTest extends \Test\TestCase { $this->migrationService->executeStep('20170130180000'); } - public function testExecuteStepWithoutSchemaChange() { + public function testExecuteStepWithoutSchemaChange(): void { $schema = $this->createMock(Schema::class); $this->db->expects($this->any()) ->method('createSchema') @@ -152,7 +164,7 @@ class MigrationsTest extends \Test\TestCase { ->method('postSchemaChange'); $this->migrationService = $this->getMockBuilder(MigrationService::class) - ->setMethods(['createInstance']) + ->onlyMethods(['createInstance']) ->setConstructorArgs(['testing', $this->db]) ->getMock(); @@ -163,7 +175,7 @@ class MigrationsTest extends \Test\TestCase { $this->migrationService->executeStep('20170130180000'); } - public function dataGetMigration() { + public static function dataGetMigration(): array { return [ ['current', '20170130180001'], ['prev', '20170130180000'], @@ -173,13 +185,13 @@ class MigrationsTest extends \Test\TestCase { } /** - * @dataProvider dataGetMigration * @param string $alias * @param string $expected */ - public function testGetMigration($alias, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataGetMigration')] + public function testGetMigration($alias, $expected): void { $this->migrationService = $this->getMockBuilder(MigrationService::class) - ->setMethods(['getMigratedVersions', 'findMigrations']) + ->onlyMethods(['getMigratedVersions', 'findMigrations']) ->setConstructorArgs(['testing', $this->db]) ->getMock(); $this->migrationService->expects($this->any())->method('getMigratedVersions')->willReturn( @@ -197,28 +209,39 @@ class MigrationsTest extends \Test\TestCase { $this->assertEquals($expected, $migration); } - public function testMigrate() { + public function testMigrate(): void { $this->migrationService = $this->getMockBuilder(MigrationService::class) - ->setMethods(['getMigratedVersions', 'findMigrations', 'executeStep']) + ->onlyMethods(['getMigratedVersions', 'findMigrations', 'executeStep']) ->setConstructorArgs(['testing', $this->db]) ->getMock(); - $this->migrationService->expects($this->any())->method('getMigratedVersions')->willReturn( - ['20170130180000', '20170130180001'] - ); - $this->migrationService->expects($this->any())->method('findMigrations')->willReturn( - ['20170130180000' => 'X', '20170130180001' => 'Y', '20170130180002' => 'Z', '20170130180003' => 'A'] - ); + $this->migrationService->method('getMigratedVersions') + ->willReturn( + ['20170130180000', '20170130180001'] + ); + $this->migrationService->method('findMigrations') + ->willReturn( + ['20170130180000' => 'X', '20170130180001' => 'Y', '20170130180002' => 'Z', '20170130180003' => 'A'] + ); $this->assertEquals( ['20170130180000', '20170130180001', '20170130180002', '20170130180003'], - $this->migrationService->getAvailableVersions()); + $this->migrationService->getAvailableVersions() + ); - $this->migrationService->expects($this->exactly(2))->method('executeStep') - ->withConsecutive(['20170130180002'], ['20170130180003']); + $calls = [ + ['20170130180002', false], + ['20170130180003', false], + ]; + $this->migrationService->expects($this->exactly(2)) + ->method('executeStep') + ->willReturnCallback(function () use (&$calls): void { + $expected = array_shift($calls); + $this->assertEquals($expected, func_get_args()); + }); $this->migrationService->migrate(); } - public function testEnsureOracleConstraintsValid() { + public function testEnsureOracleConstraintsValid(): void { $column = $this->createMock(Column::class); $column->expects($this->once()) ->method('getName') @@ -281,7 +304,7 @@ class MigrationsTest extends \Test\TestCase { self::invokePrivate($this->migrationService, 'ensureOracleConstraints', [$sourceSchema, $schema, 3]); } - public function testEnsureOracleConstraintsValidWithPrimaryKey() { + public function testEnsureOracleConstraintsValidWithPrimaryKey(): void { $index = $this->createMock(Index::class); $index->expects($this->any()) ->method('getName') @@ -324,11 +347,11 @@ class MigrationsTest extends \Test\TestCase { self::invokePrivate($this->migrationService, 'ensureOracleConstraints', [$sourceSchema, $schema, 3]); } - public function testEnsureOracleConstraintsValidWithPrimaryKeyDefault() { + public function testEnsureOracleConstraintsValidWithPrimaryKeyDefault(): void { $defaultName = 'PRIMARY'; - if ($this->db->getDatabasePlatform() instanceof PostgreSqlPlatform) { + if ($this->db->getDatabaseProvider() === IDBConnection::PLATFORM_POSTGRES) { $defaultName = \str_repeat('a', 26) . '_' . \str_repeat('b', 30) . '_seq'; - } elseif ($this->db->getDatabasePlatform() instanceof OraclePlatform) { + } elseif ($this->db->getDatabaseProvider() === IDBConnection::PLATFORM_ORACLE) { $defaultName = \str_repeat('a', 26) . '_seq'; } @@ -378,7 +401,7 @@ class MigrationsTest extends \Test\TestCase { } - public function testEnsureOracleConstraintsTooLongTableName() { + public function testEnsureOracleConstraintsTooLongTableName(): void { $this->expectException(\InvalidArgumentException::class); $table = $this->createMock(Table::class); @@ -403,13 +426,13 @@ class MigrationsTest extends \Test\TestCase { } - public function testEnsureOracleConstraintsTooLongPrimaryWithDefault() { + public function testEnsureOracleConstraintsTooLongPrimaryWithDefault(): void { $this->expectException(\InvalidArgumentException::class); $defaultName = 'PRIMARY'; - if ($this->db->getDatabasePlatform() instanceof PostgreSqlPlatform) { + if ($this->db->getDatabaseProvider() === IDBConnection::PLATFORM_POSTGRES) { $defaultName = \str_repeat('a', 27) . '_' . \str_repeat('b', 30) . '_seq'; - } elseif ($this->db->getDatabasePlatform() instanceof OraclePlatform) { + } elseif ($this->db->getDatabaseProvider() === IDBConnection::PLATFORM_ORACLE) { $defaultName = \str_repeat('a', 27) . '_seq'; } @@ -456,7 +479,7 @@ class MigrationsTest extends \Test\TestCase { } - public function testEnsureOracleConstraintsTooLongPrimaryWithName() { + public function testEnsureOracleConstraintsTooLongPrimaryWithName(): void { $this->expectException(\InvalidArgumentException::class); $index = $this->createMock(Index::class); @@ -499,7 +522,7 @@ class MigrationsTest extends \Test\TestCase { } - public function testEnsureOracleConstraintsTooLongColumnName() { + public function testEnsureOracleConstraintsTooLongColumnName(): void { $this->expectException(\InvalidArgumentException::class); $column = $this->createMock(Column::class); @@ -533,7 +556,7 @@ class MigrationsTest extends \Test\TestCase { } - public function testEnsureOracleConstraintsTooLongIndexName() { + public function testEnsureOracleConstraintsTooLongIndexName(): void { $this->expectException(\InvalidArgumentException::class); $index = $this->createMock(Index::class); @@ -570,7 +593,7 @@ class MigrationsTest extends \Test\TestCase { } - public function testEnsureOracleConstraintsTooLongForeignKeyName() { + public function testEnsureOracleConstraintsTooLongForeignKeyName(): void { $this->expectException(\InvalidArgumentException::class); $foreignKey = $this->createMock(ForeignKeyConstraint::class); @@ -610,7 +633,7 @@ class MigrationsTest extends \Test\TestCase { } - public function testEnsureOracleConstraintsNoPrimaryKey() { + public function testEnsureOracleConstraintsNoPrimaryKey(): void { $this->markTestSkipped('Test disabled for now due to multiple reasons, see https://github.com/nextcloud/server/pull/31580#issuecomment-1069182234 for details.'); $this->expectException(\InvalidArgumentException::class); @@ -651,7 +674,7 @@ class MigrationsTest extends \Test\TestCase { } - public function testEnsureOracleConstraintsTooLongSequenceName() { + public function testEnsureOracleConstraintsTooLongSequenceName(): void { $this->expectException(\InvalidArgumentException::class); $sequence = $this->createMock(Sequence::class); @@ -679,7 +702,7 @@ class MigrationsTest extends \Test\TestCase { } - public function testEnsureOracleConstraintsBooleanNotNull() { + public function testEnsureOracleConstraintsBooleanNotNull(): void { $this->expectException(\InvalidArgumentException::class); $column = $this->createMock(Column::class); @@ -719,7 +742,7 @@ class MigrationsTest extends \Test\TestCase { } - public function testEnsureOracleConstraintsStringLength4000() { + public function testEnsureOracleConstraintsStringLength4000(): void { $this->expectException(\InvalidArgumentException::class); $column = $this->createMock(Column::class); @@ -757,4 +780,162 @@ class MigrationsTest extends \Test\TestCase { self::invokePrivate($this->migrationService, 'ensureOracleConstraints', [$sourceSchema, $schema, 3]); } + + + public function testExtractMigrationAttributes(): void { + $metadataManager = Server::get(MetadataManager::class); + $this->appManager->loadApp('testing'); + + $this->assertEquals($this->getMigrationMetadata(), json_decode(json_encode($metadataManager->extractMigrationAttributes('testing')), true)); + + $this->appManager->disableApp('testing'); + } + + public function testDeserializeMigrationMetadata(): void { + $metadataManager = Server::get(MetadataManager::class); + $this->assertEquals( + [ + 'core' => [], + 'apps' => [ + 'testing' => [ + '30000Date20240102030405' => [ + new DropTable('old_table'), + new CreateTable('new_table', + description: 'Table is used to store things, but also to get more things', + notes: ['this is a notice', 'and another one, if really needed'] + ), + new AddColumn('my_table'), + new AddColumn('my_table', 'another_field'), + new AddColumn('other_table', 'last_one', ColumnType::DATE), + new AddIndex('my_table'), + new AddIndex('my_table', IndexType::PRIMARY), + new DropColumn('other_table'), + new DropColumn('other_table', 'old_column', + description: 'field is not used anymore and replaced by \'last_one\'' + ), + new DropIndex('other_table'), + new ModifyColumn('other_table'), + new ModifyColumn('other_table', 'this_field'), + new ModifyColumn('other_table', 'this_field', ColumnType::BIGINT) + ] + ] + ] + ], + $metadataManager->getMigrationsAttributesFromReleaseMetadata( + [ + 'core' => [], + 'apps' => ['testing' => $this->getMigrationMetadata()] + ] + ) + ); + } + + private function getMigrationMetadata(): array { + return [ + '30000Date20240102030405' => [ + [ + 'class' => 'OCP\\Migration\\Attributes\\DropTable', + 'table' => 'old_table', + 'description' => '', + 'notes' => [], + 'columns' => [] + ], + [ + 'class' => 'OCP\\Migration\\Attributes\\CreateTable', + 'table' => 'new_table', + 'description' => 'Table is used to store things, but also to get more things', + 'notes' => [ + 'this is a notice', + 'and another one, if really needed' + ], + 'columns' => [] + ], + [ + 'class' => 'OCP\\Migration\\Attributes\\AddColumn', + 'table' => 'my_table', + 'description' => '', + 'notes' => [], + 'name' => '', + 'type' => '' + ], + [ + 'class' => 'OCP\\Migration\\Attributes\\AddColumn', + 'table' => 'my_table', + 'description' => '', + 'notes' => [], + 'name' => 'another_field', + 'type' => '' + ], + [ + 'class' => 'OCP\\Migration\\Attributes\\AddColumn', + 'table' => 'other_table', + 'description' => '', + 'notes' => [], + 'name' => 'last_one', + 'type' => 'date' + ], + [ + 'class' => 'OCP\\Migration\\Attributes\\AddIndex', + 'table' => 'my_table', + 'description' => '', + 'notes' => [], + 'type' => '' + ], + [ + 'class' => 'OCP\\Migration\\Attributes\\AddIndex', + 'table' => 'my_table', + 'description' => '', + 'notes' => [], + 'type' => 'primary' + ], + [ + 'class' => 'OCP\\Migration\\Attributes\\DropColumn', + 'table' => 'other_table', + 'description' => '', + 'notes' => [], + 'name' => '', + 'type' => '' + ], + [ + 'class' => 'OCP\\Migration\\Attributes\\DropColumn', + 'table' => 'other_table', + 'description' => 'field is not used anymore and replaced by \'last_one\'', + 'notes' => [], + 'name' => 'old_column', + 'type' => '' + ], + [ + 'class' => 'OCP\\Migration\\Attributes\\DropIndex', + 'table' => 'other_table', + 'description' => '', + 'notes' => [], + 'type' => '' + ], + [ + 'class' => 'OCP\\Migration\\Attributes\\ModifyColumn', + 'table' => 'other_table', + 'description' => '', + 'notes' => [], + 'name' => '', + 'type' => '' + ], + [ + 'class' => 'OCP\\Migration\\Attributes\\ModifyColumn', + 'table' => 'other_table', + 'description' => '', + 'notes' => [], + 'name' => 'this_field', + 'type' => '' + ], + [ + 'class' => 'OCP\\Migration\\Attributes\\ModifyColumn', + 'table' => 'other_table', + 'description' => '', + 'notes' => [], + 'name' => 'this_field', + 'type' => 'bigint' + ], + ] + ]; + } } diff --git a/tests/lib/DB/MigratorTest.php b/tests/lib/DB/MigratorTest.php index eaa6540b93b..9d8ee6791a9 100644 --- a/tests/lib/DB/MigratorTest.php +++ b/tests/lib/DB/MigratorTest.php @@ -10,16 +10,16 @@ namespace Test\DB; use Doctrine\DBAL\Exception; use Doctrine\DBAL\ParameterType; -use Doctrine\DBAL\Platforms\OraclePlatform; -use Doctrine\DBAL\Platforms\SqlitePlatform; use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\SchemaConfig; use OC\DB\Migrator; use OC\DB\OracleMigrator; use OC\DB\SQLiteMigrator; use OCP\DB\Types; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; -use OCP\Security\ISecureRandom; +use OCP\IDBConnection; +use OCP\Server; /** * Class MigratorTest @@ -48,20 +48,18 @@ class MigratorTest extends \Test\TestCase { protected function setUp(): void { parent::setUp(); - $this->config = \OC::$server->getConfig(); - $this->connection = \OC::$server->get(\OC\DB\Connection::class); + $this->config = Server::get(IConfig::class); + $this->connection = Server::get(\OC\DB\Connection::class); $this->tableName = $this->getUniqueTableName(); $this->tableNameTmp = $this->getUniqueTableName(); } private function getMigrator(): Migrator { - $platform = $this->connection->getDatabasePlatform(); - $random = \OC::$server->get(ISecureRandom::class); - $dispatcher = \OC::$server->get(\OCP\EventDispatcher\IEventDispatcher::class); - if ($platform instanceof SqlitePlatform) { + $dispatcher = Server::get(IEventDispatcher::class); + if ($this->connection->getDatabaseProvider() === IDBConnection::PLATFORM_SQLITE) { return new SQLiteMigrator($this->connection, $this->config, $dispatcher); - } elseif ($platform instanceof OraclePlatform) { + } elseif ($this->connection->getDatabaseProvider() === IDBConnection::PLATFORM_ORACLE) { return new OracleMigrator($this->connection, $this->config, $dispatcher); } return new Migrator($this->connection, $this->config, $dispatcher); @@ -130,7 +128,7 @@ class MigratorTest extends \Test\TestCase { return $config; } - public function testUpgrade() { + public function testUpgrade(): void { [$startSchema, $endSchema] = $this->getDuplicateKeySchemas(); $migrator = $this->getMigrator(); $migrator->migrate($startSchema); @@ -143,7 +141,7 @@ class MigratorTest extends \Test\TestCase { $this->addToAssertionCount(1); } - public function testUpgradeDifferentPrefix() { + public function testUpgradeDifferentPrefix(): void { $oldTablePrefix = $this->config->getSystemValueString('dbtableprefix', 'oc_'); $this->config->setSystemValue('dbtableprefix', 'ownc_'); @@ -163,7 +161,7 @@ class MigratorTest extends \Test\TestCase { $this->config->setSystemValue('dbtableprefix', $oldTablePrefix); } - public function testInsertAfterUpgrade() { + public function testInsertAfterUpgrade(): void { [$startSchema, $endSchema] = $this->getDuplicateKeySchemas(); $migrator = $this->getMigrator(); $migrator->migrate($startSchema); @@ -180,7 +178,7 @@ class MigratorTest extends \Test\TestCase { } } - public function testAddingPrimaryKeyWithAutoIncrement() { + public function testAddingPrimaryKeyWithAutoIncrement(): void { $startSchema = new Schema([], [], $this->getSchemaConfig()); $table = $startSchema->createTable($this->tableName); $table->addColumn('id', 'integer'); @@ -200,7 +198,7 @@ class MigratorTest extends \Test\TestCase { $this->addToAssertionCount(1); } - public function testReservedKeywords() { + public function testReservedKeywords(): void { $startSchema = new Schema([], [], $this->getSchemaConfig()); $table = $startSchema->createTable($this->tableName); $table->addColumn('id', 'integer', ['autoincrement' => true]); @@ -224,7 +222,7 @@ class MigratorTest extends \Test\TestCase { /** * Test for nextcloud/server#36803 */ - public function testColumnCommentsInUpdate() { + public function testColumnCommentsInUpdate(): void { $startSchema = new Schema([], [], $this->getSchemaConfig()); $table = $startSchema->createTable($this->tableName); $table->addColumn('id', 'integer', ['autoincrement' => true, 'comment' => 'foo']); @@ -245,14 +243,14 @@ class MigratorTest extends \Test\TestCase { $this->addToAssertionCount(1); } - public function testAddingForeignKey() { + public function testAddingForeignKey(): void { $startSchema = new Schema([], [], $this->getSchemaConfig()); $table = $startSchema->createTable($this->tableName); $table->addColumn('id', 'integer', ['autoincrement' => true]); $table->addColumn('name', 'string'); $table->setPrimaryKey(['id']); - $fkName = "fkc"; + $fkName = 'fkc'; $tableFk = $startSchema->createTable($this->tableNameTmp); $tableFk->addColumn('fk_id', 'integer'); $tableFk->addColumn('name', 'string'); @@ -265,7 +263,7 @@ class MigratorTest extends \Test\TestCase { $this->assertTrue($startSchema->getTable($this->tableNameTmp)->hasForeignKey($fkName)); } - public function dataNotNullEmptyValuesFailOracle(): array { + public static function dataNotNullEmptyValuesFailOracle(): array { return [ [ParameterType::BOOLEAN, true, Types::BOOLEAN, false], [ParameterType::BOOLEAN, false, Types::BOOLEAN, true], @@ -281,13 +279,13 @@ class MigratorTest extends \Test\TestCase { } /** - * @dataProvider dataNotNullEmptyValuesFailOracle * * @param int $parameterType * @param bool|int|string $value * @param string $columnType * @param bool $oracleThrows */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataNotNullEmptyValuesFailOracle')] public function testNotNullEmptyValuesFailOracle(int $parameterType, $value, string $columnType, bool $oracleThrows): void { $startSchema = new Schema([], [], $this->getSchemaConfig()); $table = $startSchema->createTable($this->tableName); @@ -300,7 +298,7 @@ class MigratorTest extends \Test\TestCase { $migrator = $this->getMigrator(); $migrator->migrate($startSchema); - if ($oracleThrows && $this->connection->getDatabasePlatform() instanceof OraclePlatform) { + if ($oracleThrows && $this->connection->getDatabaseProvider() === IDBConnection::PLATFORM_ORACLE) { // Oracle can not store false|empty string in notnull columns $this->expectException(\Doctrine\DBAL\Exception\NotNullConstraintViolationException::class); } diff --git a/tests/lib/DB/OCPostgreSqlPlatformTest.php b/tests/lib/DB/OCPostgreSqlPlatformTest.php index 4f83e866a7c..af17b01fc13 100644 --- a/tests/lib/DB/OCPostgreSqlPlatformTest.php +++ b/tests/lib/DB/OCPostgreSqlPlatformTest.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2017 ownCloud, Inc. @@ -7,7 +8,7 @@ namespace Test\DB; -use Doctrine\DBAL\Platforms\PostgreSQL100Platform; +use Doctrine\DBAL\Platforms\PostgreSQLPlatform; use Doctrine\DBAL\Schema\Comparator; use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Types\Types; @@ -23,8 +24,8 @@ use Doctrine\DBAL\Types\Types; * @package Test\DB */ class OCPostgreSqlPlatformTest extends \Test\TestCase { - public function testAlterBigint() { - $platform = new PostgreSQL100Platform(); + public function testAlterBigint(): void { + $platform = new PostgreSQLPlatform(); $sourceSchema = new Schema(); $targetSchema = new Schema(); @@ -48,7 +49,7 @@ class OCPostgreSqlPlatformTest extends \Test\TestCase { } protected function createTableAndColumn($schema, $type) { - $table = $schema->createTable("poor_yorick"); + $table = $schema->createTable('poor_yorick'); $table->addColumn('id', $type, [ 'autoincrement' => true, 'unsigned' => true, diff --git a/tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php b/tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php index 671bcfc209e..153993f396e 100644 --- a/tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php +++ b/tests/lib/DB/QueryBuilder/ExpressionBuilderDBTest.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later @@ -7,10 +8,11 @@ namespace Test\DB\QueryBuilder; use Doctrine\DBAL\Schema\SchemaException; -use Doctrine\DBAL\Types\Types; use OC\DB\QueryBuilder\Literal; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\DB\Types; use OCP\IConfig; +use OCP\IDBConnection; use OCP\Server; use Test\TestCase; @@ -18,19 +20,19 @@ use Test\TestCase; * @group DB */ class ExpressionBuilderDBTest extends TestCase { - /** @var \Doctrine\DBAL\Connection|\OCP\IDBConnection */ + /** @var \Doctrine\DBAL\Connection|IDBConnection */ protected $connection; protected $schemaSetup = false; protected function setUp(): void { parent::setUp(); - $this->connection = \OC::$server->getDatabaseConnection(); + $this->connection = Server::get(IDBConnection::class); $this->prepareTestingTable(); } - public function likeProvider() { - $connection = \OC::$server->getDatabaseConnection(); + public static function likeProvider(): array { + $connection = Server::get(IDBConnection::class); return [ ['foo', 'bar', false], @@ -46,13 +48,13 @@ class ExpressionBuilderDBTest extends TestCase { } /** - * @dataProvider likeProvider * * @param string $param1 * @param string $param2 * @param boolean $match */ - public function testLike($param1, $param2, $match) { + #[\PHPUnit\Framework\Attributes\DataProvider('likeProvider')] + public function testLike($param1, $param2, $match): void { $query = $this->connection->getQueryBuilder(); $query->select(new Literal('1')) @@ -65,8 +67,8 @@ class ExpressionBuilderDBTest extends TestCase { $this->assertEquals($match, $column); } - public function ilikeProvider() { - $connection = \OC::$server->getDatabaseConnection(); + public static function ilikeProvider(): array { + $connection = Server::get(IDBConnection::class); return [ ['foo', 'bar', false], @@ -83,13 +85,13 @@ class ExpressionBuilderDBTest extends TestCase { } /** - * @dataProvider ilikeProvider * * @param string $param1 * @param string $param2 * @param boolean $match */ - public function testILike($param1, $param2, $match) { + #[\PHPUnit\Framework\Attributes\DataProvider('ilikeProvider')] + public function testILike($param1, $param2, $match): void { $query = $this->connection->getQueryBuilder(); $query->select(new Literal('1')) @@ -141,53 +143,53 @@ class ExpressionBuilderDBTest extends TestCase { self::assertEquals('myvalue', $entries[0]['configvalue']); } - public function testDateTimeEquals() { + public function testDateTimeEquals(): void { $dateTime = new \DateTime('2023-01-01'); $insert = $this->connection->getQueryBuilder(); $insert->insert('testing') - ->values(['datetime' => $insert->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATE)]) + ->values(['datetime' => $insert->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE)]) ->executeStatement(); $query = $this->connection->getQueryBuilder(); $result = $query->select('*') ->from('testing') - ->where($query->expr()->eq('datetime', $query->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATE))) + ->where($query->expr()->eq('datetime', $query->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE))) ->executeQuery(); $entries = $result->fetchAll(); $result->closeCursor(); self::assertCount(1, $entries); } - public function testDateTimeLess() { + public function testDateTimeLess(): void { $dateTime = new \DateTime('2022-01-01'); $dateTimeCompare = new \DateTime('2022-01-02'); $insert = $this->connection->getQueryBuilder(); $insert->insert('testing') - ->values(['datetime' => $insert->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATE)]) + ->values(['datetime' => $insert->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE)]) ->executeStatement(); $query = $this->connection->getQueryBuilder(); $result = $query->select('*') ->from('testing') - ->where($query->expr()->lt('datetime', $query->createNamedParameter($dateTimeCompare, IQueryBuilder::PARAM_DATE))) + ->where($query->expr()->lt('datetime', $query->createNamedParameter($dateTimeCompare, IQueryBuilder::PARAM_DATETIME_MUTABLE))) ->executeQuery(); $entries = $result->fetchAll(); $result->closeCursor(); self::assertCount(1, $entries); } - public function testDateTimeGreater() { + public function testDateTimeGreater(): void { $dateTime = new \DateTime('2023-01-02'); $dateTimeCompare = new \DateTime('2023-01-01'); $insert = $this->connection->getQueryBuilder(); $insert->insert('testing') - ->values(['datetime' => $insert->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATE)]) + ->values(['datetime' => $insert->createNamedParameter($dateTime, IQueryBuilder::PARAM_DATETIME_MUTABLE)]) ->executeStatement(); $query = $this->connection->getQueryBuilder(); $result = $query->select('*') ->from('testing') - ->where($query->expr()->gt('datetime', $query->createNamedParameter($dateTimeCompare, IQueryBuilder::PARAM_DATE))) + ->where($query->expr()->gt('datetime', $query->createNamedParameter($dateTimeCompare, IQueryBuilder::PARAM_DATETIME_MUTABLE))) ->executeQuery(); $entries = $result->fetchAll(); $result->closeCursor(); @@ -199,8 +201,8 @@ class ExpressionBuilderDBTest extends TestCase { $query->insert('appconfig') ->values([ 'appid' => $query->createNamedParameter($appId), - 'configkey' => $query->createNamedParameter((string) $key), - 'configvalue' => $query->createNamedParameter((string) $value), + 'configkey' => $query->createNamedParameter((string)$key), + 'configvalue' => $query->createNamedParameter((string)$value), ]) ->execute(); } @@ -223,7 +225,7 @@ class ExpressionBuilderDBTest extends TestCase { 'notnull' => true, ]); - $table->addColumn('datetime', Types::DATETIME_MUTABLE, [ + $table->addColumn('datetime', Types::DATETIME, [ 'notnull' => false, ]); diff --git a/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php b/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php index d8147035b16..1f84ebfbec1 100644 --- a/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php +++ b/tests/lib/DB/QueryBuilder/ExpressionBuilderTest.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. @@ -10,6 +11,9 @@ namespace Test\DB\QueryBuilder; use Doctrine\DBAL\Query\Expression\ExpressionBuilder as DoctrineExpressionBuilder; use OC\DB\QueryBuilder\ExpressionBuilder\ExpressionBuilder; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; +use OCP\Server; +use Psr\Log\LoggerInterface; use Test\TestCase; /** @@ -26,27 +30,31 @@ class ExpressionBuilderTest extends TestCase { /** @var DoctrineExpressionBuilder */ protected $doctrineExpressionBuilder; - /** @var \OCP\IDBConnection */ + /** @var IDBConnection */ protected $connection; /** @var \Doctrine\DBAL\Connection */ protected $internalConnection; + /** @var LoggerInterface */ + protected $logger; + protected function setUp(): void { parent::setUp(); - $this->connection = \OC::$server->getDatabaseConnection(); - $this->internalConnection = \OC::$server->get(\OC\DB\Connection::class); + $this->connection = Server::get(IDBConnection::class); + $this->internalConnection = Server::get(\OC\DB\Connection::class); + $this->logger = $this->createMock(LoggerInterface::class); $queryBuilder = $this->createMock(IQueryBuilder::class); - $this->expressionBuilder = new ExpressionBuilder($this->connection, $queryBuilder); + $this->expressionBuilder = new ExpressionBuilder($this->connection, $queryBuilder, $this->logger); $this->doctrineExpressionBuilder = new DoctrineExpressionBuilder($this->internalConnection); } - public function dataComparison() { - $valueSets = $this->dataComparisons(); + public static function dataComparison(): array { + $valueSets = self::dataComparisons(); $comparisonOperators = ['=', '<>', '<', '>', '<=', '>=']; $testSets = []; @@ -59,7 +67,6 @@ class ExpressionBuilderTest extends TestCase { } /** - * @dataProvider dataComparison * * @param string $comparison * @param mixed $input1 @@ -67,7 +74,8 @@ class ExpressionBuilderTest extends TestCase { * @param mixed $input2 * @param bool $isInput2Literal */ - public function testComparison($comparison, $input1, $isInput1Literal, $input2, $isInput2Literal) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataComparison')] + public function testComparison($comparison, $input1, $isInput1Literal, $input2, $isInput2Literal): void { [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal); [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal); @@ -77,7 +85,7 @@ class ExpressionBuilderTest extends TestCase { ); } - public function dataComparisons() { + public static function dataComparisons(): array { return [ ['value', false, 'value', false], ['value', false, 'value', true], @@ -87,14 +95,14 @@ class ExpressionBuilderTest extends TestCase { } /** - * @dataProvider dataComparisons * * @param mixed $input1 * @param bool $isInput1Literal * @param mixed $input2 * @param bool $isInput2Literal */ - public function testEquals($input1, $isInput1Literal, $input2, $isInput2Literal) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')] + public function testEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void { [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal); [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal); @@ -105,14 +113,14 @@ class ExpressionBuilderTest extends TestCase { } /** - * @dataProvider dataComparisons * * @param mixed $input1 * @param bool $isInput1Literal * @param mixed $input2 * @param bool $isInput2Literal */ - public function testNotEquals($input1, $isInput1Literal, $input2, $isInput2Literal) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')] + public function testNotEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void { [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal); [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal); @@ -123,14 +131,14 @@ class ExpressionBuilderTest extends TestCase { } /** - * @dataProvider dataComparisons * * @param mixed $input1 * @param bool $isInput1Literal * @param mixed $input2 * @param bool $isInput2Literal */ - public function testLowerThan($input1, $isInput1Literal, $input2, $isInput2Literal) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')] + public function testLowerThan($input1, $isInput1Literal, $input2, $isInput2Literal): void { [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal); [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal); @@ -141,14 +149,14 @@ class ExpressionBuilderTest extends TestCase { } /** - * @dataProvider dataComparisons * * @param mixed $input1 * @param bool $isInput1Literal * @param mixed $input2 * @param bool $isInput2Literal */ - public function testLowerThanEquals($input1, $isInput1Literal, $input2, $isInput2Literal) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')] + public function testLowerThanEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void { [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal); [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal); @@ -159,14 +167,14 @@ class ExpressionBuilderTest extends TestCase { } /** - * @dataProvider dataComparisons * * @param mixed $input1 * @param bool $isInput1Literal * @param mixed $input2 * @param bool $isInput2Literal */ - public function testGreaterThan($input1, $isInput1Literal, $input2, $isInput2Literal) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')] + public function testGreaterThan($input1, $isInput1Literal, $input2, $isInput2Literal): void { [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal); [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal); @@ -177,14 +185,14 @@ class ExpressionBuilderTest extends TestCase { } /** - * @dataProvider dataComparisons * * @param mixed $input1 * @param bool $isInput1Literal * @param mixed $input2 * @param bool $isInput2Literal */ - public function testGreaterThanEquals($input1, $isInput1Literal, $input2, $isInput2Literal) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataComparisons')] + public function testGreaterThanEquals($input1, $isInput1Literal, $input2, $isInput2Literal): void { [$doctrineInput1, $ocInput1] = $this->helpWithLiteral($input1, $isInput1Literal); [$doctrineInput2, $ocInput2] = $this->helpWithLiteral($input2, $isInput2Literal); @@ -194,21 +202,21 @@ class ExpressionBuilderTest extends TestCase { ); } - public function testIsNull() { + public function testIsNull(): void { $this->assertEquals( $this->doctrineExpressionBuilder->isNull('`test`'), $this->expressionBuilder->isNull('test') ); } - public function testIsNotNull() { + public function testIsNotNull(): void { $this->assertEquals( $this->doctrineExpressionBuilder->isNotNull('`test`'), $this->expressionBuilder->isNotNull('test') ); } - public function dataLike() { + public static function dataLike(): array { return [ ['value', false], ['value', true], @@ -216,12 +224,12 @@ class ExpressionBuilderTest extends TestCase { } /** - * @dataProvider dataLike * * @param mixed $input * @param bool $isLiteral */ - public function testLike($input, $isLiteral) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataLike')] + public function testLike($input, $isLiteral): void { [$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral); $this->assertEquals( @@ -231,12 +239,12 @@ class ExpressionBuilderTest extends TestCase { } /** - * @dataProvider dataLike * * @param mixed $input * @param bool $isLiteral */ - public function testNotLike($input, $isLiteral) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataLike')] + public function testNotLike($input, $isLiteral): void { [$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral); $this->assertEquals( @@ -245,7 +253,7 @@ class ExpressionBuilderTest extends TestCase { ); } - public function dataIn() { + public static function dataIn(): array { return [ ['value', false], ['value', true], @@ -255,12 +263,12 @@ class ExpressionBuilderTest extends TestCase { } /** - * @dataProvider dataIn * * @param mixed $input * @param bool $isLiteral */ - public function testIn($input, $isLiteral) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataIn')] + public function testIn($input, $isLiteral): void { [$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral); $this->assertEquals( @@ -270,12 +278,12 @@ class ExpressionBuilderTest extends TestCase { } /** - * @dataProvider dataIn * * @param mixed $input * @param bool $isLiteral */ - public function testNotIn($input, $isLiteral) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataIn')] + public function testNotIn($input, $isLiteral): void { [$doctrineInput, $ocInput] = $this->helpWithLiteral($input, $isLiteral); $this->assertEquals( @@ -312,7 +320,7 @@ class ExpressionBuilderTest extends TestCase { return [$doctrineInput, $ocInput]; } - public function dataLiteral() { + public static function dataLiteral(): array { return [ ['value', null], ['1', null], @@ -324,12 +332,12 @@ class ExpressionBuilderTest extends TestCase { } /** - * @dataProvider dataLiteral * * @param mixed $input * @param string|null $type */ - public function testLiteral($input, $type) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataLiteral')] + public function testLiteral($input, $type): void { /** @var \OC\DB\QueryBuilder\Literal $actual */ $actual = $this->expressionBuilder->literal($input, $type); @@ -340,7 +348,7 @@ class ExpressionBuilderTest extends TestCase { ); } - public function dataClobComparisons() { + public static function dataClobComparisons(): array { return [ ['eq', '5', IQueryBuilder::PARAM_STR, false, 3], ['eq', '5', IQueryBuilder::PARAM_STR, true, 1], @@ -368,14 +376,14 @@ class ExpressionBuilderTest extends TestCase { } /** - * @dataProvider dataClobComparisons * @param string $function * @param mixed $value * @param mixed $type * @param bool $compareKeyToValue * @param int $expected */ - public function testClobComparisons($function, $value, $type, $compareKeyToValue, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataClobComparisons')] + public function testClobComparisons($function, $value, $type, $compareKeyToValue, $expected): void { $appId = $this->getUniqueID('testing'); $this->createConfig($appId, 1, 4); $this->createConfig($appId, 2, 5); @@ -415,8 +423,8 @@ class ExpressionBuilderTest extends TestCase { $query->insert('appconfig') ->values([ 'appid' => $query->createNamedParameter($appId), - 'configkey' => $query->createNamedParameter((string) $key), - 'configvalue' => $query->createNamedParameter((string) $value), + 'configkey' => $query->createNamedParameter((string)$key), + 'configvalue' => $query->createNamedParameter((string)$value), ]) ->execute(); } diff --git a/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php b/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php index d991c78f113..5a111c91aa7 100644 --- a/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php +++ b/tests/lib/DB/QueryBuilder/FunctionBuilderTest.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-only @@ -8,6 +9,8 @@ namespace Test\DB\QueryBuilder; use OC\DB\QueryBuilder\Literal; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; +use OCP\Server; use Test\TestCase; /** @@ -18,19 +21,17 @@ use Test\TestCase; * @package Test\DB\QueryBuilder */ class FunctionBuilderTest extends TestCase { - /** @var \Doctrine\DBAL\Connection|\OCP\IDBConnection */ + /** @var \Doctrine\DBAL\Connection|IDBConnection */ protected $connection; protected function setUp(): void { parent::setUp(); - $this->connection = \OC::$server->getDatabaseConnection(); + $this->connection = Server::get(IDBConnection::class); } - /** - * @dataProvider providerTestConcatString - */ - public function testConcatString($closure) { + #[\PHPUnit\Framework\Attributes\DataProvider('providerTestConcatString')] + public function testConcatString($closure): void { $query = $this->connection->getQueryBuilder(); [$real, $arguments, $return] = $closure($query); if ($real) { @@ -49,39 +50,39 @@ class FunctionBuilderTest extends TestCase { $this->assertEquals($return, $column); } - public function providerTestConcatString(): array { + public static function providerTestConcatString(): array { return [ - '1 column: string param unicode' => - [function ($q) { + '1 column: string param unicode' + => [function ($q) { return [false, [$q->createNamedParameter('👍')], '👍']; }], - '2 columns: string param and string param' => - [function ($q) { + '2 columns: string param and string param' + => [function ($q) { return [false, [$q->createNamedParameter('foo'), $q->createNamedParameter('bar')], 'foobar']; }], - '2 columns: string param and int literal' => - [function ($q) { + '2 columns: string param and int literal' + => [function ($q) { return [false, [$q->createNamedParameter('foo'), $q->expr()->literal(1)], 'foo1']; }], - '2 columns: string param and string literal' => - [function ($q) { + '2 columns: string param and string literal' + => [function ($q) { return [false, [$q->createNamedParameter('foo'), $q->expr()->literal('bar')], 'foobar']; }], - '2 columns: string real and int literal' => - [function ($q) { + '2 columns: string real and int literal' + => [function ($q) { return [true, ['configkey', $q->expr()->literal(2)], '12']; }], - '4 columns: string literal' => - [function ($q) { + '4 columns: string literal' + => [function ($q) { return [false, [$q->expr()->literal('foo'), $q->expr()->literal('bar'), $q->expr()->literal('foo'), $q->expr()->literal('bar')], 'foobarfoobar']; }], - '4 columns: int literal' => - [function ($q) { + '4 columns: int literal' + => [function ($q) { return [false, [$q->expr()->literal(1), $q->expr()->literal(2), $q->expr()->literal(3), $q->expr()->literal(4)], '1234']; }], - '5 columns: string param with special chars used in the function' => - [function ($q) { - return [false, [$q->createNamedParameter("b"), $q->createNamedParameter("'"), $q->createNamedParameter('||'), $q->createNamedParameter(','), $q->createNamedParameter('a')], "b'||,a"]; + '5 columns: string param with special chars used in the function' + => [function ($q) { + return [false, [$q->createNamedParameter('b'), $q->createNamedParameter("'"), $q->createNamedParameter('||'), $q->createNamedParameter(','), $q->createNamedParameter('a')], "b'||,a"]; }], ]; } @@ -232,7 +233,7 @@ class FunctionBuilderTest extends TestCase { $this->assertEqualsCanonicalizing([1,2,3], $actual); } - public function testMd5() { + public function testMd5(): void { $query = $this->connection->getQueryBuilder(); $query->select($query->func()->md5($query->createNamedParameter('foobar'))); @@ -245,7 +246,7 @@ class FunctionBuilderTest extends TestCase { $this->assertEquals(md5('foobar'), $column); } - public function testSubstring() { + public function testSubstring(): void { $query = $this->connection->getQueryBuilder(); $query->select($query->func()->substring($query->createNamedParameter('foobar'), new Literal(2), $query->createNamedParameter(2))); @@ -258,7 +259,7 @@ class FunctionBuilderTest extends TestCase { $this->assertEquals('oo', $column); } - public function testSubstringNoLength() { + public function testSubstringNoLength(): void { $query = $this->connection->getQueryBuilder(); $query->select($query->func()->substring($query->createNamedParameter('foobar'), new Literal(2))); @@ -271,7 +272,7 @@ class FunctionBuilderTest extends TestCase { $this->assertEquals('oobar', $column); } - public function testLower() { + public function testLower(): void { $query = $this->connection->getQueryBuilder(); $query->select($query->func()->lower($query->createNamedParameter('FooBar'))); @@ -284,7 +285,7 @@ class FunctionBuilderTest extends TestCase { $this->assertEquals('foobar', $column); } - public function testAdd() { + public function testAdd(): void { $query = $this->connection->getQueryBuilder(); $query->select($query->func()->add($query->createNamedParameter(2, IQueryBuilder::PARAM_INT), new Literal(1))); @@ -297,7 +298,7 @@ class FunctionBuilderTest extends TestCase { $this->assertEquals(3, $column); } - public function testSubtract() { + public function testSubtract(): void { $query = $this->connection->getQueryBuilder(); $query->select($query->func()->subtract($query->createNamedParameter(2, IQueryBuilder::PARAM_INT), new Literal(1))); @@ -310,7 +311,7 @@ class FunctionBuilderTest extends TestCase { $this->assertEquals(1, $column); } - public function testCount() { + public function testCount(): void { $query = $this->connection->getQueryBuilder(); $query->select($query->func()->count('appid')); @@ -323,7 +324,7 @@ class FunctionBuilderTest extends TestCase { $this->assertGreaterThan(1, $column); } - public function octetLengthProvider() { + public static function octetLengthProvider(): array { return [ ['', 0], ['foobar', 6], @@ -332,10 +333,8 @@ class FunctionBuilderTest extends TestCase { ]; } - /** - * @dataProvider octetLengthProvider - */ - public function testOctetLength(string $str, int $bytes) { + #[\PHPUnit\Framework\Attributes\DataProvider('octetLengthProvider')] + public function testOctetLength(string $str, int $bytes): void { $query = $this->connection->getQueryBuilder(); $query->select($query->func()->octetLength($query->createNamedParameter($str, IQueryBuilder::PARAM_STR))); @@ -348,7 +347,7 @@ class FunctionBuilderTest extends TestCase { $this->assertEquals($bytes, $column); } - public function charLengthProvider() { + public static function charLengthProvider(): array { return [ ['', 0], ['foobar', 6], @@ -357,10 +356,8 @@ class FunctionBuilderTest extends TestCase { ]; } - /** - * @dataProvider charLengthProvider - */ - public function testCharLength(string $str, int $bytes) { + #[\PHPUnit\Framework\Attributes\DataProvider('charLengthProvider')] + public function testCharLength(string $str, int $bytes): void { $query = $this->connection->getQueryBuilder(); $query->select($query->func()->charLength($query->createNamedParameter($str, IQueryBuilder::PARAM_STR))); @@ -370,6 +367,7 @@ class FunctionBuilderTest extends TestCase { $result = $query->execute(); $column = $result->fetchOne(); $result->closeCursor(); + $this->assertNotNull($column); $this->assertEquals($bytes, $column); } @@ -393,7 +391,7 @@ class FunctionBuilderTest extends TestCase { $query->execute(); } - public function testMaxEmpty() { + public function testMaxEmpty(): void { $this->clearMinMax(); $query = $this->connection->getQueryBuilder(); @@ -409,7 +407,7 @@ class FunctionBuilderTest extends TestCase { $this->assertEquals(null, $row); } - public function testMinEmpty() { + public function testMinEmpty(): void { $this->clearMinMax(); $query = $this->connection->getQueryBuilder(); @@ -425,7 +423,7 @@ class FunctionBuilderTest extends TestCase { $this->assertEquals(null, $row); } - public function testMax() { + public function testMax(): void { $this->clearMinMax(); $this->setUpMinMax(10); $this->setUpMinMax(11); @@ -444,7 +442,7 @@ class FunctionBuilderTest extends TestCase { $this->assertEquals(20, $row); } - public function testMin() { + public function testMin(): void { $this->clearMinMax(); $this->setUpMinMax(10); $this->setUpMinMax(11); @@ -463,7 +461,7 @@ class FunctionBuilderTest extends TestCase { $this->assertEquals(10, $row); } - public function testGreatest() { + public function testGreatest(): void { $query = $this->connection->getQueryBuilder(); $query->select($query->func()->greatest($query->createNamedParameter(2, IQueryBuilder::PARAM_INT), new Literal(1))); @@ -476,7 +474,7 @@ class FunctionBuilderTest extends TestCase { $this->assertEquals(2, $row); } - public function testLeast() { + public function testLeast(): void { $query = $this->connection->getQueryBuilder(); $query->select($query->func()->least($query->createNamedParameter(2, IQueryBuilder::PARAM_INT), new Literal(1))); diff --git a/tests/lib/DB/QueryBuilder/Partitioned/JoinConditionTest.php b/tests/lib/DB/QueryBuilder/Partitioned/JoinConditionTest.php new file mode 100644 index 00000000000..8f84d6a0d2c --- /dev/null +++ b/tests/lib/DB/QueryBuilder/Partitioned/JoinConditionTest.php @@ -0,0 +1,74 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2024 Robin Appelman <robin@icewind.nl> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace lib\DB\QueryBuilder\Partitioned; + +use OC\DB\ConnectionAdapter; +use OC\DB\QueryBuilder\Partitioned\JoinCondition; +use OC\DB\QueryBuilder\QueryBuilder; +use OC\SystemConfig; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; +use Psr\Log\LoggerInterface; +use Test\TestCase; + +class JoinConditionTest extends TestCase { + protected function setUp(): void { + parent::setUp(); + } + + public static function platformProvider(): array { + return [ + [IDBConnection::PLATFORM_SQLITE], + [IDBConnection::PLATFORM_POSTGRES], + [IDBConnection::PLATFORM_MYSQL], + [IDBConnection::PLATFORM_ORACLE], + ]; + } + + private function getBuilder(string $platform): IQueryBuilder { + $connection = $this->createMock(ConnectionAdapter::class); + $connection->method('getDatabaseProvider')->willReturn($platform); + return new QueryBuilder( + $connection, + $this->createMock(SystemConfig::class), + $this->createMock(LoggerInterface::class) + ); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('platformProvider')] + public function testParseCondition(string $platform): void { + $query = $this->getBuilder($platform); + $param1 = $query->createNamedParameter('files'); + $param2 = $query->createNamedParameter('test'); + $condition = $query->expr()->andX( + $query->expr()->eq('tagmap.categoryid', 'tag.id'), + $query->expr()->eq('tag.type', $param1), + $query->expr()->eq('tag.uid', $param2) + ); + $parsed = JoinCondition::parse($condition, 'vcategory', 'tag', 'tagmap'); + $this->assertEquals('tagmap.categoryid', $parsed->fromColumn); + $this->assertEquals('tag.id', $parsed->toColumn); + $this->assertEquals([], $parsed->fromConditions); + $this->assertEquals([ + $query->expr()->eq('tag.type', $param1), + $query->expr()->eq('tag.uid', $param2), + ], $parsed->toConditions); + } + + #[\PHPUnit\Framework\Attributes\DataProvider('platformProvider')] + public function testParseCastCondition(string $platform): void { + $query = $this->getBuilder($platform); + + $condition = $query->expr()->eq($query->expr()->castColumn('m.objectid', IQueryBuilder::PARAM_INT), 'f.fileid'); + $parsed = JoinCondition::parse($condition, 'filecache', 'f', 'm'); + $this->assertEquals('m.objectid', $parsed->fromColumn); + $this->assertEquals('f.fileid', $parsed->toColumn); + $this->assertEquals([], $parsed->fromConditions); + } +} diff --git a/tests/lib/DB/QueryBuilder/Partitioned/PartitionedQueryBuilderTest.php b/tests/lib/DB/QueryBuilder/Partitioned/PartitionedQueryBuilderTest.php new file mode 100644 index 00000000000..f99adc73aa8 --- /dev/null +++ b/tests/lib/DB/QueryBuilder/Partitioned/PartitionedQueryBuilderTest.php @@ -0,0 +1,223 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +declare(strict_types=1); + +namespace Test\DB\QueryBuilder\Partitioned; + +use OC\DB\QueryBuilder\Partitioned\PartitionedQueryBuilder; +use OC\DB\QueryBuilder\Partitioned\PartitionSplit; +use OC\DB\QueryBuilder\Sharded\AutoIncrementHandler; +use OC\DB\QueryBuilder\Sharded\ShardConnectionManager; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; +use OCP\Server; +use Test\TestCase; + +/** + * @group DB + */ +class PartitionedQueryBuilderTest extends TestCase { + private IDBConnection $connection; + private ShardConnectionManager $shardConnectionManager; + private AutoIncrementHandler $autoIncrementHandler; + + protected function setUp(): void { + if (PHP_INT_SIZE < 8) { + $this->markTestSkipped('Test requires 64bit'); + } + $this->connection = Server::get(IDBConnection::class); + $this->shardConnectionManager = Server::get(ShardConnectionManager::class); + $this->autoIncrementHandler = Server::get(AutoIncrementHandler::class); + + $this->setupFileCache(); + } + + protected function tearDown(): void { + $this->cleanupDb(); + parent::tearDown(); + } + + + private function getQueryBuilder(): PartitionedQueryBuilder { + $builder = $this->connection->getQueryBuilder(); + if ($builder instanceof PartitionedQueryBuilder) { + return $builder; + } else { + return new PartitionedQueryBuilder($builder, [], $this->shardConnectionManager, $this->autoIncrementHandler); + } + } + + private function setupFileCache(): void { + $this->cleanupDb(); + $query = $this->getQueryBuilder(); + $query->insert('storages') + ->values([ + 'numeric_id' => $query->createNamedParameter(1001001, IQueryBuilder::PARAM_INT), + 'id' => $query->createNamedParameter('test1'), + ]); + $query->executeStatement(); + + $query = $this->getQueryBuilder(); + $query->insert('filecache') + ->values([ + 'storage' => $query->createNamedParameter(1001001, IQueryBuilder::PARAM_INT), + 'path' => $query->createNamedParameter('file1'), + 'path_hash' => $query->createNamedParameter(md5('file1')), + ]); + $query->executeStatement(); + $fileId = $query->getLastInsertId(); + + $query = $this->getQueryBuilder(); + $query->insert('filecache_extended') + ->hintShardKey('storage', 1001001) + ->values([ + 'fileid' => $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT), + 'upload_time' => $query->createNamedParameter(1234, IQueryBuilder::PARAM_INT), + ]); + $query->executeStatement(); + + $query = $this->getQueryBuilder(); + $query->insert('mounts') + ->values([ + 'storage_id' => $query->createNamedParameter(1001001, IQueryBuilder::PARAM_INT), + 'user_id' => $query->createNamedParameter('partitioned_test'), + 'mount_point' => $query->createNamedParameter('/mount/point'), + 'mount_provider_class' => $query->createNamedParameter('test'), + 'root_id' => $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT), + ]); + $query->executeStatement(); + } + + private function cleanupDb(): void { + $query = $this->getQueryBuilder(); + $query->delete('storages') + ->where($query->expr()->gt('numeric_id', $query->createNamedParameter(1000000, IQueryBuilder::PARAM_INT))); + $query->executeStatement(); + + $query = $this->getQueryBuilder(); + $query->delete('filecache') + ->where($query->expr()->gt('storage', $query->createNamedParameter(1000000, IQueryBuilder::PARAM_INT))) + ->runAcrossAllShards(); + $query->executeStatement(); + + $query = $this->getQueryBuilder(); + $query->delete('filecache_extended') + ->runAcrossAllShards(); + $query->executeStatement(); + + $query = $this->getQueryBuilder(); + $query->delete('mounts') + ->where($query->expr()->like('user_id', $query->createNamedParameter('partitioned_%'))); + $query->executeStatement(); + } + + public function testSimpleOnlyPartitionQuery(): void { + $builder = $this->getQueryBuilder(); + $builder->addPartition(new PartitionSplit('filecache', ['filecache'])); + + // query borrowed from UserMountCache + $query = $builder->select('path') + ->from('filecache') + ->where($builder->expr()->eq('storage', $builder->createNamedParameter(1001001, IQueryBuilder::PARAM_INT))); + + $results = $query->executeQuery()->fetchAll(); + $this->assertCount(1, $results); + $this->assertEquals($results[0]['path'], 'file1'); + } + + public function testSimplePartitionedQuery(): void { + $builder = $this->getQueryBuilder(); + $builder->addPartition(new PartitionSplit('filecache', ['filecache'])); + + // query borrowed from UserMountCache + $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path', 'mount_provider_class') + ->from('mounts', 'm') + ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid')) + ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter(1001001, IQueryBuilder::PARAM_INT))); + + $query->andWhere($builder->expr()->eq('user_id', $builder->createNamedParameter('partitioned_test'))); + + $this->assertEquals(2, $query->getPartitionCount()); + + $results = $query->executeQuery()->fetchAll(); + $this->assertCount(1, $results); + $this->assertEquals($results[0]['user_id'], 'partitioned_test'); + $this->assertEquals($results[0]['mount_point'], '/mount/point'); + $this->assertEquals($results[0]['mount_provider_class'], 'test'); + $this->assertEquals($results[0]['path'], 'file1'); + } + + public function testMultiTablePartitionedQuery(): void { + $builder = $this->getQueryBuilder(); + $builder->addPartition(new PartitionSplit('filecache', ['filecache', 'filecache_extended'])); + + $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path', 'mount_provider_class', 'fe.upload_time') + ->from('mounts', 'm') + ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid')) + ->innerJoin('f', 'filecache_extended', 'fe', $builder->expr()->eq('f.fileid', 'fe.fileid')) + ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter(1001001, IQueryBuilder::PARAM_INT))); + + $query->andWhere($builder->expr()->eq('user_id', $builder->createNamedParameter('partitioned_test'))); + + $this->assertEquals(2, $query->getPartitionCount()); + + $results = $query->executeQuery()->fetchAll(); + $this->assertCount(1, $results); + $this->assertEquals($results[0]['user_id'], 'partitioned_test'); + $this->assertEquals($results[0]['mount_point'], '/mount/point'); + $this->assertEquals($results[0]['mount_provider_class'], 'test'); + $this->assertEquals($results[0]['path'], 'file1'); + $this->assertEquals($results[0]['upload_time'], 1234); + } + + public function testPartitionedQueryFromSplit(): void { + $builder = $this->getQueryBuilder(); + $builder->addPartition(new PartitionSplit('filecache', ['filecache'])); + + $query = $builder->select('storage', 'm.root_id', 'm.user_id', 'm.mount_point', 'm.mount_id', 'path', 'm.mount_provider_class') + ->from('filecache', 'f') + ->innerJoin('f', 'mounts', 'm', $builder->expr()->eq('m.root_id', 'f.fileid')); + $query->where($builder->expr()->eq('storage', $builder->createNamedParameter(1001001, IQueryBuilder::PARAM_INT))); + + $query->andWhere($builder->expr()->eq('m.user_id', $builder->createNamedParameter('partitioned_test'))); + + $this->assertEquals(2, $query->getPartitionCount()); + + $results = $query->executeQuery()->fetchAll(); + $this->assertCount(1, $results); + $this->assertEquals($results[0]['user_id'], 'partitioned_test'); + $this->assertEquals($results[0]['mount_point'], '/mount/point'); + $this->assertEquals($results[0]['mount_provider_class'], 'test'); + $this->assertEquals($results[0]['path'], 'file1'); + } + + public function testMultiJoinPartitionedQuery(): void { + $builder = $this->getQueryBuilder(); + $builder->addPartition(new PartitionSplit('filecache', ['filecache'])); + + // query borrowed from UserMountCache + $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path', 'mount_provider_class') + ->selectAlias('s.id', 'storage_string_id') + ->from('mounts', 'm') + ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid')) + ->innerJoin('f', 'storages', 's', $builder->expr()->eq('f.storage', 's.numeric_id')) + ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter(1001001, IQueryBuilder::PARAM_INT))); + + $query->andWhere($builder->expr()->eq('user_id', $builder->createNamedParameter('partitioned_test'))); + + $this->assertEquals(3, $query->getPartitionCount()); + + $results = $query->executeQuery()->fetchAll(); + $this->assertCount(1, $results); + $this->assertEquals($results[0]['user_id'], 'partitioned_test'); + $this->assertEquals($results[0]['mount_point'], '/mount/point'); + $this->assertEquals($results[0]['mount_provider_class'], 'test'); + $this->assertEquals($results[0]['path'], 'file1'); + $this->assertEquals($results[0]['storage_string_id'], 'test1'); + } +} diff --git a/tests/lib/DB/QueryBuilder/QueryBuilderTest.php b/tests/lib/DB/QueryBuilder/QueryBuilderTest.php index 96cde8ba1f9..990191a9ff5 100644 --- a/tests/lib/DB/QueryBuilder/QueryBuilderTest.php +++ b/tests/lib/DB/QueryBuilder/QueryBuilderTest.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. @@ -9,13 +10,15 @@ namespace Test\DB\QueryBuilder; use Doctrine\DBAL\Query\Expression\CompositeExpression; use Doctrine\DBAL\Query\QueryException; -use Doctrine\DBAL\Result; use OC\DB\QueryBuilder\Literal; use OC\DB\QueryBuilder\Parameter; use OC\DB\QueryBuilder\QueryBuilder; use OC\SystemConfig; +use OCP\DB\IResult; +use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\DB\QueryBuilder\IQueryFunction; use OCP\IDBConnection; +use OCP\Server; use Psr\Log\LoggerInterface; /** @@ -41,7 +44,7 @@ class QueryBuilderTest extends \Test\TestCase { protected function setUp(): void { parent::setUp(); - $this->connection = \OC::$server->getDatabaseConnection(); + $this->connection = Server::get(IDBConnection::class); $this->config = $this->createMock(SystemConfig::class); $this->logger = $this->createMock(LoggerInterface::class); $this->queryBuilder = new QueryBuilder($this->connection, $this->config, $this->logger); @@ -87,7 +90,7 @@ class QueryBuilderTest extends \Test\TestCase { ->execute(); } - public function dataFirstResult() { + public static function dataFirstResult(): array { return [ [0, [99, 98, 97, 96, 95, 94, 93, 92, 91]], [0, [99, 98, 97, 96, 95, 94, 93, 92, 91]], @@ -97,12 +100,12 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataFirstResult * * @param int|null $firstResult * @param array $expectedSet */ - public function testFirstResult($firstResult, $expectedSet) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataFirstResult')] + public function testFirstResult($firstResult, $expectedSet): void { $this->deleteTestingRows(); $this->createTestingRows(); @@ -123,7 +126,7 @@ class QueryBuilderTest extends \Test\TestCase { $this->deleteTestingRows(); } - public function dataMaxResults() { + public static function dataMaxResults(): array { return [ [null, [99, 98, 97, 96, 95, 94, 93, 92, 91]], // Limit 0 gives mixed results: either all entries or none is returned @@ -134,12 +137,12 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataMaxResults * * @param int $maxResult * @param array $expectedSet */ - public function testMaxResults($maxResult, $expectedSet) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataMaxResults')] + public function testMaxResults($maxResult, $expectedSet): void { $this->deleteTestingRows(); $this->createTestingRows(); @@ -160,10 +163,10 @@ class QueryBuilderTest extends \Test\TestCase { $this->deleteTestingRows(); } - public function dataSelect() { + public function dataSelect(): array { $config = $this->createMock(SystemConfig::class); $logger = $this->createMock(LoggerInterface::class); - $queryBuilder = new QueryBuilder(\OC::$server->getDatabaseConnection(), $config, $logger); + $queryBuilder = new QueryBuilder(Server::get(IDBConnection::class), $config, $logger); return [ // select('column1') [['configvalue'], ['configvalue' => '99']], @@ -186,13 +189,13 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataSelect * * @param array $selectArguments * @param array $expected * @param string $expectedLiteral */ - public function testSelect($selectArguments, $expected, $expectedLiteral = '') { + #[\PHPUnit\Framework\Attributes\DataProvider('dataSelect')] + public function testSelect($selectArguments, $expected, $expectedLiteral = ''): void { $this->deleteTestingRows(); $this->createTestingRows(); @@ -228,10 +231,10 @@ class QueryBuilderTest extends \Test\TestCase { $this->deleteTestingRows(); } - public function dataSelectAlias() { + public function dataSelectAlias(): array { $config = $this->createMock(SystemConfig::class); $logger = $this->createMock(LoggerInterface::class); - $queryBuilder = new QueryBuilder(\OC::$server->getDatabaseConnection(), $config, $logger); + $queryBuilder = new QueryBuilder(Server::get(IDBConnection::class), $config, $logger); return [ ['configvalue', 'cv', ['cv' => '99']], [$queryBuilder->expr()->literal('column1'), 'thing', ['thing' => 'column1']], @@ -239,13 +242,13 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataSelectAlias * * @param mixed $select * @param array $alias * @param array $expected */ - public function testSelectAlias($select, $alias, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataSelectAlias')] + public function testSelectAlias($select, $alias, $expected): void { $this->deleteTestingRows(); $this->createTestingRows(); @@ -271,7 +274,7 @@ class QueryBuilderTest extends \Test\TestCase { $this->deleteTestingRows(); } - public function testSelectDistinct() { + public function testSelectDistinct(): void { $this->deleteTestingRows('testFirstResult1'); $this->deleteTestingRows('testFirstResult2'); $this->createTestingRows('testFirstResult1'); @@ -299,7 +302,7 @@ class QueryBuilderTest extends \Test\TestCase { $this->deleteTestingRows('testFirstResult2'); } - public function testSelectDistinctMultiple() { + public function testSelectDistinctMultiple(): void { $this->deleteTestingRows('testFirstResult1'); $this->deleteTestingRows('testFirstResult2'); $this->createTestingRows('testFirstResult1'); @@ -337,10 +340,10 @@ class QueryBuilderTest extends \Test\TestCase { $this->deleteTestingRows('testFirstResult2'); } - public function dataAddSelect() { + public function dataAddSelect(): array { $config = $this->createMock(SystemConfig::class); $logger = $this->createMock(LoggerInterface::class); - $queryBuilder = new QueryBuilder(\OC::$server->getDatabaseConnection(), $config, $logger); + $queryBuilder = new QueryBuilder(Server::get(IDBConnection::class), $config, $logger); return [ // addSelect('column1') [['configvalue'], ['appid' => 'testFirstResult', 'configvalue' => '99']], @@ -363,13 +366,13 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataAddSelect * * @param array $selectArguments * @param array $expected * @param string $expectedLiteral */ - public function testAddSelect($selectArguments, $expected, $expectedLiteral = '') { + #[\PHPUnit\Framework\Attributes\DataProvider('dataAddSelect')] + public function testAddSelect($selectArguments, $expected, $expectedLiteral = ''): void { $this->deleteTestingRows(); $this->createTestingRows(); @@ -407,7 +410,7 @@ class QueryBuilderTest extends \Test\TestCase { $this->deleteTestingRows(); } - public function dataDelete() { + public static function dataDelete(): array { return [ ['data', null, ['table' => '`*PREFIX*data`', 'alias' => null], '`*PREFIX*data`'], ['data', 't', ['table' => '`*PREFIX*data`', 'alias' => 't'], '`*PREFIX*data` t'], @@ -415,14 +418,14 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataDelete * * @param string $tableName * @param string $tableAlias * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testDelete($tableName, $tableAlias, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataDelete')] + public function testDelete($tableName, $tableAlias, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->delete($tableName, $tableAlias); $this->assertSame( @@ -436,7 +439,7 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function dataUpdate() { + public static function dataUpdate(): array { return [ ['data', null, ['table' => '`*PREFIX*data`', 'alias' => null], '`*PREFIX*data`'], ['data', 't', ['table' => '`*PREFIX*data`', 'alias' => 't'], '`*PREFIX*data` t'], @@ -444,14 +447,14 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataUpdate * * @param string $tableName * @param string $tableAlias * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testUpdate($tableName, $tableAlias, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataUpdate')] + public function testUpdate($tableName, $tableAlias, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->update($tableName, $tableAlias); $this->assertSame( @@ -465,20 +468,20 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function dataInsert() { + public static function dataInsert(): array { return [ ['data', ['table' => '`*PREFIX*data`'], '`*PREFIX*data`'], ]; } /** - * @dataProvider dataInsert * * @param string $tableName * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testInsert($tableName, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataInsert')] + public function testInsert($tableName, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->insert($tableName); $this->assertSame( @@ -492,10 +495,10 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function dataFrom() { + public function dataFrom(): array { $config = $this->createMock(SystemConfig::class); $logger = $this->createMock(LoggerInterface::class); - $qb = new QueryBuilder(\OC::$server->getDatabaseConnection(), $config, $logger); + $qb = new QueryBuilder(Server::get(IDBConnection::class), $config, $logger); return [ [$qb->createFunction('(' . $qb->select('*')->from('test')->getSQL() . ')'), 'q', null, null, [ ['table' => '(SELECT * FROM `*PREFIX*test`)', 'alias' => '`q`'] @@ -514,7 +517,6 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataFrom * * @param string|IQueryFunction $table1Name * @param string $table1Alias @@ -523,7 +525,8 @@ class QueryBuilderTest extends \Test\TestCase { * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testFrom($table1Name, $table1Alias, $table2Name, $table2Alias, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataFrom')] + public function testFrom($table1Name, $table1Alias, $table2Name, $table2Alias, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->from($table1Name, $table1Alias); if ($table2Name !== null) { $this->queryBuilder->from($table2Name, $table2Alias); @@ -540,7 +543,7 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function dataJoin() { + public static function dataJoin(): array { return [ [ 'd1', 'data2', null, null, @@ -562,7 +565,6 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataJoin * * @param string $fromAlias * @param string $tableName @@ -571,7 +573,8 @@ class QueryBuilderTest extends \Test\TestCase { * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataJoin')] + public function testJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->from('data1', 'd1'); $this->queryBuilder->join( $fromAlias, @@ -592,7 +595,6 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataJoin * * @param string $fromAlias * @param string $tableName @@ -601,7 +603,8 @@ class QueryBuilderTest extends \Test\TestCase { * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testInnerJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataJoin')] + public function testInnerJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->from('data1', 'd1'); $this->queryBuilder->innerJoin( $fromAlias, @@ -621,7 +624,7 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function dataLeftJoin() { + public static function dataLeftJoin(): array { return [ [ 'd1', 'data2', null, null, @@ -642,7 +645,6 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataLeftJoin * * @param string $fromAlias * @param string $tableName @@ -651,7 +653,8 @@ class QueryBuilderTest extends \Test\TestCase { * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testLeftJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataLeftJoin')] + public function testLeftJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->from('data1', 'd1'); $this->queryBuilder->leftJoin( $fromAlias, @@ -671,7 +674,7 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function dataRightJoin() { + public static function dataRightJoin(): array { return [ [ 'd1', 'data2', null, null, @@ -692,7 +695,6 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataRightJoin * * @param string $fromAlias * @param string $tableName @@ -701,7 +703,8 @@ class QueryBuilderTest extends \Test\TestCase { * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testRightJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataRightJoin')] + public function testRightJoin($fromAlias, $tableName, $tableAlias, $condition, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->from('data1', 'd1'); $this->queryBuilder->rightJoin( $fromAlias, @@ -721,7 +724,7 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function dataSet() { + public static function dataSet(): array { return [ ['column1', new Literal('value'), null, null, ['`column1` = value'], '`column1` = value'], ['column1', new Parameter(':param'), null, null, ['`column1` = :param'], '`column1` = :param'], @@ -731,7 +734,6 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataSet * * @param string $partOne1 * @param string $partOne2 @@ -740,7 +742,8 @@ class QueryBuilderTest extends \Test\TestCase { * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testSet($partOne1, $partOne2, $partTwo1, $partTwo2, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataSet')] + public function testSet($partOne1, $partOne2, $partTwo1, $partTwo2, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->update('data'); $this->queryBuilder->set($partOne1, $partOne2); if ($partTwo1 !== null) { @@ -758,7 +761,7 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function dataWhere() { + public static function dataWhere(): array { return [ [['where1'], new CompositeExpression('AND', ['where1']), 'where1'], [['where1', 'where2'], new CompositeExpression('AND', ['where1', 'where2']), '(where1) AND (where2)'], @@ -766,13 +769,13 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataWhere * * @param array $whereArguments * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testWhere($whereArguments, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataWhere')] + public function testWhere($whereArguments, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->select('column'); call_user_func_array( [$this->queryBuilder, 'where'], @@ -791,13 +794,13 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataWhere * * @param array $whereArguments * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testAndWhere($whereArguments, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataWhere')] + public function testAndWhere($whereArguments, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->select('column'); call_user_func_array( [$this->queryBuilder, 'andWhere'], @@ -815,7 +818,7 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function dataOrWhere() { + public static function dataOrWhere(): array { return [ [['where1'], new CompositeExpression('OR', ['where1']), 'where1'], [['where1', 'where2'], new CompositeExpression('OR', ['where1', 'where2']), '(where1) OR (where2)'], @@ -823,13 +826,13 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataOrWhere * * @param array $whereArguments * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testOrWhere($whereArguments, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataOrWhere')] + public function testOrWhere($whereArguments, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->select('column'); call_user_func_array( [$this->queryBuilder, 'orWhere'], @@ -847,7 +850,7 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function dataGroupBy() { + public static function dataGroupBy(): array { return [ [['column1'], ['`column1`'], '`column1`'], [['column1', 'column2'], ['`column1`', '`column2`'], '`column1`, `column2`'], @@ -855,13 +858,13 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataGroupBy * * @param array $groupByArguments * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testGroupBy($groupByArguments, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataGroupBy')] + public function testGroupBy($groupByArguments, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->select('column'); call_user_func_array( [$this->queryBuilder, 'groupBy'], @@ -879,7 +882,7 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function dataAddGroupBy() { + public static function dataAddGroupBy(): array { return [ [['column2'], ['`column1`', '`column2`'], '`column1`, `column2`'], [['column2', 'column3'], ['`column1`', '`column2`', '`column3`'], '`column1`, `column2`, `column3`'], @@ -887,13 +890,13 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataAddGroupBy * * @param array $groupByArguments * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testAddGroupBy($groupByArguments, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataAddGroupBy')] + public function testAddGroupBy($groupByArguments, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->select('column'); $this->queryBuilder->groupBy('column1'); call_user_func_array( @@ -912,21 +915,21 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function dataSetValue() { + public static function dataSetValue(): array { return [ ['column', 'value', ['`column`' => 'value'], '(`column`) VALUES(value)'], ]; } /** - * @dataProvider dataSetValue * * @param string $column * @param string $value * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testSetValue($column, $value, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataSetValue')] + public function testSetValue($column, $value, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->insert('data'); $this->queryBuilder->setValue($column, $value); @@ -942,14 +945,14 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataSetValue * * @param string $column * @param string $value * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testValues($column, $value, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataSetValue')] + public function testValues($column, $value, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->insert('data'); $this->queryBuilder->values([ $column => $value, @@ -966,7 +969,7 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function dataHaving() { + public static function dataHaving(): array { return [ [['condition1'], new CompositeExpression('AND', ['condition1']), 'HAVING condition1'], [['condition1', 'condition2'], new CompositeExpression('AND', ['condition1', 'condition2']), 'HAVING (condition1) AND (condition2)'], @@ -984,13 +987,13 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataHaving * * @param array $havingArguments * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testHaving($havingArguments, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataHaving')] + public function testHaving($havingArguments, $expectedQueryPart, $expectedQuery): void { call_user_func_array( [$this->queryBuilder, 'having'], $havingArguments @@ -1007,7 +1010,7 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function dataAndHaving() { + public static function dataAndHaving(): array { return [ [['condition2'], new CompositeExpression('AND', ['condition1', 'condition2']), 'HAVING (condition1) AND (condition2)'], [['condition2', 'condition3'], new CompositeExpression('AND', ['condition1', 'condition2', 'condition3']), 'HAVING (condition1) AND (condition2) AND (condition3)'], @@ -1025,13 +1028,13 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataAndHaving * * @param array $havingArguments * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testAndHaving($havingArguments, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataAndHaving')] + public function testAndHaving($havingArguments, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->having('condition1'); call_user_func_array( [$this->queryBuilder, 'andHaving'], @@ -1049,7 +1052,7 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function dataOrHaving() { + public static function dataOrHaving(): array { return [ [['condition2'], new CompositeExpression('OR', ['condition1', 'condition2']), 'HAVING (condition1) OR (condition2)'], [['condition2', 'condition3'], new CompositeExpression('OR', ['condition1', 'condition2', 'condition3']), 'HAVING (condition1) OR (condition2) OR (condition3)'], @@ -1067,13 +1070,13 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataOrHaving * * @param array $havingArguments * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testOrHaving($havingArguments, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataOrHaving')] + public function testOrHaving($havingArguments, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->having('condition1'); call_user_func_array( [$this->queryBuilder, 'orHaving'], @@ -1091,7 +1094,7 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function dataOrderBy() { + public static function dataOrderBy(): array { return [ ['column', null, ['`column` ASC'], 'ORDER BY `column` ASC'], ['column', 'ASC', ['`column` ASC'], 'ORDER BY `column` ASC'], @@ -1100,14 +1103,14 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataOrderBy * * @param string $sort * @param string $order * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testOrderBy($sort, $order, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataOrderBy')] + public function testOrderBy($sort, $order, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->orderBy($sort, $order); $this->assertEquals( @@ -1121,7 +1124,7 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function dataAddOrderBy() { + public static function dataAddOrderBy(): array { return [ ['column2', null, null, ['`column1` ASC', '`column2` ASC'], 'ORDER BY `column1` ASC, `column2` ASC'], ['column2', null, 'ASC', ['`column1` ASC', '`column2` ASC'], 'ORDER BY `column1` ASC, `column2` ASC'], @@ -1136,7 +1139,6 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataAddOrderBy * * @param string $sort2 * @param string $order2 @@ -1144,7 +1146,8 @@ class QueryBuilderTest extends \Test\TestCase { * @param array $expectedQueryPart * @param string $expectedQuery */ - public function testAddOrderBy($sort2, $order2, $order1, $expectedQueryPart, $expectedQuery) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataAddOrderBy')] + public function testAddOrderBy($sort2, $order2, $order1, $expectedQueryPart, $expectedQuery): void { $this->queryBuilder->orderBy('column1', $order1); $this->queryBuilder->addOrderBy($sort2, $order2); @@ -1159,7 +1162,7 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function testGetLastInsertId() { + public function testGetLastInsertId(): void { $qB = $this->connection->getQueryBuilder(); try { @@ -1196,10 +1199,10 @@ class QueryBuilderTest extends \Test\TestCase { } } - public function dataGetTableName() { + public function dataGetTableName(): array { $config = $this->createMock(SystemConfig::class); $logger = $this->createMock(LoggerInterface::class); - $qb = new QueryBuilder(\OC::$server->getDatabaseConnection(), $config, $logger); + $qb = new QueryBuilder(Server::get(IDBConnection::class), $config, $logger); return [ ['*PREFIX*table', null, '`*PREFIX*table`'], ['*PREFIX*table', true, '`*PREFIX*table`'], @@ -1216,13 +1219,13 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataGetTableName * * @param string|IQueryFunction $tableName * @param bool $automatic * @param string $expected */ - public function testGetTableName($tableName, $automatic, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataGetTableName')] + public function testGetTableName($tableName, $automatic, $expected): void { if ($automatic !== null) { $this->queryBuilder->automaticTablePrefix($automatic); } @@ -1233,7 +1236,7 @@ class QueryBuilderTest extends \Test\TestCase { ); } - public function dataGetColumnName() { + public static function dataGetColumnName(): array { return [ ['column', '', '`column`'], ['column', 'a', '`a`.`column`'], @@ -1241,28 +1244,41 @@ class QueryBuilderTest extends \Test\TestCase { } /** - * @dataProvider dataGetColumnName * @param string $column * @param string $prefix * @param string $expected */ - public function testGetColumnName($column, $prefix, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataGetColumnName')] + public function testGetColumnName($column, $prefix, $expected): void { $this->assertSame( $expected, $this->queryBuilder->getColumnName($column, $prefix) ); } - public function testExecuteWithoutLogger() { + private function getConnection(): IDBConnection { + $connection = $this->createMock(IDBConnection::class); + $connection->method('executeStatement') + ->willReturn(3); + $connection->method('executeQuery') + ->willReturn($this->createMock(IResult::class)); + return $connection; + } + + public function testExecuteWithoutLogger(): void { $queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class); $queryBuilder - ->expects($this->once()) - ->method('execute') - ->willReturn(3); + ->method('getSQL') + ->willReturn(''); $queryBuilder - ->expects($this->any()) ->method('getParameters') ->willReturn([]); + $queryBuilder + ->method('getParameterTypes') + ->willReturn([]); + $queryBuilder + ->method('getType') + ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::UPDATE); $this->logger ->expects($this->never()) ->method('debug'); @@ -1273,10 +1289,11 @@ class QueryBuilderTest extends \Test\TestCase { ->willReturn(false); $this->invokePrivate($this->queryBuilder, 'queryBuilder', [$queryBuilder]); + $this->invokePrivate($this->queryBuilder, 'connection', [$this->getConnection()]); $this->assertEquals(3, $this->queryBuilder->execute()); } - public function testExecuteWithLoggerAndNamedArray() { + public function testExecuteWithLoggerAndNamedArray(): void { $queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class); $queryBuilder ->expects($this->any()) @@ -1286,20 +1303,25 @@ class QueryBuilderTest extends \Test\TestCase { 'key' => 'value', ]); $queryBuilder + ->method('getParameterTypes') + ->willReturn([ + 'foo' => IQueryBuilder::PARAM_STR, + 'key' => IQueryBuilder::PARAM_STR, + ]); + $queryBuilder + ->method('getType') + ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::UPDATE); + $queryBuilder ->expects($this->any()) ->method('getSQL') - ->willReturn('SELECT * FROM FOO WHERE BAR = ?'); - $queryBuilder - ->expects($this->once()) - ->method('execute') - ->willReturn(3); + ->willReturn('UPDATE FOO SET bar = 1 WHERE BAR = ?'); $this->logger ->expects($this->once()) ->method('debug') ->with( 'DB QueryBuilder: \'{query}\' with parameters: {params}', [ - 'query' => 'SELECT * FROM FOO WHERE BAR = ?', + 'query' => 'UPDATE FOO SET bar = 1 WHERE BAR = ?', 'params' => 'foo => \'bar\', key => \'value\'', 'app' => 'core', ] @@ -1311,30 +1333,33 @@ class QueryBuilderTest extends \Test\TestCase { ->willReturn(true); $this->invokePrivate($this->queryBuilder, 'queryBuilder', [$queryBuilder]); + $this->invokePrivate($this->queryBuilder, 'connection', [$this->getConnection()]); $this->assertEquals(3, $this->queryBuilder->execute()); } - public function testExecuteWithLoggerAndUnnamedArray() { + public function testExecuteWithLoggerAndUnnamedArray(): void { $queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class); $queryBuilder ->expects($this->any()) ->method('getParameters') ->willReturn(['Bar']); $queryBuilder + ->method('getParameterTypes') + ->willReturn([IQueryBuilder::PARAM_STR]); + $queryBuilder + ->method('getType') + ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::UPDATE); + $queryBuilder ->expects($this->any()) ->method('getSQL') - ->willReturn('SELECT * FROM FOO WHERE BAR = ?'); - $queryBuilder - ->expects($this->once()) - ->method('execute') - ->willReturn(3); + ->willReturn('UPDATE FOO SET bar = false WHERE BAR = ?'); $this->logger ->expects($this->once()) ->method('debug') ->with( 'DB QueryBuilder: \'{query}\' with parameters: {params}', [ - 'query' => 'SELECT * FROM FOO WHERE BAR = ?', + 'query' => 'UPDATE FOO SET bar = false WHERE BAR = ?', 'params' => '0 => \'Bar\'', 'app' => 'core', ] @@ -1346,30 +1371,33 @@ class QueryBuilderTest extends \Test\TestCase { ->willReturn(true); $this->invokePrivate($this->queryBuilder, 'queryBuilder', [$queryBuilder]); + $this->invokePrivate($this->queryBuilder, 'connection', [$this->getConnection()]); $this->assertEquals(3, $this->queryBuilder->execute()); } - public function testExecuteWithLoggerAndNoParams() { + public function testExecuteWithLoggerAndNoParams(): void { $queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class); $queryBuilder ->expects($this->any()) ->method('getParameters') ->willReturn([]); $queryBuilder + ->method('getParameterTypes') + ->willReturn([]); + $queryBuilder + ->method('getType') + ->willReturn(\Doctrine\DBAL\Query\QueryBuilder::UPDATE); + $queryBuilder ->expects($this->any()) ->method('getSQL') - ->willReturn('SELECT * FROM FOO WHERE BAR = ?'); - $queryBuilder - ->expects($this->once()) - ->method('execute') - ->willReturn(3); + ->willReturn('UPDATE FOO SET bar = false WHERE BAR = ?'); $this->logger ->expects($this->once()) ->method('debug') ->with( 'DB QueryBuilder: \'{query}\'', [ - 'query' => 'SELECT * FROM FOO WHERE BAR = ?', + 'query' => 'UPDATE FOO SET bar = false WHERE BAR = ?', 'app' => 'core', ] ); @@ -1380,10 +1408,11 @@ class QueryBuilderTest extends \Test\TestCase { ->willReturn(true); $this->invokePrivate($this->queryBuilder, 'queryBuilder', [$queryBuilder]); + $this->invokePrivate($this->queryBuilder, 'connection', [$this->getConnection()]); $this->assertEquals(3, $this->queryBuilder->execute()); } - public function testExecuteWithParameterTooLarge() { + public function testExecuteWithParameterTooLarge(): void { $queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class); $p = array_fill(0, 1001, 'foo'); $queryBuilder @@ -1391,17 +1420,16 @@ class QueryBuilderTest extends \Test\TestCase { ->method('getParameters') ->willReturn([$p]); $queryBuilder + ->method('getParameterTypes') + ->willReturn([IQueryBuilder::PARAM_STR_ARRAY]); + $queryBuilder ->expects($this->any()) ->method('getSQL') ->willReturn('SELECT * FROM FOO WHERE BAR IN (?)'); - $queryBuilder - ->expects($this->once()) - ->method('execute') - ->willReturn($this->createMock(Result::class)); $this->logger ->expects($this->once()) ->method('error') - ->willReturnCallback(function ($message, $parameters) { + ->willReturnCallback(function ($message, $parameters): void { $this->assertInstanceOf(QueryException::class, $parameters['exception']); $this->assertSame( 'More than 1000 expressions in a list are not allowed on Oracle.', @@ -1415,10 +1443,11 @@ class QueryBuilderTest extends \Test\TestCase { ->willReturn(false); $this->invokePrivate($this->queryBuilder, 'queryBuilder', [$queryBuilder]); + $this->invokePrivate($this->queryBuilder, 'connection', [$this->getConnection()]); $this->queryBuilder->execute(); } - public function testExecuteWithParametersTooMany() { + public function testExecuteWithParametersTooMany(): void { $queryBuilder = $this->createMock(\Doctrine\DBAL\Query\QueryBuilder::class); $p = array_fill(0, 999, 'foo'); $queryBuilder @@ -1426,17 +1455,16 @@ class QueryBuilderTest extends \Test\TestCase { ->method('getParameters') ->willReturn(array_fill(0, 66, $p)); $queryBuilder + ->method('getParameterTypes') + ->willReturn([IQueryBuilder::PARAM_STR_ARRAY]); + $queryBuilder ->expects($this->any()) ->method('getSQL') ->willReturn('SELECT * FROM FOO WHERE BAR IN (?) OR BAR IN (?)'); - $queryBuilder - ->expects($this->once()) - ->method('execute') - ->willReturn($this->createMock(Result::class)); $this->logger ->expects($this->once()) ->method('error') - ->willReturnCallback(function ($message, $parameters) { + ->willReturnCallback(function ($message, $parameters): void { $this->assertInstanceOf(QueryException::class, $parameters['exception']); $this->assertSame( 'The number of parameters must not exceed 65535. Restriction by PostgreSQL.', @@ -1450,6 +1478,7 @@ class QueryBuilderTest extends \Test\TestCase { ->willReturn(false); $this->invokePrivate($this->queryBuilder, 'queryBuilder', [$queryBuilder]); + $this->invokePrivate($this->queryBuilder, 'connection', [$this->getConnection()]); $this->queryBuilder->execute(); } } diff --git a/tests/lib/DB/QueryBuilder/QuoteHelperTest.php b/tests/lib/DB/QueryBuilder/QuoteHelperTest.php index 12984bac3e0..6efb55708a1 100644 --- a/tests/lib/DB/QueryBuilder/QuoteHelperTest.php +++ b/tests/lib/DB/QueryBuilder/QuoteHelperTest.php @@ -1,4 +1,5 @@ <?php + /** * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2016 ownCloud, Inc. @@ -23,7 +24,7 @@ class QuoteHelperTest extends \Test\TestCase { $this->helper = new QuoteHelper(); } - public function dataQuoteColumnName() { + public static function dataQuoteColumnName(): array { return [ ['column', '`column`'], [new Literal('literal'), 'literal'], @@ -37,18 +38,18 @@ class QuoteHelperTest extends \Test\TestCase { } /** - * @dataProvider dataQuoteColumnName * @param mixed $input * @param string $expected */ - public function testQuoteColumnName($input, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataQuoteColumnName')] + public function testQuoteColumnName($input, $expected): void { $this->assertSame( $expected, $this->helper->quoteColumnName($input) ); } - public function dataQuoteColumnNames() { + public static function dataQuoteColumnNames(): array { return [ // Single case ['d.column', '`d`.`column`'], @@ -72,11 +73,11 @@ class QuoteHelperTest extends \Test\TestCase { } /** - * @dataProvider dataQuoteColumnNames * @param mixed $input * @param string $expected */ - public function testQuoteColumnNames($input, $expected) { + #[\PHPUnit\Framework\Attributes\DataProvider('dataQuoteColumnNames')] + public function testQuoteColumnNames($input, $expected): void { $this->assertSame( $expected, $this->helper->quoteColumnNames($input) diff --git a/tests/lib/DB/QueryBuilder/Sharded/SharedQueryBuilderTest.php b/tests/lib/DB/QueryBuilder/Sharded/SharedQueryBuilderTest.php new file mode 100644 index 00000000000..d0f232cb03f --- /dev/null +++ b/tests/lib/DB/QueryBuilder/Sharded/SharedQueryBuilderTest.php @@ -0,0 +1,128 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2024 Robin Appelman <robin@icewind.nl> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace Test\DB\QueryBuilder\Sharded; + +use OC\DB\QueryBuilder\Sharded\AutoIncrementHandler; +use OC\DB\QueryBuilder\Sharded\InvalidShardedQueryException; +use OC\DB\QueryBuilder\Sharded\RoundRobinShardMapper; +use OC\DB\QueryBuilder\Sharded\ShardConnectionManager; +use OC\DB\QueryBuilder\Sharded\ShardDefinition; +use OC\DB\QueryBuilder\Sharded\ShardedQueryBuilder; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; +use OCP\Server; +use Test\TestCase; + +/** + * @group DB + */ +class SharedQueryBuilderTest extends TestCase { + private IDBConnection $connection; + private AutoIncrementHandler $autoIncrementHandler; + + protected function setUp(): void { + if (PHP_INT_SIZE < 8) { + $this->markTestSkipped('Test requires 64bit'); + } + $this->connection = Server::get(IDBConnection::class); + $this->autoIncrementHandler = Server::get(AutoIncrementHandler::class); + } + + + private function getQueryBuilder(string $table, string $shardColumn, string $primaryColumn, array $companionTables = []): ShardedQueryBuilder { + return new ShardedQueryBuilder( + $this->connection->getQueryBuilder(), + [ + new ShardDefinition($table, $primaryColumn, [], $shardColumn, new RoundRobinShardMapper(), $companionTables, [], 0, 0), + ], + $this->createMock(ShardConnectionManager::class), + $this->autoIncrementHandler, + ); + } + + public function testGetShardKeySingleParam(): void { + $query = $this->getQueryBuilder('filecache', 'storage', 'fileid'); + $query->select('fileid', 'path') + ->from('filecache') + ->where($query->expr()->eq('storage', $query->createNamedParameter(10, IQueryBuilder::PARAM_INT))); + + $this->assertEquals([], $query->getPrimaryKeys()); + $this->assertEquals([10], $query->getShardKeys()); + } + + public function testGetPrimaryKeyParam(): void { + $query = $this->getQueryBuilder('filecache', 'storage', 'fileid'); + $query->select('fileid', 'path') + ->from('filecache') + ->where($query->expr()->in('fileid', $query->createNamedParameter([10, 11], IQueryBuilder::PARAM_INT))); + + $this->assertEquals([10, 11], $query->getPrimaryKeys()); + $this->assertEquals([], $query->getShardKeys()); + } + + public function testValidateWithShardKey(): void { + $query = $this->getQueryBuilder('filecache', 'storage', 'fileid'); + $query->select('fileid', 'path') + ->from('filecache') + ->where($query->expr()->eq('storage', $query->createNamedParameter(10))); + + $query->validate(); + $this->assertTrue(true); + } + + public function testValidateWithPrimaryKey(): void { + $query = $this->getQueryBuilder('filecache', 'storage', 'fileid'); + $query->select('fileid', 'path') + ->from('filecache') + ->where($query->expr()->in('fileid', $query->createNamedParameter([10, 11], IQueryBuilder::PARAM_INT))); + + $query->validate(); + $this->assertTrue(true); + } + + public function testValidateWithNoKey(): void { + $query = $this->getQueryBuilder('filecache', 'storage', 'fileid'); + $query->select('fileid', 'path') + ->from('filecache') + ->where($query->expr()->lt('size', $query->createNamedParameter(0))); + + $this->expectException(InvalidShardedQueryException::class); + $query->validate(); + $this->fail('exception expected'); + } + + public function testValidateNonSharedTable(): void { + $query = $this->getQueryBuilder('filecache', 'storage', 'fileid'); + $query->select('configvalue') + ->from('appconfig') + ->where($query->expr()->eq('configkey', $query->createNamedParameter('test'))); + + $query->validate(); + $this->assertTrue(true); + } + + public function testGetShardKeyMultipleSingleParam(): void { + $query = $this->getQueryBuilder('filecache', 'storage', 'fileid'); + $query->select('fileid', 'path') + ->from('filecache') + ->where($query->expr()->andX( + $query->expr()->gt('mtime', $query->createNamedParameter(0), IQueryBuilder::PARAM_INT), + $query->expr()->orX( + $query->expr()->eq('storage', $query->createNamedParameter(10, IQueryBuilder::PARAM_INT)), + $query->expr()->andX( + $query->expr()->eq('storage', $query->createNamedParameter(11, IQueryBuilder::PARAM_INT)), + $query->expr()->like('path', $query->createNamedParameter('foo/%')) + ) + ) + )); + + $this->assertEquals([], $query->getPrimaryKeys()); + $this->assertEquals([10, 11], $query->getShardKeys()); + } +} |