Page MenuHomePhabricator

ConfiguredReadOnlyMode has a bad config during testing
Closed, InvalidPublic

Description

I found this bug during CI of my extension with this patch (Jenkins report), but I was able to verify it is independant of my extension.

When executing PHPUnit with a test where backupGlobals is enabled, there is the following error:

PHP Fatal error:  Uncaught ConfigException: MultiConfig::get: undefined option: 'ReadOnly' in /mediawiki/includes/config/MultiConfig.php:57
Stack trace:
#0 /mediawiki/includes/ReadOnlyMode.php(98): MultiConfig->get('ReadOnly')
#1 /mediawiki/includes/GlobalFunctions.php(1301): ConfiguredReadOnlyMode->getReason()
#2 /mediawiki/includes/jobqueue/JobQueueGroup.php(74): wfConfiguredReadOnlyReason()
#3 /mediawiki/tests/phpunit/MediaWikiTestCase.php(1077): JobQueueGroup::singleton()
#4 /mediawiki/tests/phpunit/bootstrap.php(20): MediaWikiTestCase::teardownTestDB()
#5 [internal function]: MediaWikiPHPUnitBootstrap->__destruct()
#6 {main}
  thrown in /mediawiki/includes/config/MultiConfig.php on line 57

This occurs with version 820f4696 (but not with the previous version 0a873ed2) and when $wgReadOnly is not set in LocalSettings.php (so its value is null). This can be tested by copying the basic extension TestGlobals from P5315 and add wfLoadExtension( 'TestGlobals' ); in your LocalSettings.php.

Event Timeline

@tstarling This issue appears when you introduced ConfiguredReadOnlyMode in 820f4696.

I tried to investigate, but I don’t understand well the MediaWiki services. Possibly it is related to testing infrastructure specifically.

My current findings are: a MultiConfig object is created in MediaWikiTestCase::makeTestConfig() and I verified this object has the parameter "ReadOnly", hence I guess when wfConfiguredReadOnlyReason() is called it is another config object which is used.

Well. I investigated further and found. Imho it is an issue with PHPUnit, and more precisely the global-state subprogram, consequently I close this task as invalid.

  1. The global variable $wgReadOnly has the default value null.
  2. If a MediaWikiTestCase class has no explicit test method (it always has implicitely testMediaWikiTestCaseParentSetupCalled) then the backup-restore mechanism of PHPUnit is not called. But if there is at least one test method, it is called.
  3. During the 'restore' operation, only non-null global variables are restored (because of a condition isset($globalVariables[$key])), and non-existant and null global variables are unset.
  4. Consequently $wgReadOnly does no more exist after this operation (and it is also the case of other null global variables like $wgAntivirus).

I tested a fix using a condition array_key_exists( $key, $globalVariables ) and it works: null values are preserved.

The pull request fixing this was merged by Sebastian Bergmann some hours ago.

If someone else experience this issue, you must use PHPUnit ≥ 6.0 to solve it.