namespace MediaWiki\Tests\Revision;
use CommentStore;
-use HashBagOStuff;
use InvalidArgumentException;
-use Language;
use MediaWiki\MediaWikiServices;
use MediaWiki\Revision\RevisionAccessException;
use MediaWiki\Revision\RevisionStore;
use MediaWiki\Revision\SlotRoleRegistry;
-use MediaWiki\Revision\SlotRecord;
use MediaWiki\Storage\SqlBlobStore;
+use Wikimedia\Rdbms\ILoadBalancer;
+use Wikimedia\Rdbms\MaintainableDBConnRef;
use MediaWikiTestCase;
use MWException;
-use Title;
use WANObjectCache;
use Wikimedia\Rdbms\IDatabase;
use Wikimedia\Rdbms\LoadBalancer;
use Wikimedia\TestingAccessWrapper;
-use WikitextContent;
/**
* Tests RevisionStore
*/
class RevisionStoreTest extends MediaWikiTestCase {
- private function useTextId() {
- global $wgMultiContentRevisionSchemaMigrationStage;
-
- return (bool)( $wgMultiContentRevisionSchemaMigrationStage & SCHEMA_COMPAT_READ_OLD );
- }
-
/**
* @param LoadBalancer $loadBalancer
* @param SqlBlobStore $blobStore
->disableOriginalConstructor()->getMock();
}
+ /**
+ * @param ILoadBalancer $mockLoadBalancer
+ * @param Database $db
+ * @return callable
+ */
+ private function getMockDBConnRefCallback( ILoadBalancer $mockLoadBalancer, IDatabase $db ) {
+ return function ( $i, $g, $domain, $flg ) use ( $mockLoadBalancer, $db ) {
+ return new MaintainableDBConnRef( $mockLoadBalancer, $db, $i );
+ };
+ }
+
/**
* @return \PHPUnit_Framework_MockObject_MockObject|SqlBlobStore
*/
public function provideSetContentHandlerUseDB() {
return [
- // ContentHandlerUseDB can be true of false pre migration.
- [ false, SCHEMA_COMPAT_OLD, false ],
- [ true, SCHEMA_COMPAT_OLD, false ],
+ // ContentHandlerUseDB can be true or false pre migration.
// During and after migration it can not be false...
[ false, SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, true ],
[ false, SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, true ],
$this->setService( 'DBLoadBalancer', $mockLoadBalancer );
$db = $this->getMockDatabase();
- // Title calls wfGetDB() which uses a regular Connection
+ // RevisionStore uses getConnectionRef
+ $mockLoadBalancer->expects( $this->any() )
+ ->method( 'getConnectionRef' )
+ ->willReturnCallback( $this->getMockDBConnRefCallback( $mockLoadBalancer, $db ) );
+ // Title calls wfGetDB() which uses getMaintenanceConnectionRef
$mockLoadBalancer->expects( $this->atLeastOnce() )
- ->method( 'getConnection' )
- ->willReturn( $db );
+ ->method( 'getMaintenanceConnectionRef' )
+ ->willReturnCallback( $this->getMockDBConnRefCallback( $mockLoadBalancer, $db ) );
// First call to Title::newFromID, faking no result (db lag?)
$db->expects( $this->at( 0 ) )
$this->setService( 'DBLoadBalancer', $mockLoadBalancer );
$db = $this->getMockDatabase();
- // Title calls wfGetDB() which uses a regular Connection
+ // Title calls wfGetDB() which uses getMaintenanceConnectionRef
// 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 );
+ ->willReturnCallback( $this->getMockDBConnRefCallback( $mockLoadBalancer, $db ) );
+ // Title calls wfGetDB() which uses getMaintenanceConnectionRef
+ $mockLoadBalancer->expects( $this->exactly( 2 ) )
+ ->method( 'getMaintenanceConnectionRef' )
+ ->willReturnCallback( $this->getMockDBConnRefCallback( $mockLoadBalancer, $db ) );
// First call to Title::newFromID, faking no result (db lag?)
$db->expects( $this->at( 0 ) )
$this->setService( 'DBLoadBalancer', $mockLoadBalancer );
$db = $this->getMockDatabase();
- // Title calls wfGetDB() which uses a regular Connection
- $mockLoadBalancer->expects( $this->atLeastOnce() )
- ->method( 'getConnection' )
- ->willReturn( $db );
- // RevisionStore getTitle uses a ConnectionRef
$mockLoadBalancer->expects( $this->atLeastOnce() )
->method( 'getConnectionRef' )
- ->willReturn( $db );
+ ->willReturnCallback( $this->getMockDBConnRefCallback( $mockLoadBalancer, $db ) );
+ // Title calls wfGetDB() which uses getMaintenanceConnectionRef
+ // RevisionStore getTitle uses getMaintenanceConnectionRef
+ $mockLoadBalancer->expects( $this->atLeastOnce() )
+ ->method( 'getMaintenanceConnectionRef' )
+ ->willReturnCallback( $this->getMockDBConnRefCallback( $mockLoadBalancer, $db ) );
// First call to Title::newFromID, faking no result (db lag?)
$db->expects( $this->at( 0 ) )
$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
+ // RevisionStore uses getMaintenanceConnectionRef
$mockLoadBalancer->expects( $this->atLeastOnce() )
->method( 'getConnectionRef' )
- ->willReturn( $db );
+ ->willReturnCallback( $this->getMockDBConnRefCallback( $mockLoadBalancer, $db ) );
+ // Title calls wfGetDB() which uses getMaintenanceConnectionRef
+ $mockLoadBalancer->expects( $this->exactly( 2 ) )
+ ->method( 'getMaintenanceConnectionRef' )
+ ->willReturnCallback( $this->getMockDBConnRefCallback( $mockLoadBalancer, $db ) );
// First call to Title::newFromID, faking no result (db lag?)
$db->expects( $this->at( 0 ) )
$this->setService( 'DBLoadBalancer', $mockLoadBalancer );
$db = $this->getMockDatabase();
- // Title calls wfGetDB() which uses a regular Connection
+ // Title calls wfGetDB() which uses getMaintenanceConnectionRef
// 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 ) {
+ // Title::newFromID uses getMaintenanceConnectionRef
+ foreach ( [
+ 'getConnectionRef', 'getMaintenanceConnectionRef'
+ ] as $method ) {
$mockLoadBalancer->expects( $this->exactly( 2 ) )
->method( $method )
->willReturnCallback( function ( $masterOrReplica ) use ( $db ) {
$store->getTitle( 1, 2, RevisionStore::READ_NORMAL );
}
- public function provideNewRevisionFromRow_legacyEncoding_applied() {
- yield 'windows-1252, old_flags is empty' => [
- 'windows-1252',
- 'en',
- [
- 'old_flags' => '',
- 'old_text' => "S\xF6me Content",
- ],
- 'Söme Content'
- ];
-
- yield 'windows-1252, old_flags is null' => [
- 'windows-1252',
- 'en',
- [
- 'old_flags' => null,
- 'old_text' => "S\xF6me Content",
- ],
- 'Söme Content'
- ];
- }
-
- /**
- * @dataProvider provideNewRevisionFromRow_legacyEncoding_applied
- *
- * @covers \MediaWiki\Revision\RevisionStore::newRevisionFromRow
- */
- public function testNewRevisionFromRow_legacyEncoding_applied( $encoding, $locale, $row, $text ) {
- if ( !$this->useTextId() ) {
- $this->markTestSkipped( 'No longer applicable with MCR schema' );
- }
-
- $cache = new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
- $services = MediaWikiServices::getInstance();
- $lb = $services->getDBLoadBalancer();
- $access = $services->getExternalStoreAccess();
-
- $blobStore = new SqlBlobStore( $lb, $access, $cache );
-
- $blobStore->setLegacyEncoding( $encoding, Language::factory( $locale ) );
-
- $store = $this->getRevisionStore( $lb, $blobStore, $cache );
-
- $record = $store->newRevisionFromRow(
- $this->makeRow( $row ),
- 0,
- Title::newFromText( __METHOD__ . '-UTPage' )
- );
-
- $this->assertSame( $text, $record->getContent( SlotRecord::MAIN )->serialize() );
- }
-
- /**
- * @covers \MediaWiki\Revision\RevisionStore::newRevisionFromRow
- */
- public function testNewRevisionFromRow_legacyEncoding_ignored() {
- if ( !$this->useTextId() ) {
- $this->markTestSkipped( 'No longer applicable with MCR schema' );
- }
-
- $row = [
- 'old_flags' => 'utf-8',
- 'old_text' => 'Söme Content',
- ];
-
- $cache = new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
- $services = MediaWikiServices::getInstance();
- $lb = $services->getDBLoadBalancer();
- $access = $services->getExternalStoreAccess();
-
- $blobStore = new SqlBlobStore( $lb, $access, $cache );
- $blobStore->setLegacyEncoding( 'windows-1252', Language::factory( 'en' ) );
-
- $store = $this->getRevisionStore( $lb, $blobStore, $cache );
-
- $record = $store->newRevisionFromRow(
- $this->makeRow( $row ),
- 0,
- Title::newFromText( __METHOD__ . '-UTPage' )
- );
- $this->assertSame( 'Söme Content', $record->getContent( SlotRecord::MAIN )->serialize() );
- }
-
- private function makeRow( array $array ) {
- $row = $array + [
- 'rev_id' => 7,
- 'rev_page' => 5,
- 'rev_timestamp' => '20110101000000',
- 'rev_user_text' => 'Tester',
- 'rev_user' => 17,
- 'rev_minor_edit' => 0,
- 'rev_deleted' => 0,
- 'rev_len' => 100,
- 'rev_parent_id' => 0,
- 'rev_sha1' => 'deadbeef',
- 'rev_comment_text' => 'Testing',
- 'rev_comment_data' => '{}',
- 'rev_comment_cid' => 111,
- 'page_namespace' => 0,
- 'page_title' => 'TEST',
- 'page_id' => 5,
- 'page_latest' => 7,
- 'page_is_redirect' => 0,
- 'page_len' => 100,
- 'user_name' => 'Tester',
- ];
-
- if ( $this->useTextId() ) {
- $row += [
- 'rev_content_format' => CONTENT_FORMAT_TEXT,
- 'rev_content_model' => CONTENT_MODEL_TEXT,
- 'rev_text_id' => 11,
- 'old_id' => 11,
- 'old_text' => 'Hello World',
- 'old_flags' => 'utf-8',
- ];
- } elseif ( !isset( $row['content'] ) && isset( $array['old_text'] ) ) {
- $row['content'] = [
- 'main' => new WikitextContent( $array['old_text'] ),
- ];
- }
-
- return (object)$row;
- }
-
public function provideMigrationConstruction() {
return [
- [ SCHEMA_COMPAT_OLD, false ],
[ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, false ],
[ SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, false ],
[ SCHEMA_COMPAT_NEW, false ],