3 use Wikimedia\TestingAccessWrapper
;
7 * @covers MessageBlobStore
9 class MessageBlobStoreTest
extends PHPUnit\Framework\TestCase
{
11 use MediaWikiCoversValidator
;
13 protected function 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(),
21 'relayer' => new EventRelayerNull( [] )
23 ->setMethods( [ 'makePurgeValue' ] )
26 $this->wanCache
->expects( $this->any() )
27 ->method( 'makePurgeValue' )
28 ->will( $this->returnCallback( function ( $timestamp, $holdoff ) {
29 // Disable holdoff as it messes with testing. Aside from a 0-second holdoff,
30 // make sure that "time" passes between getMulti() check init and the set()
31 // in recacheMessageBlob(). This especially matters for Windows clocks.
32 $ts = (float)$timestamp - 0.0001;
34 return WANObjectCache
::PURGE_VAL_PREFIX
. $ts . ':0';
38 protected function makeBlobStore( $methods = null, $rl = null ) {
39 $blobStore = $this->getMockBuilder( MessageBlobStore
::class )
40 ->setConstructorArgs( [ $rl ] )
41 ->setMethods( $methods )
44 $access = TestingAccessWrapper
::newFromObject( $blobStore );
45 $access->wanCache
= $this->wanCache
;
49 protected function makeModule( array $messages ) {
50 $module = new ResourceLoaderTestModule( [ 'messages' => $messages ] );
51 $module->setName( 'test.blobstore' );
55 /** @covers MessageBlobStore::setLogger */
56 public function testSetLogger() {
57 $blobStore = $this->makeBlobStore();
58 $this->assertSame( null, $blobStore->setLogger( new Psr\Log\
NullLogger() ) );
61 /** @covers MessageBlobStore::getResourceLoader */
62 public function testGetResourceLoader() {
63 // Call protected method
64 $blobStore = TestingAccessWrapper
::newFromObject( $this->makeBlobStore() );
65 $this->assertInstanceOf(
66 ResourceLoader
::class,
67 $blobStore->getResourceLoader()
71 /** @covers MessageBlobStore::fetchMessage */
72 public function testFetchMessage() {
73 $module = $this->makeModule( [ 'mainpage' ] );
74 $rl = new ResourceLoader();
75 $rl->register( $module->getName(), $module );
77 $blobStore = $this->makeBlobStore( null, $rl );
78 $blob = $blobStore->getBlob( $module, 'en' );
80 $this->assertEquals( '{"mainpage":"Main Page"}', $blob, 'Generated blob' );
83 /** @covers MessageBlobStore::fetchMessage */
84 public function testFetchMessageFail() {
85 $module = $this->makeModule( [ 'i-dont-exist' ] );
86 $rl = new ResourceLoader();
87 $rl->register( $module->getName(), $module );
89 $blobStore = $this->makeBlobStore( null, $rl );
90 $blob = $blobStore->getBlob( $module, 'en' );
92 $this->assertEquals( '{"i-dont-exist":"\u29fci-dont-exist\u29fd"}', $blob, 'Generated blob' );
95 public function testGetBlob() {
96 $module = $this->makeModule( [ 'foo' ] );
97 $rl = new ResourceLoader();
98 $rl->register( $module->getName(), $module );
100 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
101 $blobStore->expects( $this->once() )
102 ->method( 'fetchMessage' )
103 ->will( $this->returnValue( 'Example' ) );
105 $blob = $blobStore->getBlob( $module, 'en' );
107 $this->assertEquals( '{"foo":"Example"}', $blob, 'Generated blob' );
111 * Seems to fail sometimes (T176097).
115 public function testGetBlobCached() {
116 $module = $this->makeModule( [ 'example' ] );
117 $rl = new ResourceLoader();
118 $rl->register( $module->getName(), $module );
120 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
121 $blobStore->expects( $this->once() )
122 ->method( 'fetchMessage' )
123 ->will( $this->returnValue( 'First' ) );
125 $module = $this->makeModule( [ 'example' ] );
126 $blob = $blobStore->getBlob( $module, 'en' );
127 $this->assertEquals( '{"example":"First"}', $blob, 'Generated blob' );
129 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
130 $blobStore->expects( $this->never() )
131 ->method( 'fetchMessage' )
132 ->will( $this->returnValue( 'Second' ) );
134 $module = $this->makeModule( [ 'example' ] );
135 $blob = $blobStore->getBlob( $module, 'en' );
136 $this->assertEquals( '{"example":"First"}', $blob, 'Cache hit' );
139 public function testUpdateMessage() {
140 $module = $this->makeModule( [ 'example' ] );
141 $rl = new ResourceLoader();
142 $rl->register( $module->getName(), $module );
143 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
144 $blobStore->expects( $this->once() )
145 ->method( 'fetchMessage' )
146 ->will( $this->returnValue( 'First' ) );
148 $blob = $blobStore->getBlob( $module, 'en' );
149 $this->assertEquals( '{"example":"First"}', $blob, 'Generated blob' );
151 $blobStore->updateMessage( 'example' );
153 $module = $this->makeModule( [ 'example' ] );
154 $rl = new ResourceLoader();
155 $rl->register( $module->getName(), $module );
156 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
157 $blobStore->expects( $this->once() )
158 ->method( 'fetchMessage' )
159 ->will( $this->returnValue( 'Second' ) );
161 $blob = $blobStore->getBlob( $module, 'en' );
162 $this->assertEquals( '{"example":"Second"}', $blob, 'Updated blob' );
165 public function testValidation() {
166 $module = $this->makeModule( [ 'foo' ] );
167 $rl = new ResourceLoader();
168 $rl->register( $module->getName(), $module );
170 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
171 $blobStore->expects( $this->once() )
172 ->method( 'fetchMessage' )
173 ->will( $this->returnValueMap( [
174 [ 'foo', 'en', 'Hello' ],
177 $blob = $blobStore->getBlob( $module, 'en' );
178 $this->assertEquals( '{"foo":"Hello"}', $blob, 'Generated blob' );
180 // Now, imagine a change to the module is deployed. The module now contains
181 // message 'foo' and 'bar'. While updateMessage() was not called (since no
182 // message values were changed) it should detect the change in list of
184 $module = $this->makeModule( [ 'foo', 'bar' ] );
185 $rl = new ResourceLoader();
186 $rl->register( $module->getName(), $module );
188 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
189 $blobStore->expects( $this->exactly( 2 ) )
190 ->method( 'fetchMessage' )
191 ->will( $this->returnValueMap( [
192 [ 'foo', 'en', 'Hello' ],
193 [ 'bar', 'en', 'World' ],
196 $blob = $blobStore->getBlob( $module, 'en' );
197 $this->assertEquals( '{"foo":"Hello","bar":"World"}', $blob, 'Updated blob' );
200 public function testClear() {
201 $module = $this->makeModule( [ 'example' ] );
202 $rl = new ResourceLoader();
203 $rl->register( $module->getName(), $module );
204 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
205 $blobStore->expects( $this->exactly( 2 ) )
206 ->method( 'fetchMessage' )
207 ->will( $this->onConsecutiveCalls( 'First', 'Second' ) );
209 $now = microtime( true );
210 $this->wanCache
->setMockTime( $now );
212 $blob = $blobStore->getBlob( $module, 'en' );
213 $this->assertEquals( '{"example":"First"}', $blob, 'Generated blob' );
215 $blob = $blobStore->getBlob( $module, 'en' );
216 $this->assertEquals( '{"example":"First"}', $blob, 'Cache-hit' );
221 $blob = $blobStore->getBlob( $module, 'en' );
222 $this->assertEquals( '{"example":"Second"}', $blob, 'Updated blob' );