wiki.techinc.nl/tests/phpunit/includes/Storage/SqlBlobStoreTest.php
Timo Tijhof 128debb64b tests: Change use of AtEase to at operator
Follows-up I361fde0de7f4406bce6ed075ed397effa5be3359.

Per T253461, not mass-changing source code, but the use of the native
error silencing operator (@) is especially useful in tests because:

1. It requires any/all statements to be explicitly marked. The
   suppressWarnings/restoreWarnings sections encourage developers to
   be "lazy" and thus encapsulate more than needed if there are multiple
   ones near each other, which would ignore potentially important
   warnings in a test case, which is generally exactly the time when
   it is really useful to get warnings etc.

2. It avoids leaking state, for example in LBFactoryTest the
   assertFalse call would throw a PHPUnit assertion error (not meant
   to be caught by the local catch), and thus won't reach
   AtEase::restoreWarnings. This then causes later code to end up
   in a mismatching state and creates a confusing error_reporting
   state.

See .phpcs.xml, where the at operator is allowed for all test code.

Change-Id: I68d1725d685e0a7586468bc9de6dc29ceea31b8a
2022-02-24 21:29:51 +00:00

715 lines
20 KiB
PHP

<?php
namespace MediaWiki\Tests\Storage;
use ExternalStoreAccess;
use ExternalStoreFactory;
use HashBagOStuff;
use InvalidArgumentException;
use MediaWiki\Storage\BlobAccessException;
use MediaWiki\Storage\SqlBlobStore;
use MediaWikiIntegrationTestCase;
use TitleValue;
use WANObjectCache;
use Wikimedia\Rdbms\LoadBalancer;
/**
* @covers \MediaWiki\Storage\SqlBlobStore
* @group Database
*/
class SqlBlobStoreTest extends MediaWikiIntegrationTestCase {
/**
* @param WANObjectCache|null $cache
* @param ExternalStoreAccess|null $extStore
*
* @return SqlBlobStore
*/
public function getBlobStore(
WANObjectCache $cache = null,
ExternalStoreAccess $extStore = null
) {
$services = $this->getServiceContainer();
$store = new SqlBlobStore(
$services->getDBLoadBalancer(),
$extStore ?: $services->getExternalStoreAccess(),
$cache ?: $services->getMainWANObjectCache()
);
return $store;
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::getCompressBlobs()
* @covers \MediaWiki\Storage\SqlBlobStore::setCompressBlobs()
*/
public function testGetSetCompressRevisions() {
$store = $this->getBlobStore();
$this->assertFalse( $store->getCompressBlobs() );
$store->setCompressBlobs( true );
$this->assertTrue( $store->getCompressBlobs() );
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::getLegacyEncoding()
* @covers \MediaWiki\Storage\SqlBlobStore::getLegacyEncodingConversionLang()
* @covers \MediaWiki\Storage\SqlBlobStore::setLegacyEncoding()
*/
public function testGetSetLegacyEncoding() {
$store = $this->getBlobStore();
$this->assertFalse( $store->getLegacyEncoding() );
$store->setLegacyEncoding( 'foo' );
$this->assertSame( 'foo', $store->getLegacyEncoding() );
$this->hideDeprecated( SqlBlobStore::class . '::getLegacyEncodingConversionLang' );
$this->assertNull( $store->getLegacyEncodingConversionLang() );
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::getCacheExpiry()
* @covers \MediaWiki\Storage\SqlBlobStore::setCacheExpiry()
*/
public function testGetSetCacheExpiry() {
$store = $this->getBlobStore();
$this->assertSame( 604800, $store->getCacheExpiry() );
$store->setCacheExpiry( 12 );
$this->assertSame( 12, $store->getCacheExpiry() );
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::getUseExternalStore()
* @covers \MediaWiki\Storage\SqlBlobStore::setUseExternalStore()
*/
public function testGetSetUseExternalStore() {
$store = $this->getBlobStore();
$this->assertFalse( $store->getUseExternalStore() );
$store->setUseExternalStore( true );
$this->assertTrue( $store->getUseExternalStore() );
}
public function provideDecompress() {
yield '(no legacy encoding), empty in empty out' => [ false, '', [], '' ];
yield '(no legacy encoding), string in string out' => [ false, 'A', [], 'A' ];
yield '(no legacy encoding), error flag -> false' => [ false, 'X', [ 'error' ], false ];
yield '(no legacy encoding), string in with gzip flag returns string' => [
// gzip string below generated with gzdeflate( 'AAAABBAAA' )
false, "sttttr\002\022\000", [ 'gzip' ], 'AAAABBAAA',
];
yield '(no legacy encoding), string in with object flag returns false' => [
// gzip string below generated with serialize( 'JOJO' )
false, "s:4:\"JOJO\";", [ 'object' ], false,
];
yield '(no legacy encoding), serialized object in with object flag returns string' => [
false,
// Using a TitleValue object as it has a getText method (which is needed)
serialize( new TitleValue( 0, 'HHJJDDFF' ) ),
[ 'object' ],
'HHJJDDFF',
];
yield '(no legacy encoding), serialized object in with object & gzip flag returns string' => [
false,
// Using a TitleValue object as it has a getText method (which is needed)
gzdeflate( serialize( new TitleValue( 0, '8219JJJ840' ) ) ),
[ 'object', 'gzip' ],
'8219JJJ840',
];
yield '(ISO-8859-1 encoding), string in string out' => [
'ISO-8859-1',
iconv( 'utf-8', 'ISO-8859-1', "1®Àþ1" ),
[],
'1®Àþ1',
];
yield '(ISO-8859-1 encoding), serialized object in with gzip flags returns string' => [
'ISO-8859-1',
gzdeflate( iconv( 'utf-8', 'ISO-8859-1', "4®Àþ4" ) ),
[ 'gzip' ],
'4®Àþ4',
];
yield '(ISO-8859-1 encoding), serialized object in with object flags returns string' => [
'ISO-8859-1',
serialize( new TitleValue( 0, iconv( 'utf-8', 'ISO-8859-1', "3®Àþ3" ) ) ),
[ 'object' ],
'3®Àþ3',
];
yield '(ISO-8859-1 encoding), serialized object in with object & gzip flags returns string' => [
'ISO-8859-1',
gzdeflate( serialize( new TitleValue( 0, iconv( 'utf-8', 'ISO-8859-1', "2®Àþ2" ) ) ) ),
[ 'gzip', 'object' ],
'2®Àþ2',
];
yield 'T184749 (windows-1252 encoding), string in string out' => [
'windows-1252',
iconv( 'utf-8', 'windows-1252', "sammansättningar" ),
[],
'sammansättningar',
];
yield 'T184749 (windows-1252 encoding), string in string out with gzip' => [
'windows-1252',
gzdeflate( iconv( 'utf-8', 'windows-1252', "sammansättningar" ) ),
[ 'gzip' ],
'sammansättningar',
];
}
/**
* @dataProvider provideDecompress
* @covers \MediaWiki\Storage\SqlBlobStore::decompressData
*
* @param string|bool $legacyEncoding
* @param mixed $data
* @param array $flags
* @param mixed $expected
*/
public function testDecompressData( $legacyEncoding, $data, $flags, $expected ) {
$store = $this->getBlobStore();
if ( $legacyEncoding ) {
$store->setLegacyEncoding( $legacyEncoding );
}
$this->assertSame(
$expected,
$store->decompressData( $data, $flags )
);
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::compressData
*/
public function testCompressRevisionTextUtf8() {
$store = $this->getBlobStore();
$row = (object)[ 'old_text' => "Wiki est l'\xc3\xa9cole superieur !" ];
$row->old_flags = $store->compressData( $row->old_text );
$this->assertTrue( strpos( $row->old_flags, 'utf-8' ) !== false,
"Flags should contain 'utf-8'" );
$this->assertFalse( strpos( $row->old_flags, 'gzip' ) !== false,
"Flags should not contain 'gzip'" );
$this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
$row->old_text, "Direct check" );
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::compressData
*/
public function testCompressRevisionTextUtf8Gzip() {
$store = $this->getBlobStore();
$store->setCompressBlobs( true );
$this->checkPHPExtension( 'zlib' );
$row = (object)[ 'old_text' => "Wiki est l'\xc3\xa9cole superieur !" ];
$row->old_flags = $store->compressData( $row->old_text );
$this->assertTrue( strpos( $row->old_flags, 'utf-8' ) !== false,
"Flags should contain 'utf-8'" );
$this->assertTrue( strpos( $row->old_flags, 'gzip' ) !== false,
"Flags should contain 'gzip'" );
$this->assertEquals( "Wiki est l'\xc3\xa9cole superieur !",
gzinflate( $row->old_text ), "Direct check" );
}
public function provideBlobs() {
yield [ '' ];
yield [ 'someText' ];
yield [ "söme\ntäxt" ];
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::getBlob
*/
public function testSimpleStoreGetBlobKnownBad() {
$store = $this->getBlobStore();
$this->assertSame( '', $store->getBlob( 'bad:lost?bug=T12345' ) );
}
/**
* @param string $blob
* @dataProvider provideBlobs
* @covers \MediaWiki\Storage\SqlBlobStore::storeBlob
* @covers \MediaWiki\Storage\SqlBlobStore::getBlob
*/
public function testSimpleStoreGetBlobSimpleRoundtrip( $blob ) {
$store = $this->getBlobStore();
$address = $store->storeBlob( $blob );
$this->assertSame( $blob, $store->getBlob( $address ) );
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::storeBlob
* @covers \MediaWiki\Storage\SqlBlobStore::getBlobBatch
*/
public function testSimpleStorageGetBlobBatchSimpleEmpty() {
$store = $this->getBlobStore();
$this->assertArrayEquals(
[],
$store->getBlobBatch( [] )->getValue()
);
}
/**
* @param string $blob
* @dataProvider provideBlobs
* @covers \MediaWiki\Storage\SqlBlobStore::storeBlob
* @covers \MediaWiki\Storage\SqlBlobStore::getBlobBatch
*/
public function testSimpleStorageGetBlobBatchSimpleRoundtrip( $blob ) {
$store = $this->getBlobStore();
$addresses = [
$store->storeBlob( $blob ),
$store->storeBlob( $blob . '1' )
];
$this->assertArrayEquals(
array_combine( $addresses, [ $blob, $blob . '1' ] ),
$store->getBlobBatch( $addresses )->getValue()
);
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::storeBlob
* @covers \MediaWiki\Storage\SqlBlobStore::getBlobBatch
*/
public function testCachingConsistency() {
$cache = new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
$store = $this->getBlobStore( $cache );
$addrA = $store->storeBlob( 'A' );
$addrB = $store->storeBlob( 'B' );
$addrC = $store->storeBlob( 'C' );
$addrD = $store->storeBlob( 'D' );
$addrX = 'tt:0';
$dataZ = "söme\ntäxt!";
$addrZ = $store->storeBlob( $dataZ );
$this->assertArrayEquals(
[ $addrA => 'A', $addrC => 'C', $addrX => null ],
$store->getBlobBatch( [ $addrA, $addrC, $addrX ] )->getValue(),
false, true
);
$this->assertEquals( 'A', $store->getBlob( $addrA ) );
$this->assertEquals( 'B', $store->getBlob( $addrB ) );
$this->assertEquals( 'C', $store->getBlob( $addrC ) );
$this->assertArrayEquals(
[ $addrB => 'B', $addrC => 'C', $addrD => 'D' ],
$store->getBlobBatch( [ $addrB, $addrC, $addrD ] )->getValue(),
false, true
);
$this->assertEquals( $dataZ, $store->getBlob( $addrZ ) );
$this->assertArrayEquals(
[ $addrA => 'A', $addrZ => $dataZ ],
$store->getBlobBatch( [ $addrA, $addrZ ] )->getValue(),
false, true
);
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::getBlob
*/
public function testSimpleStorageNonExistentBlob() {
$this->expectException( BlobAccessException::class );
$store = $this->getBlobStore();
$store->getBlob( 'tt:this_will_not_exist' );
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::getBlobBatch
*/
public function testSimpleStorageNonExistentBlobBatch() {
$store = $this->getBlobStore();
$result = $store->getBlobBatch( [
'tt:this_will_not_exist',
'tt:0',
'tt:-1',
'tt:10000',
'bla:1001'
] );
$resultBlobs = $result->getValue();
$expected = [
'tt:this_will_not_exist' => null,
'tt:0' => null,
'tt:-1' => null,
'tt:10000' => null,
'bla:1001' => null
];
ksort( $expected );
ksort( $resultBlobs );
$this->assertSame( $expected, $resultBlobs );
$this->assertSame( [
[
'type' => 'warning',
'message' => 'internalerror',
'params' => [
'Bad blob address: tt:this_will_not_exist. Use findBadBlobs.php to remedy.'
]
],
[
'type' => 'warning',
'message' => 'internalerror',
'params' => [
'Bad blob address: tt:0. Use findBadBlobs.php to remedy.'
]
],
[
'type' => 'warning',
'message' => 'internalerror',
'params' => [
'Bad blob address: tt:-1. Use findBadBlobs.php to remedy.'
]
],
[
'type' => 'warning',
'message' => 'internalerror',
'params' => [
'Unknown blob address schema: bla. Use findBadBlobs.php to remedy.'
]
],
[
'type' => 'warning',
'message' => 'internalerror',
'params' => [
'Unable to fetch blob at tt:10000. Use findBadBlobs.php to remedy.'
]
]
], $result->getErrors() );
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::getBlobBatch
*/
public function testSimpleStoragePartialNonExistentBlobBatch() {
$store = $this->getBlobStore();
$address = $store->storeBlob( 'test_data' );
$result = $store->getBlobBatch( [ $address, 'tt:this_will_not_exist_too' ] );
$resultBlobs = $result->getValue();
$expected = [
$address => 'test_data',
'tt:this_will_not_exist_too' => null
];
ksort( $expected );
ksort( $resultBlobs );
$this->assertSame( $expected, $resultBlobs );
$this->assertSame( [
[
'type' => 'warning',
'message' => 'internalerror',
'params' => [
'Bad blob address: tt:this_will_not_exist_too. Use findBadBlobs.php to remedy.'
]
],
], $result->getErrors() );
}
/**
* @dataProvider provideBlobs
* @covers \MediaWiki\Storage\SqlBlobStore::storeBlob
* @covers \MediaWiki\Storage\SqlBlobStore::getBlob
*/
public function testSimpleStoreGetBlobSimpleRoundtripWindowsLegacyEncoding( $blob ) {
$store = $this->getBlobStore();
$store->setLegacyEncoding( 'windows-1252' );
$address = $store->storeBlob( $blob );
$this->assertSame( $blob, $store->getBlob( $address ) );
}
/**
* @dataProvider provideBlobs
* @covers \MediaWiki\Storage\SqlBlobStore::storeBlob
* @covers \MediaWiki\Storage\SqlBlobStore::getBlob
*/
public function testSimpleStoreGetBlobSimpleRoundtripWindowsLegacyEncodingGzip( $blob ) {
// FIXME: fails under postgres - T298692
$this->markTestSkippedIfDbType( 'postgres' );
$store = $this->getBlobStore();
$store->setLegacyEncoding( 'windows-1252' );
$store->setCompressBlobs( true );
$address = $store->storeBlob( $blob );
$this->assertSame( $blob, $store->getBlob( $address ) );
}
public function provideGetTextIdFromAddress() {
yield [ 'tt:17', 17 ];
yield [ 'xy:17', null ];
yield [ 'xy:xyzzy', null ];
}
/**
* @dataProvider provideGetTextIdFromAddress
*/
public function testGetTextIdFromAddress( $address, $textId ) {
$store = $this->getBlobStore();
$this->assertSame( $textId, $store->getTextIdFromAddress( $address ) );
}
public function provideGetTextIdFromAddressInvalidArgumentException() {
yield [ 'tt:xy' ];
yield [ 'tt:0' ];
yield [ 'tt:' ];
yield [ 'xy' ];
yield [ '' ];
}
/**
* @dataProvider provideGetTextIdFromAddressInvalidArgumentException
*/
public function testGetTextIdFromAddressInvalidArgumentException( $address ) {
$this->expectException( InvalidArgumentException::class );
$store = $this->getBlobStore();
$store->getTextIdFromAddress( $address );
}
public function testMakeAddressFromTextId() {
$this->assertSame( 'tt:17', SqlBlobStore::makeAddressFromTextId( 17 ) );
}
public function providerSplitBlobAddress() {
yield [ 'tt:123', 'tt', '123', [] ];
yield [ 'bad:foo?x=y', 'bad', 'foo', [ 'x' => 'y' ] ];
yield [ 'http://test.com/foo/bar?a=b', 'http', 'test.com/foo/bar', [ 'a' => 'b' ] ];
}
/**
* @dataProvider providerSplitBlobAddress
*/
public function testSplitBlobAddress( $address, $schema, $id, $parameters ) {
$this->assertSame( 'tt:17', SqlBlobStore::makeAddressFromTextId( 17 ) );
}
public function provideExpandBlob() {
yield 'Generic test' => [
'This is a goat of revision text.',
'old_flags' => '',
'old_text' => 'This is a goat of revision text.',
];
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::expandBlob
* @dataProvider provideExpandBlob
*/
public function testExpandBlob( $expected, $flags, $raw ) {
$blobStore = $this->getBlobStore();
$this->assertEquals(
$expected,
$blobStore->expandBlob( $raw, explode( ',', $flags ) )
);
}
public function provideExpandBlobWithZlibExtension() {
yield 'Generic gzip test' => [
'This is a small goat of revision text.',
'old_flags' => 'gzip',
'old_text' => gzdeflate( 'This is a small goat of revision text.' ),
];
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::expandBlob
* @dataProvider provideExpandBlobWithZlibExtension
*/
public function testGetRevisionWithZlibExtension( $expected, $flags, $raw ) {
$this->checkPHPExtension( 'zlib' );
$blobStore = $this->getBlobStore();
$this->assertEquals(
$expected,
$blobStore->expandBlob( $raw, explode( ',', $flags ) )
);
}
public function provideExpandBlobWithZlibExtension_badData() {
yield 'Generic gzip test' => [
'old_flags' => 'gzip',
'old_text' => 'DEAD BEEF',
];
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::expandBlob
* @dataProvider provideExpandBlobWithZlibExtension_badData
*/
public function testGetRevisionWithZlibExtension_badData( $flags, $raw ) {
$this->checkPHPExtension( 'zlib' );
$blobStore = $this->getBlobStore();
$this->assertFalse(
@$blobStore->expandBlob( $raw, explode( ',', $flags ) )
);
}
public function provideExpandBlobWithLegacyEncoding() {
yield 'Utf8Native' => [
"Wiki est l'\xc3\xa9cole superieur !",
'iso-8859-1',
'old_flags' => 'utf-8',
'old_text' => "Wiki est l'\xc3\xa9cole superieur !",
];
yield 'Utf8Legacy' => [
"Wiki est l'\xc3\xa9cole superieur !",
'iso-8859-1',
'old_flags' => '',
'old_text' => "Wiki est l'\xe9cole superieur !",
];
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::expandBlob
* @dataProvider provideExpandBlobWithLegacyEncoding
*/
public function testGetRevisionWithLegacyEncoding( $expected, $encoding, $flags, $raw ) {
$blobStore = $this->getBlobStore();
$blobStore->setLegacyEncoding( $encoding );
$this->assertEquals(
$expected,
$blobStore->expandBlob( $raw, explode( ',', $flags ) )
);
}
public function provideExpandBlobWithGzipAndLegacyEncoding() {
/**
* WARNING!
* Do not set the external flag!
* Otherwise, getRevisionText will hit the live database (if ExternalStore is enabled)!
*/
yield 'Utf8NativeGzip' => [
"Wiki est l'\xc3\xa9cole superieur !",
'iso-8859-1',
'old_flags' => 'gzip,utf-8',
'old_text' => gzdeflate( "Wiki est l'\xc3\xa9cole superieur !" ),
];
yield 'Utf8LegacyGzip' => [
"Wiki est l'\xc3\xa9cole superieur !",
'iso-8859-1',
'old_flags' => 'gzip',
'old_text' => gzdeflate( "Wiki est l'\xe9cole superieur !" ),
];
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::expandBlob
* @dataProvider provideExpandBlobWithGzipAndLegacyEncoding
*/
public function testGetRevisionWithGzipAndLegacyEncoding( $expected, $encoding, $flags, $raw ) {
$this->checkPHPExtension( 'zlib' );
$blobStore = $this->getBlobStore();
$blobStore->setLegacyEncoding( $encoding );
$this->assertEquals(
$expected,
$blobStore->expandBlob( $raw, explode( ',', $flags ) )
);
}
public function provideTestGetRevisionText_returnsDecompressedTextFieldWhenNotExternal() {
yield 'Just text' => [
'old_flags' => '',
'old_text' => 'SomeText',
'SomeText'
];
// gzip string below generated with gzdeflate( 'AAAABBAAA' )
yield 'gzip text' => [
'old_flags' => 'gzip',
'old_text' => "sttttr\002\022\000",
'AAAABBAAA'
];
}
/**
* @dataProvider provideTestGetRevisionText_returnsDecompressedTextFieldWhenNotExternal
* @covers \MediaWiki\Storage\SqlBlobStore::expandBlob
*/
public function testGetRevisionText_returnsDecompressedTextFieldWhenNotExternal(
$flags,
$raw,
$expected
) {
$blobStore = $this->getBlobStore();
$this->assertSame( $expected, $blobStore->expandBlob( $raw, $flags ) );
}
public function provideTestGetRevisionText_external_returnsFalseWhenNotEnoughUrlParts() {
yield 'Just some text' => [ 'someNonUrlText' ];
yield 'No second URL part' => [ 'someProtocol://' ];
}
/**
* @dataProvider provideTestGetRevisionText_external_returnsFalseWhenNotEnoughUrlParts
* @covers \MediaWiki\Storage\SqlBlobStore::expandBlob
*/
public function testGetRevisionText_external_returnsFalseWhenNotEnoughUrlParts(
$text
) {
$blobStore = $this->getBlobStore();
$this->assertFalse(
$blobStore->expandBlob(
$text,
[ 'external' ]
)
);
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::expandBlob
*/
public function testGetRevisionText_external_noOldId() {
$this->setService(
'ExternalStoreFactory',
new ExternalStoreFactory( [ 'ForTesting' ], [ 'ForTesting://cluster1' ], 'test-id' )
);
$blobStore = $this->getBlobStore();
$this->assertSame(
'AAAABBAAA',
$blobStore->expandBlob(
'ForTesting://cluster1/12345',
[ 'external' , 'gzip' ]
)
);
}
private function getWANObjectCache() {
return new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
}
/**
* @covers \MediaWiki\Storage\SqlBlobStore::expandBlob
*/
public function testGetRevisionText_external_oldId() {
$cache = $this->getWANObjectCache();
$this->setService( 'MainWANObjectCache', $cache );
$this->setService(
'ExternalStoreFactory',
new ExternalStoreFactory( [ 'ForTesting' ], [ 'ForTesting://cluster1' ], 'test-id' )
);
$lb = $this->getMockBuilder( LoadBalancer::class )
->disableOriginalConstructor()
->getMock();
$access = $this->getServiceContainer()->getExternalStoreAccess();
$blobStore = new SqlBlobStore( $lb, $access, $cache );
$this->assertSame(
'AAAABBAAA',
$blobStore->expandBlob(
'ForTesting://cluster1/12345',
'external,gzip',
'tt:7777'
)
);
$cacheKey = $cache->makeGlobalKey(
'SqlBlobStore-blob',
$lb->getLocalDomainID(),
'tt:7777'
);
$this->assertSame( 'AAAABBAAA', $cache->get( $cacheKey ) );
}
}