/**
* @covers ExternalStoreFactory
+ * @covers ExternalStoreAccess
*/
-class ExternalStoreFactoryTest extends PHPUnit\Framework\TestCase {
+class ExternalStoreFactoryTest extends MediaWikiTestCase {
use MediaWikiCoversValidator;
- public function testExternalStoreFactory_noStores() {
- $factory = new ExternalStoreFactory( [] );
- $this->assertFalse( $factory->getStoreObject( 'ForTesting' ) );
- $this->assertFalse( $factory->getStoreObject( 'foo' ) );
+ /**
+ * @expectedException ExternalStoreException
+ */
+ public function testExternalStoreFactory_noStores1() {
+ $factory = new ExternalStoreFactory( [], [], 'test-id' );
+ $factory->getStore( 'ForTesting' );
+ }
+
+ /**
+ * @expectedException ExternalStoreException
+ */
+ public function testExternalStoreFactory_noStores2() {
+ $factory = new ExternalStoreFactory( [], [], 'test-id' );
+ $factory->getStore( 'foo' );
}
public function provideStoreNames() {
* @dataProvider provideStoreNames
*/
public function testExternalStoreFactory_someStore_protoMatch( $proto ) {
- $factory = new ExternalStoreFactory( [ 'ForTesting' ] );
- $store = $factory->getStoreObject( $proto );
+ $factory = new ExternalStoreFactory( [ 'ForTesting' ], [], 'test-id' );
+ $store = $factory->getStore( $proto );
$this->assertInstanceOf( ExternalStoreForTesting::class, $store );
}
/**
* @dataProvider provideStoreNames
+ * @expectedException ExternalStoreException
*/
public function testExternalStoreFactory_someStore_noProtoMatch( $proto ) {
- $factory = new ExternalStoreFactory( [ 'SomeOtherClassName' ] );
- $store = $factory->getStoreObject( $proto );
- $this->assertFalse( $store );
+ $factory = new ExternalStoreFactory( [ 'SomeOtherClassName' ], [], 'test-id' );
+ $factory->getStore( $proto );
+ }
+
+ /**
+ * @covers ExternalStoreFactory::getProtocols
+ * @covers ExternalStoreFactory::getWriteBaseUrls
+ * @covers ExternalStoreFactory::getStore
+ */
+ public function testStoreFactoryBasic() {
+ $active = [ 'memory' ];
+ $defaults = [ 'memory://cluster1', 'memory://cluster2' ];
+ $esFactory = new ExternalStoreFactory( $active, $defaults, 'db-prefix' );
+
+ $this->assertEquals( $active, $esFactory->getProtocols() );
+ $this->assertEquals( $defaults, $esFactory->getWriteBaseUrls() );
+
+ /** @var ExternalStoreMemory $store */
+ $store = $esFactory->getStore( 'memory' );
+ $this->assertInstanceOf( ExternalStoreMemory::class, $store );
+ $this->assertEquals( false, $store->isReadOnly( 'cluster1' ) );
+ $this->assertEquals( false, $store->isReadOnly( 'cluster2' ) );
+ $this->assertEquals( true, $store->isReadOnly( 'clusterOld' ) );
+
+ $lb = $this->getMockBuilder( \Wikimedia\Rdbms\LoadBalancer::class )
+ ->disableOriginalConstructor()->getMock();
+ $lb->expects( $this->any() )->method( 'getReadOnlyReason' )->willReturn( 'Locked' );
+ $lbFactory = $this->getMockBuilder( \Wikimedia\Rdbms\LBFactory::class )
+ ->disableOriginalConstructor()->getMock();
+ $lbFactory->expects( $this->any() )->method( 'getExternalLB' )->willReturn( $lb );
+
+ $this->setService( 'DBLoadBalancerFactory', $lbFactory );
+
+ $active = [ 'db', 'mwstore' ];
+ $defaults = [ 'db://clusterX' ];
+ $esFactory = new ExternalStoreFactory( $active, $defaults, 'db-prefix' );
+ $this->assertEquals( $active, $esFactory->getProtocols() );
+ $this->assertEquals( $defaults, $esFactory->getWriteBaseUrls() );
+
+ $store->clear();
}
+ /**
+ * @covers ExternalStoreFactory::getStoreForUrl
+ * @covers ExternalStoreFactory::getStoreLocationFromUrl
+ */
+ public function testStoreFactoryReadWrite() {
+ $active = [ 'memory' ]; // active store types
+ $defaults = [ 'memory://cluster1', 'memory://cluster2' ];
+ $esFactory = new ExternalStoreFactory( $active, $defaults, 'db-prefix' );
+ $access = new ExternalStoreAccess( $esFactory );
+
+ /** @var ExternalStoreMemory $storeLocal */
+ $storeLocal = $esFactory->getStore( 'memory' );
+ /** @var ExternalStoreMemory $storeOther */
+ $storeOther = $esFactory->getStore( 'memory', [ 'domain' => 'other' ] );
+ $this->assertInstanceOf( ExternalStoreMemory::class, $storeLocal );
+ $this->assertInstanceOf( ExternalStoreMemory::class, $storeOther );
+
+ $v1 = wfRandomString();
+ $v2 = wfRandomString();
+ $v3 = wfRandomString();
+
+ $this->assertEquals( false, $storeLocal->fetchFromURL( 'memory://cluster1/1' ) );
+
+ $url1 = 'memory://cluster1/1';
+ $this->assertEquals(
+ $url1,
+ $esFactory->getStoreForUrl( 'memory://cluster1' )
+ ->store( $esFactory->getStoreLocationFromUrl( 'memory://cluster1' ), $v1 )
+ );
+ $this->assertEquals(
+ $v1,
+ $esFactory->getStoreForUrl( 'memory://cluster1/1' )
+ ->fetchFromURL( 'memory://cluster1/1' )
+ );
+ $this->assertEquals( $v1, $storeLocal->fetchFromURL( 'memory://cluster1/1' ) );
+
+ $url2 = $access->insert( $v2 );
+ $url3 = $access->insert( $v3, [ 'domain' => 'other' ] );
+ $this->assertNotFalse( $url2 );
+ $this->assertNotFalse( $url3 );
+ // There is only one active store type
+ $this->assertEquals( $v2, $storeLocal->fetchFromURL( $url2 ) );
+ $this->assertEquals( $v3, $storeOther->fetchFromURL( $url3 ) );
+ $this->assertEquals( false, $storeOther->fetchFromURL( $url2 ) );
+ $this->assertEquals( false, $storeLocal->fetchFromURL( $url3 ) );
+
+ $res = $access->fetchFromURLs( [ $url1, $url2, $url3 ] );
+ $this->assertEquals( [ $url1 => $v1, $url2 => $v2, $url3 => false ], $res, "Local-only" );
+
+ $storeLocal->clear();
+ $storeOther->clear();
+ }
}