Merge "Remove unused MediaWikiTestCase::prepareConnectionForTesting"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Thu, 13 Sep 2018 09:40:18 +0000 (09:40 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Thu, 13 Sep 2018 09:40:18 +0000 (09:40 +0000)
1  2 
tests/phpunit/MediaWikiTestCase.php

@@@ -8,6 -8,8 +8,6 @@@ use Psr\Log\LoggerInterface
  use Wikimedia\Rdbms\IDatabase;
  use Wikimedia\Rdbms\IMaintainableDatabase;
  use Wikimedia\Rdbms\Database;
 -use Wikimedia\Rdbms\IResultWrapper;
 -use Wikimedia\Rdbms\LBFactory;
  use Wikimedia\TestingAccessWrapper;
  
  /**
@@@ -19,17 -21,13 +19,17 @@@ abstract class MediaWikiTestCase extend
        use PHPUnit4And6Compat;
  
        /**
 -       * The service locator created by prepareServices(). This service locator will
 -       * be restored after each test. Tests that pollute the global service locator
 -       * instance should use overrideMwServices() to isolate the test.
 +       * The original service locator. This is overridden during setUp().
         *
         * @var MediaWikiServices|null
         */
 -      private static $serviceLocator = null;
 +      private static $originalServices;
 +
 +      /**
 +       * The local service locator, created during setUp().
 +       * @var MediaWikiServices
 +       */
 +      private $localServices;
  
        /**
         * $called tracks whether the setUp and tearDown method has been called.
         */
        private $mwGlobalsToUnset = [];
  
 -      /**
 -       * Holds original contents of interwiki table
 -       * @var IResultWrapper
 -       */
 -      private $interwikiTable = null;
 -
        /**
         * Holds original loggers which have been replaced by setLogger()
         * @var LoggerInterface[]
         */
        private $loggers = [];
  
 +      /**
 +       * The CLI arguments passed through from phpunit.php
 +       * @var array
 +       */
 +      private $cliArgs = [];
 +
        /**
         * Table name prefixes. Oracle likes it shorter.
         */
        public static function setUpBeforeClass() {
                parent::setUpBeforeClass();
  
 -              // Get the service locator, and reset services if it's not done already
 -              self::$serviceLocator = self::prepareServices( new GlobalVarConfig() );
 +              // Get the original service locator
 +              if ( !self::$originalServices ) {
 +                      self::$originalServices = MediaWikiServices::getInstance();
 +              }
        }
  
        /**
        }
  
        /**
 -       * Prepare service configuration for unit testing.
 -       *
 -       * This calls MediaWikiServices::resetGlobalInstance() to allow some critical services
 -       * to be overridden for testing.
 -       *
 -       * prepareServices() only needs to be called once, but should be called as early as possible,
 -       * before any class has a chance to grab a reference to any of the global services
 -       * instances that get discarded by prepareServices(). Only the first call has any effect,
 -       * later calls are ignored.
 -       *
 -       * @note This is called by PHPUnitMaintClass::finalSetup.
 -       *
 -       * @see MediaWikiServices::resetGlobalInstance()
 -       *
 -       * @param Config $bootstrapConfig The bootstrap config to use with the new
 -       *        MediaWikiServices. Only used for the first call to this method.
 -       * @return MediaWikiServices
 +       * @deprecated since 1.32
         */
        public static function prepareServices( Config $bootstrapConfig ) {
 -              static $services = null;
 -
 -              if ( !$services ) {
 -                      $services = self::resetGlobalServices( $bootstrapConfig );
 -              }
 -              return $services;
 -      }
 -
 -      /**
 -       * Reset global services, and install testing environment.
 -       * This is the testing equivalent of MediaWikiServices::resetGlobalInstance().
 -       * This should only be used to set up the testing environment, not when
 -       * running unit tests. Use MediaWikiTestCase::overrideMwServices() for that.
 -       *
 -       * @see MediaWikiServices::resetGlobalInstance()
 -       * @see prepareServices()
 -       * @see MediaWikiTestCase::overrideMwServices()
 -       *
 -       * @param Config|null $bootstrapConfig The bootstrap config to use with the new
 -       *        MediaWikiServices.
 -       * @return MediaWikiServices
 -       */
 -      private static function resetGlobalServices( Config $bootstrapConfig = null ) {
 -              $oldServices = MediaWikiServices::getInstance();
 -              $oldConfigFactory = $oldServices->getConfigFactory();
 -              $oldLoadBalancerFactory = $oldServices->getDBLoadBalancerFactory();
 -
 -              $testConfig = self::makeTestConfig( $bootstrapConfig );
 -
 -              MediaWikiServices::resetGlobalInstance( $testConfig );
 -
 -              $serviceLocator = MediaWikiServices::getInstance();
 -              self::installTestServices(
 -                      $oldConfigFactory,
 -                      $oldLoadBalancerFactory,
 -                      $serviceLocator
 -              );
 -              return $serviceLocator;
        }
  
        /**
                $defaultOverrides = new HashConfig();
  
                if ( !$baseConfig ) {
 -                      $baseConfig = MediaWikiServices::getInstance()->getBootstrapConfig();
 +                      $baseConfig = self::$originalServices->getBootstrapConfig();
                }
  
                /* Some functions require some kind of caching, and will end up using the db,
                return $testConfig;
        }
  
 -      /**
 -       * @param ConfigFactory $oldConfigFactory
 -       * @param LBFactory $oldLoadBalancerFactory
 -       * @param MediaWikiServices $newServices
 -       *
 -       * @throws MWException
 -       */
 -      private static function installTestServices(
 -              ConfigFactory $oldConfigFactory,
 -              LBFactory $oldLoadBalancerFactory,
 -              MediaWikiServices $newServices
 -      ) {
 -              // Use bootstrap config for all configuration.
 -              // This allows config overrides via global variables to take effect.
 -              $bootstrapConfig = $newServices->getBootstrapConfig();
 -              $newServices->resetServiceForTesting( 'ConfigFactory' );
 -              $newServices->redefineService(
 -                      'ConfigFactory',
 -                      self::makeTestConfigFactoryInstantiator(
 -                              $oldConfigFactory,
 -                              [ 'main' => $bootstrapConfig ]
 -                      )
 -              );
 -              $newServices->resetServiceForTesting( 'DBLoadBalancerFactory' );
 -              $newServices->redefineService(
 -                      'DBLoadBalancerFactory',
 -                      function ( MediaWikiServices $services ) use ( $oldLoadBalancerFactory ) {
 -                              return $oldLoadBalancerFactory;
 -                      }
 -              );
 -      }
 -
        /**
         * @param ConfigFactory $oldFactory
         * @param Config[] $configurations
        }
  
        /**
 -       * Resets some well known services that typically have state that may interfere with unit tests.
 -       * This is a lightweight alternative to resetGlobalServices().
 -       *
 -       * @note There is no guarantee that no references remain to stale service instances destroyed
 -       * by a call to doLightweightServiceReset().
 -       *
 -       * @throws MWException if called outside of PHPUnit tests.
 -       *
 -       * @see resetGlobalServices()
 +       * Resets some non-service singleton instances and other static caches. It's not necessary to
 +       * reset services here.
         */
 -      private function doLightweightServiceReset() {
 +      public static function resetNonServiceCaches() {
                global $wgRequest, $wgJobClasses;
  
                foreach ( $wgJobClasses as $type => $class ) {
                JobQueueGroup::destroySingletons();
  
                ObjectCache::clear();
 -              $services = MediaWikiServices::getInstance();
 -              $services->resetServiceForTesting( 'MainObjectStash' );
 -              $services->resetServiceForTesting( 'LocalServerObjectCache' );
 -              $services->getMainWANObjectCache()->clearProcessCache();
                FileBackendGroup::destroySingleton();
                DeferredUpdates::clearPendingUpdates();
  
        }
  
        public function run( PHPUnit_Framework_TestResult $result = null ) {
 -              $needsResetDB = false;
 +              if ( $result instanceof MediaWikiTestResult ) {
 +                      $this->cliArgs = $result->getMediaWikiCliArgs();
 +              }
 +              $this->overrideMwServices();
  
 +              if ( $this->needsDB() && !$this->isTestInDatabaseGroup() ) {
 +                      throw new Exception(
 +                              get_class( $this ) . ' apparently needsDB but is not in the Database group'
 +                      );
 +              }
 +
 +              $needsResetDB = false;
                if ( !self::$dbSetup || $this->needsDB() ) {
                        // set up a DB connection for this test to use
  
                if ( $needsResetDB ) {
                        $this->resetDB( $this->db, $this->tablesUsed );
                }
 +
 +              self::restoreMwServices();
 +              $this->localServices = null;
        }
  
        /**
                        }
                        // Check for unsafe queries
                        if ( $this->db->getType() === 'mysql' ) {
 -                              $this->db->query( "SET sql_mode = 'STRICT_ALL_TABLES'" );
 +                              $this->db->query( "SET sql_mode = 'STRICT_ALL_TABLES'", __METHOD__ );
                        }
                }
  
 -              // Store contents of interwiki table in case it changes.  Unfortunately, we seem to have no
 -              // way to do this only when needed, because tablesUsed can be changed mid-test.
 -              if ( $this->db ) {
 -                      $this->interwikiTable = $this->db->select( 'interwiki', '*', '', __METHOD__ );
 -              }
 -
                // Reset all caches between tests.
 -              $this->doLightweightServiceReset();
 +              self::resetNonServiceCaches();
  
                // XXX: reset maintenance triggers
                // Hook into period lag checks which often happen in long-running scripts
 -              $services = MediaWikiServices::getInstance();
 -              $lbFactory = $services->getDBLoadBalancerFactory();
 -              Maintenance::setLBFactoryTriggers( $lbFactory, $services->getMainConfig() );
 +              $lbFactory = $this->localServices->getDBLoadBalancerFactory();
 +              Maintenance::setLBFactoryTriggers( $lbFactory, $this->localServices->getMainConfig() );
  
                ob_start( 'MediaWikiTestCase::wfResetOutputBuffersBarrier' );
        }
                                $this->db->rollback( __METHOD__, 'flush' );
                        }
                        if ( $this->db->getType() === 'mysql' ) {
 -                              $this->db->query( "SET sql_mode = " . $this->db->addQuotes( $wgSQLMode ) );
 +                              $this->db->query( "SET sql_mode = " . $this->db->addQuotes( $wgSQLMode ),
 +                                      __METHOD__ );
                        }
                }
  
                $this->mwGlobalsToUnset = [];
                $this->restoreLoggers();
  
 -              if ( self::$serviceLocator && MediaWikiServices::getInstance() !== self::$serviceLocator ) {
 -                      MediaWikiServices::forceGlobalInstance( self::$serviceLocator );
 -              }
 -
                // TODO: move global state into MediaWikiServices
                RequestContext::resetMain();
                if ( session_id() !== '' ) {
         * @param object $object
         */
        protected function setService( $name, $object ) {
 -              // If we did not yet override the service locator, so so now.
 -              if ( MediaWikiServices::getInstance() === self::$serviceLocator ) {
 -                      $this->overrideMwServices();
 +              if ( !$this->localServices ) {
 +                      throw new Exception( __METHOD__ . ' must be called after MediaWikiTestCase::run()' );
 +              }
 +
 +              if ( $this->localServices !== MediaWikiServices::getInstance() ) {
 +                      throw new Exception( __METHOD__ . ' will not work because the global MediaWikiServices '
 +                              . 'instance has been replaced by test code.' );
                }
  
 -              MediaWikiServices::getInstance()->disableService( $name );
 -              MediaWikiServices::getInstance()->redefineService(
 +              $this->localServices->disableService( $name );
 +              $this->localServices->redefineService(
                        $name,
                        function () use ( $object ) {
                                return $object;
         * Otherwise old namespace data will lurk and cause bugs.
         */
        private function resetNamespaces() {
 +              if ( !$this->localServices ) {
 +                      throw new Exception( __METHOD__ . ' must be called after MediaWikiTestCase::run()' );
 +              }
 +
 +              if ( $this->localServices !== MediaWikiServices::getInstance() ) {
 +                      throw new Exception( __METHOD__ . ' will not work because the global MediaWikiServices '
 +                              . '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.
 -              $services = MediaWikiServices::getInstance();
 -              $services->resetServiceForTesting( 'TitleFormatter' );
 -              $services->resetServiceForTesting( 'TitleParser' );
 -              $services->resetServiceForTesting( '_MediaWikiTitleCodec' );
 +              $this->localServices->resetServiceForTesting( 'TitleFormatter' );
 +              $this->localServices->resetServiceForTesting( 'TitleParser' );
 +              $this->localServices->resetServiceForTesting( '_MediaWikiTitleCodec' );
        }
  
        /**
         * @return MediaWikiServices
         * @throws MWException
         */
 -      protected static function overrideMwServices(
 +      protected function overrideMwServices(
                Config $configOverrides = null, array $services = []
        ) {
 +              $newInstance = self::installMockMwServices( $configOverrides );
 +
 +              if ( $this->localServices ) {
 +                      $this->localServices->destroy();
 +              }
 +
 +              $this->localServices = $newInstance;
 +
 +              foreach ( $services as $name => $callback ) {
 +                      $newInstance->redefineService( $name, $callback );
 +              }
 +
 +              return $newInstance;
 +      }
 +
 +      /**
 +       * Creates a new "mock" MediaWikiServices instance, and installs it.
 +       * This effectively resets all cached states in services, with the exception of
 +       * the ConfigFactory and the DBLoadBalancerFactory service, which are inherited from
 +       * the original MediaWikiServices.
 +       *
 +       * @note The new original MediaWikiServices instance can later be restored by calling
 +       * restoreMwServices(). That original is determined by the first call to this method, or
 +       * by setUpBeforeClass, whichever is called first. The caller is responsible for managing
 +       * and, when appropriate, destroying any other MediaWikiServices instances that may get
 +       * replaced when calling this method.
 +       *
 +       * @param Config|null $configOverrides Configuration overrides for the new MediaWikiServices
 +       *        instance.
 +       *
 +       * @return MediaWikiServices the new mock service locator.
 +       */
 +      public static function installMockMwServices( Config $configOverrides = null ) {
 +              // Make sure we have the original service locator
 +              if ( !self::$originalServices ) {
 +                      self::$originalServices = MediaWikiServices::getInstance();
 +              }
 +
                if ( !$configOverrides ) {
                        $configOverrides = new HashConfig();
                }
  
 -              $oldInstance = MediaWikiServices::getInstance();
 -              $oldConfigFactory = $oldInstance->getConfigFactory();
 -              $oldLoadBalancerFactory = $oldInstance->getDBLoadBalancerFactory();
 +              $oldConfigFactory = self::$originalServices->getConfigFactory();
 +              $oldLoadBalancerFactory = self::$originalServices->getDBLoadBalancerFactory();
  
                $testConfig = self::makeTestConfig( null, $configOverrides );
 -              $newInstance = new MediaWikiServices( $testConfig );
 +              $newServices = new MediaWikiServices( $testConfig );
  
                // Load the default wiring from the specified files.
                // NOTE: this logic mirrors the logic in MediaWikiServices::newInstance.
                $wiringFiles = $testConfig->get( 'ServiceWiringFiles' );
 -              $newInstance->loadWiringFiles( $wiringFiles );
 +              $newServices->loadWiringFiles( $wiringFiles );
  
                // Provide a traditional hook point to allow extensions to configure services.
 -              Hooks::run( 'MediaWikiServices', [ $newInstance ] );
 +              Hooks::run( 'MediaWikiServices', [ $newServices ] );
  
 -              foreach ( $services as $name => $callback ) {
 -                      $newInstance->redefineService( $name, $callback );
 +              // Use bootstrap config for all configuration.
 +              // This allows config overrides via global variables to take effect.
 +              $bootstrapConfig = $newServices->getBootstrapConfig();
 +              $newServices->resetServiceForTesting( 'ConfigFactory' );
 +              $newServices->redefineService(
 +                      'ConfigFactory',
 +                      self::makeTestConfigFactoryInstantiator(
 +                              $oldConfigFactory,
 +                              [ 'main' => $bootstrapConfig ]
 +                      )
 +              );
 +              $newServices->resetServiceForTesting( 'DBLoadBalancerFactory' );
 +              $newServices->redefineService(
 +                      'DBLoadBalancerFactory',
 +                      function ( MediaWikiServices $services ) use ( $oldLoadBalancerFactory ) {
 +                              return $oldLoadBalancerFactory;
 +                      }
 +              );
 +
 +              MediaWikiServices::forceGlobalInstance( $newServices );
 +              return $newServices;
 +      }
 +
 +      /**
 +       * Restores the original, non-mock MediaWikiServices instance.
 +       * The previously active MediaWikiServices instance is destroyed,
 +       * if it is different from the original that is to be restored.
 +       *
 +       * @note this if for internal use by test framework code. It should never be
 +       * called from inside a test case, a data provider, or a setUp or tearDown method.
 +       *
 +       * @return bool true if the original service locator was restored,
 +       *         false if there was nothing  too do.
 +       */
 +      public static function restoreMwServices() {
 +              if ( !self::$originalServices ) {
 +                      return false;
                }
  
 -              self::installTestServices(
 -                      $oldConfigFactory,
 -                      $oldLoadBalancerFactory,
 -                      $newInstance
 -              );
 -              MediaWikiServices::forceGlobalInstance( $newInstance );
 +              $currentServices = MediaWikiServices::getInstance();
  
 -              return $newInstance;
 +              if ( self::$originalServices === $currentServices ) {
 +                      return false;
 +              }
 +
 +              MediaWikiServices::forceGlobalInstance( self::$originalServices );
 +              $currentServices->destroy();
 +
 +              return true;
        }
  
        /**
         */
        public function needsDB() {
                // If the test says it uses database tables, it needs the database
 -              if ( $this->tablesUsed ) {
 -                      return true;
 -              }
 +              return $this->tablesUsed || $this->isTestInDatabaseGroup();
 +      }
  
 +      /**
 +       * @return bool
 +       * @since 1.32
 +       */
 +      protected function isTestInDatabaseGroup() {
                // If the test class says it belongs to the Database group, it needs the database.
                // NOTE: This ONLY checks for the group in the class level doc comment.
                $rc = new ReflectionClass( $this );
 -              if ( preg_match( '/@group +Database/im', $rc->getDocComment() ) ) {
 -                      return true;
 -              }
 -
 -              return false;
 +              return (bool)preg_match( '/@group +Database/im', $rc->getDocComment() );
        }
  
        /**
                self::$dbSetup = false;
        }
  
-       /**
-        * Prepares the given database connection for usage in the context of usage tests.
-        * This sets up clones database tables and changes the table prefix as appropriate.
-        * If the database connection already has cloned tables, calling this method has no
-        * effect. The tables are not re-cloned or reset in that case.
-        *
-        * @param IMaintainableDatabase $db
-        */
-       protected function prepareConnectionForTesting( IMaintainableDatabase $db ) {
-               if ( !self::$dbSetup ) {
-                       throw new LogicException(
-                               'Cannot use prepareConnectionForTesting()'
-                               . ' if the test case is not defined to use the database!'
-                       );
-               }
-               if ( isset( $db->_originalTablePrefix ) ) {
-                       // The DB connection was already prepared for testing.
-                       return;
-               }
-               $testPrefix = self::getTestPrefixFor( $db );
-               $oldPrefix = $db->tablePrefix();
-               $tablesCloned = self::listTables( $db );
-               if ( $oldPrefix === $testPrefix ) {
-                       // The database connection already has the test prefix, but presumably not
-                       // the cloned tables. This is the typical case, since the LBFactory will
-                       // have the prefix set during testing, but LoadBalancers will still return
-                       // connections that don't have the cloned table structure.
-                       $oldPrefix = self::$oldTablePrefix;
-               }
-               $dbClone = new CloneDatabase( $db, $tablesCloned, $testPrefix, $oldPrefix );
-               $dbClone->useTemporaryTables( self::$useTemporaryTables );
-               $db->_originalTablePrefix = $oldPrefix;
-               if ( ( $db->getType() == 'oracle' || !self::$useTemporaryTables ) && self::$reuseDB ) {
-                       throw new LogicException( 'Cannot clone database tables' );
-               } else {
-                       $dbClone->cloneTableStructure();
-               }
-       }
        /**
         * Setups a database with cloned tables using the given prefix.
         *
                // Assuming this isn't needed for External Store database, and not sure if the procedure
                // would be available there.
                if ( $db->getType() == 'oracle' ) {
 -                      $db->query( 'BEGIN FILL_WIKI_INFO; END;' );
 +                      $db->query( 'BEGIN FILL_WIKI_INFO; END;', __METHOD__ );
                }
  
                Hooks::run( 'UnitTestsAfterDatabaseSetup', [ $db, $prefix ] );
                foreach ( $tables as $tbl ) {
                        $tbl = $db->tableName( $tbl );
                        $db->query( "DROP TABLE IF EXISTS $tbl", __METHOD__ );
 -
 -                      if ( $tbl === 'page' ) {
 -                              // Forget about the pages since they don't
 -                              // exist in the DB.
 -                              MediaWikiServices::getInstance()->getLinkCache()->clear();
 -                      }
                }
        }
  
  
                $originalTables = $db->listTables( $db->_originalTablePrefix, __METHOD__ );
                if ( $prefix === 'unprefixed' ) {
 -                      $originalPrefixRegex = '/^' . preg_quote( $db->_originalTablePrefix ) . '/';
 +                      $originalPrefixRegex = '/^' . preg_quote( $db->_originalTablePrefix, '/' ) . '/';
                        $originalTables = array_map(
                                function ( $pt ) use ( $originalPrefixRegex ) {
                                        return preg_replace( $originalPrefixRegex, '', $pt );
         */
        private function resetDB( $db, $tablesUsed ) {
                if ( $db ) {
 -                      // NOTE: Do not reset the slot_roles and content_models tables, but let them
 -                      // leak across tests. Resetting them would require to reset all NamedTableStore
 -                      // instances for these tables, of which there may be several beyond the ones
 -                      // known to MediaWikiServices. See T202641.
                        $userTables = [ 'user', 'user_groups', 'user_properties', 'actor' ];
                        $pageTables = [
                                'page', 'revision', 'ip_changes', 'revision_comment_temp', 'comment', 'archive',
 -                              'revision_actor_temp', 'slots', 'content',
 +                              'revision_actor_temp', 'slots', 'content', 'content_models', 'slot_roles',
                        ];
                        $coreDBDataTables = array_merge( $userTables, $pageTables );
  
                        }
  
                        if ( array_intersect( $tablesUsed, $coreDBDataTables ) ) {
 +                              // Reset services that may contain information relating to the truncated tables
 +                              $this->overrideMwServices();
                                // Re-add core DB data that was deleted
                                $this->addCoreDBData();
                        }
                        $db->delete( $tableName, '*', __METHOD__ );
                }
  
 -              if ( in_array( $db->getType(), [ 'postgres', 'sqlite' ], true ) ) {
 +              if ( $db instanceof DatabasePostgres || $db instanceof DatabaseSqlite ) {
                        // Reset the table's sequence too.
                        $db->resetSequenceForTable( $tableName, __METHOD__ );
                }
  
 -              if ( $tableName === 'interwiki' ) {
 -                      if ( !$this->interwikiTable ) {
 -                              // @todo We should probably throw here, but this causes test failures that I
 -                              // can't figure out, so for now we silently continue.
 -                              return;
 -                      }
 -                      $db->insert(
 -                              'interwiki',
 -                              array_values( array_map( 'get_object_vars', iterator_to_array( $this->interwikiTable ) ) ),
 -                              __METHOD__
 -                      );
 -              }
 -
 -              if ( $tableName === 'page' ) {
 -                      // Forget about the pages since they don't
 -                      // exist in the DB.
 -                      MediaWikiServices::getInstance()->getLinkCache()->clear();
 +              // re-initialize site_stats table
 +              if ( $tableName === 'site_stats' ) {
 +                      SiteStatsInit::doPlaceholderInit();
                }
        }
  
         * @return mixed
         */
        public function getCliArg( $offset ) {
 -              if ( isset( PHPUnitMaintClass::$additionalOptions[$offset] ) ) {
 -                      return PHPUnitMaintClass::$additionalOptions[$offset];
 -              }
 -
 -              return null;
 +              return $this->cliArgs[$offset] ?? null;
        }
  
        /**
         * @param mixed $value
         */
        public function setCliArg( $offset, $value ) {
 -              PHPUnitMaintClass::$additionalOptions[$offset] = $value;
 +              $this->cliArgs[$offset] = $value;
        }
  
        /**
        protected function assertFileContains(
                $fileName,
                $actualData,
 -              $createIfMissing = true,
 +              $createIfMissing = false,
                $msg = ''
        ) {
                if ( $createIfMissing ) {