Merge "Prepare for REL1_33 cut, labelling master as 1.34-alpha"
[lhc/web/wiklou.git] / tests / phpunit / MediaWikiTestCase.php
index 35f396e..fd0cea1 100644 (file)
@@ -361,6 +361,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
        public static function resetNonServiceCaches() {
                global $wgRequest, $wgJobClasses;
 
+               User::resetGetDefaultOptionsForTestsOnly();
                foreach ( $wgJobClasses as $type => $class ) {
                        JobQueueGroup::singleton()->get( $type )->delete();
                }
@@ -400,7 +401,8 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                        self::$useTemporaryTables = !$this->getCliArg( 'use-normal-tables' );
                        self::$reuseDB = $this->getCliArg( 'reuse-db' );
 
-                       $this->db = wfGetDB( DB_MASTER );
+                       $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
+                       $this->db = $lb->getConnection( DB_MASTER );
 
                        $this->checkDbIsSupported();
 
@@ -542,6 +544,24 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                $this->tmpFiles = array_merge( $this->tmpFiles, (array)$files );
        }
 
+       // @todo Make const when we no longer support HHVM (T192166)
+       private static $namespaceAffectingSettings = [
+               'wgAllowImageMoving',
+               'wgCanonicalNamespaceNames',
+               'wgCapitalLinkOverrides',
+               'wgCapitalLinks',
+               'wgContentNamespaces',
+               'wgExtensionMessagesFiles',
+               'wgExtensionNamespaces',
+               'wgExtraNamespaces',
+               'wgExtraSignatureNamespaces',
+               'wgNamespaceContentModels',
+               'wgNamespaceProtection',
+               'wgNamespacesWithSubpages',
+               'wgNonincludableNamespaces',
+               'wgRestrictionLevels',
+       ];
+
        protected function tearDown() {
                global $wgRequest, $wgSQLMode;
 
@@ -586,8 +606,8 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                        ini_set( $name, $value );
                }
                if (
-                       array_key_exists( 'wgExtraNamespaces', $this->mwGlobals ) ||
-                       in_array( 'wgExtraNamespaces', $this->mwGlobalsToUnset )
+                       array_intersect( self::$namespaceAffectingSettings, array_keys( $this->mwGlobals ) ) ||
+                       array_intersect( self::$namespaceAffectingSettings, $this->mwGlobalsToUnset )
                ) {
                        $this->resetNamespaces();
                }
@@ -729,7 +749,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                        $GLOBALS[$key] = $value;
                }
 
-               if ( array_key_exists( 'wgExtraNamespaces', $pairs ) ) {
+               if ( array_intersect( self::$namespaceAffectingSettings, array_keys( $pairs ) ) ) {
                        $this->resetNamespaces();
                }
        }
@@ -760,14 +780,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                                . 'instance has been replaced by test code.' );
                }
 
-               MWNamespace::clearCaches();
                Language::clearCaches();
-
-               // We can't have the TitleFormatter holding on to an old Language object either
-               // @todo We shouldn't need to reset all the aliases here.
-               $this->localServices->resetServiceForTesting( 'TitleFormatter' );
-               $this->localServices->resetServiceForTesting( 'TitleParser' );
-               $this->localServices->resetServiceForTesting( '_MediaWikiTitleCodec' );
        }
 
        /**
@@ -1363,6 +1376,9 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                        JobQueueGroup::singleton()->get( $type )->delete();
                }
 
+               // T219673: close any connections from code that failed to call reuseConnection()
+               // or is still holding onto a DBConnRef instance (e.g. in a singleton).
+               MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->closeAll();
                CloneDatabase::changePrefix( self::$oldTablePrefix );
 
                self::$oldTablePrefix = false;
@@ -1453,12 +1469,12 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
         * @note this method only works when first called. Subsequent calls have no effect,
         * even if using different parameters.
         *
-        * @param Database $db The database connection
+        * @param IMaintainableDatabase $db The database connection
         * @param string $prefix The prefix to use for the new table set (aka schema).
         *
         * @throws MWException If the database table prefix is already $prefix
         */
