Revert "Allow reset of global services."
authorCatrope <roan.kattouw@gmail.com>
Mon, 11 Apr 2016 20:37:32 +0000 (20:37 +0000)
committerRoan Kattouw <roan.kattouw@gmail.com>
Mon, 11 Apr 2016 20:40:28 +0000 (13:40 -0700)
Completely breaks login.

This reverts commit 8e7a0a0912bb98a4a12375b354e23f03262bf213.

Change-Id: Ide7ab5632e987e81374c21173df6ab3998649df7

31 files changed:
autoload.php
docs/hooks.txt
docs/injection.txt
includes/ForkController.php
includes/GlobalFunctions.php
includes/MediaWikiServices.php
includes/ServiceWiring.php
includes/Services/CannotReplaceActiveServiceException.php [deleted file]
includes/Services/ContainerDisabledException.php [deleted file]
includes/Services/DestructibleService.php [deleted file]
includes/Services/NoSuchServiceException.php [deleted file]
includes/Services/ServiceAlreadyDefinedException.php [deleted file]
includes/Services/ServiceContainer.php
includes/Services/ServiceDisabledException.php [deleted file]
includes/Setup.php
includes/config/ConfigFactory.php
includes/context/RequestContext.php
includes/db/loadbalancer/LBFactory.php
includes/db/loadbalancer/LoadBalancer.php
includes/installer/DatabaseInstaller.php
includes/installer/Installer.php
includes/session/SessionManager.php
includes/site/SiteSQLStore.php
includes/user/CentralIdLookup.php
tests/parser/parserTest.inc
tests/phpunit/MediaWikiTestCase.php
tests/phpunit/includes/MediaWikiServicesTest.php
tests/phpunit/includes/MessageTest.php
tests/phpunit/includes/Services/ServiceContainerTest.php
tests/phpunit/includes/config/ConfigFactoryTest.php
tests/phpunit/phpunit.php

index 847e291..c3e988c 100644 (file)
@@ -794,13 +794,7 @@ $wgAutoloadLocalClasses = [
        'MediaWiki\\Logger\\NullSpi' => __DIR__ . '/includes/debug/logger/NullSpi.php',
        'MediaWiki\\Logger\\Spi' => __DIR__ . '/includes/debug/logger/Spi.php',
        'MediaWiki\\MediaWikiServices' => __DIR__ . '/includes/MediaWikiServices.php',
-       'MediaWiki\\Services\\CannotReplaceActiveServiceException' => __DIR__ . '/includes/Services/CannotReplaceActiveServiceException.php',
-       'MediaWiki\\Services\\ContainerDisabledException' => __DIR__ . '/includes/Services/ContainerDisabledException.php',
-       'MediaWiki\\Services\\DestructibleService' => __DIR__ . '/includes/Services/DestructibleService.php',
-       'MediaWiki\\Services\\NoSuchServiceException' => __DIR__ . '/includes/Services/NoSuchServiceException.php',
-       'MediaWiki\\Services\\ServiceAlreadyDefinedException' => __DIR__ . '/includes/Services/ServiceAlreadyDefinedException.php',
        'MediaWiki\\Services\\ServiceContainer' => __DIR__ . '/includes/Services/ServiceContainer.php',
-       'MediaWiki\\Services\\ServiceDisabledException' => __DIR__ . '/includes/Services/ServiceDisabledException.php',
        'MediaWiki\\Session\\BotPasswordSessionProvider' => __DIR__ . '/includes/session/BotPasswordSessionProvider.php',
        'MediaWiki\\Session\\CookieSessionProvider' => __DIR__ . '/includes/session/CookieSessionProvider.php',
        'MediaWiki\\Session\\ImmutableSessionProviderWithCookie' => __DIR__ . '/includes/session/ImmutableSessionProviderWithCookie.php',
index 9c14607..31e9d92 100644 (file)
@@ -1997,18 +1997,9 @@ $user: $wgUser
 $request: $wgRequest
 $mediaWiki: The $mediawiki object
 
-'MediaWikiServices': Called when a global MediaWikiServices instance is
-initialized. Extensions may use this to define, replace, or wrap services.
-However, the preferred way to define a new service is
-the $wgServiceWiringFiles array.
-$services: MediaWikiServices
-
-'MediaWikiServices::resetLegacyServices': Called when MediaWikiServices resets
-global instances of all well known services that are not yet managed by
-MediaWikiServices directly. Extension may use this hook to reset their own
-global service instances. However, it is preferred for extensions to have their
-services managed by MediaWikiServices directly, by registering them
-via $wgServiceWiringFiles or the 'MediaWikiServices' hook.
+'MediaWikiServices': Override services in the default MediaWikiServices instance.
+Extensions may use this to define, replace, or wrap existing services.
+However, the preferred way to define a new service is the $wgServiceWiringFiles array.
 $services: MediaWikiServices
 
 'MessageCache::get': When fetching a message. Can be used to override the key
index 219e49d..e0466c4 100644 (file)
@@ -37,15 +37,6 @@ DI framework. Per default, $wgServiceWiringFiles lists
 includes/ServiceWiring.php, which defines all default service
 implementations, and specifies how they depend on each other ("wiring").
 
-Note that services get their configuration injected, and changes to global
-configuration variables will not have any effect on services that were already
-instantiated. This would typically be the case for low level services like
-the ConfigFactory or the ObjectCacheManager, which are used during extension
-registration. To address this issue, Setup.php resets the global service
-locator instance by calling MediaWikiServices::resetGlobalInstance() once
-configuration and extension registration is complete.
-
-
 When a new service is added to MediaWiki core, an instantiator function
 that will create the appropriate default instance for that service must
 be added to ServiceWiring.php. This makes the service available through
index 655d756..2725753 100644 (file)
@@ -133,8 +133,7 @@ class ForkController {
                                $this->termReceived = false;
                        }
                } while ( count( $this->children ) );
-
-               $this->initProcess();
+               pcntl_signal( SIGTERM, SIG_DFL );
                return 'done';
        }
 
