summaryrefslogtreecommitdiff
path: root/www/wiki/tests/phpunit/includes/resourceloader/MessageBlobStoreTest.php
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/tests/phpunit/includes/resourceloader/MessageBlobStoreTest.php')
-rw-r--r--www/wiki/tests/phpunit/includes/resourceloader/MessageBlobStoreTest.php224
1 files changed, 224 insertions, 0 deletions
diff --git a/www/wiki/tests/phpunit/includes/resourceloader/MessageBlobStoreTest.php b/www/wiki/tests/phpunit/includes/resourceloader/MessageBlobStoreTest.php
new file mode 100644
index 00000000..7eb09441
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/resourceloader/MessageBlobStoreTest.php
@@ -0,0 +1,224 @@
+<?php
+
+use Wikimedia\TestingAccessWrapper;
+
+/**
+ * @group Cache
+ * @covers MessageBlobStore
+ */
+class MessageBlobStoreTest extends PHPUnit\Framework\TestCase {
+
+ use MediaWikiCoversValidator;
+
+ protected function setUp() {
+ parent::setUp();
+ // MediaWiki tests defaults $wgMainWANCache to CACHE_NONE.
+ // Use hash instead so that caching is observed
+ $this->wanCache = $this->getMockBuilder( WANObjectCache::class )
+ ->setConstructorArgs( [ [
+ 'cache' => new HashBagOStuff(),
+ 'pool' => 'test',
+ 'relayer' => new EventRelayerNull( [] )
+ ] ] )
+ ->setMethods( [ 'makePurgeValue' ] )
+ ->getMock();
+
+ $this->wanCache->expects( $this->any() )
+ ->method( 'makePurgeValue' )
+ ->will( $this->returnCallback( function ( $timestamp, $holdoff ) {
+ // Disable holdoff as it messes with testing. Aside from a 0-second holdoff,
+ // make sure that "time" passes between getMulti() check init and the set()
+ // in recacheMessageBlob(). This especially matters for Windows clocks.
+ $ts = (float)$timestamp - 0.0001;
+
+ return WANObjectCache::PURGE_VAL_PREFIX . $ts . ':0';
+ } ) );
+ }
+
+ protected function makeBlobStore( $methods = null, $rl = null ) {
+ $blobStore = $this->getMockBuilder( MessageBlobStore::class )
+ ->setConstructorArgs( [ $rl ] )
+ ->setMethods( $methods )
+ ->getMock();
+
+ $access = TestingAccessWrapper::newFromObject( $blobStore );
+ $access->wanCache = $this->wanCache;
+ return $blobStore;
+ }
+
+ protected function makeModule( array $messages ) {
+ $module = new ResourceLoaderTestModule( [ 'messages' => $messages ] );
+ $module->setName( 'test.blobstore' );
+ return $module;
+ }
+
+ /** @covers MessageBlobStore::setLogger */
+ public function testSetLogger() {
+ $blobStore = $this->makeBlobStore();
+ $this->assertSame( null, $blobStore->setLogger( new Psr\Log\NullLogger() ) );
+ }
+
+ /** @covers MessageBlobStore::getResourceLoader */
+ public function testGetResourceLoader() {
+ // Call protected method
+ $blobStore = TestingAccessWrapper::newFromObject( $this->makeBlobStore() );
+ $this->assertInstanceOf(
+ ResourceLoader::class,
+ $blobStore->getResourceLoader()
+ );
+ }
+
+ /** @covers MessageBlobStore::fetchMessage */
+ public function testFetchMessage() {
+ $module = $this->makeModule( [ 'mainpage' ] );
+ $rl = new ResourceLoader();
+ $rl->register( $module->getName(), $module );
+
+ $blobStore = $this->makeBlobStore( null, $rl );
+ $blob = $blobStore->getBlob( $module, 'en' );
+
+ $this->assertEquals( '{"mainpage":"Main Page"}', $blob, 'Generated blob' );
+ }
+
+ /** @covers MessageBlobStore::fetchMessage */
+ public function testFetchMessageFail() {
+ $module = $this->makeModule( [ 'i-dont-exist' ] );
+ $rl = new ResourceLoader();
+ $rl->register( $module->getName(), $module );
+
+ $blobStore = $this->makeBlobStore( null, $rl );
+ $blob = $blobStore->getBlob( $module, 'en' );
+
+ $this->assertEquals( '{"i-dont-exist":"\u29fci-dont-exist\u29fd"}', $blob, 'Generated blob' );
+ }
+
+ public function testGetBlob() {
+ $module = $this->makeModule( [ 'foo' ] );
+ $rl = new ResourceLoader();
+ $rl->register( $module->getName(), $module );
+
+ $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
+ $blobStore->expects( $this->once() )
+ ->method( 'fetchMessage' )
+ ->will( $this->returnValue( 'Example' ) );
+
+ $blob = $blobStore->getBlob( $module, 'en' );
+
+ $this->assertEquals( '{"foo":"Example"}', $blob, 'Generated blob' );
+ }
+
+ /**
+ * Seems to fail sometimes (T176097).
+ *
+ * @group Broken
+ */
+ public function testGetBlobCached() {
+ $module = $this->makeModule( [ 'example' ] );
+ $rl = new ResourceLoader();
+ $rl->register( $module->getName(), $module );
+
+ $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
+ $blobStore->expects( $this->once() )
+ ->method( 'fetchMessage' )
+ ->will( $this->returnValue( 'First' ) );
+
+ $module = $this->makeModule( [ 'example' ] );
+ $blob = $blobStore->getBlob( $module, 'en' );
+ $this->assertEquals( '{"example":"First"}', $blob, 'Generated blob' );
+
+ $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
+ $blobStore->expects( $this->never() )
+ ->method( 'fetchMessage' )
+ ->will( $this->returnValue( 'Second' ) );
+
+ $module = $this->makeModule( [ 'example' ] );
+ $blob = $blobStore->getBlob( $module, 'en' );
+ $this->assertEquals( '{"example":"First"}', $blob, 'Cache hit' );
+ }
+
+ public function testUpdateMessage() {
+ $module = $this->makeModule( [ 'example' ] );
+ $rl = new ResourceLoader();
+ $rl->register( $module->getName(), $module );
+ $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
+ $blobStore->expects( $this->once() )
+ ->method( 'fetchMessage' )
+ ->will( $this->returnValue( 'First' ) );
+
+ $blob = $blobStore->getBlob( $module, 'en' );
+ $this->assertEquals( '{"example":"First"}', $blob, 'Generated blob' );
+
+ $blobStore->updateMessage( 'example' );
+
+ $module = $this->makeModule( [ 'example' ] );
+ $rl = new ResourceLoader();
+ $rl->register( $module->getName(), $module );
+ $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
+ $blobStore->expects( $this->once() )
+ ->method( 'fetchMessage' )
+ ->will( $this->returnValue( 'Second' ) );
+
+ $blob = $blobStore->getBlob( $module, 'en' );
+ $this->assertEquals( '{"example":"Second"}', $blob, 'Updated blob' );
+ }
+
+ public function testValidation() {
+ $module = $this->makeModule( [ 'foo' ] );
+ $rl = new ResourceLoader();
+ $rl->register( $module->getName(), $module );
+
+ $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
+ $blobStore->expects( $this->once() )
+ ->method( 'fetchMessage' )
+ ->will( $this->returnValueMap( [
+ [ 'foo', 'en', 'Hello' ],
+ ] ) );
+
+ $blob = $blobStore->getBlob( $module, 'en' );
+ $this->assertEquals( '{"foo":"Hello"}', $blob, 'Generated blob' );
+
+ // Now, imagine a change to the module is deployed. The module now contains
+ // message 'foo' and 'bar'. While updateMessage() was not called (since no
+ // message values were changed) it should detect the change in list of
+ // message keys.
+ $module = $this->makeModule( [ 'foo', 'bar' ] );
+ $rl = new ResourceLoader();
+ $rl->register( $module->getName(), $module );
+
+ $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
+ $blobStore->expects( $this->exactly( 2 ) )
+ ->method( 'fetchMessage' )
+ ->will( $this->returnValueMap( [
+ [ 'foo', 'en', 'Hello' ],
+ [ 'bar', 'en', 'World' ],
+ ] ) );
+
+ $blob = $blobStore->getBlob( $module, 'en' );
+ $this->assertEquals( '{"foo":"Hello","bar":"World"}', $blob, 'Updated blob' );
+ }
+
+ public function testClear() {
+ $module = $this->makeModule( [ 'example' ] );
+ $rl = new ResourceLoader();
+ $rl->register( $module->getName(), $module );
+ $blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
+ $blobStore->expects( $this->exactly( 2 ) )
+ ->method( 'fetchMessage' )
+ ->will( $this->onConsecutiveCalls( 'First', 'Second' ) );
+
+ $now = microtime( true );
+ $this->wanCache->setMockTime( $now );
+
+ $blob = $blobStore->getBlob( $module, 'en' );
+ $this->assertEquals( '{"example":"First"}', $blob, 'Generated blob' );
+
+ $blob = $blobStore->getBlob( $module, 'en' );
+ $this->assertEquals( '{"example":"First"}', $blob, 'Cache-hit' );
+
+ $now += 1;
+ $blobStore->clear();
+
+ $blob = $blobStore->getBlob( $module, 'en' );
+ $this->assertEquals( '{"example":"Second"}', $blob, 'Updated blob' );
+ }
+}