Issue #3316923 by mondrake, daffie, catch: Sort out more driver specific database kernel tests
parent
104a255921
commit
92c09c8f57
|
@ -43,6 +43,24 @@ class SchemaTest extends DriverSpecificSchemaTestBase {
|
|||
$this->assertSame('ascii_general_ci', $string_ascii_check, 'test_field_string_ascii should have a ascii_general_ci collation, but it has not.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testTableWithSpecificDataType(): void {
|
||||
$table_specification = [
|
||||
'description' => 'Schema table description.',
|
||||
'fields' => [
|
||||
'timestamp' => [
|
||||
'mysql_type' => 'timestamp',
|
||||
'not null' => FALSE,
|
||||
'default' => NULL,
|
||||
],
|
||||
],
|
||||
];
|
||||
$this->schema->createTable('test_timestamp', $table_specification);
|
||||
$this->assertTrue($this->schema->tableExists('test_timestamp'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that indexes on string fields are limited to 191 characters on MySQL.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\mysql\Kernel\mysql;
|
||||
|
||||
use Drupal\KernelTests\Core\Database\DriverSpecificSyntaxTestBase;
|
||||
|
||||
/**
|
||||
* Tests MySql syntax interpretation.
|
||||
*
|
||||
* @group Database
|
||||
*/
|
||||
class SyntaxTest extends DriverSpecificSyntaxTestBase {
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\mysql\Kernel\mysql;
|
||||
|
||||
use Drupal\KernelTests\Core\Database\DriverSpecificTransactionTestBase;
|
||||
|
||||
/**
|
||||
* Tests transaction for the MySQL driver.
|
||||
*
|
||||
* @group Database
|
||||
*/
|
||||
class TransactionTest extends DriverSpecificTransactionTestBase {
|
||||
}
|
|
@ -39,6 +39,24 @@ class SchemaTest extends DriverSpecificSchemaTestBase {
|
|||
$this->assertTrue($sequenceExists, 'Sequence was renamed.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testTableWithSpecificDataType(): void {
|
||||
$table_specification = [
|
||||
'description' => 'Schema table description.',
|
||||
'fields' => [
|
||||
'timestamp' => [
|
||||
'pgsql_type' => 'timestamp',
|
||||
'not null' => FALSE,
|
||||
'default' => NULL,
|
||||
],
|
||||
],
|
||||
];
|
||||
$this->schema->createTable('test_timestamp', $table_specification);
|
||||
$this->assertTrue($this->schema->tableExists('test_timestamp'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Drupal\pgsql\Driver\Database\pgsql\Schema::introspectIndexSchema
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\pgsql\Kernel\pgsql;
|
||||
|
||||
use Drupal\KernelTests\Core\Database\DriverSpecificSyntaxTestBase;
|
||||
|
||||
/**
|
||||
* Tests PostgreSQL syntax interpretation.
|
||||
*
|
||||
* @group Database
|
||||
*/
|
||||
class SyntaxTest extends DriverSpecificSyntaxTestBase {
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\pgsql\Kernel\pgsql;
|
||||
|
||||
use Drupal\KernelTests\Core\Database\DriverSpecificTransactionTestBase;
|
||||
|
||||
/**
|
||||
* Tests transaction for the PostgreSQL driver.
|
||||
*
|
||||
* @group Database
|
||||
*/
|
||||
class TransactionTest extends DriverSpecificTransactionTestBase {
|
||||
}
|
|
@ -5,7 +5,7 @@ namespace Drupal\Tests\sqlite\Kernel\sqlite;
|
|||
use Drupal\KernelTests\Core\Database\DriverSpecificSchemaTestBase;
|
||||
|
||||
/**
|
||||
* Tests schema API for the PostgreSQL driver.
|
||||
* Tests schema API for the SQLite driver.
|
||||
*
|
||||
* @group Database
|
||||
*/
|
||||
|
@ -26,6 +26,24 @@ class SchemaTest extends DriverSpecificSchemaTestBase {
|
|||
// Sqlite does not throw an IntegrityConstraintViolationException here.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testTableWithSpecificDataType(): void {
|
||||
$table_specification = [
|
||||
'description' => 'Schema table description.',
|
||||
'fields' => [
|
||||
'timestamp' => [
|
||||
'sqlite_type' => 'datetime',
|
||||
'not null' => FALSE,
|
||||
'default' => NULL,
|
||||
],
|
||||
],
|
||||
];
|
||||
$this->schema->createTable('test_timestamp', $table_specification);
|
||||
$this->assertTrue($this->schema->tableExists('test_timestamp'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Drupal\sqlite\Driver\Database\sqlite\Schema::introspectIndexSchema
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\sqlite\Kernel\sqlite;
|
||||
|
||||
use Drupal\KernelTests\Core\Database\DriverSpecificSyntaxTestBase;
|
||||
|
||||
/**
|
||||
* Tests SQLite syntax interpretation.
|
||||
*
|
||||
* @group Database
|
||||
*/
|
||||
class SyntaxTest extends DriverSpecificSyntaxTestBase {
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\sqlite\Kernel\sqlite;
|
||||
|
||||
use Drupal\KernelTests\Core\Database\DriverSpecificTransactionTestBase;
|
||||
|
||||
/**
|
||||
* Tests transaction for the SQLite driver.
|
||||
*
|
||||
* @group Database
|
||||
*/
|
||||
class TransactionTest extends DriverSpecificTransactionTestBase {
|
||||
}
|
|
@ -4,6 +4,7 @@ namespace Drupal\KernelTests\Core\Cache;
|
|||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\DatabaseBackendFactory;
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\entity_test\Entity\EntityTest;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
@ -11,7 +12,7 @@ use Drupal\user\Entity\User;
|
|||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Tests that cache tag invalidation queries are delayed to the end of transactions.
|
||||
* Tests delaying of cache tag invalidation queries to the end of transactions.
|
||||
*
|
||||
* @group Cache
|
||||
*/
|
||||
|
@ -33,12 +34,6 @@ class EndOfTransactionQueriesTest extends KernelTestBase {
|
|||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
// This can only be checked after installing Drupal as it requires functions
|
||||
// from bootstrap.inc.
|
||||
if (!class_exists($this->getDatabaseConnectionInfo()['default']['namespace'] . '\Connection')) {
|
||||
$this->markTestSkipped(sprintf('No logging override exists for the %s database driver. Create it, subclass this test class and override ::getDatabaseConnectionInfo().', $this->getDatabaseConnectionInfo()['default']['driver']));
|
||||
}
|
||||
|
||||
$this->installSchema('system', 'sequences');
|
||||
$this->installEntitySchema('entity_test');
|
||||
$this->installEntitySchema('user');
|
||||
|
@ -61,21 +56,23 @@ class EndOfTransactionQueriesTest extends KernelTestBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* Tests an entity save.
|
||||
*/
|
||||
public function testEntitySave() {
|
||||
public function testEntitySave(): void {
|
||||
\Drupal::cache()->set('test_cache_pretransaction_foobar', 'something', Cache::PERMANENT, ['foobar']);
|
||||
\Drupal::cache()->set('test_cache_pretransaction_entity_test_list', 'something', Cache::PERMANENT, ['entity_test_list']);
|
||||
|
||||
$entity = EntityTest::create(['name' => $this->randomString()]);
|
||||
\Drupal::database()->resetLoggedStatements();
|
||||
|
||||
Database::startLog('testEntitySave');
|
||||
$entity->save();
|
||||
|
||||
$executed_statements = \Drupal::database()->getLoggedStatements();
|
||||
$executed_statements = [];
|
||||
foreach (Database::getLog('testEntitySave') as $log) {
|
||||
$executed_statements[] = $log['query'];
|
||||
}
|
||||
$last_statement_index = max(array_keys($executed_statements));
|
||||
|
||||
$cachetag_statements = array_keys($this->getStatementsForTable(\Drupal::database()->getLoggedStatements(), 'cachetags'));
|
||||
$cachetag_statements = array_keys($this->getStatementsForTable($executed_statements, 'cachetags'));
|
||||
$this->assertSame($last_statement_index - count($cachetag_statements) + 1, min($cachetag_statements), 'All of the last queries in the transaction are for the "cachetags" table.');
|
||||
|
||||
// Verify that a nested entity save occurred.
|
||||
|
@ -103,9 +100,9 @@ class EndOfTransactionQueriesTest extends KernelTestBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* Tests an entity save rollback.
|
||||
*/
|
||||
public function testEntitySaveRollback() {
|
||||
public function testEntitySaveRollback(): void {
|
||||
\Drupal::cache()
|
||||
->set('test_cache_pretransaction_entity_test_list', 'something', Cache::PERMANENT, ['entity_test_list']);
|
||||
\Drupal::cache()
|
||||
|
@ -148,44 +145,29 @@ class EndOfTransactionQueriesTest extends KernelTestBase {
|
|||
* Filtered statement list.
|
||||
*/
|
||||
protected function getStatementsForTable(array $statements, $table_name) {
|
||||
$tables = array_filter(array_map([$this, 'statementToTableName'], $statements));
|
||||
return array_filter($tables, function ($table_for_statement) use ($table_name) {
|
||||
return $table_for_statement === $table_name;
|
||||
return array_filter($statements, function ($statement) use ($table_name) {
|
||||
return $this->isStatementRelatedToTable($statement, $table_name);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the table name for a statement.
|
||||
* Determines if a statement is relative to a specified table.
|
||||
*
|
||||
* Non-core database drivers can override this method if they have different
|
||||
* patterns to identify table related statements.
|
||||
*
|
||||
* @param string $statement
|
||||
* The query statement.
|
||||
* @param string $tableName
|
||||
* The table name, Drupal style, without curly brackets or prefix.
|
||||
*
|
||||
* @return string|null
|
||||
* The name of the table or NULL if none was found.
|
||||
* @return bool
|
||||
* TRUE if the statement is relative to the table, FALSE otherwise.
|
||||
*/
|
||||
protected static function statementToTableName($statement) {
|
||||
if (preg_match('/.*\{([^\}]+)\}.*/', $statement, $matches)) {
|
||||
return $matches[1];
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDatabaseConnectionInfo() {
|
||||
$info = parent::getDatabaseConnectionInfo();
|
||||
// Override default database driver to one that does logging. Third-party
|
||||
// (non-core) database drivers can achieve the same test coverage by
|
||||
// subclassing this test class and overriding only this method.
|
||||
// @see \Drupal\database_statement_monitoring_test\LoggedStatementsTrait
|
||||
// @see \Drupal\database_statement_monitoring_test\mysql\Connection
|
||||
// @see \Drupal\database_statement_monitoring_test\pgsql\Connection
|
||||
// @see \Drupal\database_statement_monitoring_test\sqlite\Connection
|
||||
$info['default']['namespace'] = '\Drupal\database_statement_monitoring_test\\' . $info['default']['driver'];
|
||||
return $info;
|
||||
protected static function isStatementRelatedToTable(string $statement, string $tableName): bool {
|
||||
$realTableIdentifier = Database::getConnection()->prefixTables('{' . $tableName . '}');
|
||||
$pattern = '/.*(INTO|FROM|UPDATE)( |\n)' . preg_quote($realTableIdentifier, '/') . '/';
|
||||
return preg_match($pattern, $statement) === 1 ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -141,33 +141,4 @@ class BasicSyntaxTest extends DatabaseTestBase {
|
|||
$this->assertSame('4', $num_matches, 'Found 4 records.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests allowing square brackets in queries.
|
||||
*
|
||||
* @see \Drupal\Core\Database\Connection::prepareQuery()
|
||||
*/
|
||||
public function testAllowSquareBrackets() {
|
||||
$this->connection->insert('test')
|
||||
->fields(['name'])
|
||||
->values([
|
||||
'name' => '[square]',
|
||||
])
|
||||
->execute();
|
||||
|
||||
// Note that this is a very bad example query because arguments should be
|
||||
// passed in via the $args parameter.
|
||||
$result = $this->connection->query("select name from {test} where name = '[square]'", [], ['allow_square_brackets' => TRUE]);
|
||||
$this->assertSame('[square]', $result->fetchField());
|
||||
|
||||
// Test that allow_square_brackets has no effect on arguments.
|
||||
$result = $this->connection->query("select [name] from {test} where [name] = :value", [':value' => '[square]']);
|
||||
$this->assertSame('[square]', $result->fetchField());
|
||||
$result = $this->connection->query("select name from {test} where name = :value", [':value' => '[square]'], ['allow_square_brackets' => TRUE]);
|
||||
$this->assertSame('[square]', $result->fetchField());
|
||||
|
||||
// Test square brackets using the query builder.
|
||||
$result = $this->connection->select('test')->fields('test', ['name'])->condition('name', '[square]')->execute();
|
||||
$this->assertSame('[square]', $result->fetchField());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,11 +27,11 @@ abstract class DriverSpecificKernelTestBase extends KernelTestBase {
|
|||
* @inheritdoc
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->connection = Database::getConnection();
|
||||
|
||||
$running_provider = $this->connection->getProvider();
|
||||
$running_driver = $this->connection->driver();
|
||||
// Find the current SUT database driver from the connection info. If that
|
||||
// is not the one the test requires, skip before test database
|
||||
// initialization so to save cycles.
|
||||
$this->root = static::getDrupalRoot();
|
||||
$connectionInfo = $this->getDatabaseConnectionInfo();
|
||||
$test_class_parts = explode('\\', get_class($this));
|
||||
$expected_provider = $test_class_parts[2] ?? '';
|
||||
for ($i = 3; $i < count($test_class_parts); $i++) {
|
||||
|
@ -40,6 +40,17 @@ abstract class DriverSpecificKernelTestBase extends KernelTestBase {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if ($connectionInfo['default']['driver'] !== $expected_driver) {
|
||||
$this->markTestSkipped("This test only runs for the database driver '$expected_driver'. Current database driver is '{$connectionInfo['default']['driver']}'.");
|
||||
}
|
||||
|
||||
parent::setUp();
|
||||
$this->connection = Database::getConnection();
|
||||
|
||||
// After database initialization, the database driver may be not provided
|
||||
// by the expected module; skip test in that case.
|
||||
$running_provider = $this->connection->getProvider();
|
||||
$running_driver = $this->connection->driver();
|
||||
if ($running_provider !== $expected_provider || $running_driver !== $expected_driver) {
|
||||
$this->markTestSkipped("This test only runs for the database driver '$expected_driver' provided by the '$expected_provider' module. Connected database driver is '$running_driver' provided by '$running_provider'.");
|
||||
}
|
||||
|
|
|
@ -308,28 +308,13 @@ abstract class DriverSpecificSchemaTestBase extends DriverSpecificKernelTestBase
|
|||
|
||||
// Check that the ID sequence gets renamed when the table is renamed.
|
||||
$this->checkSequenceRenaming($new_table_name);
|
||||
|
||||
// Use database specific data type and ensure that table is created.
|
||||
$table_specification = [
|
||||
'description' => 'Schema table description.',
|
||||
'fields' => [
|
||||
'timestamp' => [
|
||||
'mysql_type' => 'timestamp',
|
||||
'pgsql_type' => 'timestamp',
|
||||
'sqlite_type' => 'datetime',
|
||||
'not null' => FALSE,
|
||||
'default' => NULL,
|
||||
],
|
||||
],
|
||||
];
|
||||
try {
|
||||
$this->schema->createTable('test_timestamp', $table_specification);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
}
|
||||
$this->assertTrue($this->schema->tableExists('test_timestamp'), 'Table with database specific datatype was created.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests creating a table with database specific data type.
|
||||
*/
|
||||
abstract public function testTableWithSpecificDataType(): void;
|
||||
|
||||
/**
|
||||
* Tests creating unsigned columns and data integrity thereof.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\KernelTests\Core\Database;
|
||||
|
||||
/**
|
||||
* Tests driver specific SQL syntax interpretation.
|
||||
*/
|
||||
abstract class DriverSpecificSyntaxTestBase extends DriverSpecificDatabaseTestBase {
|
||||
|
||||
/**
|
||||
* Tests allowing square brackets in queries.
|
||||
*
|
||||
* This method should be overridden if the SQL syntax of the test queries is
|
||||
* not compatible with a non-core database driver. For example, the unquoted
|
||||
* 'name' identifier in Oracle is a reserved keyword that would let the test
|
||||
* query fail.
|
||||
*
|
||||
* @see \Drupal\Core\Database\Connection::prepareQuery()
|
||||
*/
|
||||
public function testAllowSquareBrackets() {
|
||||
$this->connection->insert('test')
|
||||
->fields(['name'])
|
||||
->values([
|
||||
'name' => '[square]',
|
||||
])
|
||||
->execute();
|
||||
|
||||
// Note that this is a very bad example query because arguments should be
|
||||
// passed in via the $args parameter.
|
||||
$result = $this->connection->query("select name from {test} where name = '[square]'", [], ['allow_square_brackets' => TRUE]);
|
||||
$this->assertSame('[square]', $result->fetchField());
|
||||
|
||||
// Test that allow_square_brackets has no effect on arguments.
|
||||
$result = $this->connection->query("select [name] from {test} where [name] = :value", [':value' => '[square]']);
|
||||
$this->assertSame('[square]', $result->fetchField());
|
||||
$result = $this->connection->query("select name from {test} where name = :value", [':value' => '[square]'], ['allow_square_brackets' => TRUE]);
|
||||
$this->assertSame('[square]', $result->fetchField());
|
||||
|
||||
// Test square brackets using the query builder.
|
||||
$result = $this->connection->select('test')->fields('test', ['name'])->condition('name', '[square]')->execute();
|
||||
$this->assertSame('[square]', $result->fetchField());
|
||||
}
|
||||
|
||||
}
|
|
@ -26,9 +26,13 @@ use PHPUnit\Framework\Error\Warning;
|
|||
* Do more stuff
|
||||
* Should still be in transaction A
|
||||
*
|
||||
* @group Database
|
||||
* These method can be overridden by non-core database driver if their
|
||||
* transaction behavior is different from core. For example, both oci8 (Oracle)
|
||||
* and mysqli (MySql) clients do not have a solution to check if a transaction
|
||||
* is active, and mysqli does not fail when rolling back and no transaction
|
||||
* active.
|
||||
*/
|
||||
class TransactionTest extends DatabaseTestBase {
|
||||
class DriverSpecificTransactionTestBase extends DriverSpecificDatabaseTestBase {
|
||||
|
||||
/**
|
||||
* Encapsulates a transaction's "inner layer" with an "outer layer".
|
Loading…
Reference in New Issue