@@ -150,12 +149,14 @@ class ForkController {
 
        protected function prepareEnvironment() {
                global $wgMemc;
-               $wgMemc = null; // TODO: change all code that accesses this directly!
-
-               // NOTE: we want to destroy global service instances before forking,
-               // so no external resources such as database connections get copied
-               // to the child processes.
-               \MediaWiki\MediaWikiServices::disableStorageBackend();
+               // Don't share DB, storage, or memcached connections
+               wfGetLBFactory()->destroyInstance();
+               FileBackendGroup::destroySingleton();
+               LockManagerGroup::destroySingletons();
+               JobQueueGroup::destroySingletons();
+               ObjectCache::clear();
+               RedisConnectionPool::destroySingletons();
+               $wgMemc = null;
        }
 
        /**
@@ -177,7 +178,7 @@ class ForkController {
                        }
 
                        if ( !$pid ) {
-                               $this->initProcess();
+                               $this->initChild();
                                $this->childNumber = $i;
                                return 'child';
                        } else {
@@ -189,10 +190,9 @@ class ForkController {
                return 'parent';
        }
 
-       protected function initProcess() {
-               // Reset services, so we don't re-use connections.
-               \MediaWiki\MediaWikiServices::resetChildProcessServices();
-
+       protected function initChild() {
+               global $wgMemc, $wgMainCacheType;
+               $wgMemc = wfGetCache( $wgMainCacheType );
                $this->children = null;
                pcntl_signal( SIGTERM, SIG_DFL );
        }
index 8c55d9a..5c42bc2 100644 (file)
@@ -3109,9 +3109,6 @@ function wfSplitWikiID( $wiki ) {
  * Note 2: use $this->getDB() in maintenance scripts that may be invoked by
  * updater to ensure that a proper database is being updated.
  *
- * @todo Replace calls to wfGetDB with calls to LoadBalancer::getConnection()
- *       on an injected instance of LoadBalancer.
- *
  * @return DatabaseBase
  */
 function wfGetDB( $db, $groups = [], $wiki = false ) {
@@ -3121,30 +3118,20 @@ function wfGetDB( $db, $groups = [], $wiki = false ) {
 /**
  * Get a load balancer object.
  *
- * @deprecated since 1.27, use MediaWikiServices::getDBLoadBalancer()
- *              or MediaWikiServices::getDBLoadBalancerFactory() instead.
- *
  * @param string|bool $wiki Wiki ID, or false for the current wiki
  * @return LoadBalancer
  */
 function wfGetLB( $wiki = false ) {
-       if ( $wiki === false ) {
-               return \MediaWiki\MediaWikiServices::getInstance()->getDBLoadBalancer();
-       } else {
-               $factory = \MediaWiki\MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
-               return $factory->getMainLB( $wiki );
-       }
+       return wfGetLBFactory()->getMainLB( $wiki );
 }
 
 /**
  * Get the load balancer factory object
  *
- * @deprecated since 1.27, use MediaWikiServices::getDBLoadBalancerFactory() instead.
- *
  * @return LBFactory
  */
 function wfGetLBFactory() {
-       return \MediaWiki\MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+       return LBFactory::singleton();
 }
 
 /**
index f5ae2d5..7b1def9 100644 (file)
@@ -1,39 +1,15 @@
 <?php
 namespace MediaWiki;
 
-use ApiQueryInfo;
-use CentralIdLookup;
-use Config;
 use ConfigFactory;
-use DeferredUpdates;
-use FileBackendGroup;
 use GlobalVarConfig;
+use Config;
 use Hooks;
-use IP;
-use JobQueueAggregator;
-use Language;
 use LBFactory;
-use LinkCache;
 use LoadBalancer;
-use LockManagerGroup;
-use MagicWord;
-use MediaHandler;
 use MediaWiki\Services\ServiceContainer;
-use MediaWiki\Session\SessionManager;
-use MessageCache;
-use MWException;
-use MWNamespace;
-use MWTidy;
-use ObjectCache;
-use RedisConnectionPool;
-use RepoGroup;
-use RequestContext;
-use ResourceLoader;
 use SiteLookup;
 use SiteStore;
-use SpecialPageFactory;
-use Title;
-use User;
 
 /**
  * Service locator for MediaWiki core services.
@@ -73,11 +49,6 @@ use User;
  */
 class MediaWikiServices extends ServiceContainer {
 
-       /**
-        * @var MediaWikiServices|null
-        */
-       private static $instance = null;
-
        /**
         * Returns the global default instance of the top level service locator.
         *
@@ -91,286 +62,27 @@ class MediaWikiServices extends ServiceContainer {
         * @return MediaWikiServices
         */
        public static function getInstance() {
-               if ( self::$instance === null ) {
+               static $instance = null;
+
+               if ( $instance === null ) {
                        // NOTE: constructing GlobalVarConfig here is not particularly pretty,
                        // but some information from the global scope has to be injected here,
                        // even if it's just a file name or database credentials to load
                        // configuration from.
-                       $bootstrapConfig = new GlobalVarConfig();
-                       self::$instance = self::newInstance( $bootstrapConfig );
-               }
+                       $config = new GlobalVarConfig();
+                       $instance = new self( $config );
 
-               return self::$instance;
-       }
+                       // Load the default wiring from the specified files.
+                       $wiringFiles = $config->get( 'ServiceWiringFiles' );
+                       $instance->loadWiringFiles( $wiringFiles );
 
-       /**
-        * Replaces the global MediaWikiServices instance.
-        *
-        * @note This is for use in PHPUnit tests only!
-        *
-        * @throws MWException if called outside of PHPUnit tests.
-        *
-        * @param MediaWikiServices $services The new MediaWikiServices object.
-        *
-        * @return MediaWikiServices The old MediaWikiServices object, so it can be restored later.
-        */
-       public static function forceGlobalInstance( MediaWikiServices $services ) {
-               if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
-                       throw new MWException( __METHOD__ . ' must not be used outside unit tests.' );
-               }
-
-               $old = self::getInstance();
-               self::$instance = $services;
-
-               self::resetLegacyServices();
-
-               return $old;
-       }
-
-       /**
-        * Creates a new instance of MediaWikiServices and sets it as the global default
-        * instance. getInstance() will return a different MediaWikiServices object
-        * after every call to resetGlobalServiceLocator().
-        *
-        * @warning This should not be used during normal operation. It is intended for use
-        * when the configuration has changed significantly since bootstrap time, e.g.
-        * during the installation process or during testing.
-        *
-        * @warning Calling resetGlobalServiceLocator() may leave the application in an inconsistent
-        * state. Calling this is only safe under the ASSUMPTION that NO REFERENCE to
-        * any of the services managed by MediaWikiServices exist. If any service objects
-        * managed by the old MediaWikiServices instance remain in use, they may INTERFERE
-        * with the operation of the services managed by the new MediaWikiServices.
-        * Operating with a mix of services created by the old and the new
-        * MediaWikiServices instance may lead to INCONSISTENCIES and even DATA LOSS!
-        * Any class implementing LAZY LOADING is especially prone to this problem,
-        * since instances would typically retain a reference to a storage layer service.
-        *
-        * @see forceGlobalInstance()
-        * @see resetGlobalInstance()
-        * @see resetBetweenTest()
-        *
-        * @param Config|null $bootstrapConfig The Config object to be registered as the
-        *        'BootstrapConfig' service. This has to contain at least the information
-        *        needed to set up the 'ConfigFactory' service. If not given, the bootstrap
-        *        config of the old instance of MediaWikiServices will be re-used. If there
-        *        was no previous instance, a new GlobalVarConfig object will be used to
-        *        bootstrap the services.
-        *
-        * @throws MWException
-        */
-       public static function resetGlobalInstance( Config $bootstrapConfig = null ) {
-               if ( self::$instance === null ) {
-                       // no global instance yet, nothing to reset
-                       return;
+                       // Provide a traditional hook point to allow extensions to configure services.
+                       Hooks::run( 'MediaWikiServices', [ $instance ] );
                }
 
-               if ( $bootstrapConfig === null ) {
-                       $bootstrapConfig = self::$instance->getBootstrapConfig();
-               }
-
-               self::$instance->destroy();
-
-               self::$instance = self::newInstance( $bootstrapConfig );
-
-               self::resetLegacyServices();
-       }
-
-       /**
-        * Creates a new MediaWikiServices instance and initializes it according to the
-        * given $bootstrapConfig. In particular, all wiring files defined in the
-        * ServiceWiringFiles setting are loaded, and the MediaWikiServices hook is called.
-        *
-        * @param Config|null $bootstrapConfig The Config object to be registered as the
-        *        'BootstrapConfig' service. This has to contain at least the information
-        *        needed to set up the 'ConfigFactory' service. If not provided, any call
-        *        to getBootstrapConfig(), getConfigFactory, or getMainConfig will fail.
-        *        A MediaWikiServices instance without access to configuration is called
-        *        "primordial".
-        *
-        * @return MediaWikiServices
-        * @throws MWException
-        */
-       private static function newInstance( Config $bootstrapConfig ) {
-               $instance = new self( $bootstrapConfig );
-
-               // Load the default wiring from the specified files.
-               $wiringFiles = $bootstrapConfig->get( 'ServiceWiringFiles' );
-               $instance->loadWiringFiles( $wiringFiles );
-
-               // Provide a traditional hook point to allow extensions to configure services.
-               Hooks::run( 'MediaWikiServices', [ $instance ] );
-
                return $instance;
        }
 
-       /**
-        * Resets global instances of services that have not yet been ported to using
-        * MediaWikiServices to manage their default instance.
-        *
-        * @note eventually, all global service instances are to be managed by MediaWikiServices.
-        * To emulate the effect of resetting the global service locator, we reset the individual
-        * static singletons for now.
-        *
-        * @note As long as we don't know the interdependencies between the services, the only way
-        * to reset services consistently is to reset all services at once. This should be ok since
-        * there should rarely be a need to reset all processes.
-        */
-       private static function resetLegacyServices() {
-               global $wgContLang, $wgUser, $wgMemc, $wgRequest;
-
-               $services = self::getInstance();
-               $config = $services->getMainConfig();
-
-               // NOTE: all the services instance that get reset below should be migrated
-               // to be managed by MediaWikiServices. Eventually, this method can then be
-               // removed.
-
-               User::resetIdByNameCache();
-               LinkCache::singleton()->clear();
-               Title::clearCaches();
-
-               MWTidy::destroySingleton();
-               MagicWord::clearCache();
-               SpecialPageFactory::resetList();
-               JobQueueAggregator::destroySingleton();
-               DeferredUpdates::clearPendingUpdates();
-               CentralIdLookup::resetCache();
-               MediaHandler::resetCache();
-               IP::clearCaches();
-               ResourceLoader::clearCache();
-
-               ApiQueryInfo::resetTokenCache();
-
-               RepoGroup::destroySingleton();
-
-               MessageCache::destroyInstance();
-
-               MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
-               Language::$mLangObjCache = [];
-               Language::getLocalisationCache()->unloadAll();
-
-               ObjectCache::clear();
-               RedisConnectionPool::destroySingletons();
-               FileBackendGroup::destroySingleton();
-               LockManagerGroup::destroySingletons();
-
-               RequestContext::resetMain();
-               $wgRequest = RequestContext::getMain()->getRequest(); // BackCompat
-
-               $wgContLang = Language::factory( $config->get( 'LanguageCode' ) );
-               $wgContLang->resetNamespaces(); # reset namespace cache
-
-               $wgMemc = ObjectCache::getLocalClusterInstance();
-               $wgUser = RequestContext::getMain()->getUser();
-
-               SessionManager::resetCache();
-
-               // Provide a hook point for extensions that need to reset global service instances.
-               Hooks::run( 'MediaWikiServices::resetLegacyServices', [ $services ] );
-       }
-
-       /**
-        * Disables all storage layer services. After calling this, any attempt to access the
-        * storage layer will result in an error. Use resetGlobalInstance() to restore normal
-        * operation.
-        *
-        * @warning This is intended for extreme situations only and should never be used
-        * while serving normal web requests. Legitimate use cases for this method include
-        * the installation process. Test fixtures may also use this, if the fixture relies
-        * on globalState.
-        *
-        * @see resetGlobalInstance()
-        * @see resetChildProcessServices()
-        */
-       public static function disableStorageBackend() {
-               // TODO: also disable some Caches, JobQueues, etc
-               $destroy = [ 'DBLoadBalancer', 'DBLoadBalancerFactory' ];
-               $services = self::getInstance();
-
-               foreach ( $destroy as $name ) {
-                       $services->disableService( $name );
-               }
-       }
-
-       /**
-        * Resets any services that may have become stale after a child process
-        * returns from after pcntl_fork(). It's also safe, but generally unnecessary,
-        * to call this method from the parent process.
-        *
-        * @note This is intended for use in the context of process forking only!
-        *
-        * @see resetGlobalInstance()
-        * @see disableStorageBackend()
-        */
-       public static function resetChildProcessServices() {
-               // NOTE: for now, just reset everything. Since we don't know the interdependencies
-               // between services, we can't do this more selectively at this time.
-               self::resetGlobalInstance();
-
-               // Child, reseed because there is no bug in PHP:
-               // http://bugs.php.net/bug.php?id=42465
-               mt_srand( getmypid() );
-       }
-
-       /**
-        * Resets the given service for testing purposes.
-        *
-        * @warning This is generally unsafe! Other services may still retain references
-        * to the stale service instance, leading to failures and inconsistencies. Subclasses
-        * may use this method to reset specific services under specific instances, but
-        * it should not be exposed to application logic.
-        *
-        * @note With proper dependency injection used throughout the codebase, this method
-        * should not be needed. It is provided to allow tests that pollute global service
-        * instances to clean up.
-        *
-        * @param string $name
-        * @param string $destroy Whether the service instance should be destroyed if it exists.
-        *        When set to false, any existing service instance will effectively be detached
-        *        from the container.
-        *
-        * @throws MWException if called outside of PHPUnit tests.
-        */
-       public function resetServiceForTesting( $name, $destroy = true ) {
-               if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
-                       throw new MWException( 'resetServiceForTesting() must not be used outside unit tests.' );
-               }
-
-               $this->resetService( $name, $destroy );
-       }
-
-       /**
-        * Convenience method that throws an exception if called outside the service bootstrapping
-        * phase as indicated by the MW_SERVICE_BOOTSTRAP_COMPLETE constant - that is, after
-        * Setup.php has called resetGlobalInstance(). Additionally, no exception is thrown if
-        * this method is called during unit testing (as indicated by MW_PHPUNIT_TEST) or
-        * during installation (as indicated by MEDIAWIKI_INSTALL).
-        *
-        * This method is intended to be used to safeguard against accidentally resetting
-        * global service instances that are not yet managed by MediaWikiServices. It is
-        * defined here in the MediaWikiServices services class to keep the knowledge about
-        * how the bootstrapping phase is managed central.
-        *
-        * @param string $method the name of the caller method, as given by __METHOD__.
-        *
-        * @throws MWException if called outside bootstrap mode.
-        *
-        * @see resetGlobalInstance()
-        * @see forceGlobalInstance()
-        * @see disableStorageBackend()
-        */
-       public static function failUnlessBootstrapping( $method ) {
-               if ( !defined( 'MW_PHPUNIT_TEST' )
-                       && !defined( 'MEDIAWIKI_INSTALL' )
-                       && defined( 'MW_SERVICE_BOOTSTRAP_COMPLETE' )
-               ) {
-                       throw new MWException( $method . ' may only be called during bootstrapping unit tests!' );
-               }
-
-               ObjectCache::clear();
-       }
-
        /**
         * @param Config $config The Config object to be registered as the 'BootstrapConfig' service.
         *        This has to contain at least the information needed to set up the 'ConfigFactory'
@@ -379,14 +91,12 @@ class MediaWikiServices extends ServiceContainer {
        public function __construct( Config $config ) {
                parent::__construct();
 
-               // Register the given Config object as the bootstrap config service.
+               // register the given Config object as the bootstrap config service.
                $this->defineService( 'BootstrapConfig', function() use ( $config ) {
                        return $config;
                } );
        }
 
-       // CONVENIENCE GETTERS ////////////////////////////////////////////////////
-
        /**
         * Returns the Config object containing the bootstrap configuration.
         * Bootstrap configuration would typically include database credentials
@@ -434,20 +144,6 @@ class MediaWikiServices extends ServiceContainer {
                return $this->getService( 'SiteStore' );
        }
 
-       /**
-        * @return LBFactory
-        */
-       public function getDBLoadBalancerFactory() {
-               return $this->getService( 'DBLoadBalancerFactory' );
-       }
-
-       /**
-        * @return LoadBalancer The main DB load balancer for the local wiki.
-        */
-       public function getDBLoadBalancer() {
-               return $this->getService( 'DBLoadBalancer' );
-       }
-
        ///////////////////////////////////////////////////////////////////////////
        // NOTE: When adding a service getter here, don't forget to add a test
        // case for it in MediaWikiServicesTest::provideGetters() and in
index 5ec1d64..d8709b9 100644 (file)
 use MediaWiki\MediaWikiServices;
 
 return [
-       'DBLoadBalancerFactory' => function( MediaWikiServices $services ) {
-               // NOTE: Defining the LBFactory class via LBFactoryConf is supported for
-               // backwards compatibility. The preferred way would be to register a
-               // callback for DBLoadBalancerFactory that constructs the desired LBFactory
-               // directly.
-               $config = $services->getMainConfig()->get( 'LBFactoryConf' );
-
-               $class = LBFactory::getLBFactoryClass( $config );
-               if ( !isset( $config['readOnlyReason'] ) ) {
-                       // TODO: replace the global wfConfiguredReadOnlyReason() with a service.
-                       $config['readOnlyReason'] = wfConfiguredReadOnlyReason();
-               }
-
-               return new $class( $config );
-       },
-
-       'DBLoadBalancer' => function( MediaWikiServices $services ) {
-               // just return the default LB from the DBLoadBalancerFactory service
-               return $services->getDBLoadBalancerFactory()->getMainLB();
-       },
-
        'SiteStore' => function( MediaWikiServices $services ) {
-               $rawSiteStore = new DBSiteStore( $services->getDBLoadBalancer() );
+               $loadBalancer = wfGetLB(); // TODO: use LB from MediaWikiServices
+               $rawSiteStore = new DBSiteStore( $loadBalancer );
 
                // TODO: replace wfGetCache with a CacheFactory service.
                // TODO: replace wfIsHHVM with a capabilities service.
diff --git a/includes/Services/CannotReplaceActiveServiceException.php b/includes/Services/CannotReplaceActiveServiceException.php
deleted file mode 100644 (file)
index 4993073..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-namespace MediaWiki\Services;
-
-use Exception;
-use RuntimeException;
-
-/**
- * Exception thrown when trying to replace an already active service.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- *
- * @since 1.27
- */
-
-/**
- * Exception thrown when trying to replace an already active service.
- */
-class CannotReplaceActiveServiceException extends RuntimeException {
-
-       /**
-        * @param string $serviceName
-        * @param Exception|null $previous
-        */
-       public function __construct( $serviceName, Exception $previous = null ) {
-               parent::__construct( "Cannot replace an active service: $serviceName", 0, $previous );
-       }
-
-}
diff --git a/includes/Services/ContainerDisabledException.php b/includes/Services/ContainerDisabledException.php
deleted file mode 100644 (file)
index ede076d..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-namespace MediaWiki\Services;
-
-use Exception;
-use RuntimeException;
-
-/**
- * Exception thrown when trying to access a service on a disabled container or factory.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- *
- * @since 1.27
- */
-
-/**
- * Exception thrown when trying to access a service on a disabled container or factory.
- */
-class ContainerDisabledException extends RuntimeException {
-
-       /**
-        * @param Exception|null $previous
-        */
-       public function __construct( Exception $previous = null ) {
-               parent::__construct( 'Container disabled!', 0, $previous );
-       }
-
-}
diff --git a/includes/Services/DestructibleService.php b/includes/Services/DestructibleService.php
deleted file mode 100644 (file)
index 6ce9af2..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-<?php
-namespace MediaWiki\Services;
-
-/**
- * Interface for destructible services.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- *
- * @since 1.27
- */
-
-/**
- * DestructibleService defines a standard interface for shutting down a service instance.
- * The intended use is for a service container to be able to shut down services that should
- * no longer be used, and allow such services to release any system resources.
- *
- * @note There is no expectation that services will be destroyed when the process (or web request)
- * terminates.
- */
-interface DestructibleService {
-
-       /**
-        * Notifies the service object that it should expect to no longer be used, and should release
-        * any system resources it may own. The behavior of all service methods becomes undefined after
-        * destroy() has been called. It is recommended that implementing classes should throw an
-        * exception when service methods are accessed after destroy() has been called.
-        */
-       public function destroy();
-
-}
diff --git a/includes/Services/NoSuchServiceException.php b/includes/Services/NoSuchServiceException.php
deleted file mode 100644 (file)
index 36e50d2..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-namespace MediaWiki\Services;
-
-use Exception;
-use RuntimeException;
-
-/**
- * Exception thrown when the requested service is not known.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- *
- * @since 1.27
- */
-
-/**
- * Exception thrown when the requested service is not known.
- */
-class NoSuchServiceException extends RuntimeException {
-
-       /**
-        * @param string $serviceName
-        * @param Exception|null $previous
-        */
-       public function __construct( $serviceName, Exception $previous = null ) {
-               parent::__construct( "No such service: $serviceName", 0, $previous );
-       }
-
-}
diff --git a/includes/Services/ServiceAlreadyDefinedException.php b/includes/Services/ServiceAlreadyDefinedException.php
deleted file mode 100644 (file)
index c6344d3..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-<?php
-namespace MediaWiki\Services;
-
-use Exception;
-use RuntimeException;
-
-/**
- * Exception thrown when a service was already defined, but the
- * caller expected it to not exist.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- *
- * @since 1.27
- */
-
-/**
- * Exception thrown when a service was already defined, but the
- * caller expected it to not exist.
- */
-class ServiceAlreadyDefinedException extends RuntimeException {
-
-       /**
-        * @param string $serviceName
-        * @param Exception|null $previous
-        */
-       public function __construct( $serviceName, Exception $previous = null ) {
-               parent::__construct( "Service already defined: $serviceName", 0, $previous );
-       }
-
-}
index ba3ab32..e3cda2e 100644 (file)
@@ -43,7 +43,7 @@ use Wikimedia\Assert\Assert;
  * @see docs/injection.txt for an overview of using dependency injection in the
  *      MediaWiki code base.
  */
-class ServiceContainer implements DestructibleService {
+class ServiceContainer {
 
        /**
         * @var object[]
@@ -60,11 +60,6 @@ class ServiceContainer implements DestructibleService {
         */
        private $extraInstantiationParams;
 
-       /**
-        * @var boolean
-        */
-       private $destroyed = false;
-
        /**
         * @param array $extraInstantiationParams Any additional parameters to be passed to the
         * instantiator function when creating a service. This is typically used to provide
@@ -74,25 +69,6 @@ class ServiceContainer implements DestructibleService {
                $this->extraInstantiationParams = $extraInstantiationParams;
        }
 
-       /**
-        * Destroys all contained service instances that implement the DestructibleService
-        * interface. This will render all services obtained from this MediaWikiServices
-        * instance unusable. In particular, this will disable access to the storage backend
-        * via any of these services. Any future call to getService() will throw an exception.
-        *
-        * @see resetGlobalInstance()
-        */
-       public function destroy() {
-               foreach ( $this->getServiceNames() as $name ) {
-                       $service = $this->peekService( $name );
-                       if ( $service !== null && $service instanceof DestructibleService ) {
-                               $service->destroy();
-                       }
-               }
-
-               $this->destroyed = true;
-       }
-
        /**
         * @param array $wiringFiles A list of PHP files to load wiring information from.
         * Each file is loaded using PHP's include mechanism. Each file is expected to
@@ -138,28 +114,6 @@ class ServiceContainer implements DestructibleService {
                return isset( $this->serviceInstantiators[$name] );
        }
 
-       /**
-        * Returns the service instance for $name only if that service has already been instantiated.
-        * This is intended for situations where services get destroyed/cleaned up, so we can
-        * avoid creating a service just to destroy it again.
-        *
-        * @note Application logic should use getService() instead.
-        *
-        * @see getService().
-        *
-        * @param string $name
-        *
-        * @return object|null The service instance, or null if the service has not yet been instantiated.
-        * @throws RuntimeException if $name does not refer to a known service.
-        */
-       public function peekService( $name ) {
-               if ( !$this->hasService( $name ) ) {
-                       throw new NoSuchServiceException( $name );
-               }
-
-               return isset( $this->services[$name] ) ? $this->services[$name] : null;
-       }
-
        /**
         * @return string[]
         */
@@ -185,7 +139,7 @@ class ServiceContainer implements DestructibleService {
                Assert::parameterType( 'string', $name, '$name' );
 
                if ( $this->hasService( $name ) ) {
-                       throw new ServiceAlreadyDefinedException( $name );
+                       throw new RuntimeException( 'Service already defined: ' . $name );
                }
 
                $this->serviceInstantiators[$name] = $instantiator;
@@ -211,78 +165,16 @@ class ServiceContainer implements DestructibleService {
                Assert::parameterType( 'string', $name, '$name' );
 
                if ( !$this->hasService( $name ) ) {
-                       throw new NoSuchServiceException( $name );
+                       throw new RuntimeException( 'Service not defined: ' . $name );
                }
 
                if ( isset( $this->services[$name] ) ) {
-                       throw new CannotReplaceActiveServiceException( $name );
+                       throw new RuntimeException( 'Cannot redefine a service that is already in use: ' . $name );
                }
 
                $this->serviceInstantiators[$name] = $instantiator;
        }
 
-       /**
-        * Disables a service.
-        *
-        * @note Attempts to call getService() for a disabled service will result
-        * in a DisabledServiceException. Calling peekService for a disabled service will
-        * return null. Disabled services are listed by getServiceNames(). A disabled service
-        * can be enabled again using redefineService().
-        *
-        * @note If the service was already active (that is, instantiated) when getting disabled,
-        * and the service instance implements DestructibleService, destroy() is called on the
-        * service instance.
-        *
-        * @see redefineService()
-        * @see resetService()
-        *
-        * @param string $name The name of the service to disable.
-        *
-        * @throws RuntimeException if $name is not a known service.
-        */
-       public function disableService( $name ) {
-               $this->resetService( $name );
-
-               $this->redefineService( $name, function() use ( $name ) {
-                       throw new ServiceDisabledException( $name );
-               } );
-       }
-
-       /**
-        * Resets a service by dropping the service instance.
-        * If the service instances implements DestructibleService, destroy()
-        * is called on the service instance.
-        *
-        * @warning This is generally unsafe! Other services may still retain references
-        * to the stale service instance, leading to failures and inconsistencies. Subclasses
-        * may use this method to reset specific services under specific instances, but
-        * it should not be exposed to application logic.
-        *
-        * @note This is declared final so subclasses can not interfere with the expectations
-        * disableService() has when calling resetService().
-        *
-        * @see redefineService()
-        * @see disableService().
-        *
-        * @param string $name The name of the service to reset.
-        * @param bool $destroy Whether the service instance should be destroyed if it exists.
-        *        When set to false, any existing service instance will effectively be detached
-        *        from the container.
-        *
-        * @throws RuntimeException if $name is not a known service.
-        */
-       final protected function resetService( $name, $destroy = true ) {
-               Assert::parameterType( 'string', $name, '$name' );
-
-               $instance = $this->peekService( $name );
-
-               if ( $destroy && $instance instanceof DestructibleService )  {
-                       $instance->destroy();
-               }
-
-               unset( $this->services[$name] );
-       }
-
        /**
         * Returns a service object of the kind associated with $name.
         * Services instances are instantiated lazily, on demand.
@@ -297,16 +189,10 @@ class ServiceContainer implements DestructibleService {
         *
         * @param string $name The service name
         *
-        * @throws NoSuchServiceException if $name is not a known service.
-        * @throws ServiceDisabledException if this container has already been destroyed.
-        *
+        * @throws InvalidArgumentException if $name is not a known service.
         * @return object The service instance
         */
        public function getService( $name ) {
-               if ( $this->destroyed ) {
-                       throw new ContainerDisabledException();
-               }
-
                if ( !isset( $this->services[$name] ) ) {
                        $this->services[$name] = $this->createService( $name );
                }
@@ -327,7 +213,7 @@ class ServiceContainer implements DestructibleService {
                                array_merge( [ $this ], $this->extraInstantiationParams )
                        );
                } else {
-                       throw new NoSuchServiceException( $name );
+                       throw new InvalidArgumentException( 'Unknown service: ' . $name );
                }
 
                return $service;
diff --git a/includes/Services/ServiceDisabledException.php b/includes/Services/ServiceDisabledException.php
deleted file mode 100644 (file)
index ae15b7c..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-namespace MediaWiki\Services;
-
-use Exception;
-use RuntimeException;
-
-/**
- * Exception thrown when trying to access a disabled service.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- *
- * @since 1.27
- */
-
-/**
- * Exception thrown when trying to access a disabled service.
- */
-class ServiceDisabledException extends RuntimeException {
-
-       /**
-        * @param string $serviceName
-        * @param Exception|null $previous
-        */
-       public function __construct( $serviceName, Exception $previous = null ) {
-               parent::__construct( "Service disabled: $serviceName", 0, $previous );
-       }
-
-}
index c8910f4..d7f1189 100644 (file)
@@ -23,7 +23,6 @@
  *
  * @file
  */
-use MediaWiki\MediaWikiServices;
 
 /**
  * This file is not a valid entry point, perform no further processing unless
@@ -523,14 +522,6 @@ if ( !class_exists( 'AutoLoader' ) ) {
        require_once "$IP/includes/AutoLoader.php";
 }
 
-// Reset the global service locator, so any services that have already been created will be
-// re-created while taking into account any custom settings and extensions.
-MediaWikiServices::resetGlobalInstance( new GlobalVarConfig() );
-
-// Define a constant that indicates that the bootstrapping of the service locator
-// is complete.
-define( 'MW_SERVICE_BOOTSTRAP_COMPLETE', 1 );
-
 // Install a header callback to prevent caching of responses with cookies (T127993)
 if ( !$wgCommandLineMode ) {
        header_register_callback( function () {
@@ -688,7 +679,7 @@ if ( $wgCommandLineMode ) {
 Profiler::instance()->scopedProfileOut( $ps_misc );
 $ps_memcached = Profiler::instance()->scopedProfileIn( $fname . '-memcached' );
 
-$wgMemc = ObjectCache::getLocalClusterInstance();
+$wgMemc = wfGetMainCache();
 $messageMemc = wfGetMessageCacheStorage();
 $parserMemc = wfGetParserCacheStorage();
 
index 09b0baa..4b803d8 100644 (file)
@@ -51,39 +51,16 @@ class ConfigFactory {
        }
 
        /**
-        * @return string[]
-        */
-       public function getConfigNames() {
-               return array_keys( $this->factoryFunctions );
-       }
-
-       /**
-        * Register a new config factory function.
-        * Will override if it's already registered.
-        * Use "*" for $name to provide a fallback config for all unknown names.
+        * Register a new config factory function
+        * Will override if it's already registered
         * @param string $name
-        * @param callable|Config $callback A factory callabck that takes this ConfigFactory
-        *        as an argument and returns a Config instance, or an existing Config instance.
+        * @param callable $callback That takes this ConfigFactory as an argument
         * @throws InvalidArgumentException If an invalid callback is provided
         */
        public function register( $name, $callback ) {
-               if ( $callback instanceof Config ) {
-                       $instance = $callback;
-
-                       // Register a callback anyway, for consistency. Note that getConfigNames()
-                       // relies on $factoryFunctions to have all config names.
-                       $callback = function() use ( $instance ) {
-                               return $instance;
-                       };
-               } else {
-                       $instance = null;
-               }
-
                if ( !is_callable( $callback ) ) {
                        throw new InvalidArgumentException( 'Invalid callback provided' );
                }
-
-               $this->configs[$name] = $instance;
                $this->factoryFunctions[$name] = $callback;
        }
 
@@ -98,14 +75,10 @@ class ConfigFactory {
         */
        public function makeConfig( $name ) {
                if ( !isset( $this->configs[$name] ) ) {
-                       $key = $name;
-                       if ( !isset( $this->factoryFunctions[$key] ) ) {
-                               $key = '*';
-                       }
-                       if ( !isset( $this->factoryFunctions[$key] ) ) {
+                       if ( !isset( $this->factoryFunctions[$name] ) ) {
                                throw new ConfigException( "No registered builder available for $name." );
                        }
-                       $conf = call_user_func( $this->factoryFunctions[$key], $this );
+                       $conf = call_user_func( $this->factoryFunctions[$name], $this );
                        if ( $conf instanceof Config ) {
                                $this->configs[$name] = $conf;
                        } else {
@@ -115,5 +88,4 @@ class ConfigFactory {
 
                return $this->configs[$name];
        }
-
 }
index ba54603..c8b8108 100644 (file)
@@ -23,7 +23,6 @@
  */
 
 use MediaWiki\Logger\LoggerFactory;
-use MediaWiki\MediaWikiServices;
 
 /**
  * Group all the pieces relevant to the context of a request into one instance
@@ -497,8 +496,9 @@ class RequestContext implements IContextSource, MutableContext {
         * Resets singleton returned by getMain(). Should be called only from unit tests.
         */
        public static function resetMain() {
-               // TODO: manage service instances in MediaWikiServices
-               MediaWikiServices::failUnlessBootstrapping( __METHOD__ );
+               if ( !( defined( 'MW_PHPUNIT_TEST' ) || defined( 'MW_PARSER_TEST' ) ) ) {
+                       throw new MWException( __METHOD__ . '() should be called only from unit tests!' );
+               }
                self::$instance = null;
        }
 
index 549a8b5..a484bb4 100644 (file)
@@ -21,8 +21,6 @@
  * @ingroup Database
  */
 
-use MediaWiki\MediaWikiServices;
-use MediaWiki\Services\DestructibleService;
 use Psr\Log\LoggerInterface;
 use MediaWiki\Logger\LoggerFactory;
 
@@ -30,8 +28,7 @@ use MediaWiki\Logger\LoggerFactory;
  * An interface for generating database load balancers
  * @ingroup Database
  */
-abstract class LBFactory implements DestructibleService {
-
+abstract class LBFactory {
        /** @var ChronologyProtector */
        protected $chronProt;
 
@@ -41,6 +38,9 @@ abstract class LBFactory implements DestructibleService {
        /** @var LoggerInterface */
        protected $logger;
 
+       /** @var LBFactory */
+       private static $instance;
+
        /** @var string|bool Reason all LBs are read-only or false if not */
        protected $readOnlyReason = false;
 
@@ -60,40 +60,38 @@ abstract class LBFactory implements DestructibleService {
                $this->logger = LoggerFactory::getInstance( 'DBTransaction' );
        }
 
-       /**
-        * Disables all load balancers. All connections are closed, and any attempt to
-        * open a new connection will result in a DBAccessError.
-        * @see LoadBalancer::disable()
-        */
-       public function destroy() {
-               $this->shutdown();
-               $this->forEachLBCallMethod( 'disable' );
-       }
-
        /**
         * Disables all access to the load balancer, will cause all database access
         * to throw a DBAccessError
         */
        public static function disableBackend() {
-               MediaWikiServices::disableStorageBackend();
+               global $wgLBFactoryConf;
+               self::$instance = new LBFactoryFake( $wgLBFactoryConf );
        }
 
        /**
         * Get an LBFactory instance
         *
-        * @deprecated since 1.27, use MediaWikiServices::getDBLoadBalancerFactory() instead.
-        *
         * @return LBFactory
         */
        public static function singleton() {
-               return MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+               global $wgLBFactoryConf;
+
+               if ( is_null( self::$instance ) ) {
+                       $class = self::getLBFactoryClass( $wgLBFactoryConf );
+                       $config = $wgLBFactoryConf;
+                       if ( !isset( $config['readOnlyReason'] ) ) {
+                               $config['readOnlyReason'] = wfConfiguredReadOnlyReason();
+                       }
+                       self::$instance = new $class( $config );
+               }
+
+               return self::$instance;
        }
 
        /**
         * Returns the LBFactory class to use and the load balancer configuration.
         *
-        * @todo instead of this, use a ServiceContainer for managing the different implementations.
-        *
         * @param array $config (e.g. $wgLBFactoryConf)
         * @return string Class name
         */
@@ -120,6 +118,27 @@ abstract class LBFactory implements DestructibleService {
                return $class;
        }
 
+       /**
+        * Shut down, close connections and destroy the cached instance.
+        */
+       public static function destroyInstance() {
+               if ( self::$instance ) {
+                       self::$instance->shutdown();
+                       self::$instance->forEachLBCallMethod( 'closeAll' );
+                       self::$instance = null;
+               }
+       }
+
+       /**
+        * Set the instance to be the given object
+        *
+        * @param LBFactory $instance
+        */
+       public static function setInstance( $instance ) {
+               self::destroyInstance();
+               self::$instance = $instance;
+       }
+
        /**
         * Create a new load balancer object. The resulting object will be untracked,
         * not chronology-protected, and the caller is responsible for cleaning it up.
@@ -454,7 +473,8 @@ abstract class LBFactory implements DestructibleService {
  */
 class DBAccessError extends MWException {
        public function __construct() {
-               parent::__construct( 'The storage backend is disabled!' );
+               parent::__construct( "Mediawiki tried to access the database via wfGetDB(). " .
+                       "This is not allowed." );
        }
 }
 
index 5578099..741999c 100644 (file)
@@ -77,11 +77,6 @@ class LoadBalancer {
        /** @var integer Max time to wait for a slave to catch up (e.g. ChronologyProtector) */
        const POS_WAIT_TIMEOUT = 10;
 
-       /**
-        * @var boolean
-        */
-       private $disabled = false;
-
        /**
         * @param array $params Array with keys:
         *  - servers : Required. Array of server info structures.
@@ -671,8 +666,6 @@ class LoadBalancer {
         * On error, returns false, and the connection which caused the
         * error will be available via $this->mErrorConnection.
         *
-        * @note If disable() was called on this LoadBalancer, this method will throw a DBAccessError.
-        *
         * @param int $i Server index
         * @param string|bool $wiki Wiki ID, or false for the current wiki
         * @return DatabaseBase|bool Returns false on errors
@@ -723,8 +716,6 @@ class LoadBalancer {
         * On error, returns false, and the connection which caused the
         * error will be available via $this->mErrorConnection.
         *
-        * @note If disable() was called on this LoadBalancer, this method will throw a DBAccessError.
-        *
         * @param int $i Server index
         * @param string $wiki Wiki ID to open
         * @return DatabaseBase
@@ -812,10 +803,6 @@ class LoadBalancer {
         * @return DatabaseBase
         */
        protected function reallyOpenConnection( $server, $dbNameOverride = false ) {
-               if ( $this->disabled ) {
-                       throw new DBAccessError();
-               }
-
                if ( !is_array( $server ) ) {
                        throw new MWException( 'You must update your load-balancing configuration. ' .
                                'See DefaultSettings.php entry for $wgDBservers.' );
@@ -989,17 +976,6 @@ class LoadBalancer {
                return false;
        }
 
-       /**
-        * Disable this load balancer. All connections are closed, and any attempt to
-        * open a new connection will result in a DBAccessError.
-        *
-        * @since 1.27
-        */
-       public function disable() {
-               $this->closeAll();
-               $this->disabled = true;
-       }
-
        /**
         * Close all open connections
         */
index 701403e..79bd961 100644 (file)
@@ -287,16 +287,8 @@ abstract class DatabaseInstaller {
                if ( !$status->isOK() ) {
                        throw new MWException( __METHOD__ . ': unexpected DB connection error' );
                }
-
-               \MediaWiki\MediaWikiServices::resetGlobalInstance();
-               $services = \MediaWiki\MediaWikiServices::getInstance();
-
-               $connection = $status->value;
-               $services->redefineService( 'DBLoadBalancerFactory', function() use ( $connection ) {
-                       return new LBFactorySingle( [
-                               'connection' => $connection ] );
-               } );
-
+               LBFactory::setInstance( new LBFactorySingle( [
+                       'connection' => $status->value ] ) );
        }
 
        /**
index 97214da..3d1c860 100644 (file)
@@ -351,67 +351,37 @@ abstract class Installer {
         */
        abstract public function showStatusMessage( Status $status );
 
-       /**
-        * Constructs a Config object that contains configuration settings that should be
-        * overwritten for the installation process.
-        *
-        * @since 1.27
-        *
-        * @param Config $baseConfig
-        *
-        * @return Config The config to use during installation.
-        */
-       public static function getInstallerConfig( Config $baseConfig ) {
-               $configOverrides = new HashConfig();
-
-               // disable (problematic) object cache types explicitly, preserving all other (working) ones
-               // bug T113843
-               $emptyCache = [ 'class' => 'EmptyBagOStuff' ];
-
-               $objectCaches = [
-                               CACHE_NONE => $emptyCache,
-                               CACHE_DB => $emptyCache,
-                               CACHE_ANYTHING => $emptyCache,
-                               CACHE_MEMCACHED => $emptyCache,
-                       ] + $baseConfig->get( 'ObjectCaches' );
-
-               $configOverrides->set( 'ObjectCaches', $objectCaches );
-
-               // Load the installer's i18n.
-               $messageDirs = $baseConfig->get( 'MessagesDirs' );
-               $messageDirs['MediawikiInstaller'] = __DIR__ . '/i18n';
-
-               $configOverrides->set( 'MessagesDirs', $messageDirs );
-
-               return new MultiConfig( [ $configOverrides, $baseConfig ] );
-       }
-
        /**
         * Constructor, always call this from child classes.
         */
        public function __construct() {
-               global $wgMemc, $wgUser;
-
-               $defaultConfig = new GlobalVarConfig(); // all the stuff from DefaultSettings.php
-               $installerConfig = self::getInstallerConfig( $defaultConfig );
-
-               // Reset all services and inject config overrides
-               MediaWiki\MediaWikiServices::resetGlobalInstance( $installerConfig );
+               global $wgMessagesDirs, $wgUser;
 
                // Don't attempt to load user language options (T126177)
                // This will be overridden in the web installer with the user-specified language
                RequestContext::getMain()->setLanguage( 'en' );
 
                // Disable the i18n cache
-               // TODO: manage LocalisationCache singleton in MediaWikiServices
                Language::getLocalisationCache()->disableBackend();
-
-               // Disable all global services, since we don't have any configuration yet!
-               MediaWiki\MediaWikiServices::disableStorageBackend();
+               // Disable LoadBalancer and wfGetDB etc.
+               LBFactory::disableBackend();
 
                // Disable object cache (otherwise CACHE_ANYTHING will try CACHE_DB and
                // SqlBagOStuff will then throw since we just disabled wfGetDB)
-               $wgMemc = ObjectCache::getInstance( CACHE_NONE );
+               $GLOBALS['wgMemc'] = new EmptyBagOStuff;
+               ObjectCache::clear();
+               $emptyCache = [ 'class' => 'EmptyBagOStuff' ];
+               // disable (problematic) object cache types explicitly, preserving all other (working) ones
+               // bug T113843
+               $GLOBALS['wgObjectCaches'] = [
+                       CACHE_NONE => $emptyCache,
+                       CACHE_DB => $emptyCache,
+                       CACHE_ANYTHING => $emptyCache,
+                       CACHE_MEMCACHED => $emptyCache,
+               ] + $GLOBALS['wgObjectCaches'];
+
+               // Load the installer's i18n.
+               $wgMessagesDirs['MediawikiInstaller'] = __DIR__ . '/i18n';
 
                // Having a user with id = 0 safeguards us from DB access via User::loadOptions().
                $wgUser = User::newFromId( 0 );
index 2820712..c65fa21 100644 (file)
@@ -23,7 +23,7 @@
 
 namespace MediaWiki\Session;
 
-use MediaWiki\MediaWikiServices;
+use MWException;
 use Psr\Log\LoggerInterface;
 use BagOStuff;
 use CachedBagOStuff;
@@ -1091,7 +1091,11 @@ final class SessionManager implements SessionManagerInterface {
         * Reset the internal caching for unit testing
         */
        public static function resetCache() {
-               MediaWikiServices::failUnlessBootstrapping( __METHOD__ );
+               if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
+                       // @codeCoverageIgnoreStart
+                       throw new MWException( __METHOD__ . ' may only be called from unit tests!' );
+                       // @codeCoverageIgnoreEnd
+               }
 
                self::$globalSession = null;
                self::$globalSessionRequest = null;
index bb64510..a4116ae 100644 (file)
@@ -23,8 +23,6 @@
  * @file
  * @ingroup Site
  *
- * @deprecated 1.27 use DBSiteStore and CachingSiteStore instead.
- *
  * @license GNU GPL v2+
  * @author Daniel Kinzler
  */
index 616ae93..f67a8d8 100644 (file)
@@ -19,7 +19,6 @@
  *
  * @file
  */
-use MediaWiki\MediaWikiServices;
 
 /**
  * The CentralIdLookup service allows for connecting local users with
@@ -69,8 +68,9 @@ abstract class CentralIdLookup implements IDBAccessObject {
         * Reset internal cache for unit testing
         */
        public static function resetCache() {
-               // TODO: manage service instances in MediaWikiServices
-               MediaWikiServices::failUnlessBootstrapping( __METHOD__ );
+               if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
+                       throw new MWException( __METHOD__ . ' may only be called from unit tests!' );
+               }
                self::$instances = [];
        }
 
index 0987c0f..56108c9 100644 (file)
@@ -27,7 +27,6 @@
  * @file
  * @ingroup Testing
  */
-use MediaWiki\MediaWikiServices;
 
 /**
  * @ingroup Testing
@@ -245,9 +244,6 @@ class ParserTest {
                // "extra language links"
                // see https://gerrit.wikimedia.org/r/111390
                array_push( $wgExtraInterlanguageLinkPrefixes, 'mul' );
-
-               // Reset all services to be consistent with the new settings!
-               MediaWikiServices::resetGlobalInstance();
        }
 
        /**
@@ -1009,6 +1005,11 @@ class ParserTest {
 
                $this->databaseSetupDone = true;
 
+               # SqlBagOStuff broke when using temporary tables on r40209 (bug 15892).
+               # It seems to have been fixed since (r55079?), but regressed at some point before r85701.
+               # This works around it for now...
+               ObjectCache::$instances[CACHE_DB] = new HashBagOStuff;
+
                # CREATE TEMPORARY TABLE breaks if there is more than one server
                if ( wfGetLB()->getServerCount() != 1 ) {
                        $this->useTemporaryTables = false;
@@ -1035,22 +1036,11 @@ class ParserTest {
                $this->db->insert( 'site_stats',
                        [ 'ss_row_id' => 1, 'ss_images' => 2, 'ss_good_articles' => 1 ] );
 
-               $bootstrapConfig = MediaWikiServices::getInstance()->getBootstrapConfig();
-               $configOverrides = new HashConfig();
+               # Reinitialise the LocalisationCache to match the database state
+               Language::getLocalisationCache()->unloadAll();
 
-               # SqlBagOStuff broke when using temporary tables on r40209 (bug 15892).
-               # It seems to have been fixed since (r55079?), but regressed at some point before r85701.
-               # This works around it for now...
-               $objectCaches = [
-                               CACHE_DB => [ 'class' => 'HashBagOStuff' ],
-                       ] + $bootstrapConfig->get( 'ObjectCaches' );
-
-               $configOverrides->set( 'ObjectCaches', $objectCaches );
-
-               // Reset all services to be consistent with the new settings!
-               MediaWikiServices::resetGlobalInstance(
-                       new MultiConfig( [ $configOverrides, $bootstrapConfig ] )
-               );
+               # Clear the message cache
+               MessageCache::singleton()->clear();
 
                // Remember to update newParserTests.php after changing the below
                // (and it uses a slightly different syntax just for teh lulz)
@@ -1251,7 +1241,11 @@ class ParserTest {
         * after each test runs.
         */
        private function teardownGlobals() {
-               MediaWikiServices::resetGlobalInstance();
+               RepoGroup::destroySingleton();
+               FileBackendGroup::destroySingleton();
+               LockManagerGroup::destroySingletons();
+               LinkCache::singleton()->clear();
+               MWTidy::destroySingleton();
 
                foreach ( $this->savedGlobals as $var => $val ) {
                        $GLOBALS[$var] = $val;
index 08785ea..a99b4b9 100644 (file)
@@ -2,23 +2,12 @@
 use MediaWiki\Logger\LegacySpi;
 use MediaWiki\Logger\LoggerFactory;
 use MediaWiki\Logger\MonologSpi;
-use MediaWiki\MediaWikiServices;
 use Psr\Log\LoggerInterface;
 
 /**
  * @since 1.18
  */
 abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
-
-       /**
-        * The service locator created by prepareServices(). This service locator will
-        * be restored after each test. Tests that pollute the global service locator
-        * instance should use overrideMwServices() to isolate the test.
-        *
-        * @var MediaWikiServices|null
-        */
-       private static $serviceLocator = null;
-
        /**
         * $called tracks whether the setUp and tearDown method has been called.
         * class extending MediaWikiTestCase usually override setUp and tearDown
@@ -119,204 +108,18 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
                }
        }
 
-       public static function setUpBeforeClass() {
-               parent::setUpBeforeClass();
-
-               // NOTE: Usually, PHPUnitMaintClass::finalSetup already called this,
-               // but let's make doubly sure.
-               self::prepareServices( new GlobalVarConfig() );
-       }
-
-       /**
-        * Prepare service configuration for unit testing.
-        *
-        * This calls MediaWikiServices::resetGlobalInstance() to allow some critical services
-        * to be overridden for testing.
-        *
-        * prepareServices() only needs to be called once, but should be called as early as possible,
-        * before any class has a chance to grab a reference to any of the global services
-        * instances that get discarded by prepareServices(). Only the first call has any effect,
-        * later calls are ignored.
-        *
-        * @note This is called by PHPUnitMaintClass::finalSetup.
-        *
-        * @see MediaWikiServices::resetGlobalInstance()
-        *
-        * @param Config $bootstrapConfig The bootstrap config to use with the new
-        *        MediaWikiServices. Only used for the first call to this method.
-        */
-       public static function prepareServices( Config $bootstrapConfig ) {
-               static $servicesPrepared = false;
-
-               if ( $servicesPrepared ) {
-                       return;
-               } else {
-                       $servicesPrepared = true;
-               }
-
-               self::resetGlobalServices( $bootstrapConfig );
-       }
-
-       /**
-        * Reset global services, and install testing environment.
-        * This is the testing equivalent of MediaWikiServices::resetGlobalInstance().
-        * This should only be used to set up the testing environment, not when
-        * runnnig unit tests. Use overrideMwServices() for that.
-        *
-        * @see MediaWikiServices::resetGlobalInstance()
-        * @see prepareServices()
-        * @see overrideMwServices()
-        *
-        * @param Config|null $bootstrapConfig The bootstrap config to use with the new
-        *        MediaWikiServices.
-        */
-       protected static function resetGlobalServices( Config $bootstrapConfig = null ) {
-               $oldServices = MediaWikiServices::getInstance();
-               $oldConfigFactory = $oldServices->getConfigFactory();
-
-               $testConfig = self::makeTestConfig( $bootstrapConfig );
-
-               MediaWikiServices::resetGlobalInstance( $testConfig );
-
-               self::$serviceLocator = MediaWikiServices::getInstance();
-               self::installTestServices(
-                       $oldConfigFactory,
-                       self::$serviceLocator
-               );
-       }
-
-       /**
-        * Create a config suitable for testing, based on a base config, default overrides,
-        * and custom overrdies.
-        *
-        * @param Config|null $baseConfig
-        * @param Config|null $customOverrides
-        *
-        * @return Config
-        */
-       private static function makeTestConfig(
-               Config $baseConfig = null,
-               Config $customOverrides = null
-       ) {
-               $defaultOverrides = new HashConfig();
-
-               if ( !$baseConfig ) {
-                       $baseConfig = MediaWikiServices::getInstance()->getBootstrapConfig();
-               }
-
+       public function run( PHPUnit_Framework_TestResult $result = null ) {
                /* Some functions require some kind of caching, and will end up using the db,
                 * which we can't allow, as that would open a new connection for mysql.
                 * Replace with a HashBag. They would not be going to persist anyway.
                 */
-               $hashCache = [ 'class' => 'HashBagOStuff' ];
-               $objectCaches = [
-                               CACHE_DB => $hashCache,
-                               CACHE_ACCEL => $hashCache,
-                               CACHE_MEMCACHED => $hashCache,
-                               'apc' => $hashCache,
-                               'xcache' => $hashCache,
-                               'wincache' => $hashCache,
-                       ] + $baseConfig->get( 'ObjectCaches' );
-
-               $defaultOverrides->set( 'ObjectCaches', $objectCaches );
-               $defaultOverrides->set( 'MainCacheType', CACHE_NONE );
-
-               $testConfig = $customOverrides
-                       ? new MultiConfig( [ $customOverrides, $defaultOverrides, $baseConfig ] )
-                       : new MultiConfig( [ $defaultOverrides, $baseConfig ] );
-
-               return $testConfig;
-       }
+               ObjectCache::$instances[CACHE_DB] = new HashBagOStuff;
 
-       /**
-        * @param ConfigFactory $oldConfigFactory
-        * @param MediaWikiServices $newServices
-        *
-        * @throws MWException
-        */
-       private static function installTestServices(
-               ConfigFactory $oldConfigFactory,
-               MediaWikiServices $newServices
-       ) {
-               // Use bootstrap config for all configuration.
-               // This allows config overrides via global variables to take effect.
-               $bootstrapConfig = $newServices->getBootstrapConfig();
-               $newServices->resetServiceForTesting( 'ConfigFactory' );
-               $newServices->redefineService(
-                       'ConfigFactory',
-                       self::makeTestConfigFactoryInstantiator(
-                               $oldConfigFactory,
-                               [ 'main' =>  $bootstrapConfig ]
-                       )
-               );
-       }
-
-       /**
-        * @param ConfigFactory $oldFactory
-        * @param Config[] $config
-        *
-        * @return Closure
-        */
-       private static function makeTestConfigFactoryInstantiator(
-               ConfigFactory $oldFactory,
-               array $configurations
-       ) {
-               return function( MediaWikiServices $services ) use ( $oldFactory, $configurations ) {
-                       $factory = new ConfigFactory();
-
-                       // clone configurations from $oldFactory that are not overwritten by $configurations
-                       $namesToClone = array_diff(
-                               $oldFactory->getConfigNames(),
-                               array_keys( $configurations )
-                       );
-
-                       foreach ( $namesToClone as $name ) {
-                               $factory->register( $name, $oldFactory->makeConfig( $name ) );
-                       }
-
-                       foreach ( $configurations as $name => $config ) {
-                               $factory->register( $name, $config );
-                       }
-
-                       return $factory;
-               };
-       }
-
-       /**
-        * Resets some well known services that typically have state that may interfere with unit tests.
-        * This is a lightweight alternative to resetGlobalServices().
-        *
-        * @note There is no guarantee that no references remain to stale service instances destroyed
-        * by a call to doLightweightServiceReset().
-        *
-        * @throws MWException if called outside of PHPUnit tests.
-        *
-        * @see resetGlobalServices()
-        */
-       private function doLightweightServiceReset() {
-               global $wgRequest;
-
-               $services = MediaWikiServices::getInstance();
-
-               JobQueueGroup::destroySingletons();
-               ObjectCache::clear();
-               FileBackendGroup::destroySingleton();
-
-               // TODO: move global state into MediaWikiServices
-               RequestContext::resetMain();
-               MediaHandler::resetCache();
-               if ( session_id() !== '' ) {
-                       session_write_close();
-                       session_id( '' );
-               }
-
-               $wgRequest = new FauxRequest();
-               MediaWiki\Session\SessionManager::resetCache();
-       }
-
-       public function run( PHPUnit_Framework_TestResult $result = null ) {
-               // Reset all caches between tests.
-               $this->doLightweightServiceReset();
+               // Sandbox APC by replacing with in-process hash instead.
+               // Ensures values are removed between tests.
+               ObjectCache::$instances['apc'] =
+               ObjectCache::$instances['xcache'] =
+               ObjectCache::$instances['wincache'] = new HashBagOStuff;
 
                $needsResetDB = false;
 
@@ -486,12 +289,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
                }
                $this->mwGlobals = [];
                $this->restoreLoggers();
-
-               if ( self::$serviceLocator && MediaWikiServices::getInstance() !== self::$serviceLocator ) {
-                       MediaWikiServices::forceGlobalInstance( self::$serviceLocator );
-               }
-
-               // TODO: move global state into MediaWikiServices
                RequestContext::resetMain();
                MediaHandler::resetCache();
                if ( session_id() !== '' ) {
@@ -527,28 +324,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
                );
        }
 
-       /**
-        * Sets a service, maintaining a stashed version of the previous service to be
-        * restored in tearDown
-        *
-        * @param string $name
-        * @param object $object
-        */
-       protected function setService( $name, $object ) {
-               // If we did not yet override the service locator, so so now.
-               if ( MediaWikiServices::getInstance() === self::$serviceLocator ) {
-                       $this->overrideMwServices();
-               }
-
-               MediaWikiServices::getInstance()->disableService( $name );
-               MediaWikiServices::getInstance()->redefineService(
-                       $name,
-                       function () use ( $object ) {
-                               return $object;
-                       }
-               );
-       }
-
        /**
         * Sets a global, maintaining a stashed version of the previous global to be
         * restored in tearDown
@@ -579,9 +354,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
         * @param mixed $value Value to set the global to (ignored
         *  if an array is given as first argument).
         *
-        * @note To allow changes to global variables to take effect on global service instances,
-        *       call overrideMwServices().
-        *
         * @since 1.21
         */
        protected function setMwGlobals( $pairs, $value = null ) {
@@ -609,10 +381,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
         * @param array|string $globalKeys Key to the global variable, or an array of keys.
         *
         * @throws Exception When trying to stash an unset global
-        *
-        * @note To allow changes to global variables to take effect on global service instances,
-        *       call overrideMwServices().
-        *
         * @since 1.23
         */
        protected function stashMwGlobals( $globalKeys ) {
@@ -653,9 +421,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
         *
         * @throws MWException If the designated global is not an array.
         *
-        * @note To allow changes to global variables to take effect on global service instances,
-        *       call overrideMwServices().
-        *
         * @since 1.21
         */
        protected function mergeMwGlobalArrayValue( $name, $values ) {
@@ -676,52 +441,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
                $this->setMwGlobals( $name, $merged );
        }
 
-       /**
-        * Stashes the global instance of MediaWikiServices, and installs a new one,
-        * allowing test cases to override settings and services.
-        * The previous instance of MediaWikiServices will be restored on tearDown.
-        *
-        * @since 1.27
-        *
-        * @param Config $configOverrides Configuration overrides for the new MediaWikiServices instance.
-        * @param callable[] $services An associative array of services to re-define. Keys are service
-        *        names, values are callables.
-        *
-        * @return MediaWikiServices
-        * @throws MWException
-        */
-       protected function overrideMwServices( Config $configOverrides = null, array $services = [] ) {
-               if ( !$configOverrides ) {
-                       $configOverrides = new HashConfig();
-               }
-
-               $oldInstance = MediaWikiServices::getInstance();
-               $oldConfigFactory = $oldInstance->getConfigFactory();
-
-               $testConfig = self::makeTestConfig( null, $configOverrides );
-               $newInstance = new MediaWikiServices( $testConfig );
-
-               // Load the default wiring from the specified files.
-               // NOTE: this logic mirrors the logic in MediaWikiServices::newInstance.
-               $wiringFiles = $testConfig->get( 'ServiceWiringFiles' );
-               $newInstance->loadWiringFiles( $wiringFiles );
-
-               // Provide a traditional hook point to allow extensions to configure services.
-               Hooks::run( 'MediaWikiServices', [ $newInstance ] );
-
-               foreach ( $services as $name => $callback ) {
-                       $newInstance->redefineService( $name, $callback );
-               }
-
-               self::installTestServices(
-                       $oldConfigFactory,
-                       $newInstance
-               );
-               MediaWikiServices::forceGlobalInstance( $newInstance );
-
-               return $newInstance;
-       }
-
        /**
         * @since 1.27
         * @param string|Language $lang
@@ -756,9 +475,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
         * @param LoggerInterface $logger
         */
        protected function setLogger( $channel, LoggerInterface $logger ) {
-               // TODO: Once loggers are managed by MediaWikiServices, use
-               //       overrideMwServices() to set loggers.
-
                $provider = LoggerFactory::getProvider();
                $wrappedProvider = TestingAccessWrapper::newFromObject( $provider );
                $singletons = $wrappedProvider->singletons;
@@ -850,10 +566,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
                $user = User::newFromName( 'UTSysop' );
                $comment = __METHOD__ . ': Sample page for unit test.';
 
-               // Avoid memory leak...?
-               // LinkCache::singleton()->clear();
-               // Maybe.  But doing this absolutely breaks $title->isRedirect() when called during unit tests....
-
                $page = WikiPage::factory( $title );
                $page->doEditContent( ContentHandler::makeContent( $text, $title ), $comment, 0, false, $user );
 
@@ -1053,9 +765,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
                        return;
                }
 
-               // TODO: the below should be re-written as soon as LBFactory, LoadBalancer,
-               // and DatabaseBase no longer use global state.
-
                self::$dbSetup = true;
 
                if ( !self::setupDatabaseWithTestPrefix( $db, $prefix ) ) {
index 53cd0b1..127f869 100644 (file)
@@ -1,6 +1,5 @@
 <?php
 use MediaWiki\MediaWikiServices;
-use MediaWiki\Services\ServiceDisabledException;
 
 /**
  * @covers MediaWiki\MediaWikiServices
@@ -9,203 +8,22 @@ use MediaWiki\Services\ServiceDisabledException;
  */
 class MediaWikiServicesTest extends PHPUnit_Framework_TestCase {
 
-       /**
-        * @return Config
-        */
-       private function newTestConfig() {
-               $globalConfig = new GlobalVarConfig();
-
-               $testConfig = new HashConfig();
-               $testConfig->set( 'ServiceWiringFiles', $globalConfig->get( 'ServiceWiringFiles' ) );
-               $testConfig->set( 'ConfigRegistry', $globalConfig->get( 'ConfigRegistry' ) );
-
-               return $testConfig;
-       }
-
-       /**
-        * @return MediaWikiServices
-        */
-       private function newMediaWikiServices( Config $config = null ) {
-               if ( $config === null ) {
-                       $config = $this->newTestConfig();
-               }
-
-               $instance = new MediaWikiServices( $config );
-
-               // Load the default wiring from the specified files.
-               $wiringFiles = $config->get( 'ServiceWiringFiles' );
-               $instance->loadWiringFiles( $wiringFiles );
-
-               return $instance;
-       }
-
        public function testGetInstance() {
                $services = MediaWikiServices::getInstance();
                $this->assertInstanceOf( 'MediaWiki\\MediaWikiServices', $services );
        }
 
-       public function testForceGlobalInstance() {
-               $newServices = $this->newMediaWikiServices();
-               $oldServices = MediaWikiServices::forceGlobalInstance( $newServices );
-
-               $this->assertInstanceOf( 'MediaWiki\\MediaWikiServices', $oldServices );
-               $this->assertNotSame( $oldServices, $newServices );
-
-               $theServices = MediaWikiServices::getInstance();
-               $this->assertSame( $theServices, $newServices );
-
-               MediaWikiServices::forceGlobalInstance( $oldServices );
-
-               $theServices = MediaWikiServices::getInstance();
-               $this->assertSame( $theServices, $oldServices );
-       }
-
-       public function testResetGlobalInstance() {
-               $newServices = $this->newMediaWikiServices();
-               $oldServices = MediaWikiServices::forceGlobalInstance( $newServices );
-
-               MediaWikiServices::resetGlobalInstance( $this->newTestConfig() );
-               $theServices = MediaWikiServices::getInstance();
-
-               $this->assertNotSame( $theServices, $newServices );
-               $this->assertNotSame( $theServices, $oldServices );
-
-               MediaWikiServices::forceGlobalInstance( $oldServices );
-       }
-
-       public function testDisableStorageBackend() {
-               $newServices = $this->newMediaWikiServices();
-               $oldServices = MediaWikiServices::forceGlobalInstance( $newServices );
-
-               $lbFactory = $this->getMockBuilder( 'LBFactorySimple' )
-                       ->disableOriginalConstructor()
-                       ->getMock();
-
-               $lbFactory->expects( $this->once() )
-                       ->method( 'destroy' );
-
-               $newServices->redefineService(
-                       'DBLoadBalancerFactory',
-                       function() use ( $lbFactory ) {
-                               return $lbFactory;
-                       }
-               );
-
-               // force the service to become active, so we can check that it does get destroyed
-               $newServices->getService( 'DBLoadBalancerFactory' );
-
-               MediaWikiServices::disableStorageBackend(); // should destroy DBLoadBalancerFactory
-
-               try {
-                       MediaWikiServices::getInstance()->getService( 'DBLoadBalancerFactory' );
-                       $this->fail( 'DBLoadBalancerFactory shoudl have been disabled' );
-               }
-               catch ( ServiceDisabledException $ex ) {
-                       // ok, as expected
-               }
-               catch ( Throwable $ex ) {
-                       $this->fail( 'ServiceDisabledException expected, caught ' . get_class( $ex ) );
-               }
-
-               MediaWikiServices::forceGlobalInstance( $oldServices );
-       }
-
-       public function testResetChildProcessServices() {
-               $newServices = $this->newMediaWikiServices();
-               $oldServices = MediaWikiServices::forceGlobalInstance( $newServices );
-
-               $lbFactory = $this->getMockBuilder( 'LBFactorySimple' )
-                       ->disableOriginalConstructor()
-                       ->getMock();
-
-               $lbFactory->expects( $this->once() )
-                       ->method( 'destroy' );
-
-               $newServices->redefineService(
-                       'DBLoadBalancerFactory',
-                       function() use ( $lbFactory ) {
-                               return $lbFactory;
-                       }
-               );
-
-               // force the service to become active, so we can check that it does get destroyed
-               $oldLBFactory = $newServices->getService( 'DBLoadBalancerFactory' );
-
-               MediaWikiServices::resetChildProcessServices();
-               $finalServices = MediaWikiServices::getInstance();
-
-               $newLBFactory = $finalServices->getService( 'DBLoadBalancerFactory' );
-
-               $this->assertNotSame( $oldLBFactory, $newLBFactory );
-
-               MediaWikiServices::forceGlobalInstance( $oldServices );
-       }
-
-       public function testResetServiceForTesting() {
-               $services = $this->newMediaWikiServices();
-               $serviceCounter = 0;
-
-               $services->defineService(
-                       'Test',
-                       function() use ( &$serviceCounter ) {
-                               $serviceCounter++;
-                               $service = $this->getMock( 'MediaWiki\Services\DestructibleService' );
-                               $service->expects( $this->once() )->method( 'destroy' );
-                               return $service;
-                       }
-               );
-
-               // This should do nothing. In particular, it should not create a service instance.
-               $services->resetServiceForTesting( 'Test' );
-               $this->assertEquals( 0, $serviceCounter, 'No service instance should be created yet.' );
-
-               $oldInstance = $services->getService( 'Test' );
-               $this->assertEquals( 1, $serviceCounter, 'A service instance should exit now.' );
-
-               // The old instance should be detached, and destroy() called.
-               $services->resetServiceForTesting( 'Test' );
-               $newInstance = $services->getService( 'Test' );
-
-               $this->assertNotSame( $oldInstance, $newInstance );
-
-               // Satisfy the expectation that destroy() is called also for the second service instance.
-               $newInstance->destroy();
-       }
-
-       public function testResetServiceForTesting_noDestroy() {
-               $services = $this->newMediaWikiServices();
-
-               $services->defineService(
-                       'Test',
-                       function() {
-                               $service = $this->getMock( 'MediaWiki\Services\DestructibleService' );
-                               $service->expects( $this->never() )->method( 'destroy' );
-                               return $service;
-                       }
-               );
-
-               $oldInstance = $services->getService( 'Test' );
-
-               // The old instance should be detached, but destroy() not called.
-               $services->resetServiceForTesting( 'Test', false );
-               $newInstance = $services->getService( 'Test' );
-
-               $this->assertNotSame( $oldInstance, $newInstance );
-       }
-
        public function provideGetters() {
-               $getServiceCases = $this->provideGetService();
-               $getterCases = [];
-
-               // All getters should be named just like the service, with "get" added.
-               foreach ( $getServiceCases as $name => $case ) {
-                       $getterCases[$name] = [
-                               'get' . $case[0],
-                               $case[1]
-                       ];
-               }
-
-               return $getterCases;
+               // NOTE: This should list all service getters defined in MediaWikiServices.
+               // NOTE: For every test case defined here there should be a corresponding
+               // test case defined in provideGetService().
+               return [
+                       'BootstrapConfig' => [ 'getBootstrapConfig', Config::class ],
+                       'ConfigFactory' => [ 'getConfigFactory', ConfigFactory::class ],
+                       'MainConfig' => [ 'getMainConfig', Config::class ],
+                       'SiteStore' => [ 'getSiteStore', SiteStore::class ],
+                       'SiteLookup' => [ 'getSiteLookup', SiteLookup::class ],
+               ];
        }
 
        /**
@@ -228,8 +46,6 @@ class MediaWikiServicesTest extends PHPUnit_Framework_TestCase {
                        'MainConfig' => [ 'MainConfig', Config::class ],
                        'SiteStore' => [ 'SiteStore', SiteStore::class ],
                        'SiteLookup' => [ 'SiteLookup', SiteLookup::class ],
-                       'DBLoadBalancerFactory' => [ 'DBLoadBalancerFactory', 'LBFactory' ],
-                       'DBLoadBalancer' => [ 'DBLoadBalancer', 'LoadBalancer' ],
                ];
        }
 
index 97852cf..cf34b18 100644 (file)
@@ -15,12 +15,12 @@ class MessageTest extends MediaWikiLangTestCase {
         * @covers Message::__construct
         * @dataProvider provideConstructor
         */
-       public function testConstructor( Language $expectedLang, $key, $params, $language ) {
+       public function testConstructor( $expectedLang, $key, $params, $language ) {
                $message = new Message( $key, $params, $language );
 
                $this->assertEquals( $key, $message->getKey() );
                $this->assertEquals( $params, $message->getParams() );
-               $this->assertEquals( $expectedLang->getCode(), $message->getLanguage()->getCode() );
+               $this->assertEquals( $expectedLang, $message->getLanguage() );
 
                $messageSpecifier = $this->getMockForAbstractClass( 'MessageSpecifier' );
                $messageSpecifier->expects( $this->any() )
@@ -31,7 +31,7 @@ class MessageTest extends MediaWikiLangTestCase {
 
                $this->assertEquals( $key, $message->getKey() );
                $this->assertEquals( $params, $message->getParams() );
-               $this->assertEquals( $expectedLang->getCode(), $message->getLanguage()->getCode() );
+               $this->assertEquals( $expectedLang, $message->getLanguage() );
        }
 
        public static function provideConstructor() {
index 933777c..942c45e 100644 (file)
@@ -69,53 +69,11 @@ class ServiceContainerTest extends PHPUnit_Framework_TestCase {
 
                $name = 'TestService92834576';
 
-               $this->setExpectedException( 'MediaWiki\Services\NoSuchServiceException' );
+               $this->setExpectedException( 'InvalidArgumentException' );
 
                $services->getService( $name );
        }
 
-       public function testPeekService() {
-               $services = $this->newServiceContainer();
-
-               $services->defineService(
-                       'Foo',
-                       function() {
-                               return new stdClass();
-                       }
-               );
-
-               $services->defineService(
-                       'Bar',
-                       function() {
-                               return new stdClass();
-                       }
-               );
-
-               // trigger instantiation of Foo
-               $services->getService( 'Foo' );
-
-               $this->assertInternalType(
-                       'object',
-                       $services->peekService( 'Foo' ),
-                       'Peek should return the service object if it had been accessed before.'
-               );
-
-               $this->assertNull(
-                       $services->peekService( 'Bar' ),
-                       'Peek should return null if the service was never accessed.'
-               );
-       }
-
-       public function testPeekService_fail_unknown() {
-               $services = $this->newServiceContainer();
-
-               $name = 'TestService92834576';
-
-               $this->setExpectedException( 'MediaWiki\Services\NoSuchServiceException' );
-
-               $services->peekService( $name );
-       }
-
        public function testDefineService() {
                $services = $this->newServiceContainer();
 
@@ -141,7 +99,7 @@ class ServiceContainerTest extends PHPUnit_Framework_TestCase {
                        return $theService;
                } );
 
-               $this->setExpectedException( 'MediaWiki\Services\ServiceAlreadyDefinedException' );
+               $this->setExpectedException( 'RuntimeException' );
 
                $services->defineService( $name, function() use ( $theService ) {
                        return $theService;
@@ -189,7 +147,7 @@ class ServiceContainerTest extends PHPUnit_Framework_TestCase {
                ];
 
                // loading the same file twice should fail, because
-               $this->setExpectedException( 'MediaWiki\Services\ServiceAlreadyDefinedException' );
+               $this->setExpectedException( 'RuntimeException' );
 
                $services->loadWiringFiles( $wiringFiles );
        }
@@ -226,7 +184,7 @@ class ServiceContainerTest extends PHPUnit_Framework_TestCase {
                $theService = new stdClass();
                $name = 'TestService92834576';
 
-               $this->setExpectedException( 'MediaWiki\Services\NoSuchServiceException' );
+               $this->setExpectedException( 'RuntimeException' );
 
                $services->redefineService( $name, function() use ( $theService ) {
                        return $theService;
@@ -246,101 +204,11 @@ class ServiceContainerTest extends PHPUnit_Framework_TestCase {
                // create the service, so it can no longer be redefined
                $services->getService( $name );
 
-               $this->setExpectedException( 'MediaWiki\Services\CannotReplaceActiveServiceException' );
-
-               $services->redefineService( $name, function() use ( $theService ) {
-                       return $theService;
-               } );
-       }
-
-       public function testDisableService() {
-               $services = $this->newServiceContainer( [ 'Foo' ] );
-
-               $destructible = $this->getMock( 'MediaWiki\Services\DestructibleService' );
-               $destructible->expects( $this->once() )
-                       ->method( 'destroy' );
-
-               $services->defineService( 'Foo', function() use ( $destructible ) {
-                       return $destructible;
-               } );
-               $services->defineService( 'Bar', function() {
-                       return new stdClass();
-               } );
-               $services->defineService( 'Qux', function() {
-                       return new stdClass();
-               } );
-
-               // instantiate Foo and Bar services
-               $services->getService( 'Foo' );
-               $services->getService( 'Bar' );
-
-               // disable service, should call destroy() once.
-               $services->disableService( 'Foo' );
-
-               // disabled service should still be listed
-               $this->assertContains( 'Foo', $services->getServiceNames() );
-
-               // getting other services should still work
-               $services->getService( 'Bar' );
-
-               // disable non-destructible service, and not-yet-instantiated service
-               $services->disableService( 'Bar' );
-               $services->disableService( 'Qux' );
-
-               $this->assertNull( $services->peekService( 'Bar' ) );
-               $this->assertNull( $services->peekService( 'Qux' ) );
-
-               // disabled service should still be listed
-               $this->assertContains( 'Bar', $services->getServiceNames() );
-               $this->assertContains( 'Qux', $services->getServiceNames() );
-
-               // re-enable Bar service
-               $services->redefineService( 'Bar', function() {
-                       return new stdClass();
-               } );
-
-               $services->getService( 'Bar' );
-
-               $this->setExpectedException( 'MediaWiki\Services\ServiceDisabledException' );
-               $services->getService( 'Qux' );
-       }
-
-       public function testDisableService_fail_undefined() {
-               $services = $this->newServiceContainer();
-
-               $theService = new stdClass();
-               $name = 'TestService92834576';
-
-               $this->setExpectedException( 'MediaWiki\Services\NoSuchServiceException' );
+               $this->setExpectedException( 'RuntimeException' );
 
                $services->redefineService( $name, function() use ( $theService ) {
                        return $theService;
                } );
        }
 
-       public function testDestroy() {
-               $services = $this->newServiceContainer();
-
-               $destructible = $this->getMock( 'MediaWiki\Services\DestructibleService' );
-               $destructible->expects( $this->once() )
-                       ->method( 'destroy' );
-
-               $services->defineService( 'Foo', function() use ( $destructible ) {
-                       return $destructible;
-               } );
-
-               $services->defineService( 'Bar', function() {
-                       return new stdClass();
-               } );
-
-               // create the service
-               $services->getService( 'Foo' );
-
-               // destroy the container
-               $services->destroy();
-
-               $this->setExpectedException( 'MediaWiki\Services\ContainerDisabledException' );
-               $services->getService( 'Bar' );
-       }
-
 }
index 2c1d1e6..2288507 100644 (file)
@@ -8,71 +8,17 @@ class ConfigFactoryTest extends MediaWikiTestCase {
        public function testRegister() {
                $factory = new ConfigFactory();
                $factory->register( 'unittest', 'GlobalVarConfig::newInstance' );
-               $this->assertInstanceOf( GlobalVarConfig::class, $factory->makeConfig( 'unittest' ) );
-       }
-
-       /**
-        * @covers ConfigFactory::register
-        */
-       public function testRegisterInvalid() {
-               $factory = new ConfigFactory();
+               $this->assertTrue( true ); // No exception thrown
                $this->setExpectedException( 'InvalidArgumentException' );
                $factory->register( 'invalid', 'Invalid callback' );
        }
 
-       /**
-        * @covers ConfigFactory::register
-        */
-       public function testRegisterInstance() {
-               $config = GlobalVarConfig::newInstance();
-               $factory = new ConfigFactory();
-               $factory->register( 'unittest', $config );
-               $this->assertSame( $config, $factory->makeConfig( 'unittest' ) );
-       }
-
-       /**
-        * @covers ConfigFactory::register
-        */
-       public function testRegisterAgain() {
-               $factory = new ConfigFactory();
-               $factory->register( 'unittest', 'GlobalVarConfig::newInstance' );
-               $config1 = $factory->makeConfig( 'unittest' );
-
-               $factory->register( 'unittest', 'GlobalVarConfig::newInstance' );
-               $config2 = $factory->makeConfig( 'unittest' );
-
-               $this->assertNotSame( $config1, $config2 );
-       }
-
-       /**
-        * @covers ConfigFactory::register
-        */
-       public function testGetConfigNames() {
-               $factory = new ConfigFactory();
-               $factory->register( 'foo', 'GlobalVarConfig::newInstance' );
-               $factory->register( 'bar', new HashConfig() );
-
-               $this->assertEquals( [ 'foo', 'bar' ], $factory->getConfigNames() );
-       }
-
        /**
         * @covers ConfigFactory::makeConfig
         */
        public function testMakeConfig() {
                $factory = new ConfigFactory();
                $factory->register( 'unittest', 'GlobalVarConfig::newInstance' );
-
-               $conf = $factory->makeConfig( 'unittest' );
-               $this->assertInstanceOf( 'Config', $conf );
-               $this->assertSame( $conf, $factory->makeConfig( 'unittest' ) );
-       }
-
-       /**
-        * @covers ConfigFactory::makeConfig
-        */
-       public function testMakeConfigFallback() {
-               $factory = new ConfigFactory();
-               $factory->register( '*', 'GlobalVarConfig::newInstance' );
                $conf = $factory->makeConfig( 'unittest' );
                $this->assertInstanceOf( 'Config', $conf );
        }
@@ -102,10 +48,10 @@ class ConfigFactoryTest extends MediaWikiTestCase {
         * @covers ConfigFactory::getDefaultInstance
         */
        public function testGetDefaultInstance() {
-               // NOTE: the global config factory returned here has been overwritten
-               // for operation in test mode. It may not reflect LocalSettings.
                $factory = ConfigFactory::getDefaultInstance();
                $this->assertInstanceOf( 'Config', $factory->makeConfig( 'main' ) );
-       }
 
+               $this->setExpectedException( 'ConfigException' );
+               $factory->makeConfig( 'xyzzy' );
+       }
 }
index d876c45..77690cd 100755 (executable)
@@ -139,10 +139,6 @@ class PHPUnitMaintClass extends Maintenance {
                // may break testing against floating point values
                // treated with PHP's serialize()
                ini_set( 'serialize_precision', 17 );
-
-               // TODO: we should call MediaWikiTestCase::prepareServices( new GlobalVarConfig() ) here.
-               // But PHPUnit may not be loaded yet, so we have to wait until just
-               // before PHPUnit_TextUI_Command::main() is executed at the end of this file.
        }
 
        public function execute() {
@@ -241,9 +237,4 @@ echo defined( 'HHVM_VERSION' ) ?
        'Using HHVM ' . HHVM_VERSION . ' (' . PHP_VERSION . ")\n" :
        'Using PHP ' . PHP_VERSION . "\n";
 
-// Prepare global services for unit tests.
-// FIXME: this should be done in the finalSetup() method,
-// but PHPUnit may not have been loaded at that point.
-MediaWikiTestCase::prepareServices( new GlobalVarConfig() );
-
 $wgPhpUnitClass::main();