A service for read-only mode
authorTim Starling <tstarling@wikimedia.org>
Mon, 10 Apr 2017 05:34:30 +0000 (15:34 +1000)
committerTimo Tijhof <krinklemail@gmail.com>
Wed, 19 Apr 2017 19:27:06 +0000 (12:27 -0700)
Introduce a service to represent wfReadOnly() and friends.

It's necessary to have two service instances, one for wfReadOnly() and
one for wfConfiguredReadOnlyReason(), to avoid a circular dependency,
since LoadBalancer needs the configured reason during construction, but
wfReadOnly() needs to query the currently active load balancer.

Not having a cache of the configuration makes it possible to dynamically
change the configuration. Ideally things would not change the
configuration, and I removed such instances in core, but to support
extensions, I added a test ensuring that the configuration can be changed.

Change-Id: I9bbee946c10742526d3423208efd68cb3cc5a7ee

13 files changed:
autoload.php
includes/GlobalFunctions.php
includes/MediaWikiServices.php
includes/ReadOnlyMode.php [new file with mode: 0644]
includes/ServiceWiring.php
includes/WatchedItemStore.php
includes/db/MWLBFactory.php
maintenance/rebuildFileCache.php
maintenance/rebuildImages.php
tests/phpunit/includes/GlobalFunctions/GlobalTest.php
tests/phpunit/includes/ReadOnlyModeTest.php [new file with mode: 0644]
tests/phpunit/includes/WatchedItemStoreUnitTest.php
tests/phpunit/includes/auth/AuthManagerTest.php

