4d98773890f16fd3b3e390f97d644f80430bcf68
[lhc/web/wiklou.git] / tests / phpunit / includes / resourceloader / MessageBlobStoreTest.php
1 <?php
2
3 use Wikimedia\TestingAccessWrapper;
4
5 /**
6 * @group Cache
7 * @covers MessageBlobStore
8 */
9 class MessageBlobStoreTest extends PHPUnit\Framework\TestCase {
10
11 use MediaWikiCoversValidator;
12
13 protected function setUp() {
14 parent::setUp();
15 // MediaWiki tests defaults $wgMainWANCache to CACHE_NONE.
16 // Use hash instead so that caching is observed
17 $this->wanCache = $this->getMockBuilder( WANObjectCache::class )
18 ->setConstructorArgs( [ [
19 'cache' => new HashBagOStuff(),
20 'pool' => 'test',
21 'relayer' => new EventRelayerNull( [] )
22 ] ] )
23 ->setMethods( [ 'makePurgeValue' ] )
24 ->getMock();
25
26 $this->wanCache->expects( $this->any() )
27 ->method( 'makePurgeValue' )
28 ->will( $this->returnCallback( function ( $timestamp, $holdoff ) {
29 // Disable holdoff as it messes with testing
30 return WANObjectCache::PURGE_VAL_PREFIX . (float)$timestamp . ':0';
31 } ) );
32 }
33
34 protected function makeBlobStore( $methods = null, $rl = null ) {
35 $blobStore = $this->getMockBuilder( MessageBlobStore::class )
36 ->setConstructorArgs( [ $rl ] )
37 ->setMethods( $methods )
38 ->getMock();
39
40 $access = TestingAccessWrapper::newFromObject( $blobStore );
41 $access->wanCache = $this->wanCache;
42 return $blobStore;
43 }
44
45 protected function makeModule( array $messages ) {
46 $module = new ResourceLoaderTestModule( [ 'messages' => $messages ] );
47 $module->setName( 'test.blobstore' );
48 return $module;
49 }
50
51 /** @covers MessageBlobStore::setLogger */
52 public function testSetLogger() {
53 $blobStore = $this->makeBlobStore();
54 $this->assertSame( null, $blobStore->setLogger( new Psr\Log\NullLogger() ) );
55 }
56
57 /** @covers MessageBlobStore::getResourceLoader */
58 public function testGetResourceLoader() {
59 // Call protected method
60 $blobStore = TestingAccessWrapper::newFromObject( $this->makeBlobStore() );
61 $this->assertInstanceOf(
62 ResourceLoader::class,
63 $blobStore->getResourceLoader()
64 );
65 }
66
67 /** @covers MessageBlobStore::fetchMessage */
68 public function testFetchMessage() {
69 $module = $this->makeModule( [ 'mainpage' ] );
70 $rl = new ResourceLoader();
71 $rl->register( $module->getName(), $module );
72
73 $blobStore = $this->makeBlobStore( null, $rl );
74 $blob = $blobStore->getBlob( $module, 'en' );
75
76 $this->assertEquals( '{"mainpage":"Main Page"}', $blob, 'Generated blob' );
77 }
78
79 /** @covers MessageBlobStore::fetchMessage */
80 public function testFetchMessageFail() {
81 $module = $this->makeModule( [ 'i-dont-exist' ] );
82 $rl = new ResourceLoader();
83 $rl->register( $module->getName(), $module );
84
85 $blobStore = $this->makeBlobStore( null, $rl );
86 $blob = $blobStore->getBlob( $module, 'en' );
87
88 $this->assertEquals( '{"i-dont-exist":"\u29fci-dont-exist\u29fd"}', $blob, 'Generated blob' );
89 }
90
91 public function testGetBlob() {
92 $module = $this->makeModule( [ 'foo' ] );
93 $rl = new ResourceLoader();
94 $rl->register( $module->getName(), $module );
95
96 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
97 $blobStore->expects( $this->once() )
98 ->method( 'fetchMessage' )
99 ->will( $this->returnValue( 'Example' ) );
100
101 $blob = $blobStore->getBlob( $module, 'en' );
102
103 $this->assertEquals( '{"foo":"Example"}', $blob, 'Generated blob' );
104 }
105
106 /**
107 * Seems to fail sometimes (T176097).
108 *
109 * @group Broken
110 */
111 public function testGetBlobCached() {
112 $module = $this->makeModule( [ 'example' ] );
113 $rl = new ResourceLoader();
114 $rl->register( $module->getName(), $module );
115
116 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
117 $blobStore->expects( $this->once() )
118 ->method( 'fetchMessage' )
119 ->will( $this->returnValue( 'First' ) );
120
121 $module = $this->makeModule( [ 'example' ] );
122 $blob = $blobStore->getBlob( $module, 'en' );
123 $this->assertEquals( '{"example":"First"}', $blob, 'Generated blob' );
124
125 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
126 $blobStore->expects( $this->never() )
127 ->method( 'fetchMessage' )
128 ->will( $this->returnValue( 'Second' ) );
129
130 $module = $this->makeModule( [ 'example' ] );
131 $blob = $blobStore->getBlob( $module, 'en' );
132 $this->assertEquals( '{"example":"First"}', $blob, 'Cache hit' );
133 }
134
135 public function testUpdateMessage() {
136 $module = $this->makeModule( [ 'example' ] );
137 $rl = new ResourceLoader();
138 $rl->register( $module->getName(), $module );
139 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
140 $blobStore->expects( $this->once() )
141 ->method( 'fetchMessage' )
142 ->will( $this->returnValue( 'First' ) );
143
144 $blob = $blobStore->getBlob( $module, 'en' );
145 $this->assertEquals( '{"example":"First"}', $blob, 'Generated blob' );
146
147 $blobStore->updateMessage( 'example' );
148
149 $module = $this->makeModule( [ 'example' ] );
150 $rl = new ResourceLoader();
151 $rl->register( $module->getName(), $module );
152 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
153 $blobStore->expects( $this->once() )
154 ->method( 'fetchMessage' )
155 ->will( $this->returnValue( 'Second' ) );
156
157 $blob = $blobStore->getBlob( $module, 'en' );
158 $this->assertEquals( '{"example":"Second"}', $blob, 'Updated blob' );
159 }
160
161 public function testValidation() {
162 $module = $this->makeModule( [ 'foo' ] );
163 $rl = new ResourceLoader();
164 $rl->register( $module->getName(), $module );
165
166 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
167 $blobStore->expects( $this->once() )
168 ->method( 'fetchMessage' )
169 ->will( $this->returnValueMap( [
170 [ 'foo', 'en', 'Hello' ],
171 ] ) );
172
173 $blob = $blobStore->getBlob( $module, 'en' );
174 $this->assertEquals( '{"foo":"Hello"}', $blob, 'Generated blob' );
175
176 // Now, imagine a change to the module is deployed. The module now contains
177 // message 'foo' and 'bar'. While updateMessage() was not called (since no
178 // message values were changed) it should detect the change in list of
179 // message keys.
180 $module = $this->makeModule( [ 'foo', 'bar' ] );
181 $rl = new ResourceLoader();
182 $rl->register( $module->getName(), $module );
183
184 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
185 $blobStore->expects( $this->exactly( 2 ) )
186 ->method( 'fetchMessage' )
187 ->will( $this->returnValueMap( [
188 [ 'foo', 'en', 'Hello' ],
189 [ 'bar', 'en', 'World' ],
190 ] ) );
191
192 $blob = $blobStore->getBlob( $module, 'en' );
193 $this->assertEquals( '{"foo":"Hello","bar":"World"}', $blob, 'Updated blob' );
194 }
195
196 public function testClear() {
197 $module = $this->makeModule( [ 'example' ] );
198 $rl = new ResourceLoader();
199 $rl->register( $module->getName(), $module );
200 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
201 $blobStore->expects( $this->exactly( 2 ) )
202 ->method( 'fetchMessage' )
203 ->will( $this->onConsecutiveCalls( 'First', 'Second' ) );
204
205 $blob = $blobStore->getBlob( $module, 'en' );
206 $this->assertEquals( '{"example":"First"}', $blob, 'Generated blob' );
207
208 $blob = $blobStore->getBlob( $module, 'en' );
209 $this->assertEquals( '{"example":"First"}', $blob, 'Cache-hit' );
210
211 $blobStore->clear();
212
213 $blob = $blobStore->getBlob( $module, 'en' );
214 $this->assertEquals( '{"example":"Second"}', $blob, 'Updated blob' );
215 }
216 }