MediaWiki REL1_31
ServiceContainerTest.php
Go to the documentation of this file.
1<?php
3
9class ServiceContainerTest extends PHPUnit\Framework\TestCase {
10
11 use MediaWikiCoversValidator;
12 use PHPUnit4And6Compat;
13
14 private function newServiceContainer( $extraArgs = [] ) {
15 return new ServiceContainer( $extraArgs );
16 }
17
18 public function testGetServiceNames() {
20 $names = $services->getServiceNames();
21
22 $this->assertInternalType( 'array', $names );
23 $this->assertEmpty( $names );
24
25 $name = 'TestService92834576';
26 $services->defineService( $name, function () {
27 return null;
28 } );
29
30 $names = $services->getServiceNames();
31 $this->assertContains( $name, $names );
32 }
33
34 public function testHasService() {
36
37 $name = 'TestService92834576';
38 $this->assertFalse( $services->hasService( $name ) );
39
40 $services->defineService( $name, function () {
41 return null;
42 } );
43
44 $this->assertTrue( $services->hasService( $name ) );
45 }
46
47 public function testGetService() {
48 $services = $this->newServiceContainer( [ 'Foo' ] );
49
50 $theService = new stdClass();
51 $name = 'TestService92834576';
52 $count = 0;
53
54 $services->defineService(
55 $name,
56 function ( $actualLocator, $extra ) use ( $services, $theService, &$count ) {
57 $count++;
58 PHPUnit_Framework_Assert::assertSame( $services, $actualLocator );
59 PHPUnit_Framework_Assert::assertSame( $extra, 'Foo' );
60 return $theService;
61 }
62 );
63
64 $this->assertSame( $theService, $services->getService( $name ) );
65
66 $services->getService( $name );
67 $this->assertSame( 1, $count, 'instantiator should be called exactly once!' );
68 }
69
70 public function testGetService_fail_unknown() {
72
73 $name = 'TestService92834576';
74
75 $this->setExpectedException( MediaWiki\Services\NoSuchServiceException::class );
76
77 $services->getService( $name );
78 }
79
80 public function testPeekService() {
82
83 $services->defineService(
84 'Foo',
85 function () {
86 return new stdClass();
87 }
88 );
89
90 $services->defineService(
91 'Bar',
92 function () {
93 return new stdClass();
94 }
95 );
96
97 // trigger instantiation of Foo
98 $services->getService( 'Foo' );
99
100 $this->assertInternalType(
101 'object',
102 $services->peekService( 'Foo' ),
103 'Peek should return the service object if it had been accessed before.'
104 );
105
106 $this->assertNull(
107 $services->peekService( 'Bar' ),
108 'Peek should return null if the service was never accessed.'
109 );
110 }
111
114
115 $name = 'TestService92834576';
116
117 $this->setExpectedException( MediaWiki\Services\NoSuchServiceException::class );
118
119 $services->peekService( $name );
120 }
121
122 public function testDefineService() {
124
125 $theService = new stdClass();
126 $name = 'TestService92834576';
127
128 $services->defineService( $name, function ( $actualLocator ) use ( $services, $theService ) {
129 PHPUnit_Framework_Assert::assertSame( $services, $actualLocator );
130 return $theService;
131 } );
132
133 $this->assertTrue( $services->hasService( $name ) );
134 $this->assertSame( $theService, $services->getService( $name ) );
135 }
136
139
140 $theService = new stdClass();
141 $name = 'TestService92834576';
142
143 $services->defineService( $name, function () use ( $theService ) {
144 return $theService;
145 } );
146
147 $this->setExpectedException( MediaWiki\Services\ServiceAlreadyDefinedException::class );
148
149 $services->defineService( $name, function () use ( $theService ) {
150 return $theService;
151 } );
152 }
153
154 public function testApplyWiring() {
156
157 $wiring = [
158 'Foo' => function () {
159 return 'Foo!';
160 },
161 'Bar' => function () {
162 return 'Bar!';
163 },
164 ];
165
166 $services->applyWiring( $wiring );
167
168 $this->assertSame( 'Foo!', $services->getService( 'Foo' ) );
169 $this->assertSame( 'Bar!', $services->getService( 'Bar' ) );
170 }
171
172 public function testImportWiring() {
174
175 $wiring = [
176 'Foo' => function () {
177 return 'Foo!';
178 },
179 'Bar' => function () {
180 return 'Bar!';
181 },
182 'Car' => function () {
183 return 'FUBAR!';
184 },
185 ];
186
187 $services->applyWiring( $wiring );
188
189 $newServices = $this->newServiceContainer();
190
191 // define a service before importing, so we can later check that
192 // existing service instances survive importWiring()
193 $newServices->defineService( 'Car', function () {
194 return 'Car!';
195 } );
196
197 // force instantiation
198 $newServices->getService( 'Car' );
199
200 // Define another service, so we can later check that extra wiring
201 // is not lost.
202 $newServices->defineService( 'Xar', function () {
203 return 'Xar!';
204 } );
205
206 // import wiring, but skip `Bar`
207 $newServices->importWiring( $services, [ 'Bar' ] );
208
209 $this->assertNotContains( 'Bar', $newServices->getServiceNames(), 'Skip `Bar` service' );
210 $this->assertSame( 'Foo!', $newServices->getService( 'Foo' ) );
211
212 // import all wiring, but preserve existing service instance
213 $newServices->importWiring( $services );
214
215 $this->assertContains( 'Bar', $newServices->getServiceNames(), 'Import all services' );
216 $this->assertSame( 'Bar!', $newServices->getService( 'Bar' ) );
217 $this->assertSame( 'Car!', $newServices->getService( 'Car' ), 'Use existing service instance' );
218 $this->assertSame( 'Xar!', $newServices->getService( 'Xar' ), 'Predefined services are kept' );
219 }
220
221 public function testLoadWiringFiles() {
223
224 $wiringFiles = [
225 __DIR__ . '/TestWiring1.php',
226 __DIR__ . '/TestWiring2.php',
227 ];
228
229 $services->loadWiringFiles( $wiringFiles );
230
231 $this->assertSame( 'Foo!', $services->getService( 'Foo' ) );
232 $this->assertSame( 'Bar!', $services->getService( 'Bar' ) );
233 }
234
237
238 $wiringFiles = [
239 __DIR__ . '/TestWiring1.php',
240 __DIR__ . '/./TestWiring1.php',
241 ];
242
243 // loading the same file twice should fail, because
244 $this->setExpectedException( MediaWiki\Services\ServiceAlreadyDefinedException::class );
245
246 $services->loadWiringFiles( $wiringFiles );
247 }
248
249 public function testRedefineService() {
250 $services = $this->newServiceContainer( [ 'Foo' ] );
251
252 $theService1 = new stdClass();
253 $name = 'TestService92834576';
254
255 $services->defineService( $name, function () {
256 PHPUnit_Framework_Assert::fail(
257 'The original instantiator function should not get called'
258 );
259 } );
260
261 // redefine before instantiation
262 $services->redefineService(
263 $name,
264 function ( $actualLocator, $extra ) use ( $services, $theService1 ) {
265 PHPUnit_Framework_Assert::assertSame( $services, $actualLocator );
266 PHPUnit_Framework_Assert::assertSame( 'Foo', $extra );
267 return $theService1;
268 }
269 );
270
271 // force instantiation, check result
272 $this->assertSame( $theService1, $services->getService( $name ) );
273 }
274
276 $services = $this->newServiceContainer( [ 'Foo' ] );
277
278 $theService1 = new stdClass();
279 $name = 'TestService92834576';
280
281 $services->defineService( $name, function () {
282 return 'Foo';
283 } );
284
285 // disable the service. we should be able to redefine it anyway.
286 $services->disableService( $name );
287
288 $services->redefineService( $name, function () use ( $theService1 ) {
289 return $theService1;
290 } );
291
292 // force instantiation, check result
293 $this->assertSame( $theService1, $services->getService( $name ) );
294 }
295
298
299 $theService = new stdClass();
300 $name = 'TestService92834576';
301
302 $this->setExpectedException( MediaWiki\Services\NoSuchServiceException::class );
303
304 $services->redefineService( $name, function () use ( $theService ) {
305 return $theService;
306 } );
307 }
308
310 $services = $this->newServiceContainer( [ 'Foo' ] );
311
312 $theService = new stdClass();
313 $name = 'TestService92834576';
314
315 $services->defineService( $name, function () {
316 return 'Foo';
317 } );
318
319 // create the service, so it can no longer be redefined
320 $services->getService( $name );
321
322 $this->setExpectedException( MediaWiki\Services\CannotReplaceActiveServiceException::class );
323
324 $services->redefineService( $name, function () use ( $theService ) {
325 return $theService;
326 } );
327 }
328
329 public function testDisableService() {
330 $services = $this->newServiceContainer( [ 'Foo' ] );
331
332 $destructible = $this->getMockBuilder( MediaWiki\Services\DestructibleService::class )
333 ->getMock();
334 $destructible->expects( $this->once() )
335 ->method( 'destroy' );
336
337 $services->defineService( 'Foo', function () use ( $destructible ) {
338 return $destructible;
339 } );
340 $services->defineService( 'Bar', function () {
341 return new stdClass();
342 } );
343 $services->defineService( 'Qux', function () {
344 return new stdClass();
345 } );
346
347 // instantiate Foo and Bar services
348 $services->getService( 'Foo' );
349 $services->getService( 'Bar' );
350
351 // disable service, should call destroy() once.
352 $services->disableService( 'Foo' );
353
354 // disabled service should still be listed
355 $this->assertContains( 'Foo', $services->getServiceNames() );
356
357 // getting other services should still work
358 $services->getService( 'Bar' );
359
360 // disable non-destructible service, and not-yet-instantiated service
361 $services->disableService( 'Bar' );
362 $services->disableService( 'Qux' );
363
364 $this->assertNull( $services->peekService( 'Bar' ) );
365 $this->assertNull( $services->peekService( 'Qux' ) );
366
367 // disabled service should still be listed
368 $this->assertContains( 'Bar', $services->getServiceNames() );
369 $this->assertContains( 'Qux', $services->getServiceNames() );
370
371 $this->setExpectedException( MediaWiki\Services\ServiceDisabledException::class );
372 $services->getService( 'Qux' );
373 }
374
377
378 $theService = new stdClass();
379 $name = 'TestService92834576';
380
381 $this->setExpectedException( MediaWiki\Services\NoSuchServiceException::class );
382
383 $services->redefineService( $name, function () use ( $theService ) {
384 return $theService;
385 } );
386 }
387
388 public function testDestroy() {
390
391 $destructible = $this->getMockBuilder( MediaWiki\Services\DestructibleService::class )
392 ->getMock();
393 $destructible->expects( $this->once() )
394 ->method( 'destroy' );
395
396 $services->defineService( 'Foo', function () use ( $destructible ) {
397 return $destructible;
398 } );
399
400 $services->defineService( 'Bar', function () {
401 return new stdClass();
402 } );
403
404 // create the service
405 $services->getService( 'Foo' );
406
407 // destroy the container
408 $services->destroy();
409
410 $this->setExpectedException( MediaWiki\Services\ContainerDisabledException::class );
411 $services->getService( 'Bar' );
412 }
413
414}
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
ServiceContainer provides a generic service to manage named services using lazy instantiation based o...
MediaWiki\Services\ServiceContainer.
newServiceContainer( $extraArgs=[])
static configuration should be added through ResourceLoaderGetConfigVars instead can be used to get the real title after the basic globals have been set but before ordinary actions take place or wrap services the preferred way to define a new service is the $wgServiceWiringFiles array $services
Definition hooks.txt:2273
A helper class for throttling authentication attempts.