index 20a1bf4..ba5b774 100644 (file)
@@ -285,6 +285,7 @@ $wgAutoloadLocalClasses = [
        'Config' => __DIR__ . '/includes/config/Config.php',
        'ConfigException' => __DIR__ . '/includes/config/ConfigException.php',
        'ConfigFactory' => __DIR__ . '/includes/config/ConfigFactory.php',
+       'ConfiguredReadOnlyMode' => __DIR__ . '/includes/ReadOnlyMode.php',
        'ConstantDependency' => __DIR__ . '/includes/cache/CacheDependency.php',
        'Content' => __DIR__ . '/includes/content/Content.php',
        'ContentHandler' => __DIR__ . '/includes/content/ContentHandler.php',
@@ -1160,6 +1161,7 @@ $wgAutoloadLocalClasses = [
        'RawAction' => __DIR__ . '/includes/actions/RawAction.php',
        'RawMessage' => __DIR__ . '/includes/Message.php',
        'ReadOnlyError' => __DIR__ . '/includes/exception/ReadOnlyError.php',
+       'ReadOnlyMode' => __DIR__ . '/includes/ReadOnlyMode.php',
        'ReassignEdits' => __DIR__ . '/maintenance/reassignEdits.php',
        'RebuildAll' => __DIR__ . '/maintenance/rebuildall.php',
        'RebuildFileCache' => __DIR__ . '/maintenance/rebuildFileCache.php',
index 4e60e63..8b857ea 100644 (file)
@@ -1273,7 +1273,8 @@ function wfIncrStats( $key, $count = 1 ) {
  * @return bool
  */
 function wfReadOnly() {
-       return wfReadOnlyReason() !== false;
+       return \MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode()
+               ->isReadOnly();
 }
 
 /**
@@ -1285,19 +1286,8 @@ function wfReadOnly() {
  * @return string|bool String when in read-only mode; false otherwise
  */
 function wfReadOnlyReason() {
-       $readOnly = wfConfiguredReadOnlyReason();
-       if ( $readOnly !== false ) {
-               return $readOnly;
-       }
-
-       static $lbReadOnly = null;
-       if ( $lbReadOnly === null ) {
-               // Callers use this method to be aware that data presented to a user
-               // may be very stale and thus allowing submissions can be problematic.
-               $lbReadOnly = wfGetLB()->getReadOnlyReason();
-       }
-
-       return $lbReadOnly;
+       return \MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode()
+               ->getReason();
 }
 
 /**
@@ -1307,18 +1297,8 @@ function wfReadOnlyReason() {
  * @since 1.27
  */
 function wfConfiguredReadOnlyReason() {
-       global $wgReadOnly, $wgReadOnlyFile;
-
-       if ( $wgReadOnly === null ) {
-               // Set $wgReadOnly for faster access next time
-               if ( is_file( $wgReadOnlyFile ) && filesize( $wgReadOnlyFile ) > 0 ) {
-                       $wgReadOnly = file_get_contents( $wgReadOnlyFile );
-               } else {
-                       $wgReadOnly = false;
-               }
-       }
-
-       return $wgReadOnly;
+       return \MediaWiki\MediaWikiServices::getInstance()->getConfiguredReadOnlyMode()
+               ->getReason();
 }
 
 /**
index e44fefe..d84a2b9 100644 (file)
@@ -656,6 +656,22 @@ class MediaWikiServices extends ServiceContainer {
                return $this->getService( 'VirtualRESTServiceClient' );
        }
 
+       /**
+        * @since 1.29
+        * @return \ReadOnlyMode
+        */
+       public function getConfiguredReadOnlyMode() {
+               return $this->getService( 'ConfiguredReadOnlyMode' );
+       }
+
+       /**
+        * @since 1.29
+        * @return \ReadOnlyMode
+        */
+       public function getReadOnlyMode() {
+               return $this->getService( 'ReadOnlyMode' );
+       }
+
        ///////////////////////////////////////////////////////////////////////////
        // NOTE: When adding a service getter here, don't forget to add a test
        // case for it in MediaWikiServicesTest::provideGetters() and in
diff --git a/includes/ReadOnlyMode.php b/includes/ReadOnlyMode.php
new file mode 100644 (file)
index 0000000..044e3f5
--- /dev/null
@@ -0,0 +1,128 @@
+<?php
+
+use Wikimedia\Rdbms\LoadBalancer;
+
+/**
+ * A service class for fetching the wiki's current read-only mode.
+ * To obtain an instance, use MediaWikiServices::getReadOnlyMode().
+ *
+ * @since 1.29
+ */
+class ReadOnlyMode {
+       private $configuredReadOnly;
+       private $loadBalancer;
+
+       public function __construct( ConfiguredReadOnlyMode $cro, LoadBalancer $loadBalancer ) {
+               $this->configuredReadOnly = $cro;
+               $this->loadBalancer = $loadBalancer;
+       }
+
+       /**
+        * Check whether the wiki is in read-only mode.
+        *
+        * @return bool
+        */
+       public function isReadOnly() {
+               return $this->getReason() !== false;
+       }
+
+       /**
+        * Check if the site is in read-only mode and return the message if so
+        *
+        * This checks the configuration and registered DB load balancers for
+        * read-only mode. This may result in DB connection being made.
+        *
+        * @return string|bool String when in read-only mode; false otherwise
+        */
+       public function getReason() {
+               $reason = $this->configuredReadOnly->getReason();
+               if ( $reason !== false ) {
+                       return $reason;
+               }
+               $reason = $this->loadBalancer->getReadOnlyReason();
+               if ( $reason !== false && $reason !== null ) {
+                       return $reason;
+               }
+               return false;
+       }
+
+       /**
+        * Set the read-only mode, which will apply for the remainder of the
+        * request or until a service reset.
+        */
+       public function setReason( $msg ) {
+               $this->configuredReadOnly->setReason( $msg );
+       }
+
+       /**
+        * Clear the cache of the read only file
+        */
+       public function clearCache() {
+               $this->configuredReadOnly->clearCache();
+       }
+}
+
+/**
+ * A read-only mode service which does not depend on LoadBalancer.
+ * To obtain an instance, use MediaWikiServices::getConfiguredReadOnlyMode().
+ *
+ * @since 1.29
+ */
+class ConfiguredReadOnlyMode {
+       private $config;
+       private $fileReason;
+       private $overrideReason;
+
+       public function __construct( Config $config ) {
+               $this->config = $config;
+       }
+
+       /**
+        * Check whether the wiki is in read-only mode.
+        *
+        * @return bool
+        */
+       public function isReadOnly() {
+               return $this->getReason() !== false;
+       }
+
+       /**
+        * Get the value of $wgReadOnly or the contents of $wgReadOnlyFile.
+        *
+        * @return string|bool String when in read-only mode; false otherwise
+        */
+       public function getReason() {
+               if ( $this->overrideReason !== null ) {
+                       return $this->overrideReason;
+               }
+               $confReason = $this->config->get( 'ReadOnly' );
+               if ( $confReason !== null ) {
+                       return $confReason;
+               }
+               if ( $this->fileReason === null ) {
+                       // Cache for faster access next time
+                       $readOnlyFile = $this->config->get( 'ReadOnlyFile' );
+                       if ( is_file( $readOnlyFile ) && filesize( $readOnlyFile ) > 0 ) {
+                               $this->fileReason = file_get_contents( $readOnlyFile );
+                       } else {
+                               $this->fileReason = false;
+                       }
+               }
+               return $this->fileReason;
+       }
+
+       /**
+        * Set the read-only mode, which will apply for the remainder of the
+        * request or until a service reset.
+        */
+       public function setReason( $msg ) {
+               $this->overrideReason = $msg;
+       }
+
+       /**
+        * Clear the cache of the read only file
+        */
+       public function clearCache() {
+               $this->fileReason = null;
+       }
+}
index ce82702..6afabed 100644 (file)
@@ -48,7 +48,8 @@ return [
 
                $lbConf = MWLBFactory::applyDefaultConfig(
                        $mainConfig->get( 'LBFactoryConf' ),
-                       $mainConfig
+                       $mainConfig,
+                       $services->getConfiguredReadOnlyMode()
                );
                $class = MWLBFactory::getLBFactoryClass( $lbConf );
 
@@ -155,7 +156,8 @@ return [
        'WatchedItemStore' => function( MediaWikiServices $services ) {
                $store = new WatchedItemStore(
                        $services->getDBLoadBalancer(),
-                       new HashBagOStuff( [ 'maxKeys' => 100 ] )
+                       new HashBagOStuff( [ 'maxKeys' => 100 ] ),
+                       $services->getReadOnlyMode()
                );
                $store->setStatsdDataFactory( $services->getStatsdDataFactory() );
                return $store;
@@ -404,6 +406,17 @@ return [
                return $vrsClient;
        },
 
+       'ConfiguredReadOnlyMode' => function( MediaWikiServices $services ) {
+               return new ConfiguredReadOnlyMode( $services->getMainConfig() );
+       },
+
+       'ReadOnlyMode' => function( MediaWikiServices $services ) {
+               return new ReadOnlyMode(
+                       $services->getConfiguredReadOnlyMode(),
+                       $services->getDBLoadBalancer()
+               );
+       },
+
        ///////////////////////////////////////////////////////////////////////////
        // NOTE: When adding a service here, don't forget to add a getter function
        // in the MediaWikiServices class. The convenience getter should just call
index b334098..17728fa 100644 (file)
@@ -30,6 +30,11 @@ class WatchedItemStore implements StatsdAwareInterface {
         */
        private $loadBalancer;
 
+       /**
+        * @var ReadOnlyMode
+        */
+       private $readOnlyMode;
+
        /**
         * @var HashBagOStuff
         */
@@ -61,13 +66,16 @@ class WatchedItemStore implements StatsdAwareInterface {
        /**
         * @param LoadBalancer $loadBalancer
         * @param HashBagOStuff $cache
+        * @param ReadOnlyMode $readOnlyMode
         */
        public function __construct(
                LoadBalancer $loadBalancer,
-               HashBagOStuff $cache
+               HashBagOStuff $cache,
+               ReadOnlyMode $readOnlyMode
        ) {
                $this->loadBalancer = $loadBalancer;
                $this->cache = $cache;
+               $this->readOnlyMode = $readOnlyMode;
                $this->stats = new NullStatsdDataFactory();
                $this->deferredUpdatesAddCallableUpdateCallback = [ 'DeferredUpdates', 'addCallableUpdate' ];
                $this->revisionGetTimestampFromIdCallback = [ 'Revision', 'getTimestampFromId' ];
@@ -596,7 +604,7 @@ class WatchedItemStore implements StatsdAwareInterface {
         * @return bool success
         */
        public function addWatchBatchForUser( User $user, array $targets ) {
-               if ( $this->loadBalancer->getReadOnlyReason() !== false ) {
+               if ( $this->readOnlyMode->isReadOnly() ) {
                        return false;
                }
                // Only loggedin user can have a watchlist
@@ -654,7 +662,7 @@ class WatchedItemStore implements StatsdAwareInterface {
         */
        public function removeWatch( User $user, LinkTarget $target ) {
                // Only logged in user can have a watchlist
-               if ( $this->loadBalancer->getReadOnlyReason() !== false || $user->isAnon() ) {
+               if ( $this->readOnlyMode->isReadOnly() || $user->isAnon() ) {
                        return false;
                }
 
@@ -785,7 +793,7 @@ class WatchedItemStore implements StatsdAwareInterface {
         */
        public function resetNotificationTimestamp( User $user, Title $title, $force = '', $oldid = 0 ) {
                // Only loggedin user can have a watchlist
-               if ( $this->loadBalancer->getReadOnlyReason() !== false || $user->isAnon() ) {
+               if ( $this->readOnlyMode->isReadOnly() || $user->isAnon() ) {
                        return false;
                }
 
index fe063f2..464a918 100644 (file)
@@ -33,9 +33,12 @@ abstract class MWLBFactory {
        /**
         * @param array $lbConf Config for LBFactory::__construct()
         * @param Config $mainConfig Main config object from MediaWikiServices
+        * @param ConfiguredReadOnlyMode $readOnlyMode
         * @return array
         */
-       public static function applyDefaultConfig( array $lbConf, Config $mainConfig ) {
+       public static function applyDefaultConfig( array $lbConf, Config $mainConfig,
+               ConfiguredReadOnlyMode $readOnlyMode
+       ) {
                global $wgCommandLineMode;
 
                static $typesWithSchema = [ 'postgres', 'msssql' ];
@@ -55,8 +58,7 @@ abstract class MWLBFactory {
                        'errorLogger' => [ MWExceptionHandler::class, 'logException' ],
                        'cliMode' => $wgCommandLineMode,
                        'hostname' => wfHostname(),
-                       // TODO: replace the global wfConfiguredReadOnlyReason() with a service.
-                       'readOnlyReason' => wfConfiguredReadOnlyReason(),
+                       'readOnlyReason' => $readOnlyMode->getReason(),
                ];
 
                // When making changes here, remember to also specify MediaWiki-specific options
index 3520279..04ac967 100644 (file)
@@ -41,7 +41,7 @@ class RebuildFileCache extends Maintenance {
        }
 
        public function finalSetup() {
-               global $wgDebugToolbar, $wgUseFileCache, $wgReadOnly;
+               global $wgDebugToolbar, $wgUseFileCache;
 
                $this->enabled = $wgUseFileCache;
                // Script will handle capturing output and saving it itself
@@ -50,7 +50,8 @@ class RebuildFileCache extends Maintenance {
                // Has to be done before Setup.php initialize MWDebug
                $wgDebugToolbar = false;
                //  Avoid DB writes (like enotif/counters)
-               $wgReadOnly = 'Building cache'; // avoid DB writes (like enotif/counters)
+               MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode()
+                       ->setReason( 'Building cache' );
 
                parent::finalSetup();
        }
index 966864e..109350c 100644 (file)
@@ -63,7 +63,8 @@ class ImageBuilder extends Maintenance {
                $this->dbw = $this->getDB( DB_MASTER );
                $this->dryrun = $this->hasOption( 'dry-run' );
                if ( $this->dryrun ) {
-                       $GLOBALS['wgReadOnly'] = 'Dry run mode, image upgrades are suppressed';
+                       MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode()
+                               ->setReason( 'Dry run mode, image upgrades are suppressed' );
                }
 
                if ( $this->hasOption( 'missing' ) ) {
index 2206fbd..33b6e2f 100644 (file)
@@ -102,22 +102,28 @@ class GlobalTest extends MediaWikiTestCase {
        }
 
        /**
+        * Intended to cover the relevant bits of ServiceWiring.php, as well as GlobalFunctions.php
         * @covers ::wfReadOnly
         */
        public function testReadOnlyEmpty() {
                global $wgReadOnly;
                $wgReadOnly = null;
 
+               MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode()->clearCache();
                $this->assertFalse( wfReadOnly() );
                $this->assertFalse( wfReadOnly() );
        }
 
        /**
+        * Intended to cover the relevant bits of ServiceWiring.php, as well as GlobalFunctions.php
         * @covers ::wfReadOnly
         */
        public function testReadOnlySet() {
                global $wgReadOnly, $wgReadOnlyFile;
 
+               $readOnlyMode = MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode();
+               $readOnlyMode->clearCache();
+
                $f = fopen( $wgReadOnlyFile, "wt" );
                fwrite( $f, 'Message' );
                fclose( $f );
@@ -127,12 +133,23 @@ class GlobalTest extends MediaWikiTestCase {
                $this->assertTrue( wfReadOnly() ); # Check cached
 
                unlink( $wgReadOnlyFile );
-               $wgReadOnly = null; # Clean cache
-
+               $readOnlyMode->clearCache();
                $this->assertFalse( wfReadOnly() );
                $this->assertFalse( wfReadOnly() );
        }
 
+       /**
+        * This behaviour could probably be deprecated. Several extensions rely on it as of 1.29.
+        * @covers ::wfReadOnlyReason
+        */
+       public function testReadOnlyGlobalChange() {
+               $this->assertFalse( wfReadOnlyReason() );
+               $this->setMwGlobals( [
+                       'wgReadOnly' => 'reason'
+               ] );
+               $this->assertSame( 'reason', wfReadOnlyReason() );
+       }
+
        public static function provideArrayToCGI() {
                return [
                        [ [], '' ], // empty
diff --git a/tests/phpunit/includes/ReadOnlyModeTest.php b/tests/phpunit/includes/ReadOnlyModeTest.php
new file mode 100644 (file)
index 0000000..9c02bbd
--- /dev/null
@@ -0,0 +1,196 @@
+<?php
+
+use MediaWiki\MediaWikiServices;
+
+/**
+ * @group Database
+ *
+ * @covers ReadOnlyMode
+ * @covers ConfiguredReadOnlyMode
+ */
+class ReadOnlyModeTest extends MediaWikiTestCase {
+       public function provider() {
+               $rawTests = [
+                       'None of anything' => [
+                               'confMessage' => null,
+                               'hasFileName' => false,
+                               'fileContents' => false,
+                               'lbMessage' => false,
+                               'expectedState' => false,
+                               'expectedMessage' => false,
+                               'expectedConfState' => false,
+                               'expectedConfMessage' => false
+                       ],
+                       'File missing' => [
+                               'confMessage' => null,
+                               'hasFileName' => true,
+                               'fileContents' => false,
+                               'lbMessage' => false,
+                               'expectedState' => false,
+                               'expectedMessage' => false,
+                               'expectedConfState' => false,
+                               'expectedConfMessage' => false
+                       ],
+                       'File empty' => [
+                               'confMessage' => null,
+                               'hasFileName' => true,
+                               'fileContents' => '',
+                               'lbMessage' => false,
+                               'expectedState' => false,
+                               'expectedMessage' => false,
+                               'expectedConfState' => false,
+                               'expectedConfMessage' => false
+                       ],
+                       'File has message' => [
+                               'confMessage' => null,
+                               'hasFileName' => true,
+                               'fileContents' => 'Message',
+                               'lbMessage' => false,
+                               'expectedState' => true,
+                               'expectedMessage' => 'Message',
+                               'expectedConfState' => true,
+                               'expectedConfMessage' => 'Message',
+                       ],
+                       'Conf has message' => [
+                               'confMessage' => 'Message',
+                               'hasFileName' => false,
+                               'fileContents' => false,
+                               'lbMessage' => false,
+                               'expectedState' => true,
+                               'expectedMessage' => 'Message',
+                               'expectedConfState' => true,
+                               'expectedConfMessage' => 'Message'
+                       ],
+                       "Conf=false means don't check the file" => [
+                               'confMessage' => false,
+                               'hasFileName' => true,
+                               'fileContents' => 'Message',
+                               'lbMessage' => false,
+                               'expectedState' => false,
+                               'expectedMessage' => false,
+                               'expectedConfState' => false,
+                               'expectedConfMessage' => false,
+                       ],
+                       'LB has message' => [
+                               'confMessage' => null,
+                               'hasFileName' => false,
+                               'fileContents' => false,
+                               'lbMessage' => 'Message',
+                               'expectedState' => true,
+                               'expectedMessage' => 'Message',
+                               'expectedConfState' => false,
+                               'expectedConfMessage' => false
+                       ],
+                       'All three have a message: conf wins' => [
+                               'confMessage' => 'conf',
+                               'hasFileName' => true,
+                               'fileContents' => 'file',
+                               'lbMessage' => 'lb',
+                               'expectedState' => true,
+                               'expectedMessage' => 'conf',
+                               'expectedConfState' => true,
+                               'expectedConfMessage' => 'conf'
+                       ]
+               ];
+               $cookedTests = [];
+               foreach ( $rawTests as $desc => $test ) {
+                       $cookedTests[$desc] = [ $test ];
+               }
+               return $cookedTests;
+       }
+
+       private function createMode( $params, $makeLB ) {
+               $config = new HashConfig( [
+                       'ReadOnly' => $params['confMessage'],
+                       'ReadOnlyFile' => $this->createFile( $params ),
+               ] );
+
+               $rom = new ConfiguredReadOnlyMode( $config );
+
+               if ( $makeLB ) {
+                       $lb = $this->createLB( $params );
+                       $rom = new ReadOnlyMode( $rom, $lb );
+               }
+
+               return $rom;
+       }
+
+       private function createLB( $params ) {
+               $lb = $this->getMockBuilder( \Wikimedia\Rdbms\LoadBalancer::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+               $lb->expects( $this->any() )->method( 'getReadOnlyReason' )
+                       ->willReturn( $params['lbMessage'] );
+               return $lb;
+       }
+
+       private function createFile( $params ) {
+               if ( $params['hasFileName'] ) {
+                       $fileName = $this->getNewTempFile();
+
+                       if ( $params['fileContents'] === false ) {
+                               unlink( $fileName );
+                       } else {
+                               file_put_contents( $fileName, $params['fileContents'] );
+                       }
+               } else {
+                       $fileName = null;
+               }
+               return $fileName;
+       }
+
+       /**
+        * @dataProvider provider
+        */
+       public function testWithLB( $params ) {
+               $rom = $this->createMode( $params, true );
+               $this->assertSame( $params['expectedMessage'], $rom->getReason() );
+               $this->assertSame( $params['expectedState'], $rom->isReadOnly() );
+       }
+
+       /**
+        * @dataProvider provider
+        */
+       public function testWithoutLB( $params ) {
+               $cro = $this->createMode( $params, false );
+               $this->assertSame( $params['expectedConfMessage'], $cro->getReason() );
+               $this->assertSame( $params['expectedConfState'], $cro->isReadOnly() );
+       }
+
+       public function testSetReadOnlyReason() {
+               $rom = $this->createMode(
+                       [
+                               'confMessage' => 'conf',
+                               'hasFileName' => false,
+                               'fileContents' => false,
+                               'lbMessage' => 'lb'
+                       ],
+                       true );
+               $rom->setReason( 'override' );
+               $this->assertSame( 'override', $rom->getReason() );
+       }
+
+       /**
+        * @covers ReadOnlyMode::clearCache
+        * @covers ConfiguredReadOnlyMode::clearCache
+        */
+       public function testClearCache() {
+               $fileName = $this->getNewTempFile();
+               unlink( $fileName );
+               $config = new HashConfig( [
+                       'ReadOnly' => null,
+                       'ReadOnlyFile' => $fileName,
+               ] );
+               $cro = new ConfiguredReadOnlyMode( $config );
+               $lb = $this->createLB( [ 'lbMessage' => false ] );
+               $rom = new ReadOnlyMode( $cro, $lb );
+
+               $this->assertSame( false, $rom->getReason(), 'initial' );
+
+               file_put_contents( $fileName, 'file' );
+               $this->assertSame( false, $rom->getReason(), 'stale' );
+
+               $rom->clearCache();
+               $this->assertSame( 'file', $rom->getReason(), 'fresh' );
+       }
+}
index b71e8f4..f31028d 100644 (file)
@@ -21,8 +21,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
         */
        private function getMockLoadBalancer(
                $mockDb,
-               $expectedConnectionType = null,
-               $readOnlyReason = false
+               $expectedConnectionType = null
        ) {
                $mock = $this->getMockBuilder( LoadBalancer::class )
                        ->disableOriginalConstructor()
@@ -37,9 +36,6 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                                ->method( 'getConnectionRef' )
                                ->will( $this->returnValue( $mockDb ) );
                }
-               $mock->expects( $this->any() )
-                       ->method( 'getReadOnlyReason' )
-                       ->will( $this->returnValue( $readOnlyReason ) );
                return $mock;
        }
 
@@ -58,6 +54,19 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                return $mock;
        }
 
+       /**
+        * @return PHPUnit_Framework_MockObject_MockObject|ReadOnlyMode
+        */
+       private function getMockReadOnlyMode( $readOnly = false ) {
+               $mock = $this->getMockBuilder( ReadOnlyMode::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+               $mock->expects( $this->any() )
+                       ->method( 'isReadOnly' )
+                       ->will( $this->returnValue( $readOnly ) );
+               return $mock;
+       }
+
        /**
         * @param int $id
         * @return PHPUnit_Framework_MockObject_MockObject|User
@@ -88,10 +97,13 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                return $fakeRow;
        }
 
-       private function newWatchedItemStore( LoadBalancer $loadBalancer, HashBagOStuff $cache ) {
+       private function newWatchedItemStore( LoadBalancer $loadBalancer, HashBagOStuff $cache,
+               ReadOnlyMode $readOnlyMode
+       ) {
                return new WatchedItemStore(
                        $loadBalancer,
-                       $cache
+                       $cache,
+                       $readOnlyMode
                );
        }
 
@@ -118,7 +130,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertEquals( 12, $store->countWatchedItems( $user ) );
@@ -148,7 +161,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertEquals( 7, $store->countWatchers( $titleValue ) );
@@ -199,7 +213,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $expected = [
@@ -265,7 +280,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $expected = [
@@ -313,7 +329,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertEquals( 7, $store->countVisitingWatchers( $titleValue, '111' ) );
@@ -392,7 +409,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $expected = [
@@ -494,7 +512,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $expected = [
@@ -547,7 +566,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $expected = [
@@ -584,7 +604,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertEquals( 9, $store->countUnreadNotifications( $user ) );
@@ -618,7 +639,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertSame(
@@ -655,7 +677,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertEquals(
@@ -685,7 +708,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $this->getMockCache()
+                       $this->getMockCache(),
+                       $this->getMockReadOnlyMode()
                );
 
                $store->duplicateEntry(
@@ -743,7 +767,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $store->duplicateEntry(
@@ -789,7 +814,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $store->duplicateAllAssociatedEntries(
@@ -882,7 +908,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $store->duplicateAllAssociatedEntries(
@@ -914,7 +941,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $store->addWatch(
@@ -934,7 +962,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $store->addWatch(
@@ -945,8 +974,9 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
        public function testAddWatchBatchForUser_readOnlyDBReturnsFalse() {
                $store = $this->newWatchedItemStore(
-                       $this->getMockLoadBalancer( $this->getMockDb(), null, 'Some Reason' ),
-                       $this->getMockCache()
+                       $this->getMockLoadBalancer( $this->getMockDb() ),
+                       $this->getMockCache(),
+                       $this->getMockReadOnlyMode( true )
                );
 
                $this->assertFalse(
@@ -991,7 +1021,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $mockUser = $this->getMockNonAnonUserWithId( 1 );
@@ -1015,7 +1046,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertFalse(
@@ -1038,7 +1070,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertTrue(
@@ -1072,7 +1105,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $watchedItem = $store->loadWatchedItem(
@@ -1106,7 +1140,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertFalse(
@@ -1128,7 +1163,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertFalse(
@@ -1163,7 +1199,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertTrue(
@@ -1198,7 +1235,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertFalse(
@@ -1221,7 +1259,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertFalse(
@@ -1265,7 +1304,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $watchedItem = $store->getWatchedItem(
@@ -1299,7 +1339,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertEquals(
@@ -1336,7 +1377,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertFalse(
@@ -1359,7 +1401,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertFalse(
@@ -1399,7 +1442,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
                $user = $this->getMockNonAnonUserWithId( 1 );
 
@@ -1449,7 +1493,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $mockLoadBalancer,
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $watchedItems = $store->getWatchedItemsForUser(
@@ -1462,7 +1507,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
        public function testGetWatchedItemsForUser_badSortOptionThrowsException() {
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $this->getMockDb() ),
-                       $this->getMockCache()
+                       $this->getMockCache(),
+                       $this->getMockReadOnlyMode()
                );
 
                $this->setExpectedException( 'InvalidArgumentException' );
@@ -1503,7 +1549,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertTrue(
@@ -1539,7 +1586,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertFalse(
@@ -1562,7 +1610,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertFalse(
@@ -1629,7 +1678,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertEquals(
@@ -1679,7 +1729,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertEquals(
@@ -1740,7 +1791,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertEquals(
@@ -1780,7 +1832,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertEquals(
@@ -1806,7 +1859,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertEquals(
@@ -1830,7 +1884,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertFalse(
@@ -1863,7 +1918,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertFalse(
@@ -1908,7 +1964,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                // Note: This does not actually assert the job is correct
@@ -1948,7 +2005,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                // Note: This does not actually assert the job is correct
@@ -2041,7 +2099,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $callableCallCounter = 0;
@@ -2107,7 +2166,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $addUpdateCallCounter = 0;
@@ -2182,7 +2242,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $callableCallCounter = 0;
@@ -2248,7 +2309,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $addUpdateCallCounter = 0;
@@ -2325,7 +2387,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $addUpdateCallCounter = 0;
@@ -2370,7 +2433,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
        public function testSetNotificationTimestampsForUser_anonUser() {
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $this->getMockDb() ),
-                       $this->getMockCache()
+                       $this->getMockCache(),
+                       $this->getMockReadOnlyMode()
                );
                $this->assertFalse( $store->setNotificationTimestampsForUser( $this->getAnonUser(), '' ) );
        }
@@ -2396,7 +2460,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $this->getMockCache()
+                       $this->getMockCache(),
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertTrue(
@@ -2425,7 +2490,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $this->getMockCache()
+                       $this->getMockCache(),
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertTrue(
@@ -2463,7 +2529,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $this->getMockCache()
+                       $this->getMockCache(),
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertTrue(
@@ -2505,7 +2572,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $this->assertEquals(
@@ -2545,7 +2613,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                $watchers = $store->updateNotificationTimestamp(
@@ -2588,7 +2657,8 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
 
                $store = $this->newWatchedItemStore(
                        $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
+                       $mockCache,
+                       $this->getMockReadOnlyMode()
                );
 
                // This will add the item to the cache
index 5c268f8..802e4ae 100644 (file)
@@ -1404,12 +1404,13 @@ class AuthManagerTest extends \MediaWikiTestCase {
                        $this->manager->checkAccountCreatePermissions( new \User )
                );
 
-               $this->setMwGlobals( [ 'wgReadOnly' => 'Because' ] );
+               $readOnlyMode = \MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode();
+               $readOnlyMode->setReason( 'Because' );
                $this->assertEquals(
                        \Status::newFatal( 'readonlytext', 'Because' ),
                        $this->manager->checkAccountCreatePermissions( new \User )
                );
-               $this->setMwGlobals( [ 'wgReadOnly' => false ] );
+               $readOnlyMode->setReason( false );
 
                $wgGroupPermissions['*']['createaccount'] = false;
                $status = $this->manager->checkAccountCreatePermissions( new \User );
@@ -1597,7 +1598,8 @@ class AuthManagerTest extends \MediaWikiTestCase {
                $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
                $this->assertSame( 'noname', $ret->message->getKey() );
 
-               $this->setMwGlobals( [ 'wgReadOnly' => 'Because' ] );
+               $readOnlyMode = \MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode();
+               $readOnlyMode->setReason( 'Because' );
                $this->hook( 'LocalUserCreated', $this->never() );
                $userReq->username = self::usernameForCreation();
                $ret = $this->manager->beginAccountCreation( $creator, [ $userReq ], 'http://localhost/' );
@@ -1605,7 +1607,7 @@ class AuthManagerTest extends \MediaWikiTestCase {
                $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
                $this->assertSame( 'readonlytext', $ret->message->getKey() );
                $this->assertSame( [ 'Because' ], $ret->message->getParams() );
-               $this->setMwGlobals( [ 'wgReadOnly' => false ] );
+               $readOnlyMode->setReason( false );
 
                $this->hook( 'LocalUserCreated', $this->never() );
                $userReq->username = self::usernameForCreation();
@@ -1770,14 +1772,15 @@ class AuthManagerTest extends \MediaWikiTestCase {
 
                $this->request->getSession()->setSecret( 'AuthManager::accountCreationState',
                        [ 'username' => $creator->getName() ] + $session );
-               $this->setMwGlobals( [ 'wgReadOnly' => 'Because' ] );
+               $readOnlyMode = \MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode();
+               $readOnlyMode->setReason( 'Because' );
                $this->hook( 'LocalUserCreated', $this->never() );
                $ret = $this->manager->continueAccountCreation( [] );
                $this->unhook( 'LocalUserCreated' );
                $this->assertSame( AuthenticationResponse::FAIL, $ret->status );
                $this->assertSame( 'readonlytext', $ret->message->getKey() );
                $this->assertSame( [ 'Because' ], $ret->message->getParams() );
-               $this->setMwGlobals( [ 'wgReadOnly' => false ] );
+               $readOnlyMode->setReason( false );
 
                $this->request->getSession()->setSecret( 'AuthManager::accountCreationState',
                        [ 'username' => $creator->getName() ] + $session );
@@ -2468,7 +2471,8 @@ class AuthManagerTest extends \MediaWikiTestCase {
 
                // Wiki is read-only
                $session->clear();
-               $this->setMwGlobals( [ 'wgReadOnly' => 'Because' ] );
+               $readOnlyMode = \MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode();
+               $readOnlyMode->setReason( 'Because' );
                $user = \User::newFromName( $username );
                $this->hook( 'LocalUserCreated', $this->never() );
                $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true );
@@ -2481,7 +2485,7 @@ class AuthManagerTest extends \MediaWikiTestCase {
                        [ LogLevel::DEBUG, 'denied by wfReadOnly(): {reason}' ],
                ], $logger->getBuffer() );
                $logger->clearBuffer();
-               $this->setMwGlobals( [ 'wgReadOnly' => false ] );
+               $readOnlyMode->setReason( false );
 
                // Session blacklisted
                $session->clear();