3 use Wikimedia\TestingAccessWrapper
;
6 * @group ResourceLoader
7 * @covers MessageBlobStore
9 class MessageBlobStoreTest
extends PHPUnit\Framework\TestCase
{
11 use MediaWikiCoversValidator
;
12 use PHPUnit4And6Compat
;
14 protected function 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()
22 $this->clock
= 1301655600.000;
23 $this->wanCache
->setMockTime( $this->clock
);
26 public function testBlobCreation() {
27 $module = $this->makeModule( [ 'mainpage' ] );
28 $rl = new EmptyResourceLoader();
29 $rl->register( $module->getName(), $module );
31 $blobStore = $this->makeBlobStore( null, $rl );
32 $blob = $blobStore->getBlob( $module, 'en' );
34 $this->assertEquals( '{"mainpage":"Main Page"}', $blob, 'Generated blob' );
37 public function testBlobCreation_empty() {
38 $module = $this->makeModule( [] );
39 $rl = new EmptyResourceLoader();
40 $rl->register( $module->getName(), $module );
42 $blobStore = $this->makeBlobStore( null, $rl );
43 $blob = $blobStore->getBlob( $module, 'en' );
45 $this->assertEquals( '{}', $blob, 'Generated blob' );
48 public function testBlobCreation_unknownMessage() {
49 $module = $this->makeModule( [ 'i-dont-exist', 'mainpage', 'i-dont-exist2' ] );
50 $rl = new EmptyResourceLoader();
51 $rl->register( $module->getName(), $module );
52 $blobStore = $this->makeBlobStore( null, $rl );
54 // Generating a blob should continue without errors,
55 // with keys of unknown messages excluded from the blob.
56 $blob = $blobStore->getBlob( $module, 'en' );
57 $this->assertEquals( '{"mainpage":"Main Page"}', $blob, 'Generated blob' );
60 public function testMessageCachingAndPurging() {
61 $module = $this->makeModule( [ 'example' ] );
62 $rl = new EmptyResourceLoader();
63 $rl->register( $module->getName(), $module );
64 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
66 // Advance this new WANObjectCache instance to a normal state,
67 // by doing one "get" and letting its hold off period expire.
68 // Without this, the first real "get" would lazy-initialise the
69 // checkKey and thus reject the first "set".
70 $blobStore->getBlob( $module, 'en' );
73 // Arrange version 1 of a message
74 $blobStore->expects( $this->once() )
75 ->method( 'fetchMessage' )
76 ->will( $this->returnValue( 'First version' ) );
79 $blob = $blobStore->getBlob( $module, 'en' );
80 $this->assertEquals( '{"example":"First version"}', $blob, 'Blob for v1' );
83 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
84 $blobStore->expects( $this->once() )
85 ->method( 'fetchMessage' )
86 ->will( $this->returnValue( 'Second version' ) );
90 // We do not validate whether a cached message is up-to-date.
91 // Instead, changes to messages will send us a purge.
92 // When cache is not purged or expired, it must be used.
93 $blob = $blobStore->getBlob( $module, 'en' );
94 $this->assertEquals( '{"example":"First version"}', $blob, 'Reuse cached v1 blob' );
97 $blobStore->updateMessage( 'example' );
101 $blob = $blobStore->getBlob( $module, 'en' );
102 $this->assertEquals( '{"example":"Second version"}', $blob, 'Updated blob for v2' );
105 public function testPurgeEverything() {
106 $module = $this->makeModule( [ 'example' ] );
107 $rl = new EmptyResourceLoader();
108 $rl->register( $module->getName(), $module );
109 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
110 // Advance this new WANObjectCache instance to a normal state.
111 $blobStore->getBlob( $module, 'en' );
114 // Arrange version 1 and 2
115 $blobStore->expects( $this->exactly( 2 ) )
116 ->method( 'fetchMessage' )
117 ->will( $this->onConsecutiveCalls( 'First', 'Second' ) );
120 $blob = $blobStore->getBlob( $module, 'en' );
121 $this->assertEquals( '{"example":"First"}', $blob, 'Blob for v1' );
126 $blob = $blobStore->getBlob( $module, 'en' );
127 $this->assertEquals( '{"example":"First"}', $blob, 'Blob for v1 again' );
134 $blob = $blobStore->getBlob( $module, 'en' );
135 $this->assertEquals( '{"example":"Second"}', $blob, 'Blob for v2' );
138 public function testValidateAgainstModuleRegistry() {
139 // Arrange version 1 of a module
140 $module = $this->makeModule( [ 'foo' ] );
141 $rl = new EmptyResourceLoader();
142 $rl->register( $module->getName(), $module );
143 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
144 $blobStore->expects( $this->once() )
145 ->method( 'fetchMessage' )
146 ->will( $this->returnValueMap( [
147 // message key, language code, message value
148 [ 'foo', 'en', 'Hello' ],
152 $blob = $blobStore->getBlob( $module, 'en' );
153 $this->assertEquals( '{"foo":"Hello"}', $blob, 'Blob for v1' );
155 // Arrange version 2 of module
156 // While message values may be out of date, the set of messages returned
157 // must always match the set of message keys required by the module.
158 // We do not receive purges for this because no messages were changed.
159 $module = $this->makeModule( [ 'foo', 'bar' ] );
160 $rl = new EmptyResourceLoader();
161 $rl->register( $module->getName(), $module );
162 $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
163 $blobStore->expects( $this->exactly( 2 ) )
164 ->method( 'fetchMessage' )
165 ->will( $this->returnValueMap( [
166 // message key, language code, message value
167 [ 'foo', 'en', 'Hello' ],
168 [ 'bar', 'en', 'World' ],
172 $blob = $blobStore->getBlob( $module, 'en' );
173 $this->assertEquals( '{"foo":"Hello","bar":"World"}', $blob, 'Blob for v2' );
176 public function testSetLoggedIsVoid() {
177 $blobStore = $this->makeBlobStore();
178 $this->assertSame( null, $blobStore->setLogger( new Psr\Log\
NullLogger() ) );
181 private function makeBlobStore( $methods = null, $rl = null ) {
182 $blobStore = $this->getMockBuilder( MessageBlobStore
::class )
183 ->setConstructorArgs( [ $rl ??
$this->createMock( ResourceLoader
::class ) ] )
184 ->setMethods( $methods )
187 $access = TestingAccessWrapper
::newFromObject( $blobStore );
188 $access->wanCache
= $this->wanCache
;
192 private function makeModule( array $messages ) {
193 $module = new ResourceLoaderTestModule( [ 'messages' => $messages ] );
194 $module->setName( 'test.blobstore' );