MediaWiki REL1_33
MessageBlobStoreTest.php
Go to the documentation of this file.
1<?php
2
3use Wikimedia\TestingAccessWrapper;
4
9class MessageBlobStoreTest extends PHPUnit\Framework\TestCase {
10
11 use MediaWikiCoversValidator;
12 use PHPUnit4And6Compat;
13
14 protected function setUp() {
15 parent::setUp();
16 // MediaWiki's test wrapper sets $wgMainWANCache to CACHE_NONE.
17 // Use HashBagOStuff here so that we can observe caching.
18 $this->wanCache = new WANObjectCache( [
19 'cache' => new HashBagOStuff()
20 ] );
21
22 $this->clock = 1301655600.000;
23 $this->wanCache->setMockTime( $this->clock );
24 }
25
26 public function testBlobCreation() {
27 $module = $this->makeModule( [ 'mainpage' ] );
28 $rl = new ResourceLoader();
29 $rl->register( $module->getName(), $module );
30
31 $blobStore = $this->makeBlobStore( null, $rl );
32 $blob = $blobStore->getBlob( $module, 'en' );
33
34 $this->assertEquals( '{"mainpage":"Main Page"}', $blob, 'Generated blob' );
35 }
36
38 $module = $this->makeModule( [ 'i-dont-exist' ] );
39 $rl = new ResourceLoader();
40 $rl->register( $module->getName(), $module );
41 $blobStore = $this->makeBlobStore( null, $rl );
42
43 // Generating a blob should succeed without errors,
44 // even if a message is unknown.
45 $blob = $blobStore->getBlob( $module, 'en' );
46 $this->assertEquals( '{"i-dont-exist":"\u29fci-dont-exist\u29fd"}', $blob, 'Generated blob' );
47 }
48
49 public function testMessageCachingAndPurging() {
50 $module = $this->makeModule( [ 'example' ] );
51 $rl = new ResourceLoader();
52 $rl->register( $module->getName(), $module );
53 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
54
55 // Advance this new WANObjectCache instance to a normal state,
56 // by doing one "get" and letting its hold off period expire.
57 // Without this, the first real "get" would lazy-initialise the
58 // checkKey and thus reject the first "set".
59 $blobStore->getBlob( $module, 'en' );
60 $this->clock += 20;
61
62 // Arrange version 1 of a message
63 $blobStore->expects( $this->once() )
64 ->method( 'fetchMessage' )
65 ->will( $this->returnValue( 'First version' ) );
66
67 // Assert
68 $blob = $blobStore->getBlob( $module, 'en' );
69 $this->assertEquals( '{"example":"First version"}', $blob, 'Blob for v1' );
70
71 // Arrange version 2
72 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
73 $blobStore->expects( $this->once() )
74 ->method( 'fetchMessage' )
75 ->will( $this->returnValue( 'Second version' ) );
76 $this->clock += 20;
77
78 // Assert
79 // We do not validate whether a cached message is up-to-date.
80 // Instead, changes to messages will send us a purge.
81 // When cache is not purged or expired, it must be used.
82 $blob = $blobStore->getBlob( $module, 'en' );
83 $this->assertEquals( '{"example":"First version"}', $blob, 'Reuse cached v1 blob' );
84
85 // Purge cache
86 $blobStore->updateMessage( 'example' );
87 $this->clock += 20;
88
89 // Assert
90 $blob = $blobStore->getBlob( $module, 'en' );
91 $this->assertEquals( '{"example":"Second version"}', $blob, 'Updated blob for v2' );
92 }
93
94 public function testPurgeEverything() {
95 $module = $this->makeModule( [ 'example' ] );
96 $rl = new ResourceLoader();
97 $rl->register( $module->getName(), $module );
98 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
99 // Advance this new WANObjectCache instance to a normal state.
100 $blobStore->getBlob( $module, 'en' );
101 $this->clock += 20;
102
103 // Arrange version 1 and 2
104 $blobStore->expects( $this->exactly( 2 ) )
105 ->method( 'fetchMessage' )
106 ->will( $this->onConsecutiveCalls( 'First', 'Second' ) );
107
108 // Assert
109 $blob = $blobStore->getBlob( $module, 'en' );
110 $this->assertEquals( '{"example":"First"}', $blob, 'Blob for v1' );
111
112 $this->clock += 20;
113
114 // Assert
115 $blob = $blobStore->getBlob( $module, 'en' );
116 $this->assertEquals( '{"example":"First"}', $blob, 'Blob for v1 again' );
117
118 // Purge everything
119 $blobStore->clear();
120 $this->clock += 20;
121
122 // Assert
123 $blob = $blobStore->getBlob( $module, 'en' );
124 $this->assertEquals( '{"example":"Second"}', $blob, 'Blob for v2' );
125 }
126
128 // Arrange version 1 of a module
129 $module = $this->makeModule( [ 'foo' ] );
130 $rl = new ResourceLoader();
131 $rl->register( $module->getName(), $module );
132 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
133 $blobStore->expects( $this->once() )
134 ->method( 'fetchMessage' )
135 ->will( $this->returnValueMap( [
136 // message key, language code, message value
137 [ 'foo', 'en', 'Hello' ],
138 ] ) );
139
140 // Assert
141 $blob = $blobStore->getBlob( $module, 'en' );
142 $this->assertEquals( '{"foo":"Hello"}', $blob, 'Blob for v1' );
143
144 // Arrange version 2 of module
145 // While message values may be out of date, the set of messages returned
146 // must always match the set of message keys required by the module.
147 // We do not receive purges for this because no messages were changed.
148 $module = $this->makeModule( [ 'foo', 'bar' ] );
149 $rl = new ResourceLoader();
150 $rl->register( $module->getName(), $module );
151 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
152 $blobStore->expects( $this->exactly( 2 ) )
153 ->method( 'fetchMessage' )
154 ->will( $this->returnValueMap( [
155 // message key, language code, message value
156 [ 'foo', 'en', 'Hello' ],
157 [ 'bar', 'en', 'World' ],
158 ] ) );
159
160 // Assert
161 $blob = $blobStore->getBlob( $module, 'en' );
162 $this->assertEquals( '{"foo":"Hello","bar":"World"}', $blob, 'Blob for v2' );
163 }
164
165 public function testSetLoggedIsVoid() {
166 $blobStore = $this->makeBlobStore();
167 $this->assertSame( null, $blobStore->setLogger( new Psr\Log\NullLogger() ) );
168 }
169
170 private function makeBlobStore( $methods = null, $rl = null ) {
171 $blobStore = $this->getMockBuilder( MessageBlobStore::class )
172 ->setConstructorArgs( [ $rl ?? $this->createMock( ResourceLoader::class ) ] )
173 ->setMethods( $methods )
174 ->getMock();
175
176 $access = TestingAccessWrapper::newFromObject( $blobStore );
177 $access->wanCache = $this->wanCache;
178 return $blobStore;
179 }
180
181 private function makeModule( array $messages ) {
182 $module = new ResourceLoaderTestModule( [ 'messages' => $messages ] );
183 $module->setName( 'test.blobstore' );
184 return $module;
185 }
186}
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
$messages
Simple store for keeping values in an associative array for the current process.
ResourceLoader MessageBlobStore.
makeBlobStore( $methods=null, $rl=null)
Dynamic JavaScript and CSS resource loading system.
Multi-datacenter aware caching interface.
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition injection.txt:37
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))