aboutsummaryrefslogtreecommitdiffstats
path: root/tests/phpunit/structure
diff options
context:
space:
mode:
authorDaimona Eaytoy <daimona.wiki@gmail.com>2024-12-13 00:28:49 +0100
committerDaimona Eaytoy <daimona.wiki@gmail.com>2024-12-14 04:33:16 +0100
commit6650a279004515d8a43e5290d02ad5fcb06bf514 (patch)
treebb9f2a53516ce88c77210225b5ceef8e44d39c58 /tests/phpunit/structure
parent648ae4d2fbafd76c826bfb487918d614a01bf396 (diff)
downloadmediawikicore-6650a279004515d8a43e5290d02ad5fcb06bf514.tar.gz
mediawikicore-6650a279004515d8a43e5290d02ad5fcb06bf514.zip
test: Introduce AbstractSchemaTestBase
Extensions can extend it to run structure tests on their database schema and schema changes, just like core. In the future, this might be run as part of extension.json tests, when T237839 is completed. Bug: T381981 Change-Id: I8ae59ce6854922c2804d12986c870d3f0e0c3299
Diffstat (limited to 'tests/phpunit/structure')
-rw-r--r--tests/phpunit/structure/AbstractSchemaTest.php138
-rw-r--r--tests/phpunit/structure/AbstractSchemaTestBase.php182
2 files changed, 183 insertions, 137 deletions
diff --git a/tests/phpunit/structure/AbstractSchemaTest.php b/tests/phpunit/structure/AbstractSchemaTest.php
index 73524b1300e5..f231a1063fe3 100644
--- a/tests/phpunit/structure/AbstractSchemaTest.php
+++ b/tests/phpunit/structure/AbstractSchemaTest.php
@@ -18,142 +18,10 @@
namespace MediaWiki\Tests\Structure;
-use Doctrine\SqlFormatter\NullHighlighter;
-use Doctrine\SqlFormatter\SqlFormatter;
-use Generator;
-use MediaWiki\DB\AbstractSchemaValidationError;
-use MediaWiki\DB\AbstractSchemaValidator;
-use MediaWiki\Maintenance\SchemaGenerator;
-use MediaWikiIntegrationTestCase;
-
/**
- * Validates all abstract schemas against the abstract-schema schemas in the docs/ folder, and makes sure that
- * they match the autogenerated output.
* @coversNothing
*/
-class AbstractSchemaTest extends MediaWikiIntegrationTestCase {
- private AbstractSchemaValidator $validator;
-
- protected function setUp(): void {
- parent::setUp();
-
- $this->validator = new AbstractSchemaValidator();
- }
-
- /**
- * @dataProvider provideSchemas
- * @param string $path Path to tables.json file
- */
- public function testSchemaIsValid( string $path ): void {
- try {
- $this->validator->validate( $path );
- // All good
- $this->addToAssertionCount( 1 );
- } catch ( AbstractSchemaValidationError $e ) {
- $this->fail( "The abstract schema in $path is not valid: " . $e->getMessage() );
- }
- }
-
- /**
- * @dataProvider provideSchemaChanges
- * @param string $path Path to the schema change JSON file
- */
- public function testSchemaChangesAreValid( string $path ): void {
- try {
- $this->validator->validate( $path );
- // All good
- $this->addToAssertionCount( 1 );
- } catch ( AbstractSchemaValidationError $e ) {
- $this->fail( "The abstract schema change in $path is not valid: " . $e->getMessage() );
- }
- }
-
- /**
- * @dataProvider provideSchemas
- */
- public function testSchemasHaveAutoGeneratedFiles( string $jsonPath ) {
- $jsonName = basename( $jsonPath );
- // Same as SchemaMaintenance::getSqlPathWithFileName()
- $nameReplacement = str_starts_with( $jsonName, 'tables' ) ? '-generated.sql' : '.sql';
- $expectedSQLName = str_replace( '.json', $nameReplacement, $jsonName );
-
- foreach ( static::getSchemaSQLDirs() as $platform => $dir ) {
- $expectedSQLPath = rtrim( $dir, '/' ) . '/' . $expectedSQLName;
- $realSQLPath = realpath( $expectedSQLPath );
- $this->assertFileExists(
- $expectedSQLPath,
- "Schema file $realSQLPath for $platform not found. Generate it using generateSchemaSql.php."
- );
- $actualSQL = file_get_contents( $expectedSQLPath );
- $expectedSQL = ( new SchemaGenerator() )->generateSchema( $platform, $jsonPath );
- $this->assertSQLSame(
- $expectedSQL,
- $actualSQL,
- "SQL in $realSQLPath for $platform does not appear to be autogenerated. Re-generate it " .
- "using generateSchemaSql.php."
- );
- }
- }
-
- /**
- * @dataProvider provideSchemaChanges
- */
- public function testSchemaChangesHaveAutoGeneratedFiles( string $jsonPath ) {
- $expectedSQLName = str_replace( '.json', '.sql', basename( $jsonPath ) );
-
- $foundOne = false;
- foreach ( static::getSchemaChangesSQLDirs() as $platform => $dir ) {
- $expectedSQLPath = rtrim( $dir, '/' ) . '/' . $expectedSQLName;
- if ( !file_exists( $expectedSQLPath ) ) {
- // Schema changes don't necessarily have to exist for all platforms. One is enough.
- continue;
- }
- $foundOne = true;
- $actualSQL = file_get_contents( $expectedSQLPath );
- $expectedSQL = ( new SchemaGenerator() )->generateSchemaChange( $platform, $jsonPath );
- $realSQLPath = realpath( $expectedSQLPath );
- $this->assertSQLSame(
- $expectedSQL,
- $actualSQL,
- "SQL in $realSQLPath for $platform does not appear to be autogenerated. Re-generate it " .
- "using generateSchemaChangeSql.php."
- );
- }
- $realJSONPath = realpath( $jsonPath );
- $this->assertTrue(
- $foundOne,
- "Did not find SQL files for any platforms for schema change $realJSONPath. Generate them using " .
- "generateSchemaChangeSql.php."
- );
- }
-
- /**
- * Asserts that two SQL strings are identical, modulo formatting (whitespace) differences. We can't just compare
- * the raw output, otherwise changing the format would be massively painful due to test failures everywhere.
- */
- private function assertSQLSame( string $expected, string $actual, string $message ): void {
- $formatter = new SqlFormatter( new NullHighlighter() );
- $this->assertSame(
- $formatter->format( $expected ),
- $formatter->format( $actual ),
- $message
- );
- }
-
- final public static function provideSchemas(): Generator {
- $schemaDir = rtrim( static::getSchemasDirectory(), '/' ) . '/';
- foreach ( glob( $schemaDir . '*.json' ) as $schemaFile ) {
- yield basename( $schemaFile ) => [ $schemaFile ];
- }
- }
-
- final public static function provideSchemaChanges(): Generator {
- $schemaChangesDir = rtrim( static::getSchemaChangesDirectory(), '/' ) . '/';
- foreach ( glob( $schemaChangesDir . '*.json' ) as $schemaChange ) {
- yield basename( $schemaChange ) => [ $schemaChange ];
- }
- }
-
+class AbstractSchemaTest extends AbstractSchemaTestBase {
protected static function getSchemasDirectory(): string {
return __DIR__ . '/../../../sql/';
}
@@ -169,8 +37,4 @@ class AbstractSchemaTest extends MediaWikiIntegrationTestCase {
'postgres' => __DIR__ . '/../../../sql/postgres',
];
}
-
- protected static function getSchemaChangesSQLDirs(): array {
- return static::getSchemaSQLDirs();
- }
}
diff --git a/tests/phpunit/structure/AbstractSchemaTestBase.php b/tests/phpunit/structure/AbstractSchemaTestBase.php
new file mode 100644
index 000000000000..f1c6638c34c3
--- /dev/null
+++ b/tests/phpunit/structure/AbstractSchemaTestBase.php
@@ -0,0 +1,182 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+namespace MediaWiki\Tests\Structure;
+
+use Doctrine\SqlFormatter\NullHighlighter;
+use Doctrine\SqlFormatter\SqlFormatter;
+use Generator;
+use MediaWiki\DB\AbstractSchemaValidationError;
+use MediaWiki\DB\AbstractSchemaValidator;
+use MediaWiki\Maintenance\SchemaGenerator;
+use MediaWikiIntegrationTestCase;
+
+/**
+ * Validates all abstract schemas against the abstract-schema schemas in the docs/ folder, and makes sure that
+ * they match the autogenerated output.
+ *
+ * Extensions can extend this class, implementing its abstract methods, to validate their DB schemas.
+ */
+abstract class AbstractSchemaTestBase extends MediaWikiIntegrationTestCase {
+ private AbstractSchemaValidator $validator;
+
+ protected function setUp(): void {
+ parent::setUp();
+
+ $this->validator = new AbstractSchemaValidator();
+ }
+
+ /**
+ * @dataProvider provideSchemas
+ * @param string $path Path to tables.json file
+ */
+ public function testSchemaIsValid( string $path ): void {
+ try {
+ $this->validator->validate( $path );
+ // All good
+ $this->addToAssertionCount( 1 );
+ } catch ( AbstractSchemaValidationError $e ) {
+ $this->fail( "The abstract schema in $path is not valid: " . $e->getMessage() );
+ }
+ }
+
+ /**
+ * @dataProvider provideSchemaChanges
+ * @param string $path Path to the schema change JSON file
+ */
+ public function testSchemaChangesAreValid( string $path ): void {
+ try {
+ $this->validator->validate( $path );
+ // All good
+ $this->addToAssertionCount( 1 );
+ } catch ( AbstractSchemaValidationError $e ) {
+ $this->fail( "The abstract schema change in $path is not valid: " . $e->getMessage() );
+ }
+ }
+
+ /**
+ * @dataProvider provideSchemas
+ */
+ public function testSchemasHaveAutoGeneratedFiles( string $jsonPath ) {
+ $jsonName = basename( $jsonPath );
+ // Same as SchemaMaintenance::getSqlPathWithFileName()
+ $nameReplacement = str_starts_with( $jsonName, 'tables' ) ? '-generated.sql' : '.sql';
+ $expectedSQLName = str_replace( '.json', $nameReplacement, $jsonName );
+
+ foreach ( static::getSchemaSQLDirs() as $platform => $dir ) {
+ $expectedSQLPath = rtrim( $dir, '/' ) . '/' . $expectedSQLName;
+ $realSQLPath = realpath( $expectedSQLPath );
+ $this->assertFileExists(
+ $expectedSQLPath,
+ "Schema file $realSQLPath for $platform not found. Generate it using generateSchemaSql.php."
+ );
+ $actualSQL = file_get_contents( $expectedSQLPath );
+ $expectedSQL = ( new SchemaGenerator() )->generateSchema( $platform, $jsonPath );
+ $this->assertSQLSame(
+ $expectedSQL,
+ $actualSQL,
+ "SQL in $realSQLPath for $platform does not appear to be autogenerated. Re-generate it " .
+ "using generateSchemaSql.php."
+ );
+ }
+ }
+
+ /**
+ * @dataProvider provideSchemaChanges
+ */
+ public function testSchemaChangesHaveAutoGeneratedFiles( string $jsonPath ) {
+ $expectedSQLName = str_replace( '.json', '.sql', basename( $jsonPath ) );
+
+ $foundOne = false;
+ foreach ( static::getSchemaChangesSQLDirs() as $platform => $dir ) {
+ $expectedSQLPath = rtrim( $dir, '/' ) . '/' . $expectedSQLName;
+ if ( !file_exists( $expectedSQLPath ) ) {
+ // Schema changes don't necessarily have to exist for all platforms. One is enough.
+ continue;
+ }
+ $foundOne = true;
+ $actualSQL = file_get_contents( $expectedSQLPath );
+ $expectedSQL = ( new SchemaGenerator() )->generateSchemaChange( $platform, $jsonPath );
+ $realSQLPath = realpath( $expectedSQLPath );
+ $this->assertSQLSame(
+ $expectedSQL,
+ $actualSQL,
+ "SQL in $realSQLPath for $platform does not appear to be autogenerated. Re-generate it " .
+ "using generateSchemaChangeSql.php."
+ );
+ }
+ $realJSONPath = realpath( $jsonPath );
+ $this->assertTrue(
+ $foundOne,
+ "Did not find SQL files for any platforms for schema change $realJSONPath. Generate them using " .
+ "generateSchemaChangeSql.php."
+ );
+ }
+
+ /**
+ * Asserts that two SQL strings are identical, modulo formatting (whitespace) differences. We can't just compare
+ * the raw output, otherwise changing the format would be massively painful due to test failures everywhere.
+ */
+ private function assertSQLSame( string $expected, string $actual, string $message ): void {
+ $formatter = new SqlFormatter( new NullHighlighter() );
+ $this->assertSame(
+ $formatter->format( $expected ),
+ $formatter->format( $actual ),
+ $message
+ );
+ }
+
+ final public static function provideSchemas(): Generator {
+ $schemaDir = rtrim( static::getSchemasDirectory(), '/' ) . '/';
+ foreach ( glob( $schemaDir . '*.json' ) as $schemaFile ) {
+ yield basename( $schemaFile ) => [ $schemaFile ];
+ }
+ }
+
+ final public static function provideSchemaChanges(): Generator {
+ $schemaChangesDir = rtrim( static::getSchemaChangesDirectory(), '/' ) . '/';
+ foreach ( glob( $schemaChangesDir . '*.json' ) as $schemaChange ) {
+ yield basename( $schemaChange ) => [ $schemaChange ];
+ }
+ }
+
+ /**
+ * Returns the path to a directory with JSON files for the schema. All JSON files in this directory are assumed
+ * to be schema files and tested accordingly.
+ */
+ abstract protected static function getSchemasDirectory(): string;
+
+ /**
+ * Returns the path to a directory with schema change JSON files. All JSON files in this directory are assumed
+ * to be schema change files and tested accordingly.
+ */
+ abstract protected static function getSchemaChangesDirectory(): string;
+
+ /**
+ * Returns a map of supported DB types to the path of a directory with the .sql files for that DB type's schema.
+ */
+ abstract protected static function getSchemaSQLDirs(): array;
+
+ /**
+ * Returns a map of supported DB types to the path of a directory with the .sql schema change files for that DB
+ * type. Uses the same directory as {@see self::getSchemaSQLDirs} by default.
+ */
+ protected static function getSchemaChangesSQLDirs(): array {
+ return static::getSchemaSQLDirs();
+ }
+}