SchemaTest.php

Same filename in this branch
  1. 11.x core/modules/sqlite/tests/src/Kernel/sqlite/SchemaTest.php
  2. 11.x core/modules/pgsql/tests/src/Unit/SchemaTest.php
  3. 11.x core/modules/pgsql/tests/src/Kernel/pgsql/SchemaTest.php
Same filename in other branches
  1. 9 core/modules/mysql/tests/src/Kernel/mysql/SchemaTest.php
  2. 9 core/modules/pgsql/tests/src/Unit/SchemaTest.php
  3. 9 core/modules/pgsql/tests/src/Kernel/pgsql/SchemaTest.php
  4. 9 core/tests/Drupal/KernelTests/Core/Database/SchemaTest.php
  5. 8.9.x core/tests/Drupal/KernelTests/Core/Database/SchemaTest.php
  6. 10 core/modules/sqlite/tests/src/Kernel/sqlite/SchemaTest.php
  7. 10 core/modules/mysql/tests/src/Kernel/mysql/SchemaTest.php
  8. 10 core/modules/pgsql/tests/src/Unit/SchemaTest.php
  9. 10 core/modules/pgsql/tests/src/Kernel/pgsql/SchemaTest.php

Namespace

Drupal\Tests\mysql\Kernel\mysql

File

core/modules/mysql/tests/src/Kernel/mysql/SchemaTest.php

View source
<?php

declare (strict_types=1);
namespace Drupal\Tests\mysql\Kernel\mysql;

use Drupal\Component\Utility\Unicode;
use Drupal\Core\Database\DatabaseExceptionWrapper;
use Drupal\Core\Database\Exception\SchemaTableColumnSizeTooLargeException;
use Drupal\Core\Database\Exception\SchemaTableKeyTooLargeException;
use Drupal\Core\Database\SchemaException;
use Drupal\Core\Database\SchemaObjectDoesNotExistException;
use Drupal\Core\Database\SchemaObjectExistsException;
use Drupal\KernelTests\Core\Database\DriverSpecificSchemaTestBase;

/**
 * Tests schema API for the MySQL driver.
 *
 * @group Database
 */
class SchemaTest extends DriverSpecificSchemaTestBase {
    
    /**
     * {@inheritdoc}
     */
    public function checkSchemaComment(string $description, string $table, ?string $column = NULL) : void {
        $comment = $this->schema
            ->getComment($table, $column);
        $max_length = $column ? 255 : 60;
        $description = Unicode::truncate($description, $max_length, TRUE, TRUE);
        $this->assertSame($description, $comment, 'The comment matches the schema description.');
    }
    
