Update Codex from v1.20.0 to v1.20.1
[mediawiki.git] / tests / phpunit / bootstrap.php
blobcb4bfe23c7a1a800a91d4e4f93ac6c0103756915
1 <?php
3 /**
4 * PHPUnit bootstrap file. This file loads MW classes, and optionally MW settings if integration tests
5 * are probably going to be run. Note that MW settings are not loaded for unit tests, but a settings
6 * file must still exist in order to determine what extensions should be loaded and to add any custom
7 * tests that they might add.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 * http://www.gnu.org/copyleft/gpl.html
24 * @file
25 * @ingroup Testing
28 use MediaWiki\HookContainer\HookRunner;
29 use MediaWiki\MainConfigSchema;
30 use MediaWiki\MediaWikiServices;
31 use MediaWiki\Registration\ExtensionProcessor;
32 use MediaWiki\Registration\ExtensionRegistry;
33 use PHPUnit\TextUI\CliArguments\Builder;
35 require_once __DIR__ . '/bootstrap.common.php';
37 // Try to determine if this entry point is being used to run integration tests (possibly together with
38 // unit tests). If so, load all settings files. It's better to do this now, instead of later upon executing
39 // an integration test, to avoid scenarios where unit tests that run before the first integration test would
40 // run without the config being loaded, whereas the ones running after could potentially be affected by config.
41 // TODO This check is obviously imperfect. Once we upgrade to PHPUnit 10 we might be able to use its events
42 // (https://docs.phpunit.de/en/10.2/events.html) to get a list of tests that will be run, and check if there's
43 // any integration test in there.
44 /** @internal Only use this environment variable if you temporarily need it. */
45 $envVar = getenv( 'MEDIAWIKI_HAS_INTEGRATION_TESTS' );
46 if ( $envVar !== false ) {
47 // Allow the developer to override the detection if necessary.
48 if ( $envVar === 'true' || $envVar === '1' || $envVar === 'yes' ) {
49 $hasIntegrationTests = true;
50 } elseif ( $envVar === 'false' || $envVar === '0' || $envVar === 'no' ) {
51 $hasIntegrationTests = false;
52 } else {
53 fwrite( STDERR,
54 "Unsupported value in MEDIAWIKI_HAS_INTEGRATION_TESTS environment variable,\n" .
55 "assuming there are integration tests (but you should fix the environment variable)\n"
57 $hasIntegrationTests = true;
59 } elseif ( $GLOBALS['argc'] === 1 ) {
60 // PHPUnit has been invoked with no arguments. We're going to execute all and every test (from core, and potentially
61 // extension tests too), which includes integration tests.
62 $hasIntegrationTests = true;
63 } else {
64 // PHPUnit has been invoked with arguments. This can be very complex to handle, so the heuristic below is meant
65 // to cover just the most common use cases.
66 // Make PHPUnit not complain about unrecognized options when paratest options are passed in
67 $paratestArgs = [ 'runner', 'processes', 'passthru-php', 'write-to' ];
68 $phpunitArgs = ( new Builder )->fromParameters( $GLOBALS['argv'], $paratestArgs );
69 if ( $phpunitArgs->hasArgument() ) {
70 // A test or test directory was specified explicitly. Normalize line endings and case, and see if we likely
71 // got a directory of unit tests only (or a file therein).
72 $testArgument = strtolower( strtr( $phpunitArgs->argument(), '\\', '/' ) );
73 $hasIntegrationTests = !( str_contains( $testArgument, '/unit/' ) || str_ends_with( $testArgument, '/unit' ) );
74 } elseif ( $phpunitArgs->hasTestSuite() ) {
75 // If only unit test suites are being run, there can't be integration tests. Otherwise,
76 // there *might* be integration tests.
77 // See TestSuiteMapper for handling of the 'testsuites' argument.
78 $suites = explode( ',', $phpunitArgs->testSuite() );
79 $unitSuites = [ 'core:unit', 'extensions:unit', 'skins:unit' ];
80 $hasIntegrationTests = array_diff( $suites, $unitSuites ) !== [];
81 } else {
82 // Something more complex, just assume there might be integration tests
83 $hasIntegrationTests = true;
87 if ( !$hasIntegrationTests ) {
88 fwrite( STDERR, "Running without MediaWiki settings because there are no integration tests\n" );
89 // Faking in lieu of Setup.php
90 $GLOBALS['wgAutoloadClasses'] = [];
92 TestSetup::requireOnceInGlobalScope( MW_INSTALL_PATH . "/includes/AutoLoader.php" );
93 TestSetup::requireOnceInGlobalScope( MW_INSTALL_PATH . "/tests/common/TestsAutoLoader.php" );
94 TestSetup::requireOnceInGlobalScope( MW_INSTALL_PATH . "/includes/Defines.php" );
95 TestSetup::requireOnceInGlobalScope( MW_INSTALL_PATH . "/includes/GlobalFunctions.php" );
97 // Extract the defaults into global variables.
98 // NOTE: this does not apply any dynamic defaults.
99 foreach ( MainConfigSchema::listDefaultValues( 'wg' ) as $var => $value ) {
100 $GLOBALS[$var] = $value;
103 TestSetup::requireOnceInGlobalScope( MW_INSTALL_PATH . "/includes/DevelopmentSettings.php" );
105 TestSetup::applyInitialConfig();
107 // Shell out to another script that will give us a list of loaded extensions and skins. We need to do that in
108 // another process, not in this one, because loading setting files may have non-trivial side effects that could be
109 // hard to undo. This sucks, but there doesn't seem to be a way to get a list of extensions and skins without
110 // loading all of MediaWiki, which we don't want to do for unit tests.
112 // Disable XDEBUG, so it doesn't cause the sub-process to hang. T358097
113 $env = getenv();
114 unset( $env['XDEBUG_CONFIG'] );
115 unset( $env['XDEBUG_MODE'] );
116 unset( $env['XDEBUG_SESSION'] );
118 // phpcs:ignore MediaWiki.Usage.ForbiddenFunctions.proc_open
119 $process = proc_open(
120 PHP_BINARY . ' ' . __DIR__ . '/getPHPUnitExtensionsAndSkins.php',
122 0 => [ 'pipe', 'r' ],
123 1 => [ 'pipe', 'w' ],
124 2 => [ 'pipe', 'w' ]
126 $pipes,
127 null,
128 $env
131 $extensionData = stream_get_contents( $pipes[1] );
132 fclose( $pipes[1] );
133 $cmdErr = stream_get_contents( $pipes[2] );
134 fclose( $pipes[2] );
136 $exitCode = proc_close( $process );
137 if ( $exitCode !== 0 ) {
138 echo "Cannot load list of extensions and skins. Output:\n$cmdErr\n";
139 exit( 1 );
142 // For simplicity, getPHPUnitExtensionsAndSkins uses `\n\nTESTPATHS\n\n` to separate the lists of JSON files and
143 // additional test paths, so split the output into the individual lists.
144 [ $pathsToJsonFilesStr, $testPathsStr ] = explode( "\n\nTESTPATHS\n\n", $extensionData );
145 $pathsToJsonFiles = explode( "\n", $pathsToJsonFilesStr );
146 $testPaths = explode( "\n", $testPathsStr );
148 $extensionProcessor = new ExtensionProcessor();
149 foreach ( $pathsToJsonFiles as $filePath ) {
150 $extensionProcessor->extractInfoFromFile( $filePath );
153 $autoload = $extensionProcessor->getExtractedAutoloadInfo( true );
154 AutoLoader::loadFiles( $autoload['files'] );
155 AutoLoader::registerClasses( $autoload['classes'] );
156 AutoLoader::registerNamespaces( $autoload['namespaces'] );
158 // More faking in lieu of Setup.php
159 Profiler::init( [] );
160 } else {
161 fwrite( STDERR, "Running with MediaWiki settings because there might be integration tests\n" );
162 TestSetup::loadSettingsFiles();
164 $extensionRegistry = ExtensionRegistry::getInstance();
165 $extensionsAndSkins = $extensionRegistry->getQueue();
167 $pathsToJsonFiles = array_keys( $extensionsAndSkins );
169 $testPaths = [];
170 foreach ( $extensionRegistry->getAllThings() as $info ) {
171 $testPaths[] = dirname( $info['path'] ) . '/tests/phpunit';
174 ( new HookRunner( MediaWikiServices::getInstance()->getHookContainer() ) )->onUnitTestsList( $testPaths );
177 /** @internal For use in ExtensionsUnitTestSuite and SkinsUnitTestSuite only */
178 define( 'MW_PHPUNIT_EXTENSIONS_PATHS', array_map( 'dirname', $pathsToJsonFiles ) );
179 /** @internal For use in ExtensionsTestSuite only */
180 define( 'MW_PHPUNIT_EXTENSIONS_TEST_PATHS', $testPaths );
182 TestSetup::maybeCheckComposerLockUpToDate();