use HashBagOStuff;
use Language;
+use MediaWiki\MediaWikiServices;
use MediaWiki\Storage\RevisionAccessException;
use MediaWiki\Storage\RevisionStore;
use MediaWiki\Storage\SqlBlobStore;
return new RevisionStore(
$loadBalancer ? $loadBalancer : $this->getMockLoadBalancer(),
$blobStore ? $blobStore : $this->getMockSqlBlobStore(),
- $WANObjectCache ? $WANObjectCache : $this->getHashWANObjectCache()
+ $WANObjectCache ? $WANObjectCache : $this->getHashWANObjectCache(),
+ MediaWikiServices::getInstance()->getCommentStore()
);
}
* @covers \MediaWiki\Storage\RevisionStore::getQueryInfo
*/
public function testGetQueryInfo( $contentHandlerUseDb, $options, $expected ) {
+ $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
+ $this->overrideMwServices();
$store = $this->getRevisionStore();
$store->setContentHandlerUseDB( $contentHandlerUseDb );
- $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
$this->assertEquals( $expected, $store->getQueryInfo( $options ) );
}
* @covers \MediaWiki\Storage\RevisionStore::getArchiveQueryInfo
*/
public function testGetArchiveQueryInfo_contentHandlerDb() {
+ $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
+ $this->overrideMwServices();
$store = $this->getRevisionStore();
$store->setContentHandlerUseDB( true );
- $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
$this->assertEquals(
[
'tables' => [
* @covers \MediaWiki\Storage\RevisionStore::getArchiveQueryInfo
*/
public function testGetArchiveQueryInfo_noContentHandlerDb() {
+ $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
+ $this->overrideMwServices();
$store = $this->getRevisionStore();
$store->setContentHandlerUseDB( false );
- $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
$this->assertEquals(
[
'tables' => [
$this->assertSame( 'Food', $title->getDBkey() );
}
+ public function testGetTitle_successFromPageIdOnFallback() {
+ $mockLoadBalancer = $this->getMockLoadBalancer();
+ // Title calls wfGetDB() so we have to set the main service
+ $this->setService( 'DBLoadBalancer', $mockLoadBalancer );
+
+ $db = $this->getMockDatabase();
+ // Title calls wfGetDB() which uses a regular Connection
+ // Assert that the first call uses a REPLICA and the second falls back to master
+ $mockLoadBalancer->expects( $this->exactly( 2 ) )
+ ->method( 'getConnection' )
+ ->willReturn( $db );
+ // RevisionStore getTitle uses a ConnectionRef
+ $mockLoadBalancer->expects( $this->atLeastOnce() )
+ ->method( 'getConnectionRef' )
+ ->willReturn( $db );
+
+ // First call to Title::newFromID, faking no result (db lag?)
+ $db->expects( $this->at( 0 ) )
+ ->method( 'selectRow' )
+ ->with(
+ 'page',
+ $this->anything(),
+ [ 'page_id' => 1 ]
+ )
+ ->willReturn( false );
+
+ // First select using rev_id, faking no result (db lag?)
+ $db->expects( $this->at( 1 ) )
+ ->method( 'selectRow' )
+ ->with(
+ [ 'revision', 'page' ],
+ $this->anything(),
+ [ 'rev_id' => 2 ]
+ )
+ ->willReturn( false );
+
+ // Second call to Title::newFromID, no result
+ $db->expects( $this->at( 2 ) )
+ ->method( 'selectRow' )
+ ->with(
+ 'page',
+ $this->anything(),
+ [ 'page_id' => 1 ]
+ )
+ ->willReturn( (object)[
+ 'page_namespace' => '2',
+ 'page_title' => 'Foodey',
+ ] );
+
+ $store = $this->getRevisionStore( $mockLoadBalancer );
+ $title = $store->getTitle( 1, 2, RevisionStore::READ_NORMAL );
+
+ $this->assertSame( 2, $title->getNamespace() );
+ $this->assertSame( 'Foodey', $title->getDBkey() );
+ }
+
public function testGetTitle_successFromRevId() {
$mockLoadBalancer = $this->getMockLoadBalancer();
// Title calls wfGetDB() so we have to set the main service
$this->assertSame( 'Food2', $title->getDBkey() );
}
- /**
- * @covers \MediaWiki\Storage\RevisionStore::getTitle
- */
- public function testGetTitle_throwsExceptionAfterFallbacks() {
+ public function testGetTitle_successFromRevIdOnFallback() {
$mockLoadBalancer = $this->getMockLoadBalancer();
// Title calls wfGetDB() so we have to set the main service
$this->setService( 'DBLoadBalancer', $mockLoadBalancer );
$db = $this->getMockDatabase();
// Title calls wfGetDB() which uses a regular Connection
- $mockLoadBalancer->expects( $this->atLeastOnce() )
+ // Assert that the first call uses a REPLICA and the second falls back to master
+ $mockLoadBalancer->expects( $this->exactly( 2 ) )
->method( 'getConnection' )
->willReturn( $db );
// RevisionStore getTitle uses a ConnectionRef
)
->willReturn( false );
+ // Second call to Title::newFromID, no result
+ $db->expects( $this->at( 2 ) )
+ ->method( 'selectRow' )
+ ->with(
+ 'page',
+ $this->anything(),
+ [ 'page_id' => 1 ]
+ )
+ ->willReturn( false );
+
+ // Second select using rev_id, result
+ $db->expects( $this->at( 3 ) )
+ ->method( 'selectRow' )
+ ->with(
+ [ 'revision', 'page' ],
+ $this->anything(),
+ [ 'rev_id' => 2 ]
+ )
+ ->willReturn( (object)[
+ 'page_namespace' => '2',
+ 'page_title' => 'Foodey',
+ ] );
+
+ $store = $this->getRevisionStore( $mockLoadBalancer );
+ $title = $store->getTitle( 1, 2, RevisionStore::READ_NORMAL );
+
+ $this->assertSame( 2, $title->getNamespace() );
+ $this->assertSame( 'Foodey', $title->getDBkey() );
+ }
+
+ /**
+ * @covers \MediaWiki\Storage\RevisionStore::getTitle
+ */
+ public function testGetTitle_correctFallbackAndthrowsExceptionAfterFallbacks() {
+ $mockLoadBalancer = $this->getMockLoadBalancer();
+ // Title calls wfGetDB() so we have to set the main service
+ $this->setService( 'DBLoadBalancer', $mockLoadBalancer );
+
+ $db = $this->getMockDatabase();
+ // Title calls wfGetDB() which uses a regular Connection
+ // Assert that the first call uses a REPLICA and the second falls back to master
+
+ // RevisionStore getTitle uses getConnectionRef
+ // Title::newFromID uses getConnection
+ foreach ( [ 'getConnection', 'getConnectionRef' ] as $method ) {
+ $mockLoadBalancer->expects( $this->exactly( 2 ) )
+ ->method( $method )
+ ->willReturnCallback( function ( $masterOrReplica ) use ( $db ) {
+ static $callCounter = 0;
+ $callCounter++;
+ // The first call should be to a REPLICA, and the second a MASTER.
+ if ( $callCounter === 1 ) {
+ $this->assertSame( DB_REPLICA, $masterOrReplica );
+ } elseif ( $callCounter === 2 ) {
+ $this->assertSame( DB_MASTER, $masterOrReplica );
+ }
+ return $db;
+ } );
+ }
+ // First and third call to Title::newFromID, faking no result
+ foreach ( [ 0, 2 ] as $counter ) {
+ $db->expects( $this->at( $counter ) )
+ ->method( 'selectRow' )
+ ->with(
+ 'page',
+ $this->anything(),
+ [ 'page_id' => 1 ]
+ )
+ ->willReturn( false );
+ }
+
+ foreach ( [ 1, 3 ] as $counter ) {
+ $db->expects( $this->at( $counter ) )
+ ->method( 'selectRow' )
+ ->with(
+ [ 'revision', 'page' ],
+ $this->anything(),
+ [ 'rev_id' => 2 ]
+ )
+ ->willReturn( false );
+ }
+
$store = $this->getRevisionStore( $mockLoadBalancer );
$this->setExpectedException( RevisionAccessException::class );
$blobStore = new SqlBlobStore( wfGetLB(), $cache );
$blobStore->setLegacyEncoding( $encoding, Language::factory( $locale ) );
- $store = new RevisionStore( wfGetLB(), $blobStore, $cache );
+ $store = $this->getRevisionStore( wfGetLB(), $blobStore, $cache );
$record = $store->newRevisionFromRow(
$this->makeRow( $row ),
$blobStore = new SqlBlobStore( wfGetLB(), $cache );
$blobStore->setLegacyEncoding( 'windows-1252', Language::factory( 'en' ) );
- $store = new RevisionStore( wfGetLB(), $blobStore, $cache );
+ $store = $this->getRevisionStore( wfGetLB(), $blobStore, $cache );
$record = $store->newRevisionFromRow(
$this->makeRow( $row ),