    /**
     * {@inheritdoc}
     */
    protected function assertCollation() : void {
        // Make sure that varchar fields have the correct collations.
        $columns = $this->connection
            ->query('SHOW FULL COLUMNS FROM {test_table}');
        foreach ($columns as $column) {
            if ($column->Field == 'test_field_string') {
                $string_check = $column->Collation;
            }
            if ($column->Field == 'test_field_string_ascii') {
                $string_ascii_check = $column->Collation;
            }
        }
        $this->assertMatchesRegularExpression('#^(utf8mb4_general_ci|utf8mb4_0900_ai_ci)$#', $string_check, 'test_field_string should have a utf8mb4_general_ci or a utf8mb4_0900_ai_ci collation, but it has not.');
        $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.
     *
     * @see \Drupal\mysql\Driver\Database\mysql\Schema::getNormalizedIndexes()
     */
    public function testIndexLength() : void {
        $table_specification = [
            'fields' => [
                'id' => [
                    'type' => 'int',
                    'default' => NULL,
                ],
                'test_field_text' => [
                    'type' => 'text',
                    'not null' => TRUE,
                ],
                'test_field_string_long' => [
                    'type' => 'varchar',
                    'length' => 255,
                    'not null' => TRUE,
                ],
                'test_field_string_ascii_long' => [
                    'type' => 'varchar_ascii',
                    'length' => 255,
                ],
                'test_field_string_short' => [
                    'type' => 'varchar',
                    'length' => 128,
                    'not null' => TRUE,
                ],
            ],
            'indexes' => [
                'test_regular' => [
                    'test_field_text',
                    'test_field_string_long',
                    'test_field_string_ascii_long',
                    'test_field_string_short',
                ],
                'test_length' => [
                    [
                        'test_field_text',
                        128,
                    ],
                    [
                        'test_field_string_long',
                        128,
                    ],
                    [
                        'test_field_string_ascii_long',
                        128,
                    ],
                    [
                        'test_field_string_short',
                        128,
                    ],
                ],
                'test_mixed' => [
                    [
                        'test_field_text',
                        200,
                    ],
                    'test_field_string_long',
                    [
                        'test_field_string_ascii_long',
                        200,
                    ],
                    'test_field_string_short',
                ],
            ],
        ];
        $this->schema
            ->createTable('test_table_index_length', $table_specification);
        // Ensure expected exception thrown when adding index with missing info.
        $expected_exception_message = "MySQL needs the 'test_field_text' field specification in order to normalize the 'test_regular' index";
        $missing_field_spec = $table_specification;
        unset($missing_field_spec['fields']['test_field_text']);
        try {
            $this->schema
                ->addIndex('test_table_index_length', 'test_separate', [
                [
                    'test_field_text',
                    200,
                ],
            ], $missing_field_spec);
            $this->fail('SchemaException not thrown when adding index with missing information.');
        } catch (SchemaException $e) {
            $this->assertEquals($expected_exception_message, $e->getMessage());
        }
        // Add a separate index.
        $this->schema
            ->addIndex('test_table_index_length', 'test_separate', [
            [
                'test_field_text',
                200,
            ],
        ], $table_specification);
        $table_specification_with_new_index = $table_specification;
        $table_specification_with_new_index['indexes']['test_separate'] = [
            [
                'test_field_text',
                200,
            ],
        ];
        // Ensure that the exceptions of addIndex are thrown as expected.
        try {
            $this->schema
                ->addIndex('test_table_index_length', 'test_separate', [
                [
                    'test_field_text',
                    200,
                ],
            ], $table_specification);
            $this->fail('\\Drupal\\Core\\Database\\SchemaObjectExistsException exception missed.');
        } catch (SchemaObjectExistsException) {
            // Expected exception; just continue testing.
        }
        try {
            $this->schema
                ->addIndex('test_table_non_existing', 'test_separate', [
                [
                    'test_field_text',
                    200,
                ],
            ], $table_specification);
            $this->fail('\\Drupal\\Core\\Database\\SchemaObjectDoesNotExistException exception missed.');
        } catch (SchemaObjectDoesNotExistException) {
            // Expected exception; just continue testing.
        }
        // Get index information.
        $results = $this->connection
            ->query('SHOW INDEX FROM {test_table_index_length}');
        $expected_lengths = [
            'test_regular' => [
                'test_field_text' => 191,
                'test_field_string_long' => 191,
                'test_field_string_ascii_long' => NULL,
                'test_field_string_short' => NULL,
            ],
            'test_length' => [
                'test_field_text' => 128,
                'test_field_string_long' => 128,
                'test_field_string_ascii_long' => 128,
                'test_field_string_short' => NULL,
            ],
            'test_mixed' => [
                'test_field_text' => 191,
                'test_field_string_long' => 191,
                'test_field_string_ascii_long' => 200,
                'test_field_string_short' => NULL,
            ],
            'test_separate' => [
                'test_field_text' => 191,
            ],
        ];
        // Count the number of columns defined in the indexes.
        $column_count = 0;
        foreach ($table_specification_with_new_index['indexes'] as $index) {
            $column_count += count($index);
        }
        $test_count = 0;
        foreach ($results as $result) {
            $this->assertEquals($expected_lengths[$result->Key_name][$result->Column_name], $result->Sub_part, 'Index length matches expected value.');
            $test_count++;
        }
        $this->assertEquals($column_count, $test_count, 'Number of tests matches expected value.');
    }
    
    /**
     * @covers \Drupal\mysql\Driver\Database\mysql\Schema::introspectIndexSchema
     */
    public function testIntrospectIndexSchema() : void {
        $table_specification = [
            'fields' => [
                'id' => [
                    'type' => 'int',
                    'not null' => TRUE,
                    'default' => 0,
                ],
                'test_field_1' => [
                    'type' => 'int',
                    'not null' => TRUE,
                    'default' => 0,
                ],
                'test_field_2' => [
                    'type' => 'int',
                    'default' => 0,
                ],
                'test_field_3' => [
                    'type' => 'int',
                    'default' => 0,
                ],
                'test_field_4' => [
                    'type' => 'int',
                    'default' => 0,
                ],
                'test_field_5' => [
                    'type' => 'int',
                    'default' => 0,
                ],
            ],
            'primary key' => [
                'id',
                'test_field_1',
            ],
            'unique keys' => [
                'test_field_2' => [
                    'test_field_2',
                ],
                'test_field_3_test_field_4' => [
                    'test_field_3',
                    'test_field_4',
                ],
            ],
            'indexes' => [
                'test_field_4' => [
                    'test_field_4',
                ],
                'test_field_4_test_field_5' => [
                    'test_field_4',
                    'test_field_5',
                ],
            ],
        ];
        $table_name = strtolower($this->getRandomGenerator()
            ->name());
        $this->schema
            ->createTable($table_name, $table_specification);
        unset($table_specification['fields']);
        $introspect_index_schema = new \ReflectionMethod(get_class($this->schema), 'introspectIndexSchema');
        $index_schema = $introspect_index_schema->invoke($this->schema, $table_name);
        $this->assertEquals($table_specification, $index_schema);
    }
    
    /**
     * Tests SchemaTableKeyTooLargeException.
     */
    public function testSchemaTableKeyTooLargeException() : void {
        $this->expectException(SchemaTableKeyTooLargeException::class);
        $this->schema
            ->createTable('test_schema', [
            'description' => 'Tests SchemaTableKeyTooLargeException.',
            'fields' => [
                'id' => [
                    'type' => 'varchar',
                    'length' => 64,
                    'not null' => TRUE,
                ],
                'id1' => [
                    'type' => 'varchar',
                    'length' => 255,
                    'not null' => TRUE,
                ],
                'id2' => [
                    'type' => 'varchar',
                    'length' => 255,
                    'not null' => TRUE,
                ],
                'id3' => [
                    'type' => 'varchar',
                    'length' => 255,
                    'not null' => TRUE,
                ],
                'id4' => [
                    'type' => 'varchar',
                    'length' => 255,
                    'not null' => TRUE,
                ],
                'id5' => [
                    'type' => 'varchar',
                    'length' => 255,
                    'not null' => TRUE,
                ],
            ],
            'primary key' => [
                'id',
            ],
            'indexes' => [
                'key1' => [
                    'id1',
                    'id2',
                    'id3',
                    'id4',
                    'id5',
                ],
            ],
        ]);
    }
    
    /**
     * Tests SchemaTableColumnSizeTooLargeException.
     */
    public function testSchemaTableColumnSizeTooLargeException() : void {
        $this->expectException(SchemaTableColumnSizeTooLargeException::class);
        $this->expectExceptionMessage("Column length too big for column 'too_large' (max = 16383); use BLOB or TEXT instead");
        $this->schema
            ->createTable('test_schema', [
            'description' => 'Tests SchemaTableColumnSizeTooLargeException.',
            'fields' => [
                'too_large' => [
                    'type' => 'varchar',
                    'length' => 65536,
                    'not null' => TRUE,
                ],
            ],
        ]);
    }
    
    /**
     * Tests adding a primary key when sql_generate_invisible_primary_key is on.
     */
    public function testGeneratedInvisiblePrimaryKey() : void {
        $is_maria = method_exists($this->connection, 'isMariaDb') && $this->connection
            ->isMariaDb();
        if ($this->connection
            ->databaseType() !== 'mysql' || $is_maria || version_compare($this->connection
            ->version(), '8.0.30', '<')) {
            $this->markTestSkipped('This test only runs on MySQL 8.0.30 and above');
        }
        try {
            $this->connection
                ->query("SET sql_generate_invisible_primary_key = 1;")
                ->execute();
        } catch (DatabaseExceptionWrapper) {
            $this->markTestSkipped('This test requires the SESSION_VARIABLES_ADMIN privilege.');
        }
        $this->schema
            ->createTable('test_primary_key', [
            'fields' => [
                'foo' => [
                    'type' => 'varchar',
                    'length' => 1,
                ],
            ],
        ]);
        $this->schema
            ->addField('test_primary_key', 'id', [
            'type' => 'serial',
            'not null' => TRUE,
        ], [
            'primary key' => [
                'id',
            ],
        ]);
        $this->assertTrue($this->schema
            ->fieldExists('test_primary_key', 'id'));
    }

}

Classes

Title Deprecated Summary
SchemaTest Tests schema API for the MySQL driver.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.