2 use Liuggio\StatsdClient\Factory\StatsdDataFactory
;
3 use MediaWiki\Interwiki\InterwikiLookup
;
4 use MediaWiki\MediaWikiServices
;
5 use MediaWiki\Services\ServiceDisabledException
;
8 * @covers MediaWiki\MediaWikiServices
12 class MediaWikiServicesTest
extends PHPUnit_Framework_TestCase
{
17 private function newTestConfig() {
18 $globalConfig = new GlobalVarConfig();
20 $testConfig = new HashConfig();
21 $testConfig->set( 'ServiceWiringFiles', $globalConfig->get( 'ServiceWiringFiles' ) );
22 $testConfig->set( 'ConfigRegistry', $globalConfig->get( 'ConfigRegistry' ) );
28 * @return MediaWikiServices
30 private function newMediaWikiServices( Config
$config = null ) {
31 if ( $config === null ) {
32 $config = $this->newTestConfig();
35 $instance = new MediaWikiServices( $config );
37 // Load the default wiring from the specified files.
38 $wiringFiles = $config->get( 'ServiceWiringFiles' );
39 $instance->loadWiringFiles( $wiringFiles );
44 public function testGetInstance() {
45 $services = MediaWikiServices
::getInstance();
46 $this->assertInstanceOf( 'MediaWiki\\MediaWikiServices', $services );
49 public function testForceGlobalInstance() {
50 $newServices = $this->newMediaWikiServices();
51 $oldServices = MediaWikiServices
::forceGlobalInstance( $newServices );
53 $this->assertInstanceOf( 'MediaWiki\\MediaWikiServices', $oldServices );
54 $this->assertNotSame( $oldServices, $newServices );
56 $theServices = MediaWikiServices
::getInstance();
57 $this->assertSame( $theServices, $newServices );
59 MediaWikiServices
::forceGlobalInstance( $oldServices );
61 $theServices = MediaWikiServices
::getInstance();
62 $this->assertSame( $theServices, $oldServices );
65 public function testResetGlobalInstance() {
66 $newServices = $this->newMediaWikiServices();
67 $oldServices = MediaWikiServices
::forceGlobalInstance( $newServices );
69 MediaWikiServices
::resetGlobalInstance( $this->newTestConfig() );
70 $theServices = MediaWikiServices
::getInstance();
72 $this->assertNotSame( $theServices, $newServices );
73 $this->assertNotSame( $theServices, $oldServices );
75 MediaWikiServices
::forceGlobalInstance( $oldServices );
78 public function testDisableStorageBackend() {
79 $newServices = $this->newMediaWikiServices();
80 $oldServices = MediaWikiServices
::forceGlobalInstance( $newServices );
82 $lbFactory = $this->getMockBuilder( 'LBFactorySimple' )
83 ->disableOriginalConstructor()
86 $lbFactory->expects( $this->once() )
87 ->method( 'destroy' );
89 $newServices->redefineService(
90 'DBLoadBalancerFactory',
91 function() use ( $lbFactory ) {
96 // force the service to become active, so we can check that it does get destroyed
97 $newServices->getService( 'DBLoadBalancerFactory' );
99 MediaWikiServices
::disableStorageBackend(); // should destroy DBLoadBalancerFactory
102 MediaWikiServices
::getInstance()->getService( 'DBLoadBalancerFactory' );
103 $this->fail( 'DBLoadBalancerFactory shoudl have been disabled' );
105 catch ( ServiceDisabledException
$ex ) {
108 catch ( Throwable
$ex ) {
109 $this->fail( 'ServiceDisabledException expected, caught ' . get_class( $ex ) );
112 MediaWikiServices
::forceGlobalInstance( $oldServices );
115 public function testResetChildProcessServices() {
116 $newServices = $this->newMediaWikiServices();
117 $oldServices = MediaWikiServices
::forceGlobalInstance( $newServices );
119 $lbFactory = $this->getMockBuilder( 'LBFactorySimple' )
120 ->disableOriginalConstructor()
123 $lbFactory->expects( $this->once() )
124 ->method( 'destroy' );
126 $newServices->redefineService(
127 'DBLoadBalancerFactory',
128 function() use ( $lbFactory ) {
133 // force the service to become active, so we can check that it does get destroyed
134 $oldLBFactory = $newServices->getService( 'DBLoadBalancerFactory' );
136 MediaWikiServices
::resetChildProcessServices();
137 $finalServices = MediaWikiServices
::getInstance();
139 $newLBFactory = $finalServices->getService( 'DBLoadBalancerFactory' );
141 $this->assertNotSame( $oldLBFactory, $newLBFactory );
143 MediaWikiServices
::forceGlobalInstance( $oldServices );
146 public function testResetServiceForTesting() {
147 $services = $this->newMediaWikiServices();
150 $services->defineService(
152 function() use ( &$serviceCounter ) {
154 $service = $this->getMock( 'MediaWiki\Services\DestructibleService' );
155 $service->expects( $this->once() )->method( 'destroy' );
160 // This should do nothing. In particular, it should not create a service instance.
161 $services->resetServiceForTesting( 'Test' );
162 $this->assertEquals( 0, $serviceCounter, 'No service instance should be created yet.' );
164 $oldInstance = $services->getService( 'Test' );
165 $this->assertEquals( 1, $serviceCounter, 'A service instance should exit now.' );
167 // The old instance should be detached, and destroy() called.
168 $services->resetServiceForTesting( 'Test' );
169 $newInstance = $services->getService( 'Test' );
171 $this->assertNotSame( $oldInstance, $newInstance );
173 // Satisfy the expectation that destroy() is called also for the second service instance.
174 $newInstance->destroy();
177 public function testResetServiceForTesting_noDestroy() {
178 $services = $this->newMediaWikiServices();
180 $services->defineService(
183 $service = $this->getMock( 'MediaWiki\Services\DestructibleService' );
184 $service->expects( $this->never() )->method( 'destroy' );
189 $oldInstance = $services->getService( 'Test' );
191 // The old instance should be detached, but destroy() not called.
192 $services->resetServiceForTesting( 'Test', false );
193 $newInstance = $services->getService( 'Test' );
195 $this->assertNotSame( $oldInstance, $newInstance );
198 public function provideGetters() {
199 $getServiceCases = $this->provideGetService();
202 // All getters should be named just like the service, with "get" added.
203 foreach ( $getServiceCases as $name => $case ) {
204 if ( $name[0] === '_' ) {
205 // Internal service, no getter
208 list( $service, $class ) = $case;
209 $getterCases[$name] = [
219 * @dataProvider provideGetters
221 public function testGetters( $getter, $type ) {
222 // Test against the default instance, since the dummy will not know the default services.
223 $services = MediaWikiServices
::getInstance();
224 $service = $services->$getter();
225 $this->assertInstanceOf( $type, $service );
228 public function provideGetService() {
229 // NOTE: This should list all service getters defined in ServiceWiring.php.
230 // NOTE: For every test case defined here there should be a corresponding
231 // test case defined in provideGetters().
233 'BootstrapConfig' => [ 'BootstrapConfig', Config
::class ],
234 'ConfigFactory' => [ 'ConfigFactory', ConfigFactory
::class ],
235 'MainConfig' => [ 'MainConfig', Config
::class ],
236 'SiteStore' => [ 'SiteStore', SiteStore
::class ],
237 'SiteLookup' => [ 'SiteLookup', SiteLookup
::class ],
238 'StatsdDataFactory' => [ 'StatsdDataFactory', StatsdDataFactory
::class ],
239 'InterwikiLookup' => [ 'InterwikiLookup', InterwikiLookup
::class ],
240 'EventRelayerGroup' => [ 'EventRelayerGroup', EventRelayerGroup
::class ],
241 'SearchEngineFactory' => [ 'SearchEngineFactory', SearchEngineFactory
::class ],
242 'SearchEngineConfig' => [ 'SearchEngineConfig', SearchEngineConfig
::class ],
243 'SkinFactory' => [ 'SkinFactory', SkinFactory
::class ],
244 'DBLoadBalancerFactory' => [ 'DBLoadBalancerFactory', 'LBFactory' ],
245 'DBLoadBalancer' => [ 'DBLoadBalancer', 'LoadBalancer' ],
246 'WatchedItemStore' => [ 'WatchedItemStore', WatchedItemStore
::class ],
247 'GenderCache' => [ 'GenderCache', GenderCache
::class ],
248 'LinkCache' => [ 'LinkCache', LinkCache
::class ],
249 '_MediaWikiTitleCodec' => [ '_MediaWikiTitleCodec', MediaWikiTitleCodec
::class ],
250 'TitleFormatter' => [ 'TitleFormatter', TitleFormatter
::class ],
251 'TitleParser' => [ 'TitleParser', TitleParser
::class ],
256 * @dataProvider provideGetService
258 public function testGetService( $name, $type ) {
259 // Test against the default instance, since the dummy will not know the default services.
260 $services = MediaWikiServices
::getInstance();
262 $service = $services->getService( $name );
263 $this->assertInstanceOf( $type, $service );
266 public function testDefaultServiceInstantiation() {
267 // Check all services in the default instance, not a dummy instance!
268 // Note that we instantiate all services here, including any that
269 // were registered by extensions.
270 $services = MediaWikiServices
::getInstance();
271 $names = $services->getServiceNames();
273 foreach ( $names as $name ) {
274 $this->assertTrue( $services->hasService( $name ) );
275 $service = $services->getService( $name );
276 $this->assertInternalType( 'object', $service );