From: Tim Starling Date: Mon, 10 Apr 2017 05:34:30 +0000 (+1000) Subject: A service for read-only mode X-Git-Tag: 1.31.0-rc.0~3465^2 X-Git-Url: http://git.cyclocoop.org/%7B%24admin_url%7Dcompta/comptes/journal.php?a=commitdiff_plain;h=820f46964f7968a8f534a678dc528348445b666d;p=lhc%2Fweb%2Fwiklou.git A service for read-only mode 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 --- diff --git a/autoload.php b/autoload.php index 20a1bf41c2..ba5b77478e 100644 --- a/autoload.php +++ b/autoload.php @@ -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', diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index 4e60e633fd..8b857eae8b 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -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(); } /** diff --git a/includes/MediaWikiServices.php b/includes/MediaWikiServices.php index e44fefe9b5..d84a2b9f3b 100644 --- a/includes/MediaWikiServices.php +++ b/includes/MediaWikiServices.php @@ -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 index 0000000000..044e3f51a8 --- /dev/null +++ b/includes/ReadOnlyMode.php @@ -0,0 +1,128 @@ +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; + } +} diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php index ce82702f0a..6afabedde1 100644 --- a/includes/ServiceWiring.php +++ b/includes/ServiceWiring.php @@ -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 diff --git a/includes/WatchedItemStore.php b/includes/WatchedItemStore.php index b334098e63..17728fa33e 100644 --- a/includes/WatchedItemStore.php +++ b/includes/WatchedItemStore.php @@ -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; } diff --git a/includes/db/MWLBFactory.php b/includes/db/MWLBFactory.php index fe063f20b1..464a91827f 100644 --- a/includes/db/MWLBFactory.php +++ b/includes/db/MWLBFactory.php @@ -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 diff --git a/maintenance/rebuildFileCache.php b/maintenance/rebuildFileCache.php index 3520279fc3..04ac9678d9 100644 --- a/maintenance/rebuildFileCache.php +++ b/maintenance/rebuildFileCache.php @@ -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(); } diff --git a/maintenance/rebuildImages.php b/maintenance/rebuildImages.php index 966864e62d..109350cd74 100644 --- a/maintenance/rebuildImages.php +++ b/maintenance/rebuildImages.php @@ -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' ) ) { diff --git a/tests/phpunit/includes/GlobalFunctions/GlobalTest.php b/tests/phpunit/includes/GlobalFunctions/GlobalTest.php index 2206fbdfee..33b6e2f664 100644 --- a/tests/phpunit/includes/GlobalFunctions/GlobalTest.php +++ b/tests/phpunit/includes/GlobalFunctions/GlobalTest.php @@ -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 index 0000000000..9c02bbd9d4 --- /dev/null +++ b/tests/phpunit/includes/ReadOnlyModeTest.php @@ -0,0 +1,196 @@ + [ + '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' ); + } +} diff --git a/tests/phpunit/includes/WatchedItemStoreUnitTest.php b/tests/phpunit/includes/WatchedItemStoreUnitTest.php index b71e8f4d5c..f31028da6f 100644 --- a/tests/phpunit/includes/WatchedItemStoreUnitTest.php +++ b/tests/phpunit/includes/WatchedItemStoreUnitTest.php @@ -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 diff --git a/tests/phpunit/includes/auth/AuthManagerTest.php b/tests/phpunit/includes/auth/AuthManagerTest.php index 5c268f84cf..802e4ae5d1 100644 --- a/tests/phpunit/includes/auth/AuthManagerTest.php +++ b/tests/phpunit/includes/auth/AuthManagerTest.php @@ -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();