X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=blobdiff_plain;f=tests%2Fphpunit%2FMediaWikiTestCase.php;h=4d424983c7c64e17902ae1d6a43a21f394d0df6c;hp=652b1ee1bf8863412ca8fc1368c891a6e8a97923;hb=0898ab0a5d99c0d92c83d26d8b8b090f76e023de;hpb=f2327b448c13a5c40d6026eb9b1f6d2b6a7ff138 diff --git a/tests/phpunit/MediaWikiTestCase.php b/tests/phpunit/MediaWikiTestCase.php index 652b1ee1bf..4d424983c7 100644 --- a/tests/phpunit/MediaWikiTestCase.php +++ b/tests/phpunit/MediaWikiTestCase.php @@ -17,6 +17,7 @@ use Wikimedia\TestingAccessWrapper; abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase { use MediaWikiCoversValidator; + use PHPUnit4And6Compat; /** * The service locator created by prepareServices(). This service locator will @@ -902,6 +903,36 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase { ] ); } + /** + * Alters $wgGroupPermissions for the duration of the test. Can be called + * with an array, like + * [ '*' => [ 'read' => false ], 'user' => [ 'read' => false ] ] + * or three values to set a single permission, like + * $this->setGroupPermissions( '*', 'read', false ); + * + * @since 1.31 + * @param array|string $newPerms Either an array of permissions to change, + * in which case the next two parameters are ignored; or a single string + * identifying a group, to use with the next two parameters. + * @param string|null $newKey + * @param mixed $newValue + */ + public function setGroupPermissions( $newPerms, $newKey = null, $newValue = null ) { + global $wgGroupPermissions; + + $this->stashMwGlobals( 'wgGroupPermissions' ); + + if ( is_string( $newPerms ) ) { + $newPerms = [ $newPerms => [ $newKey => $newValue ] ]; + } + + foreach ( $newPerms as $group => $permissions ) { + foreach ( $permissions as $key => $value ) { + $wgGroupPermissions[$group][$key] = $value; + } + } + } + /** * Sets the logger for a specified channel, for the duration of the test. * @since 1.27 @@ -1313,57 +1344,113 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase { } } + private static $schemaOverrideDefaults = [ + 'scripts' => [], + 'create' => [], + 'drop' => [], + 'alter' => [], + ]; + /** * Stub. If a test suite needs to test against a specific database schema, it should * override this method and return the appropriate information from it. * - * @return [ $tables, $scripts ] A tuple of two lists, with $tables being a list of tables - * that will be re-created by the scripts, and $scripts being a list of SQL script - * files for creating the tables listed. + * @param IMaintainableDatabase $db The DB connection to use for the mock schema. + * May be used to check the current state of the schema, to determine what + * overrides are needed. + * + * @return array An associative array with the following fields: + * - 'scripts': any SQL scripts to run. If empty or not present, schema overrides are skipped. + * - 'create': A list of tables created (may or may not exist in the original schema). + * - 'drop': A list of tables dropped (expected to be present in the original schema). + * - 'alter': A list of tables altered (expected to be present in the original schema). + */ + protected function getSchemaOverrides( IMaintainableDatabase $db ) { + return []; + } + + /** + * Undoes the dpecified schema overrides.. + * Called once per test class, just before addDataOnce(). + * + * @param IMaintainableDatabase $db + * @param array $oldOverrides */ - protected function getSchemaOverrides() { - return [ [], [] ]; + private function undoSchemaOverrides( IMaintainableDatabase $db, $oldOverrides ) { + $this->ensureMockDatabaseConnection( $db ); + + $oldOverrides = $oldOverrides + self::$schemaOverrideDefaults; + $originalTables = $this->listOriginalTables( $db ); + + // Drop tables that need to be restored or removed. + $tablesToDrop = array_merge( $oldOverrides['create'], $oldOverrides['alter'] ); + + // Restore tables that have been dropped or created or altered, + // if they exist in the original schema. + $tablesToRestore = array_merge( $tablesToDrop, $oldOverrides['drop'] ); + $tablesToRestore = array_intersect( $originalTables, $tablesToRestore ); + + if ( $tablesToDrop ) { + $this->dropMockTables( $db, $tablesToDrop ); + } + + if ( $tablesToRestore ) { + $this->recloneMockTables( $db, $tablesToRestore ); + } } /** - * Applies any schema changes requested by calling setDbSchema(). + * Applies the schema overrides returned by getSchemaOverrides(), + * after undoing any previously applied schema overrides. * Called once per test class, just before addDataOnce(). */ private function setUpSchema( IMaintainableDatabase $db ) { - list( $tablesToAlter, $scriptsToRun ) = $this->getSchemaOverrides(); + // Undo any active overrides. + $oldOverrides = isset( $db->_schemaOverrides ) ? $db->_schemaOverrides + : self::$schemaOverrideDefaults; + + if ( $oldOverrides['alter'] || $oldOverrides['create'] || $oldOverrides['drop'] ) { + $this->undoSchemaOverrides( $db, $oldOverrides ); + } + + // Determine new overrides. + $overrides = $this->getSchemaOverrides( $db ) + self::$schemaOverrideDefaults; + + $extraKeys = array_diff( + array_keys( $overrides ), + array_keys( self::$schemaOverrideDefaults ) + ); - if ( $tablesToAlter && !$scriptsToRun ) { + if ( $extraKeys ) { throw new InvalidArgumentException( - 'No scripts supplied for applying the database schema.' + 'Schema override contains extra keys: ' . var_export( $extraKeys, true ) ); } - if ( !$tablesToAlter && $scriptsToRun ) { + if ( !$overrides['scripts'] ) { + // no scripts to run + return; + } + + if ( !$overrides['create'] && !$overrides['drop'] && !$overrides['alter'] ) { throw new InvalidArgumentException( - 'No tables declared to be altered by schema scripts.' + 'Schema override scripts given, but no tables are declared to be ' + . 'created, dropped or altered.' ); } $this->ensureMockDatabaseConnection( $db ); - $previouslyAlteredTables = isset( $db->_alteredMockTables ) ? $db->_alteredMockTables : []; - - if ( !$tablesToAlter && !$previouslyAlteredTables ) { - return; // nothing to do - } - - $tablesToDrop = array_merge( $previouslyAlteredTables, $tablesToAlter ); - $tablesToRestore = array_diff( $previouslyAlteredTables, $tablesToAlter ); + // Drop the tables that will be created by the schema scripts. + $originalTables = $this->listOriginalTables( $db ); + $tablesToDrop = array_intersect( $originalTables, $overrides['create'] ); if ( $tablesToDrop ) { $this->dropMockTables( $db, $tablesToDrop ); } - if ( $tablesToRestore ) { - $this->recloneMockTables( $db, $tablesToRestore ); - } - - foreach ( $scriptsToRun as $script ) { + // Run schema override scripts. + foreach ( $overrides['scripts'] as $script ) { $db->sourceFile( $script, null, @@ -1375,7 +1462,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase { ); } - $db->_alteredMockTables = $tablesToAlter; + $db->_schemaOverrides = $overrides; } private function mungeSchemaUpdateQuery( $cmd ) { @@ -1405,8 +1492,25 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase { } } + /** + * Lists all tables in the live database schema. + * + * @param IMaintainableDatabase $db + * @return array + */ + private function listOriginalTables( IMaintainableDatabase $db ) { + if ( !isset( $db->_originalTablePrefix ) ) { + throw new LogicException( 'No original table prefix know, cannot list tables!' ); + } + + $originalTables = $db->listTables( $db->_originalTablePrefix, __METHOD__ ); + return $originalTables; + } + /** * Re-clones the given mock tables to restore them based on the live database schema. + * The tables listed in $tables are expected to currently not exist, so dropMockTables() + * should be called first. * * @param IMaintainableDatabase $db * @param array $tables @@ -1418,7 +1522,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase { throw new LogicException( 'No original table prefix know, cannot restore tables!' ); } - $originalTables = $db->listTables( $db->_originalTablePrefix, __METHOD__ ); + $originalTables = $this->listOriginalTables( $db ); $tables = array_intersect( $tables, $originalTables ); $dbClone = new CloneDatabase( $db, $tables, $db->tablePrefix(), $db->_originalTablePrefix ); @@ -1435,8 +1539,9 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase { */ private function resetDB( $db, $tablesUsed ) { if ( $db ) { - $userTables = [ 'user', 'user_groups', 'user_properties' ]; - $pageTables = [ 'page', 'revision', 'ip_changes', 'revision_comment_temp', 'comment' ]; + $userTables = [ 'user', 'user_groups', 'user_properties', 'actor' ]; + $pageTables = [ 'page', 'revision', 'ip_changes', 'revision_comment_temp', + 'revision_actor_temp', 'comment' ]; $coreDBDataTables = array_merge( $userTables, $pageTables ); // If any of the user or page tables were marked as used, we should clear all of them. @@ -1455,12 +1560,21 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase { continue; } + if ( !$db->tableExists( $tbl ) ) { + continue; + } + if ( $truncate ) { $db->query( 'TRUNCATE TABLE ' . $db->tableName( $tbl ), __METHOD__ ); } else { $db->delete( $tbl, '*', __METHOD__ ); } + if ( $db->getType() === 'postgres' ) { + // Reset the table's sequence too. + $db->resetSequenceForTable( $tbl, __METHOD__ ); + } + if ( $tbl === 'page' ) { // Forget about the pages since they don't // exist in the DB. @@ -1475,44 +1589,6 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase { } } - /** - * @since 1.18 - * - * @param string $func - * @param array $args - * - * @return mixed - * @throws MWException - */ - public function __call( $func, $args ) { - static $compatibility = [ - 'createMock' => 'createMock2', - ]; - - if ( isset( $compatibility[$func] ) ) { - return call_user_func_array( [ $this, $compatibility[$func] ], $args ); - } else { - throw new MWException( "Called non-existent $func method on " . static::class ); - } - } - - /** - * Return a test double for the specified class. - * - * @param string $originalClassName - * @return PHPUnit_Framework_MockObject_MockObject - * @throws Exception - */ - private function createMock2( $originalClassName ) { - return $this->getMockBuilder( $originalClassName ) - ->disableOriginalConstructor() - ->disableOriginalClone() - ->disableArgumentCloning() - // New in phpunit-mock-objects 3.2 (phpunit 5.4.0) - // ->disallowMockingUnknownTypes() - ->getMock(); - } - private static function unprefixTable( &$tableName, $ind, $prefix ) { $tableName = substr( $tableName, strlen( $prefix ) ); }