wiki.techinc.nl/tests/phpunit/includes/resourceloader/MessageBlobStoreTest.php

210 lines
6.8 KiB
PHP
Raw Normal View History

<?php
use Wikimedia\TestingAccessWrapper;
/**
* @group Cache
* @covers MessageBlobStore
*/
resourceloader: Migrate from msg_resource table to object cache MessageBlobStore class: * Make logger aware. * Log an error if json encoding fails. * Stop using the DB table. WANObjectCache supports everything we need: - Batch retrieval. - Invalidate keys with wildcard selects or cascading check keys. * Update tests slightly since the actual update now happens on-demand as part of get() instead of within updateMessage(). ResourceLoader class: * Remove all interaction with the msg_resource table. Remove db table later. * Refactor code to use a hash of the blob instead of a timestamp. Timestamps are unreliable and roll over too frequently for message blob store because there is no authoritative source. The timestamps were inferred based on when a change is observed. Message overrides from the local wiki have an explicit update event when the page is edited. All other messages, such as from MediaWiki core and extensions using LocalisationCache, have a single timestamp for all messages which rolls over every time the cache is rebuilt. A hash is deterministic, and won't cause needless invalidation (T102578). * Remove redundant pre-fetching in makeModuleResponse(). This is already done by preloadModuleInfo() in respond(). * Don't bother storing and retreiving empty "{}" objects. Instead, detect whether a module's message list is empty at runtime. ResourceLoaderModule class: * Make logger aware. * Log if a module's message blob was not preloaded. cleanupRemovedModules: * Now that blobs have a TTL, there's no need to prune old entries. Bug: T113092 Bug: T92357 Change-Id: Id8c26f41a82597e34013f95294cdc3971a4f52ae
2015-11-13 00:04:12 +00:00
class MessageBlobStoreTest extends PHPUnit_Framework_TestCase {
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' )
->setConstructorArgs( [ [
resourceloader: Migrate from msg_resource table to object cache MessageBlobStore class: * Make logger aware. * Log an error if json encoding fails. * Stop using the DB table. WANObjectCache supports everything we need: - Batch retrieval. - Invalidate keys with wildcard selects or cascading check keys. * Update tests slightly since the actual update now happens on-demand as part of get() instead of within updateMessage(). ResourceLoader class: * Remove all interaction with the msg_resource table. Remove db table later. * Refactor code to use a hash of the blob instead of a timestamp. Timestamps are unreliable and roll over too frequently for message blob store because there is no authoritative source. The timestamps were inferred based on when a change is observed. Message overrides from the local wiki have an explicit update event when the page is edited. All other messages, such as from MediaWiki core and extensions using LocalisationCache, have a single timestamp for all messages which rolls over every time the cache is rebuilt. A hash is deterministic, and won't cause needless invalidation (T102578). * Remove redundant pre-fetching in makeModuleResponse(). This is already done by preloadModuleInfo() in respond(). * Don't bother storing and retreiving empty "{}" objects. Instead, detect whether a module's message list is empty at runtime. ResourceLoaderModule class: * Make logger aware. * Log if a module's message blob was not preloaded. cleanupRemovedModules: * Now that blobs have a TTL, there's no need to prune old entries. Bug: T113092 Bug: T92357 Change-Id: Id8c26f41a82597e34013f95294cdc3971a4f52ae
2015-11-13 00:04:12 +00:00
'cache' => new HashBagOStuff(),
'pool' => 'test',
'relayer' => new EventRelayerNull( [] )
] ] )
->setMethods( [ 'makePurgeValue' ] )
resourceloader: Migrate from msg_resource table to object cache MessageBlobStore class: * Make logger aware. * Log an error if json encoding fails. * Stop using the DB table. WANObjectCache supports everything we need: - Batch retrieval. - Invalidate keys with wildcard selects or cascading check keys. * Update tests slightly since the actual update now happens on-demand as part of get() instead of within updateMessage(). ResourceLoader class: * Remove all interaction with the msg_resource table. Remove db table later. * Refactor code to use a hash of the blob instead of a timestamp. Timestamps are unreliable and roll over too frequently for message blob store because there is no authoritative source. The timestamps were inferred based on when a change is observed. Message overrides from the local wiki have an explicit update event when the page is edited. All other messages, such as from MediaWiki core and extensions using LocalisationCache, have a single timestamp for all messages which rolls over every time the cache is rebuilt. A hash is deterministic, and won't cause needless invalidation (T102578). * Remove redundant pre-fetching in makeModuleResponse(). This is already done by preloadModuleInfo() in respond(). * Don't bother storing and retreiving empty "{}" objects. Instead, detect whether a module's message list is empty at runtime. ResourceLoaderModule class: * Make logger aware. * Log if a module's message blob was not preloaded. cleanupRemovedModules: * Now that blobs have a TTL, there's no need to prune old entries. Bug: T113092 Bug: T92357 Change-Id: Id8c26f41a82597e34013f95294cdc3971a4f52ae
2015-11-13 00:04:12 +00:00
->getMock();
$this->wanCache->expects( $this->any() )
->method( 'makePurgeValue' )
->will( $this->returnCallback( function ( $timestamp, $holdoff ) {
// Disable holdoff as it messes with testing
return WANObjectCache::PURGE_VAL_PREFIX . (float)$timestamp . ':0';
} ) );
}
protected function makeBlobStore( $methods = null, $rl = null ) {
$blobStore = $this->getMockBuilder( 'MessageBlobStore' )
->setConstructorArgs( [ $rl ] )
->setMethods( $methods )
->getMock();
resourceloader: Migrate from msg_resource table to object cache MessageBlobStore class: * Make logger aware. * Log an error if json encoding fails. * Stop using the DB table. WANObjectCache supports everything we need: - Batch retrieval. - Invalidate keys with wildcard selects or cascading check keys. * Update tests slightly since the actual update now happens on-demand as part of get() instead of within updateMessage(). ResourceLoader class: * Remove all interaction with the msg_resource table. Remove db table later. * Refactor code to use a hash of the blob instead of a timestamp. Timestamps are unreliable and roll over too frequently for message blob store because there is no authoritative source. The timestamps were inferred based on when a change is observed. Message overrides from the local wiki have an explicit update event when the page is edited. All other messages, such as from MediaWiki core and extensions using LocalisationCache, have a single timestamp for all messages which rolls over every time the cache is rebuilt. A hash is deterministic, and won't cause needless invalidation (T102578). * Remove redundant pre-fetching in makeModuleResponse(). This is already done by preloadModuleInfo() in respond(). * Don't bother storing and retreiving empty "{}" objects. Instead, detect whether a module's message list is empty at runtime. ResourceLoaderModule class: * Make logger aware. * Log if a module's message blob was not preloaded. cleanupRemovedModules: * Now that blobs have a TTL, there's no need to prune old entries. Bug: T113092 Bug: T92357 Change-Id: Id8c26f41a82597e34013f95294cdc3971a4f52ae
2015-11-13 00:04:12 +00:00
$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' );
}
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 );
resourceloader: Migrate from msg_resource table to object cache MessageBlobStore class: * Make logger aware. * Log an error if json encoding fails. * Stop using the DB table. WANObjectCache supports everything we need: - Batch retrieval. - Invalidate keys with wildcard selects or cascading check keys. * Update tests slightly since the actual update now happens on-demand as part of get() instead of within updateMessage(). ResourceLoader class: * Remove all interaction with the msg_resource table. Remove db table later. * Refactor code to use a hash of the blob instead of a timestamp. Timestamps are unreliable and roll over too frequently for message blob store because there is no authoritative source. The timestamps were inferred based on when a change is observed. Message overrides from the local wiki have an explicit update event when the page is edited. All other messages, such as from MediaWiki core and extensions using LocalisationCache, have a single timestamp for all messages which rolls over every time the cache is rebuilt. A hash is deterministic, and won't cause needless invalidation (T102578). * Remove redundant pre-fetching in makeModuleResponse(). This is already done by preloadModuleInfo() in respond(). * Don't bother storing and retreiving empty "{}" objects. Instead, detect whether a module's message list is empty at runtime. ResourceLoaderModule class: * Make logger aware. * Log if a module's message blob was not preloaded. cleanupRemovedModules: * Now that blobs have a TTL, there's no need to prune old entries. Bug: T113092 Bug: T92357 Change-Id: Id8c26f41a82597e34013f95294cdc3971a4f52ae
2015-11-13 00:04:12 +00:00
$blobStore->expects( $this->once() )
->method( 'fetchMessage' )
resourceloader: Migrate from msg_resource table to object cache MessageBlobStore class: * Make logger aware. * Log an error if json encoding fails. * Stop using the DB table. WANObjectCache supports everything we need: - Batch retrieval. - Invalidate keys with wildcard selects or cascading check keys. * Update tests slightly since the actual update now happens on-demand as part of get() instead of within updateMessage(). ResourceLoader class: * Remove all interaction with the msg_resource table. Remove db table later. * Refactor code to use a hash of the blob instead of a timestamp. Timestamps are unreliable and roll over too frequently for message blob store because there is no authoritative source. The timestamps were inferred based on when a change is observed. Message overrides from the local wiki have an explicit update event when the page is edited. All other messages, such as from MediaWiki core and extensions using LocalisationCache, have a single timestamp for all messages which rolls over every time the cache is rebuilt. A hash is deterministic, and won't cause needless invalidation (T102578). * Remove redundant pre-fetching in makeModuleResponse(). This is already done by preloadModuleInfo() in respond(). * Don't bother storing and retreiving empty "{}" objects. Instead, detect whether a module's message list is empty at runtime. ResourceLoaderModule class: * Make logger aware. * Log if a module's message blob was not preloaded. cleanupRemovedModules: * Now that blobs have a TTL, there's no need to prune old entries. Bug: T113092 Bug: T92357 Change-Id: Id8c26f41a82597e34013f95294cdc3971a4f52ae
2015-11-13 00:04:12 +00:00
->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 );
resourceloader: Migrate from msg_resource table to object cache MessageBlobStore class: * Make logger aware. * Log an error if json encoding fails. * Stop using the DB table. WANObjectCache supports everything we need: - Batch retrieval. - Invalidate keys with wildcard selects or cascading check keys. * Update tests slightly since the actual update now happens on-demand as part of get() instead of within updateMessage(). ResourceLoader class: * Remove all interaction with the msg_resource table. Remove db table later. * Refactor code to use a hash of the blob instead of a timestamp. Timestamps are unreliable and roll over too frequently for message blob store because there is no authoritative source. The timestamps were inferred based on when a change is observed. Message overrides from the local wiki have an explicit update event when the page is edited. All other messages, such as from MediaWiki core and extensions using LocalisationCache, have a single timestamp for all messages which rolls over every time the cache is rebuilt. A hash is deterministic, and won't cause needless invalidation (T102578). * Remove redundant pre-fetching in makeModuleResponse(). This is already done by preloadModuleInfo() in respond(). * Don't bother storing and retreiving empty "{}" objects. Instead, detect whether a module's message list is empty at runtime. ResourceLoaderModule class: * Make logger aware. * Log if a module's message blob was not preloaded. cleanupRemovedModules: * Now that blobs have a TTL, there's no need to prune old entries. Bug: T113092 Bug: T92357 Change-Id: Id8c26f41a82597e34013f95294cdc3971a4f52ae
2015-11-13 00:04:12 +00:00
$blobStore->expects( $this->once() )
->method( 'fetchMessage' )
resourceloader: Migrate from msg_resource table to object cache MessageBlobStore class: * Make logger aware. * Log an error if json encoding fails. * Stop using the DB table. WANObjectCache supports everything we need: - Batch retrieval. - Invalidate keys with wildcard selects or cascading check keys. * Update tests slightly since the actual update now happens on-demand as part of get() instead of within updateMessage(). ResourceLoader class: * Remove all interaction with the msg_resource table. Remove db table later. * Refactor code to use a hash of the blob instead of a timestamp. Timestamps are unreliable and roll over too frequently for message blob store because there is no authoritative source. The timestamps were inferred based on when a change is observed. Message overrides from the local wiki have an explicit update event when the page is edited. All other messages, such as from MediaWiki core and extensions using LocalisationCache, have a single timestamp for all messages which rolls over every time the cache is rebuilt. A hash is deterministic, and won't cause needless invalidation (T102578). * Remove redundant pre-fetching in makeModuleResponse(). This is already done by preloadModuleInfo() in respond(). * Don't bother storing and retreiving empty "{}" objects. Instead, detect whether a module's message list is empty at runtime. ResourceLoaderModule class: * Make logger aware. * Log if a module's message blob was not preloaded. cleanupRemovedModules: * Now that blobs have a TTL, there's no need to prune old entries. Bug: T113092 Bug: T92357 Change-Id: Id8c26f41a82597e34013f95294cdc3971a4f52ae
2015-11-13 00:04:12 +00:00
->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' );
}
resourceloader: Migrate from msg_resource table to object cache MessageBlobStore class: * Make logger aware. * Log an error if json encoding fails. * Stop using the DB table. WANObjectCache supports everything we need: - Batch retrieval. - Invalidate keys with wildcard selects or cascading check keys. * Update tests slightly since the actual update now happens on-demand as part of get() instead of within updateMessage(). ResourceLoader class: * Remove all interaction with the msg_resource table. Remove db table later. * Refactor code to use a hash of the blob instead of a timestamp. Timestamps are unreliable and roll over too frequently for message blob store because there is no authoritative source. The timestamps were inferred based on when a change is observed. Message overrides from the local wiki have an explicit update event when the page is edited. All other messages, such as from MediaWiki core and extensions using LocalisationCache, have a single timestamp for all messages which rolls over every time the cache is rebuilt. A hash is deterministic, and won't cause needless invalidation (T102578). * Remove redundant pre-fetching in makeModuleResponse(). This is already done by preloadModuleInfo() in respond(). * Don't bother storing and retreiving empty "{}" objects. Instead, detect whether a module's message list is empty at runtime. ResourceLoaderModule class: * Make logger aware. * Log if a module's message blob was not preloaded. cleanupRemovedModules: * Now that blobs have a TTL, there's no need to prune old entries. Bug: T113092 Bug: T92357 Change-Id: Id8c26f41a82597e34013f95294cdc3971a4f52ae
2015-11-13 00:04:12 +00:00
public function testClear() {
$module = $this->makeModule( [ 'example' ] );
resourceloader: Migrate from msg_resource table to object cache MessageBlobStore class: * Make logger aware. * Log an error if json encoding fails. * Stop using the DB table. WANObjectCache supports everything we need: - Batch retrieval. - Invalidate keys with wildcard selects or cascading check keys. * Update tests slightly since the actual update now happens on-demand as part of get() instead of within updateMessage(). ResourceLoader class: * Remove all interaction with the msg_resource table. Remove db table later. * Refactor code to use a hash of the blob instead of a timestamp. Timestamps are unreliable and roll over too frequently for message blob store because there is no authoritative source. The timestamps were inferred based on when a change is observed. Message overrides from the local wiki have an explicit update event when the page is edited. All other messages, such as from MediaWiki core and extensions using LocalisationCache, have a single timestamp for all messages which rolls over every time the cache is rebuilt. A hash is deterministic, and won't cause needless invalidation (T102578). * Remove redundant pre-fetching in makeModuleResponse(). This is already done by preloadModuleInfo() in respond(). * Don't bother storing and retreiving empty "{}" objects. Instead, detect whether a module's message list is empty at runtime. ResourceLoaderModule class: * Make logger aware. * Log if a module's message blob was not preloaded. cleanupRemovedModules: * Now that blobs have a TTL, there's no need to prune old entries. Bug: T113092 Bug: T92357 Change-Id: Id8c26f41a82597e34013f95294cdc3971a4f52ae
2015-11-13 00:04:12 +00:00
$rl = new ResourceLoader();
$rl->register( $module->getName(), $module );
$blobStore = $this->makeBlobStore( [ 'fetchMessage' ], $rl );
resourceloader: Migrate from msg_resource table to object cache MessageBlobStore class: * Make logger aware. * Log an error if json encoding fails. * Stop using the DB table. WANObjectCache supports everything we need: - Batch retrieval. - Invalidate keys with wildcard selects or cascading check keys. * Update tests slightly since the actual update now happens on-demand as part of get() instead of within updateMessage(). ResourceLoader class: * Remove all interaction with the msg_resource table. Remove db table later. * Refactor code to use a hash of the blob instead of a timestamp. Timestamps are unreliable and roll over too frequently for message blob store because there is no authoritative source. The timestamps were inferred based on when a change is observed. Message overrides from the local wiki have an explicit update event when the page is edited. All other messages, such as from MediaWiki core and extensions using LocalisationCache, have a single timestamp for all messages which rolls over every time the cache is rebuilt. A hash is deterministic, and won't cause needless invalidation (T102578). * Remove redundant pre-fetching in makeModuleResponse(). This is already done by preloadModuleInfo() in respond(). * Don't bother storing and retreiving empty "{}" objects. Instead, detect whether a module's message list is empty at runtime. ResourceLoaderModule class: * Make logger aware. * Log if a module's message blob was not preloaded. cleanupRemovedModules: * Now that blobs have a TTL, there's no need to prune old entries. Bug: T113092 Bug: T92357 Change-Id: Id8c26f41a82597e34013f95294cdc3971a4f52ae
2015-11-13 00:04:12 +00:00
$blobStore->expects( $this->exactly( 2 ) )
->method( 'fetchMessage' )
->will( $this->onConsecutiveCalls( 'First', 'Second' ) );
$blob = $blobStore->getBlob( $module, 'en' );
$this->assertEquals( '{"example":"First"}', $blob, 'Generated blob' );
$blob = $blobStore->getBlob( $module, 'en' );
$this->assertEquals( '{"example":"First"}', $blob, 'Cache-hit' );
$blobStore->clear();
$blob = $blobStore->getBlob( $module, 'en' );
$this->assertEquals( '{"example":"Second"}', $blob, 'Updated blob' );
}
}