MediaWiki  1.33.0
MessageBlobStoreTest.php
Go to the documentation of this file.
1 <?php
2 
3 use Wikimedia\TestingAccessWrapper;
4 
9 class 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 
37  public function testBlobCreation_unknownMessage() {
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 }
MessageBlobStoreTest\setUp
setUp()
Definition: MessageBlobStoreTest.php:14
HashBagOStuff
Simple store for keeping values in an associative array for the current process.
Definition: HashBagOStuff.php:31
$messages
$messages
Definition: LogTests.i18n.php:8
MessageBlobStoreTest\makeBlobStore
makeBlobStore( $methods=null, $rl=null)
Definition: MessageBlobStoreTest.php:170
php
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:35
MessageBlobStoreTest\testBlobCreation
testBlobCreation()
Definition: MessageBlobStoreTest.php:26
$blob
$blob
Definition: testCompression.php:65
MessageBlobStoreTest\testMessageCachingAndPurging
testMessageCachingAndPurging()
Definition: MessageBlobStoreTest.php:49
MessageBlobStoreTest\makeModule
makeModule(array $messages)
Definition: MessageBlobStoreTest.php:181
use
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
Definition: MIT-LICENSE.txt:10
array
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))
ResourceLoaderTestModule
Definition: ResourceLoaderTestCase.php:85
MessageBlobStoreTest\testSetLoggedIsVoid
testSetLoggedIsVoid()
Definition: MessageBlobStoreTest.php:165
MessageBlobStoreTest\testBlobCreation_unknownMessage
testBlobCreation_unknownMessage()
Definition: MessageBlobStoreTest.php:37
WANObjectCache
Multi-datacenter aware caching interface.
Definition: WANObjectCache.php:116
MessageBlobStoreTest\testValidateAgainstModuleRegistry
testValidateAgainstModuleRegistry()
Definition: MessageBlobStoreTest.php:127
class
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
MessageBlobStoreTest
ResourceLoader MessageBlobStore.
Definition: MessageBlobStoreTest.php:9
MessageBlobStoreTest\testPurgeEverything
testPurgeEverything()
Definition: MessageBlobStoreTest.php:94