-       public static function setupTestDB( Database $db, $prefix ) {
+       public static function setupTestDB( IMaintainableDatabase $db, $prefix ) {
                if ( self::$dbSetup ) {
                        return;
                }
@@ -1595,7 +1611,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                $this->ensureMockDatabaseConnection( $db );
 
                $oldOverrides = $oldOverrides + self::$schemaOverrideDefaults;
-               $originalTables = $this->listOriginalTables( $db, 'unprefixed' );
+               $originalTables = $this->listOriginalTables( $db );
 
                // Drop tables that need to be restored or removed.
                $tablesToDrop = array_merge( $oldOverrides['create'], $oldOverrides['alter'] );
@@ -1611,6 +1627,10 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
 
                if ( $tablesToRestore ) {
                        $this->recloneMockTables( $db, $tablesToRestore );
+
+                       // Reset the restored tables, mainly for the side effect of
+                       // re-calling $this->addCoreDBData() if necessary.
+                       $this->resetDB( $db, $tablesToRestore );
                }
        }
 
@@ -1625,6 +1645,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
 
                if ( $oldOverrides['alter'] || $oldOverrides['create'] || $oldOverrides['drop'] ) {
                        $this->undoSchemaOverrides( $db, $oldOverrides );
+                       unset( $db->_schemaOverrides );
                }
 
                // Determine new overrides.
@@ -1656,7 +1677,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                $this->ensureMockDatabaseConnection( $db );
 
                // Drop the tables that will be created by the schema scripts.
-               $originalTables = $this->listOriginalTables( $db, 'unprefixed' );
+               $originalTables = $this->listOriginalTables( $db );
                $tablesToDrop = array_intersect( $originalTables, $overrides['create'] );
 
                if ( $tablesToDrop ) {
@@ -1701,29 +1722,36 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
        }
 
        /**
-        * Lists all tables in the live database schema.
+        * Lists all tables in the live database schema, without a prefix.
         *
         * @param IMaintainableDatabase $db
-        * @param string $prefix Either 'prefixed' or 'unprefixed'
         * @return array
         */
-       private function listOriginalTables( IMaintainableDatabase $db, $prefix = 'prefixed' ) {
+       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__ );
-               if ( $prefix === 'unprefixed' ) {
-                       $originalPrefixRegex = '/^' . preg_quote( $db->_originalTablePrefix, '/' ) . '/';
-                       $originalTables = array_map(
-                               function ( $pt ) use ( $originalPrefixRegex ) {
-                                       return preg_replace( $originalPrefixRegex, '', $pt );
-                               },
-                               $originalTables
-                       );
-               }
 
-               return $originalTables;
+               $unittestPrefixRegex = '/^' . preg_quote( $this->dbPrefix(), '/' ) . '/';
+               $originalPrefixRegex = '/^' . preg_quote( $db->_originalTablePrefix, '/' ) . '/';
+
+               $originalTables = array_filter(
+                       $originalTables,
+                       function ( $pt ) use ( $unittestPrefixRegex ) {
+                               return !preg_match( $unittestPrefixRegex, $pt );
+                       }
+               );
+
+               $originalTables = array_map(
+                       function ( $pt ) use ( $originalPrefixRegex ) {
+                               return preg_replace( $originalPrefixRegex, '', $pt );
+                       },
+                       $originalTables
+               );
+
+               return array_unique( $originalTables );
        }
 
        /**
@@ -1741,7 +1769,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                        throw new LogicException( 'No original table prefix know, cannot restore tables!' );
                }
 
-               $originalTables = $this->listOriginalTables( $db, 'unprefixed' );
+               $originalTables = $this->listOriginalTables( $db );
                $tables = array_intersect( $tables, $originalTables );
 
                $dbClone = new CloneDatabase( $db, $tables, $db->tablePrefix(), $db->_originalTablePrefix );
@@ -1769,6 +1797,12 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
                        if ( array_intersect( $tablesUsed, $userTables ) ) {
                                $tablesUsed = array_unique( array_merge( $tablesUsed, $userTables ) );
                                TestUserRegistry::clear();
+
+                               // Reset $wgUser, which is probably 127.0.0.1, as its loaded data is probably not valid
+                               // @todo Should we start setting $wgUser to something nondeterministic
+                               //  to encourage tests to be updated to not depend on it?
+                               global $wgUser;
+                               $wgUser->clearInstanceCache( $wgUser->mFrom );
                        }
                        if ( array_intersect( $tablesUsed, $pageTables ) ) {
                                $tablesUsed = array_unique( array_merge( $tablesUsed, $pageTables ) );
@@ -1889,7 +1923,17 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase {
         * @param IDatabase $target
         */
        public function copyTestData( IDatabase $source, IDatabase $target ) {
-               $tables = self::listOriginalTables( $source, 'unprefixed' );
+               if ( $this->db->getType() === 'sqlite' ) {
+                       // SQLite uses a non-temporary copy of the searchindex table for testing,
+                       // which gets deleted and re-created when setting up the secondary connection,
+                       // causing "Error 17" when trying to copy the data. See T191863#4130112.
+                       throw new RuntimeException(
+                               'Setting up a secondary database connection with test data is currently not'
+                               . 'with SQLite. You may want to use markTestSkippedIfDbType() to bypass this issue.'
+                       );
+               }
+
+               $tables = self::listOriginalTables( $source );
 
                foreach ( $tables as $table ) {
                        $res = $source->select( $table, '*', [], __METHOD__ );