/** * Do any setup which can be done once for all tests, independent of test * options, except for database setup. * * Public setup functions in this class return a ScopedCallback object. When * this object is destroyed by going out of scope, teardown of the * corresponding test setup is performed. * * Teardown objects may be chained by passing a ScopedCallback from a * previous setup stage as the $nextTeardown parameter. This enforces the * convention that teardown actions are taken in reverse order to the * corresponding setup actions. When $nextTeardown is specified, a * ScopedCallback will be returned which first tears down the current * setup stage, and then tears down the previous setup stage which was * specified by $nextTeardown. * * @param ScopedCallback|null $nextTeardown * @return ScopedCallback */ public function staticSetup($nextTeardown = null) { // A note on coding style: // The general idea here is to keep setup code together with // corresponding teardown code, in a fine-grained manner. We have two // arrays: $setup and $teardown. The code snippets in the $setup array // are executed at the end of the method, before it returns, and the // code snippets in the $teardown array are executed in reverse order // when the Wikimedia\ScopedCallback object is consumed. // Because it is a common operation to save, set and restore global // variables, we have an additional convention: when the array key of // $setup is a string, the string is taken to be the name of the global // variable, and the element value is taken to be the desired new value. // It's acceptable to just do the setup immediately, instead of adding // a closure to $setup, except when the setup action depends on global // variable initialisation being done first. In this case, you have to // append a closure to $setup after the global variable is appended. // When you add to setup functions in this class, please keep associated // setup and teardown actions together in the source code, and please // add comments explaining why the setup action is necessary. $setup = []; $teardown = []; $teardown[] = $this->markSetupDone('staticSetup'); // Some settings which influence HTML output $setup['wgSitename'] = 'MediaWiki'; $setup['wgServer'] = 'http://example.org'; $setup['wgServerName'] = 'example.org'; $setup['wgScriptPath'] = ''; $setup['wgScript'] = '/index.php'; $setup['wgResourceBasePath'] = ''; $setup['wgStylePath'] = '/skins'; $setup['wgExtensionAssetsPath'] = '/extensions'; $setup['wgArticlePath'] = '/wiki/$1'; $setup['wgActionPaths'] = []; $setup['wgVariantArticlePath'] = false; $setup['wgUploadNavigationUrl'] = false; $setup['wgCapitalLinks'] = true; $setup['wgNoFollowLinks'] = true; $setup['wgNoFollowDomainExceptions'] = ['no-nofollow.org']; $setup['wgExternalLinkTarget'] = false; $setup['wgExperimentalHtmlIds'] = false; $setup['wgLocaltimezone'] = 'UTC'; $setup['wgHtml5'] = true; $setup['wgDisableLangConversion'] = false; $setup['wgDisableTitleConversion'] = false; // "extra language links" // see https://gerrit.wikimedia.org/r/111390 $setup['wgExtraInterlanguageLinkPrefixes'] = ['mul']; // All FileRepo changes should be done here by injecting services, // there should be no need to change global variables. RepoGroup::setSingleton($this->createRepoGroup()); $teardown[] = function () { RepoGroup::destroySingleton(); }; // Set up null lock managers $setup['wgLockManagers'] = [['name' => 'fsLockManager', 'class' => 'NullLockManager'], ['name' => 'nullLockManager', 'class' => 'NullLockManager']]; $reset = function () { LockManagerGroup::destroySingletons(); }; $setup[] = $reset; $teardown[] = $reset; // This allows article insertion into the prefixed DB $setup['wgDefaultExternalStore'] = false; // This might slightly reduce memory usage $setup['wgAdaptiveMessageCache'] = true; // This is essential and overrides disabling of database messages in TestSetup $setup['wgUseDatabaseMessages'] = true; $reset = function () { MessageCache::destroyInstance(); }; $setup[] = $reset; $teardown[] = $reset; // It's not necessary to actually convert any files $setup['wgSVGConverter'] = 'null'; $setup['wgSVGConverters'] = ['null' => 'echo "1">$output']; // Fake constant timestamp Hooks::register('ParserGetVariableValueTs', 'ParserTestRunner::getFakeTimestamp'); $teardown[] = function () { Hooks::clear('ParserGetVariableValueTs'); }; $this->appendNamespaceSetup($setup, $teardown); // Set up interwikis and append teardown function $teardown[] = $this->setupInterwikis(); // This affects title normalization in links. It invalidates // MediaWikiTitleCodec objects. $setup['wgLocalInterwikis'] = ['local', 'mi']; $reset = function () { $this->resetTitleServices(); }; $setup[] = $reset; $teardown[] = $reset; // Set up a mock MediaHandlerFactory MediaWikiServices::getInstance()->disableService('MediaHandlerFactory'); MediaWikiServices::getInstance()->redefineService('MediaHandlerFactory', function () { return new MockMediaHandlerFactory(); }); $teardown[] = function () { MediaWikiServices::getInstance()->resetServiceForTesting('MediaHandlerFactory'); }; // SqlBagOStuff broke when using temporary tables on r40209 (bug 15892). // It seems to have been fixed since (r55079?), but regressed at some point before r85701. // This works around it for now... global $wgObjectCaches; $setup['wgObjectCaches'] = [CACHE_DB => $wgObjectCaches['hash']] + $wgObjectCaches; if (isset(ObjectCache::$instances[CACHE_DB])) { $savedCache = ObjectCache::$instances[CACHE_DB]; ObjectCache::$instances[CACHE_DB] = new HashBagOStuff(); $teardown[] = function () use($savedCache) { ObjectCache::$instances[CACHE_DB] = $savedCache; }; } $teardown[] = $this->executeSetupSnippets($setup); // Schedule teardown snippets in reverse order return $this->createTeardownObject($teardown, $nextTeardown); }