Skip to content
Snippets Groups Projects
Commit cf3ae0f9 authored by catch's avatar catch
Browse files

Issue #3316923 by mondrake, daffie: Sort out more driver specific database kernel tests

parent 08b0f54b
No related branches found
No related tags found
36 merge requests!7452Issue #1797438. HTML5 validation is preventing form submit and not fully...,!54479.5.x SF update,!5014Issue #3071143: Table Render Array Example Is Incorrect,!4868Issue #1428520: Improve menu parent link selection,!4289Issue #1344552 by marcingy, Niklas Fiekas, Ravi.J, aleevas, Eduardo Morales...,!4114Issue #2707291: Disable body-level scrolling when a dialog is open as a modal,!4100Issue #3249600: Add support for PHP 8.1 Enums as allowed values for list_* data types,!3630Issue #2815301 by Chi, DanielVeza, kostyashupenko, smustgrave: Allow to create...,!3600Issue #3344629: Passing null to parameter #1 ($haystack) of type string is deprecated,!3291Issue #3336463: Rewrite rules for gzipped CSS and JavaScript aggregates never match,!3102Issue #3164428 by DonAtt, longwave, sahil.goyal, Anchal_gupta, alexpott: Use...,!2378Issue #2875033: Optimize joins and table selection in SQL entity query implementation,!2334Issue #3228209: Add hasRole() method to AccountInterface,!2074Issue #2707689: NodeForm::actions() checks for delete access on new entities,!2062Issue #3246454: Add weekly granularity to views date sort,!1591Issue #3199697: Add JSON:API Translation experimental module,!1484Exposed filters get values from URL when Ajax is on,!1255Issue #3238922: Refactor (if feasible) uses of the jQuery serialize function to use vanillaJS,!1254Issue #3238915: Refactor (if feasible) uses of the jQuery ready function to use VanillaJS,!1162Issue #3100350: Unable to save '/' root path alias,!1105Issue #3025039: New non translatable field on translatable content throws error,!1073issue #3191727: Focus states on mobile second level navigation items fixed,!10223132456: Fix issue where views instances are emptied before an ajax request is complete,!957Added throwing of InvalidPluginDefinitionException from getDefinition().,!925Issue #2339235: Remove taxonomy hard dependency on node module,!877Issue #2708101: Default value for link text is not saved,!873Issue #2875228: Site install not using batch API service,!872Draft: Issue #3221319: Race condition when creating menu links and editing content deletes menu links,!844Resolve #3036010 "Updaters",!712Issue #2909128: Autocomplete intermittent on Chrome Android,!617Issue #3043725: Provide a Entity Handler for user cancelation,!579Issue #2230909: Simple decimals fail to pass validation,!560Move callback classRemove outside of the loop,!555Issue #3202493,!485Sets the autocomplete attribute for username/password input field on login form.,!30Issue #3182188: Updates composer usage to point at ./vendor/bin/composer
Showing
with 229 additions and 79 deletions
......@@ -43,6 +43,24 @@ protected function assertCollation(): void {
$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.
*
......
<?php
namespace Drupal\Tests\mysql\Kernel\mysql;
use Drupal\KernelTests\Core\Database\DriverSpecificSyntaxTestBase;
/**
* Tests MySql syntax interpretation.
*
* @group Database
*/
class SyntaxTest extends DriverSpecificSyntaxTestBase {
}
<?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 @@ protected function checkSequenceRenaming(string $tableName): void {
$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
*/
......
<?php
namespace Drupal\Tests\pgsql\Kernel\pgsql;
use Drupal\KernelTests\Core\Database\DriverSpecificSyntaxTestBase;
/**
* Tests PostgreSQL syntax interpretation.
*
* @group Database
*/
class SyntaxTest extends DriverSpecificSyntaxTestBase {
}
<?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 @@
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 @@ protected function tryInsertExpectsIntegrityConstraintViolationException(string
// 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
*/
......
<?php
namespace Drupal\Tests\sqlite\Kernel\sqlite;
use Drupal\KernelTests\Core\Database\DriverSpecificSyntaxTestBase;
/**
* Tests SQLite syntax interpretation.
*
* @group Database
*/
class SyntaxTest extends DriverSpecificSyntaxTestBase {
}
<?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 {
}
......@@ -3,3 +3,5 @@ type: module
description: 'Support module for Database layer tests that need to monitor executed database statements.'
package: Testing
version: VERSION
lifecycle: deprecated
lifecycle_link: 'https://www.drupal.org/node/3318162'
......@@ -2,8 +2,15 @@
namespace Drupal\database_statement_monitoring_test;
@trigger_error('\Drupal\database_statement_monitoring_test\LoggedStatementsTrait is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. There is no replacement. See https://www.drupal.org/node/3318162', E_USER_DEPRECATED);
/**
* Trait for Connection classes that can store logged statements.
*
* @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. There is no
* replacement.
*
* @see https://www.drupal.org/node/3318162
*/
trait LoggedStatementsTrait {
......
......@@ -5,8 +5,15 @@
use Drupal\mysql\Driver\Database\mysql\Connection as BaseConnection;
use Drupal\database_statement_monitoring_test\LoggedStatementsTrait;
@trigger_error('\Drupal\database_statement_monitoring_test\mysql\Connection is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. There is no replacement. See https://www.drupal.org/node/3318162', E_USER_DEPRECATED);
/**
* MySQL Connection class that can log executed queries.
*
* @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. There is no
* replacement.
*
* @see https://www.drupal.org/node/3318162
*/
class Connection extends BaseConnection {
use LoggedStatementsTrait;
......
......@@ -4,5 +4,13 @@
use Drupal\mysql\Driver\Database\mysql\Install\Tasks as BaseTasks;
@trigger_error('\Drupal\database_statement_monitoring_test\mysql\Install\Tasks is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. There is no replacement. See https://www.drupal.org/node/3318162', E_USER_DEPRECATED);
/**
* @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. There is no
* replacement.
*
* @see https://www.drupal.org/node/3318162
*/
class Tasks extends BaseTasks {
}
......@@ -5,8 +5,15 @@
use Drupal\pgsql\Driver\Database\pgsql\Connection as BaseConnection;
use Drupal\database_statement_monitoring_test\LoggedStatementsTrait;
@trigger_error('\Drupal\database_statement_monitoring_test\pgsql\Connection is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. There is no replacement. See https://www.drupal.org/node/3318162', E_USER_DEPRECATED);
/**
* PostgreSQL Connection class that can log executed queries.
*
* @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. There is no
* replacement.
*
* @see https://www.drupal.org/node/3318162
*/
class Connection extends BaseConnection {
use LoggedStatementsTrait;
......
......@@ -4,5 +4,13 @@
use Drupal\pgsql\Driver\Database\pgsql\Install\Tasks as BaseTasks;
@trigger_error('\Drupal\database_statement_monitoring_test\pgsql\Install\Tasks is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. There is no replacement. See https://www.drupal.org/node/3318162', E_USER_DEPRECATED);
/**
* @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. There is no
* replacement.
*
* @see https://www.drupal.org/node/3318162
*/
class Tasks extends BaseTasks {
}
......@@ -5,8 +5,15 @@
use Drupal\sqlite\Driver\Database\sqlite\Connection as BaseConnection;
use Drupal\database_statement_monitoring_test\LoggedStatementsTrait;
@trigger_error('\Drupal\database_statement_monitoring_test\sqlite\Connection is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. There is no replacement. See https://www.drupal.org/node/3318162', E_USER_DEPRECATED);
/**
* SQlite Connection class that can log executed queries.
*
* @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. There is no
* replacement.
*
* @see https://www.drupal.org/node/3318162
*/
class Connection extends BaseConnection {
use LoggedStatementsTrait;
......
......@@ -4,5 +4,13 @@
use Drupal\sqlite\Driver\Database\sqlite\Install\Tasks as BaseTasks;
@trigger_error('\Drupal\database_statement_monitoring_test\sqlite\Install\Tasks is deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. There is no replacement. See https://www.drupal.org/node/3318162', E_USER_DEPRECATED);
/**
* @deprecated in drupal:10.1.0 and is removed from drupal:11.0.0. There is no
* replacement.
*
* @see https://www.drupal.org/node/3318162
*/
class Tasks extends BaseTasks {
}
......@@ -4,6 +4,7 @@
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 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 @@ public function register(ContainerBuilder $container) {
}
/**
* {@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 @@ public function testEntitySave() {
}
/**
* {@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 @@ public function testEntitySaveRollback() {
* 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.
*/
protected static function statementToTableName($statement) {
if (preg_match('/.*\{([^\}]+)\}.*/', $statement, $matches)) {
return $matches[1];
}
else {
return NULL;
}
}
/**
* {@inheritdoc}
* @return bool
* TRUE if the statement is relative to the table, FALSE otherwise.
*/
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 @@ public function testGetFullQualifiedTableName() {
$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 @@ protected function setUp(): void {
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'.");
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment