From 452c71663bd143b74af1af7c88d423b4178cfff5 Mon Sep 17 00:00:00 2001 From: daniel Date: Mon, 3 Sep 2018 19:15:37 +0200 Subject: [PATCH] Consolidate tests for getQueryInfo() and related methods. This consolidates tests for getQueryInfo, getArchiveQueryInfo, getSlotQueryInfo, and similar methods that help application logic be compatible with different migration stages of different aspects of the revision storage schema. Bug: T198561 Change-Id: I8e4ae69d7e00721a0af125afaf9a708f7fe99b0a --- tests/phpunit/includes/RevisionDbTestBase.php | 65 +- tests/phpunit/includes/RevisionMcrDbTest.php | 22 + .../includes/RevisionMcrReadNewDbTest.php | 22 + .../includes/RevisionMcrWriteBothDbTest.php | 23 + .../includes/RevisionNoContentModelDbTest.php | 24 + .../phpunit/includes/RevisionPreMcrDbTest.php | 24 + tests/phpunit/includes/RevisionTest.php | 656 +-------- .../Storage/McrReadNewRevisionStoreDbTest.php | 139 -- .../Storage/McrRevisionStoreDbTest.php | 139 -- .../McrWriteBothRevisionStoreDbTest.php | 107 -- .../Storage/PreMcrRevisionStoreDbTest.php | 110 -- .../Storage/RevisionQueryInfoTest.php | 1177 +++++++++++++++++ .../Storage/RevisionStoreDbTestBase.php | 217 +-- 13 files changed, 1395 insertions(+), 1330 deletions(-) create mode 100644 tests/phpunit/includes/Storage/RevisionQueryInfoTest.php diff --git a/tests/phpunit/includes/RevisionDbTestBase.php b/tests/phpunit/includes/RevisionDbTestBase.php index c760b41e05..8bf87a23e2 100644 --- a/tests/phpunit/includes/RevisionDbTestBase.php +++ b/tests/phpunit/includes/RevisionDbTestBase.php @@ -1,8 +1,10 @@ setMwGlobals( 'wgContentHandlerUseDB', $this->getContentHandlerUseDB() ); - $this->setMwGlobals( - 'wgMultiContentRevisionSchemaMigrationStage', - $this->getMcrMigrationStage() - ); + $this->setMwGlobals( [ + 'wgMultiContentRevisionSchemaMigrationStage' => $this->getMcrMigrationStage(), + 'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(), + 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD, + 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD, + ] ); $this->overrideMwServices(); @@ -102,6 +105,30 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase { } } + /** + * @param string $model + * @return Title + */ + protected function getMockTitle() { + $mock = $this->getMockBuilder( Title::class ) + ->disableOriginalConstructor() + ->getMock(); + $mock->expects( $this->any() ) + ->method( 'getNamespace' ) + ->will( $this->returnValue( $this->getDefaultWikitextNS() ) ); + $mock->expects( $this->any() ) + ->method( 'getPrefixedText' ) + ->will( $this->returnValue( __CLASS__ ) ); + $mock->expects( $this->any() ) + ->method( 'getDBkey' ) + ->will( $this->returnValue( __CLASS__ ) ); + $mock->expects( $this->any() ) + ->method( 'getArticleID' ) + ->will( $this->returnValue( 23 ) ); + + return $mock; + } + abstract protected function getContentHandlerUseDB(); private function makeRevisionWithProps( $props = null ) { @@ -1546,4 +1573,32 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase { ); } + public function provideGetTextId() { + yield [ [], null ]; + + $slot = new SlotRecord( (object)[ + 'slot_revision_id' => 42, + 'slot_content_id' => 1, + 'content_address' => 'tt:789', + 'model_name' => CONTENT_MODEL_WIKITEXT, + 'role_name' => 'main', + 'slot_origin' => 1, + ], new WikitextContent( 'Test' ) ); + + $rec = new MutableRevisionRecord( $this->testPage->getTitle() ); + $rec->setId( 42 ); + $rec->setSlot( $slot ); + + yield [ $rec, 789 ]; + } + + /** + * @dataProvider provideGetTextId + * @covers Revision::getTextId() + */ + public function testGetTextId( $spec, $expected ) { + $rev = new Revision( $spec, 0, $this->testPage->getTitle() ); + $this->assertSame( $expected, $rev->getTextId() ); + } + } diff --git a/tests/phpunit/includes/RevisionMcrDbTest.php b/tests/phpunit/includes/RevisionMcrDbTest.php index 3c30efe32d..3e4746a3d6 100644 --- a/tests/phpunit/includes/RevisionMcrDbTest.php +++ b/tests/phpunit/includes/RevisionMcrDbTest.php @@ -1,4 +1,7 @@ 42, + 'slot_content_id' => 1, + 'content_address' => 'tt:789', + 'model_name' => CONTENT_MODEL_WIKITEXT, + 'role_name' => 'main', + 'slot_origin' => 1, + ], new WikitextContent( 'Test' ) ); + + $rec = new MutableRevisionRecord( $this->getMockTitle() ); + $rec->setId( 42 ); + $rec->setSlot( $slot ); + + yield [ $rec, 789 ]; + } + } diff --git a/tests/phpunit/includes/RevisionMcrReadNewDbTest.php b/tests/phpunit/includes/RevisionMcrReadNewDbTest.php index 1054b7d03b..b446a8cff4 100644 --- a/tests/phpunit/includes/RevisionMcrReadNewDbTest.php +++ b/tests/phpunit/includes/RevisionMcrReadNewDbTest.php @@ -1,4 +1,7 @@ 42, + 'slot_content_id' => 1, + 'content_address' => 'tt:789', + 'model_name' => CONTENT_MODEL_WIKITEXT, + 'role_name' => 'main', + 'slot_origin' => 1, + ], new WikitextContent( 'Test' ) ); + + $rec = new MutableRevisionRecord( $this->getMockTitle() ); + $rec->setId( 42 ); + $rec->setSlot( $slot ); + + yield [ $rec, 789 ]; + } + } diff --git a/tests/phpunit/includes/RevisionMcrWriteBothDbTest.php b/tests/phpunit/includes/RevisionMcrWriteBothDbTest.php index 436b37995d..826b83d071 100644 --- a/tests/phpunit/includes/RevisionMcrWriteBothDbTest.php +++ b/tests/phpunit/includes/RevisionMcrWriteBothDbTest.php @@ -20,4 +20,27 @@ class RevisionMcrWriteBothDbTest extends RevisionDbTestBase { return true; } + public function provideGetTextId() { + yield [ [], null ]; + + $row = (object)[ + 'rev_id' => 7, + 'rev_page' => 1, // should match actual page id + 'rev_text_id' => 789, + 'rev_timestamp' => '20180101000000', + 'rev_len' => 7, + 'rev_minor_edit' => 0, + 'rev_deleted' => 0, + 'rev_parent_id' => 0, + 'rev_sha1' => 'deadbeef', + 'rev_comment' => 'some comment', + 'rev_comment_text' => 'some comment', + 'rev_comment_data' => '{}', + 'rev_user' => 17, + 'rev_user_text' => 'some user', + ]; + + yield [ $row, 789 ]; + } + } diff --git a/tests/phpunit/includes/RevisionNoContentModelDbTest.php b/tests/phpunit/includes/RevisionNoContentModelDbTest.php index 7923b2201b..f07d1692e5 100644 --- a/tests/phpunit/includes/RevisionNoContentModelDbTest.php +++ b/tests/phpunit/includes/RevisionNoContentModelDbTest.php @@ -1,4 +1,5 @@ 7, + 'rev_page' => 1, // should match actual page id + 'rev_text_id' => 789, + 'rev_timestamp' => '20180101000000', + 'rev_len' => 7, + 'rev_minor_edit' => 0, + 'rev_deleted' => 0, + 'rev_parent_id' => 0, + 'rev_sha1' => 'deadbeef', + 'rev_comment' => 'some comment', + 'rev_comment_text' => 'some comment', + 'rev_comment_data' => '{}', + 'rev_user' => 17, + 'rev_user_text' => 'some user', + ]; + + yield [ $row, 789 ]; + } + } diff --git a/tests/phpunit/includes/RevisionPreMcrDbTest.php b/tests/phpunit/includes/RevisionPreMcrDbTest.php index 90f1140934..9a62881d7b 100644 --- a/tests/phpunit/includes/RevisionPreMcrDbTest.php +++ b/tests/phpunit/includes/RevisionPreMcrDbTest.php @@ -1,4 +1,5 @@ 7, + 'rev_page' => 1, // should match actual page id + 'rev_text_id' => 789, + 'rev_timestamp' => '20180101000000', + 'rev_len' => 7, + 'rev_minor_edit' => 0, + 'rev_deleted' => 0, + 'rev_parent_id' => 0, + 'rev_sha1' => 'deadbeef', + 'rev_comment' => 'some comment', + 'rev_comment_text' => 'some comment', + 'rev_comment_data' => '{}', + 'rev_user' => 17, + 'rev_user_text' => 'some user', + ]; + + yield [ $row, 789 ]; + } + } diff --git a/tests/phpunit/includes/RevisionTest.php b/tests/phpunit/includes/RevisionTest.php index 7ef1182906..6359995c2e 100644 --- a/tests/phpunit/includes/RevisionTest.php +++ b/tests/phpunit/includes/RevisionTest.php @@ -19,7 +19,10 @@ class RevisionTest extends MediaWikiTestCase { public function setUp() { parent::setUp(); - $this->setMwGlobals( 'wgMultiContentRevisionSchemaMigrationStage', MIGRATION_OLD ); + $this->setMwGlobals( + 'wgMultiContentRevisionSchemaMigrationStage', + SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW + ); } public function provideConstructFromArray() { @@ -159,8 +162,9 @@ class RevisionTest extends MediaWikiTestCase { 'content' => new WikitextContent( 'GOAT' ), 'text_id' => 'someid', ], - new MWException( 'Text already stored in external store (id someid),' ) + new MWException( 'The text_id field is only available in the pre-MCR schema' ) ]; + yield 'with bad content object (class)' => [ [ 'content' => new stdClass() ], new MWException( 'content field must contain a Content object' ) @@ -207,7 +211,6 @@ class RevisionTest extends MediaWikiTestCase { [ 'rev_id' => '42', 'rev_page' => '23', - 'rev_text_id' => '2', 'rev_timestamp' => '20171017114835', 'rev_user_text' => '127.0.0.1', 'rev_user' => '0', @@ -219,13 +222,10 @@ class RevisionTest extends MediaWikiTestCase { 'rev_comment_text' => 'Goat Comment!', 'rev_comment_data' => null, 'rev_comment_cid' => null, - 'rev_content_format' => 'GOATFORMAT', - 'rev_content_model' => 'GOATMODEL', ], function ( RevisionTest $testCase, Revision $rev ) { $testCase->assertSame( 42, $rev->getId() ); $testCase->assertSame( 23, $rev->getPage() ); - $testCase->assertSame( 2, $rev->getTextId() ); $testCase->assertSame( '20171017114835', $rev->getTimestamp() ); $testCase->assertSame( '127.0.0.1', $rev->getUserText() ); $testCase->assertSame( 0, $rev->getUser() ); @@ -235,15 +235,12 @@ class RevisionTest extends MediaWikiTestCase { $testCase->assertSame( 1, $rev->getParentId() ); $testCase->assertSame( 'rdqbbzs3pkhihgbs8qf2q9jsvheag5z', $rev->getSha1() ); $testCase->assertSame( 'Goat Comment!', $rev->getComment() ); - $testCase->assertSame( 'GOATFORMAT', $rev->getContentFormat() ); - $testCase->assertSame( 'GOATMODEL', $rev->getContentModel() ); } ]; yield 'default field values' => [ [ 'rev_id' => '42', 'rev_page' => '23', - 'rev_text_id' => '2', 'rev_timestamp' => '20171017114835', 'rev_user_text' => '127.0.0.1', 'rev_user' => '0', @@ -264,14 +261,6 @@ class RevisionTest extends MediaWikiTestCase { $testCase->assertSame( $rev->getComment(), 'Goat Comment!' ); $testCase->assertSame( false, $rev->isMinor(), 'minor edit' ); $testCase->assertSame( 0, $rev->getVisibility(), 'visibility flags' ); - - // computed fields - $testCase->assertNotNull( $rev->getSize(), 'size' ); - $testCase->assertNotNull( $rev->getSha1(), 'hash' ); - - // NOTE: model and format will be detected based on the namespace of the (mock) title - $testCase->assertSame( 'text/x-wiki', $rev->getContentFormat(), 'format' ); - $testCase->assertSame( 'wikitext', $rev->getContentModel(), 'model' ); } ]; } @@ -281,30 +270,7 @@ class RevisionTest extends MediaWikiTestCase { * @covers Revision::__construct * @covers \MediaWiki\Storage\RevisionStore::newMutableRevisionFromArray */ - public function testConstructFromRow( array $arrayData, $assertions ) { - $data = 'Hello goat.'; // needs to match model and format - - $blobStore = $this->getMockBuilder( SqlBlobStore::class ) - ->disableOriginalConstructor() - ->getMock(); - - $blobStore->method( 'getBlob' ) - ->will( $this->returnValue( $data ) ); - - $blobStore->method( 'getTextIdFromAddress' ) - ->will( $this->returnCallback( - function ( $address ) { - // Turn "tt:1234" into 12345. - // Note that this must be functional so we can test getTextId(). - // Ideally, we'd un-mock getTextIdFromAddress and use its actual implementation. - $parts = explode( ':', $address ); - return (int)array_pop( $parts ); - } - ) ); - - // Note override internal service, so RevisionStore uses it as well. - $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) ); - + public function testConstructFromRow( array $arrayData, callable $assertions ) { $row = (object)$arrayData; $rev = new Revision( $row, 0, $this->getMockTitle() ); $assertions( $this, $rev ); @@ -384,21 +350,6 @@ class RevisionTest extends MediaWikiTestCase { $this->assertEquals( $name, $rev->getUserText( Revision::RAW ) ); } - public function provideGetTextId() { - yield [ [], null ]; - yield [ [ 'text_id' => '123' ], 123 ]; - yield [ [ 'text_id' => 456 ], 456 ]; - } - - /** - * @dataProvider provideGetTextId - * @covers Revision::getTextId() - */ - public function testGetTextId( $rowArray, $expected ) { - $rev = new Revision( $rowArray, 0, $this->getMockTitle() ); - $this->assertSame( $expected, $rev->getTextId() ); - } - public function provideGetParentId() { yield [ [], null ]; yield [ [ 'parent_id' => '123' ], 123 ]; @@ -656,7 +607,6 @@ class RevisionTest extends MediaWikiTestCase { $row = (object)[ 'rev_id' => '42', 'rev_page' => $title->getArticleID(), - 'rev_text_id' => '2', 'rev_timestamp' => '20171017114835', 'rev_user_text' => '127.0.0.1', 'rev_user' => '0', @@ -904,598 +854,6 @@ class RevisionTest extends MediaWikiTestCase { $this->assertSame( 'AAAABBAAA', $cache->get( $cacheKey ) ); } - /** - * @covers Revision::userJoinCond - */ - public function testUserJoinCond() { - $this->hideDeprecated( 'Revision::userJoinCond' ); - $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', MIGRATION_OLD ); - $this->overrideMwServices(); - $this->assertEquals( - [ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ], - Revision::userJoinCond() - ); - } - - /** - * @covers Revision::pageJoinCond - */ - public function testPageJoinCond() { - $this->hideDeprecated( 'Revision::pageJoinCond' ); - $this->assertEquals( - [ 'INNER JOIN', [ 'page_id = rev_page' ] ], - Revision::pageJoinCond() - ); - } - - private function overrideCommentStoreAndActorMigration() { - $mockStore = $this->getMockBuilder( CommentStore::class ) - ->disableOriginalConstructor() - ->getMock(); - $mockStore->expects( $this->any() ) - ->method( 'getFields' ) - ->willReturn( [ 'commentstore' => 'fields' ] ); - $mockStore->expects( $this->any() ) - ->method( 'getJoin' ) - ->willReturn( [ - 'tables' => [ 'commentstore' => 'table' ], - 'fields' => [ 'commentstore' => 'field' ], - 'joins' => [ 'commentstore' => 'join' ], - ] ); - $this->setService( 'CommentStore', $mockStore ); - - $mockStore = $this->getMockBuilder( ActorMigration::class ) - ->disableOriginalConstructor() - ->getMock(); - $mockStore->expects( $this->any() ) - ->method( 'getJoin' ) - ->willReturnCallback( function ( $key ) { - $p = strtok( $key, '_' ); - return [ - 'tables' => [ 'actormigration' => 'table' ], - 'fields' => [ - $p . '_user' => 'actormigration_user', - $p . '_user_text' => 'actormigration_user_text', - $p . '_actor' => 'actormigration_actor', - ], - 'joins' => [ 'actormigration' => 'join' ], - ]; - } ); - $this->setService( 'ActorMigration', $mockStore ); - } - - public function provideSelectFields() { - yield [ - true, - [ - 'rev_id', - 'rev_page', - 'rev_text_id', - 'rev_timestamp', - 'rev_user_text', - 'rev_user', - 'rev_actor' => 'NULL', - 'rev_minor_edit', - 'rev_deleted', - 'rev_len', - 'rev_parent_id', - 'rev_sha1', - 'commentstore' => 'fields', - 'rev_content_format', - 'rev_content_model', - ] - ]; - yield [ - false, - [ - 'rev_id', - 'rev_page', - 'rev_text_id', - 'rev_timestamp', - 'rev_user_text', - 'rev_user', - 'rev_actor' => 'NULL', - 'rev_minor_edit', - 'rev_deleted', - 'rev_len', - 'rev_parent_id', - 'rev_sha1', - 'commentstore' => 'fields', - ] - ]; - } - - /** - * @dataProvider provideSelectFields - * @covers Revision::selectFields - */ - public function testSelectFields( $contentHandlerUseDB, $expected ) { - $this->hideDeprecated( 'Revision::selectFields' ); - $this->setMwGlobals( 'wgContentHandlerUseDB', $contentHandlerUseDB ); - $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', MIGRATION_OLD ); - $this->overrideCommentStoreAndActorMigration(); - $this->assertEquals( $expected, Revision::selectFields() ); - } - - public function provideSelectArchiveFields() { - yield [ - true, - [ - 'ar_id', - 'ar_page_id', - 'ar_rev_id', - 'ar_text_id', - 'ar_timestamp', - 'ar_user_text', - 'ar_user', - 'ar_actor' => 'NULL', - 'ar_minor_edit', - 'ar_deleted', - 'ar_len', - 'ar_parent_id', - 'ar_sha1', - 'commentstore' => 'fields', - 'ar_content_format', - 'ar_content_model', - ] - ]; - yield [ - false, - [ - 'ar_id', - 'ar_page_id', - 'ar_rev_id', - 'ar_text_id', - 'ar_timestamp', - 'ar_user_text', - 'ar_user', - 'ar_actor' => 'NULL', - 'ar_minor_edit', - 'ar_deleted', - 'ar_len', - 'ar_parent_id', - 'ar_sha1', - 'commentstore' => 'fields', - ] - ]; - } - - /** - * @dataProvider provideSelectArchiveFields - * @covers Revision::selectArchiveFields - */ - public function testSelectArchiveFields( $contentHandlerUseDB, $expected ) { - $this->hideDeprecated( 'Revision::selectArchiveFields' ); - $this->setMwGlobals( 'wgContentHandlerUseDB', $contentHandlerUseDB ); - $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', MIGRATION_OLD ); - $this->overrideCommentStoreAndActorMigration(); - $this->assertEquals( $expected, Revision::selectArchiveFields() ); - } - - /** - * @covers Revision::selectTextFields - */ - public function testSelectTextFields() { - $this->hideDeprecated( 'Revision::selectTextFields' ); - $this->assertEquals( - [ - 'old_text', - 'old_flags', - ], - Revision::selectTextFields() - ); - } - - /** - * @covers Revision::selectPageFields - */ - public function testSelectPageFields() { - $this->hideDeprecated( 'Revision::selectPageFields' ); - $this->assertEquals( - [ - 'page_namespace', - 'page_title', - 'page_id', - 'page_latest', - 'page_is_redirect', - 'page_len', - ], - Revision::selectPageFields() - ); - } - - /** - * @covers Revision::selectUserFields - */ - public function testSelectUserFields() { - $this->hideDeprecated( 'Revision::selectUserFields' ); - $this->assertEquals( - [ - 'user_name', - ], - Revision::selectUserFields() - ); - } - - public function provideGetArchiveQueryInfo() { - yield 'wgContentHandlerUseDB false' => [ - [ - 'wgContentHandlerUseDB' => false, - ], - [ - 'tables' => [ - 'archive', - 'commentstore' => 'table', - 'actormigration' => 'table', - ], - 'fields' => [ - 'ar_id', - 'ar_page_id', - 'ar_namespace', - 'ar_title', - 'ar_rev_id', - 'ar_text_id', - 'ar_timestamp', - 'ar_minor_edit', - 'ar_deleted', - 'ar_len', - 'ar_parent_id', - 'ar_sha1', - 'commentstore' => 'field', - 'ar_user' => 'actormigration_user', - 'ar_user_text' => 'actormigration_user_text', - 'ar_actor' => 'actormigration_actor', - ], - 'joins' => [ 'commentstore' => 'join', 'actormigration' => 'join' ], - ] - ]; - yield 'wgContentHandlerUseDB true' => [ - [ - 'wgContentHandlerUseDB' => true, - ], - [ - 'tables' => [ - 'archive', - 'commentstore' => 'table', - 'actormigration' => 'table', - ], - 'fields' => [ - 'ar_id', - 'ar_page_id', - 'ar_namespace', - 'ar_title', - 'ar_rev_id', - 'ar_text_id', - 'ar_timestamp', - 'ar_minor_edit', - 'ar_deleted', - 'ar_len', - 'ar_parent_id', - 'ar_sha1', - 'commentstore' => 'field', - 'ar_user' => 'actormigration_user', - 'ar_user_text' => 'actormigration_user_text', - 'ar_actor' => 'actormigration_actor', - 'ar_content_format', - 'ar_content_model', - ], - 'joins' => [ 'commentstore' => 'join', 'actormigration' => 'join' ], - ] - ]; - } - - /** - * @covers Revision::getArchiveQueryInfo - * @dataProvider provideGetArchiveQueryInfo - */ - public function testGetArchiveQueryInfo( $globals, $expected ) { - $this->setMwGlobals( $globals ); - $this->overrideCommentStoreAndActorMigration(); - - $revisionStore = $this->getRevisionStore(); - $revisionStore->setContentHandlerUseDB( $globals['wgContentHandlerUseDB'] ); - $this->setService( 'RevisionStore', $revisionStore ); - - $queryInfo = Revision::getArchiveQueryInfo(); - - $this->assertArrayEqualsIgnoringIntKeyOrder( - $expected['tables'], - $queryInfo['tables'] - ); - $this->assertArrayEqualsIgnoringIntKeyOrder( - $expected['fields'], - $queryInfo['fields'] - ); - $this->assertArrayEqualsIgnoringIntKeyOrder( - $expected['joins'], - $queryInfo['joins'] - ); - } - - /** - * Assert that the two arrays passed are equal, ignoring the order of the values that integer - * keys. - * - * Note: Failures of this assertion can be slightly confusing as the arrays are actually - * split into a string key array and an int key array before assertions occur. - * - * @param array $expected - * @param array $actual - */ - private function assertArrayEqualsIgnoringIntKeyOrder( array $expected, array $actual ) { - $this->objectAssociativeSort( $expected ); - $this->objectAssociativeSort( $actual ); - - // Separate the int key values from the string key values so that assertion failures are - // easier to understand. - $expectedIntKeyValues = []; - $actualIntKeyValues = []; - - // Remove all int keys and re add them at the end after sorting by value - // This will result in all int keys being in the same order with same ints at the end of - // the array - foreach ( $expected as $key => $value ) { - if ( is_int( $key ) ) { - unset( $expected[$key] ); - $expectedIntKeyValues[] = $value; - } - } - foreach ( $actual as $key => $value ) { - if ( is_int( $key ) ) { - unset( $actual[$key] ); - $actualIntKeyValues[] = $value; - } - } - - $this->assertArrayEquals( $expected, $actual, false, true ); - $this->assertArrayEquals( $expectedIntKeyValues, $actualIntKeyValues, false, true ); - } - - public function provideGetQueryInfo() { - yield 'wgContentHandlerUseDB false, opts none' => [ - [ - 'wgContentHandlerUseDB' => false, - ], - [], - [ - 'tables' => [ 'revision', 'commentstore' => 'table', 'actormigration' => 'table' ], - 'fields' => [ - 'rev_id', - 'rev_page', - 'rev_text_id', - 'rev_timestamp', - 'rev_minor_edit', - 'rev_deleted', - 'rev_len', - 'rev_parent_id', - 'rev_sha1', - 'commentstore' => 'field', - 'rev_user' => 'actormigration_user', - 'rev_user_text' => 'actormigration_user_text', - 'rev_actor' => 'actormigration_actor', - ], - 'joins' => [ 'commentstore' => 'join', 'actormigration' => 'join' ], - ], - ]; - yield 'wgContentHandlerUseDB false, opts page' => [ - [ - 'wgContentHandlerUseDB' => false, - ], - [ 'page' ], - [ - 'tables' => [ 'revision', 'commentstore' => 'table', 'actormigration' => 'table', 'page' ], - 'fields' => [ - 'rev_id', - 'rev_page', - 'rev_text_id', - 'rev_timestamp', - 'rev_minor_edit', - 'rev_deleted', - 'rev_len', - 'rev_parent_id', - 'rev_sha1', - 'commentstore' => 'field', - 'rev_user' => 'actormigration_user', - 'rev_user_text' => 'actormigration_user_text', - 'rev_actor' => 'actormigration_actor', - 'page_namespace', - 'page_title', - 'page_id', - 'page_latest', - 'page_is_redirect', - 'page_len', - ], - 'joins' => [ - 'page' => [ - 'INNER JOIN', - [ 'page_id = rev_page' ], - ], - 'commentstore' => 'join', - 'actormigration' => 'join', - ], - ], - ]; - yield 'wgContentHandlerUseDB false, opts user' => [ - [ - 'wgContentHandlerUseDB' => false, - ], - [ 'user' ], - [ - 'tables' => [ 'revision', 'commentstore' => 'table', 'actormigration' => 'table', 'user' ], - 'fields' => [ - 'rev_id', - 'rev_page', - 'rev_text_id', - 'rev_timestamp', - 'rev_minor_edit', - 'rev_deleted', - 'rev_len', - 'rev_parent_id', - 'rev_sha1', - 'commentstore' => 'field', - 'rev_user' => 'actormigration_user', - 'rev_user_text' => 'actormigration_user_text', - 'rev_actor' => 'actormigration_actor', - 'user_name', - ], - 'joins' => [ - 'user' => [ - 'LEFT JOIN', - [ - 'actormigration_user != 0', - 'user_id = actormigration_user', - ], - ], - 'commentstore' => 'join', - 'actormigration' => 'join', - ], - ], - ]; - yield 'wgContentHandlerUseDB false, opts text' => [ - [ - 'wgContentHandlerUseDB' => false, - ], - [ 'text' ], - [ - 'tables' => [ 'revision', 'commentstore' => 'table', 'actormigration' => 'table', 'text' ], - 'fields' => [ - 'rev_id', - 'rev_page', - 'rev_text_id', - 'rev_timestamp', - 'rev_minor_edit', - 'rev_deleted', - 'rev_len', - 'rev_parent_id', - 'rev_sha1', - 'commentstore' => 'field', - 'rev_user' => 'actormigration_user', - 'rev_user_text' => 'actormigration_user_text', - 'rev_actor' => 'actormigration_actor', - 'old_text', - 'old_flags', - ], - 'joins' => [ - 'text' => [ - 'INNER JOIN', - [ 'rev_text_id=old_id' ], - ], - 'commentstore' => 'join', - 'actormigration' => 'join', - ], - ], - ]; - yield 'wgContentHandlerUseDB false, opts 3' => [ - [ - 'wgContentHandlerUseDB' => false, - ], - [ 'text', 'page', 'user' ], - [ - 'tables' => [ - 'revision', 'commentstore' => 'table', 'actormigration' => 'table', 'page', 'user', 'text' - ], - 'fields' => [ - 'rev_id', - 'rev_page', - 'rev_text_id', - 'rev_timestamp', - 'rev_minor_edit', - 'rev_deleted', - 'rev_len', - 'rev_parent_id', - 'rev_sha1', - 'commentstore' => 'field', - 'rev_user' => 'actormigration_user', - 'rev_user_text' => 'actormigration_user_text', - 'rev_actor' => 'actormigration_actor', - 'page_namespace', - 'page_title', - 'page_id', - 'page_latest', - 'page_is_redirect', - 'page_len', - 'user_name', - 'old_text', - 'old_flags', - ], - 'joins' => [ - 'page' => [ - 'INNER JOIN', - [ 'page_id = rev_page' ], - ], - 'user' => [ - 'LEFT JOIN', - [ - 'actormigration_user != 0', - 'user_id = actormigration_user', - ], - ], - 'text' => [ - 'INNER JOIN', - [ 'rev_text_id=old_id' ], - ], - 'commentstore' => 'join', - 'actormigration' => 'join', - ], - ], - ]; - yield 'wgContentHandlerUseDB true, opts none' => [ - [ - 'wgContentHandlerUseDB' => true, - ], - [], - [ - 'tables' => [ 'revision', 'commentstore' => 'table', 'actormigration' => 'table' ], - 'fields' => [ - 'rev_id', - 'rev_page', - 'rev_text_id', - 'rev_timestamp', - 'rev_minor_edit', - 'rev_deleted', - 'rev_len', - 'rev_parent_id', - 'rev_sha1', - 'commentstore' => 'field', - 'rev_user' => 'actormigration_user', - 'rev_user_text' => 'actormigration_user_text', - 'rev_actor' => 'actormigration_actor', - 'rev_content_format', - 'rev_content_model', - ], - 'joins' => [ 'commentstore' => 'join', 'actormigration' => 'join' ], - ], - ]; - } - - /** - * @covers Revision::getQueryInfo - * @dataProvider provideGetQueryInfo - */ - public function testGetQueryInfo( $globals, $options, $expected ) { - $this->setMwGlobals( $globals ); - $this->overrideCommentStoreAndActorMigration(); - - $revisionStore = $this->getRevisionStore(); - $revisionStore->setContentHandlerUseDB( $globals['wgContentHandlerUseDB'] ); - $this->setService( 'RevisionStore', $revisionStore ); - - $queryInfo = Revision::getQueryInfo( $options ); - - $this->assertArrayEqualsIgnoringIntKeyOrder( - $expected['tables'], - $queryInfo['tables'] - ); - $this->assertArrayEqualsIgnoringIntKeyOrder( - $expected['fields'], - $queryInfo['fields'] - ); - $this->assertArrayEqualsIgnoringIntKeyOrder( - $expected['joins'], - $queryInfo['joins'] - ); - } - /** * @covers Revision::getSize */ diff --git a/tests/phpunit/includes/Storage/McrReadNewRevisionStoreDbTest.php b/tests/phpunit/includes/Storage/McrReadNewRevisionStoreDbTest.php index 492d00c862..3b3b3441a1 100644 --- a/tests/phpunit/includes/Storage/McrReadNewRevisionStoreDbTest.php +++ b/tests/phpunit/includes/Storage/McrReadNewRevisionStoreDbTest.php @@ -117,145 +117,6 @@ class McrReadNewRevisionStoreDbTest extends RevisionStoreDbTestBase { $this->assertFalse( array_key_exists( 'a_slot_data', $queryInfo['joins'] ) ); } - public function provideGetArchiveQueryInfo() { - yield [ - [ - 'tables' => [ - 'archive', - ], - 'fields' => array_merge( - $this->getDefaultArchiveFields( false ), - [ - 'ar_comment_text' => 'ar_comment', - 'ar_comment_data' => 'NULL', - 'ar_comment_cid' => 'NULL', - 'ar_user_text' => 'ar_user_text', - 'ar_user' => 'ar_user', - 'ar_actor' => 'NULL', - ] - ), - 'joins' => [ - ], - ] - ]; - } - - public function provideGetQueryInfo() { - // TODO: more option variations - yield [ - [ 'page', 'user' ], - [ - 'tables' => [ - 'revision', - 'page', - 'user', - ], - 'fields' => array_merge( - $this->getDefaultQueryFields( false ), - $this->getCommentQueryFields(), - $this->getActorQueryFields(), - [ - 'page_namespace', - 'page_title', - 'page_id', - 'page_latest', - 'page_is_redirect', - 'page_len', - 'user_name', - ] - ), - 'joins' => [ - 'page' => [ 'INNER JOIN', [ 'page_id = rev_page' ] ], - 'user' => [ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ], - ], - ] - ]; - } - - public function provideGetSlotsQueryInfo() { - yield 'no options' => [ - [], - [ - 'tables' => [ - 'slots' - ], - 'fields' => [ - 'slot_revision_id', - 'slot_content_id', - 'slot_origin', - 'slot_role_id', - ], - 'joins' => [], - ] - ]; - yield 'role option' => [ - [ 'role' ], - [ - 'tables' => [ - 'slots', - 'slot_roles', - ], - 'fields' => [ - 'slot_revision_id', - 'slot_content_id', - 'slot_origin', - 'slot_role_id', - 'role_name', - ], - 'joins' => [ - 'slot_roles' => [ 'LEFT JOIN', [ 'slot_role_id = role_id' ] ], - ], - ] - ]; - yield 'content option' => [ - [ 'content' ], - [ - 'tables' => [ - 'slots', - 'content', - ], - 'fields' => [ - 'slot_revision_id', - 'slot_content_id', - 'slot_origin', - 'slot_role_id', - 'content_size', - 'content_sha1', - 'content_address', - 'content_model', - ], - 'joins' => [ - 'content' => [ 'INNER JOIN', [ 'slot_content_id = content_id' ] ], - ], - ] - ]; - yield 'content and model options' => [ - [ 'content', 'model' ], - [ - 'tables' => [ - 'slots', - 'content', - 'content_models', - ], - 'fields' => [ - 'slot_revision_id', - 'slot_content_id', - 'slot_origin', - 'slot_role_id', - 'content_size', - 'content_sha1', - 'content_address', - 'content_model', - 'model_name', - ], - 'joins' => [ - 'content' => [ 'INNER JOIN', [ 'slot_content_id = content_id' ] ], - 'content_models' => [ 'LEFT JOIN', [ 'content_model = model_id' ] ], - ], - ] - ]; - } - public function provideNewMutableRevisionFromArray() { foreach ( parent::provideNewMutableRevisionFromArray() as $case ) { yield $case; diff --git a/tests/phpunit/includes/Storage/McrRevisionStoreDbTest.php b/tests/phpunit/includes/Storage/McrRevisionStoreDbTest.php index af19f722fd..f4fcfb4a13 100644 --- a/tests/phpunit/includes/Storage/McrRevisionStoreDbTest.php +++ b/tests/phpunit/includes/Storage/McrRevisionStoreDbTest.php @@ -134,145 +134,6 @@ class McrRevisionStoreDbTest extends RevisionStoreDbTestBase { $this->assertFalse( array_key_exists( 'a_slot_data', $queryInfo['joins'] ) ); } - public function provideGetArchiveQueryInfo() { - yield [ - [ - 'tables' => [ - 'archive', - ], - 'fields' => array_merge( - $this->getDefaultArchiveFields( false ), - [ - 'ar_comment_text' => 'ar_comment', - 'ar_comment_data' => 'NULL', - 'ar_comment_cid' => 'NULL', - 'ar_user_text' => 'ar_user_text', - 'ar_user' => 'ar_user', - 'ar_actor' => 'NULL', - ] - ), - 'joins' => [ - ], - ] - ]; - } - - public function provideGetQueryInfo() { - // TODO: more option variations - yield [ - [ 'page', 'user' ], - [ - 'tables' => [ - 'revision', - 'page', - 'user', - ], - 'fields' => array_merge( - $this->getDefaultQueryFields( false ), - $this->getCommentQueryFields(), - $this->getActorQueryFields(), - [ - 'page_namespace', - 'page_title', - 'page_id', - 'page_latest', - 'page_is_redirect', - 'page_len', - 'user_name', - ] - ), - 'joins' => [ - 'page' => [ 'INNER JOIN', [ 'page_id = rev_page' ] ], - 'user' => [ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ], - ], - ] - ]; - } - - public function provideGetSlotsQueryInfo() { - yield 'no options' => [ - [], - [ - 'tables' => [ - 'slots' - ], - 'fields' => [ - 'slot_revision_id', - 'slot_content_id', - 'slot_origin', - 'slot_role_id', - ], - 'joins' => [], - ] - ]; - yield 'role option' => [ - [ 'role' ], - [ - 'tables' => [ - 'slots', - 'slot_roles', - ], - 'fields' => [ - 'slot_revision_id', - 'slot_content_id', - 'slot_origin', - 'slot_role_id', - 'role_name', - ], - 'joins' => [ - 'slot_roles' => [ 'LEFT JOIN', [ 'slot_role_id = role_id' ] ], - ], - ] - ]; - yield 'content option' => [ - [ 'content' ], - [ - 'tables' => [ - 'slots', - 'content', - ], - 'fields' => [ - 'slot_revision_id', - 'slot_content_id', - 'slot_origin', - 'slot_role_id', - 'content_size', - 'content_sha1', - 'content_address', - 'content_model', - ], - 'joins' => [ - 'content' => [ 'INNER JOIN', [ 'slot_content_id = content_id' ] ], - ], - ] - ]; - yield 'content and model options' => [ - [ 'content', 'model' ], - [ - 'tables' => [ - 'slots', - 'content', - 'content_models', - ], - 'fields' => [ - 'slot_revision_id', - 'slot_content_id', - 'slot_origin', - 'slot_role_id', - 'content_size', - 'content_sha1', - 'content_address', - 'content_model', - 'model_name', - ], - 'joins' => [ - 'content' => [ 'INNER JOIN', [ 'slot_content_id = content_id' ] ], - 'content_models' => [ 'LEFT JOIN', [ 'content_model = model_id' ] ], - ], - ] - ]; - } - /** * @covers \MediaWiki\Storage\RevisionStore::insertRevisionOn * @covers \MediaWiki\Storage\RevisionStore::insertSlotRowOn diff --git a/tests/phpunit/includes/Storage/McrWriteBothRevisionStoreDbTest.php b/tests/phpunit/includes/Storage/McrWriteBothRevisionStoreDbTest.php index 9d5dc29884..f05016aa3c 100644 --- a/tests/phpunit/includes/Storage/McrWriteBothRevisionStoreDbTest.php +++ b/tests/phpunit/includes/Storage/McrWriteBothRevisionStoreDbTest.php @@ -73,113 +73,6 @@ class McrWriteBothRevisionStoreDbTest extends RevisionStoreDbTestBase { } } - public function provideGetArchiveQueryInfo() { - yield [ - [ - 'tables' => [ 'archive' ], - 'fields' => array_merge( - $this->getDefaultArchiveFields(), - [ - 'ar_comment_text' => 'ar_comment', - 'ar_comment_data' => 'NULL', - 'ar_comment_cid' => 'NULL', - 'ar_user_text' => 'ar_user_text', - 'ar_user' => 'ar_user', - 'ar_actor' => 'NULL', - 'ar_content_format', - 'ar_content_model', - ] - ), - 'joins' => [], - ] - ]; - } - - public function provideGetQueryInfo() { - yield [ - [], - [ - 'tables' => [ 'revision' ], - 'fields' => array_merge( - $this->getDefaultQueryFields(), - $this->getCommentQueryFields(), - $this->getActorQueryFields(), - $this->getContentHandlerQueryFields() - ), - 'joins' => [], - ] - ]; - yield [ - [ 'page', 'user' ], - [ - 'tables' => [ 'revision', 'page', 'user' ], - 'fields' => array_merge( - $this->getDefaultQueryFields(), - $this->getCommentQueryFields(), - $this->getActorQueryFields(), - $this->getContentHandlerQueryFields(), - [ - 'page_namespace', - 'page_title', - 'page_id', - 'page_latest', - 'page_is_redirect', - 'page_len', - 'user_name', - ] - ), - 'joins' => [ - 'page' => [ 'INNER JOIN', [ 'page_id = rev_page' ] ], - 'user' => [ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ], - ], - ] - ]; - } - - public function provideGetSlotsQueryInfo() { - $db = wfGetDB( DB_REPLICA ); - - yield [ - [], - [ - 'tables' => [ - 'slots' => 'revision', - ], - 'fields' => array_merge( - [ - 'slot_revision_id' => 'slots.rev_id', - 'slot_content_id' => 'NULL', - 'slot_origin' => 'slots.rev_id', - 'role_name' => $db->addQuotes( 'main' ), - ] - ), - 'joins' => [], - ] - ]; - yield [ - [ 'content' ], - [ - 'tables' => [ - 'slots' => 'revision', - ], - 'fields' => array_merge( - [ - 'slot_revision_id' => 'slots.rev_id', - 'slot_content_id' => 'NULL', - 'slot_origin' => 'slots.rev_id', - 'role_name' => $db->addQuotes( 'main' ), - 'content_size' => 'slots.rev_len', - 'content_sha1' => 'slots.rev_sha1', - 'content_address' => $db->buildConcat( [ - $db->addQuotes( 'tt:' ), 'slots.rev_text_id' ] ), - 'model_name' => 'slots.rev_content_model', - ] - ), - 'joins' => [], - ] - ]; - } - public function provideInsertRevisionOn_failures() { foreach ( parent::provideInsertRevisionOn_failures() as $case ) { yield $case; diff --git a/tests/phpunit/includes/Storage/PreMcrRevisionStoreDbTest.php b/tests/phpunit/includes/Storage/PreMcrRevisionStoreDbTest.php index cee5f9600e..687ad4f309 100644 --- a/tests/phpunit/includes/Storage/PreMcrRevisionStoreDbTest.php +++ b/tests/phpunit/includes/Storage/PreMcrRevisionStoreDbTest.php @@ -44,116 +44,6 @@ class PreMcrRevisionStoreDbTest extends RevisionStoreDbTestBase { parent::assertRevisionExistsInDatabase( $rev ); } - public function provideGetArchiveQueryInfo() { - yield [ - [ - 'tables' => [ 'archive' ], - 'fields' => array_merge( - $this->getDefaultArchiveFields(), - [ - 'ar_comment_text' => 'ar_comment', - 'ar_comment_data' => 'NULL', - 'ar_comment_cid' => 'NULL', - 'ar_user_text' => 'ar_user_text', - 'ar_user' => 'ar_user', - 'ar_actor' => 'NULL', - 'ar_content_format', - 'ar_content_model', - ] - ), - 'joins' => [], - ] - ]; - } - - public function provideGetQueryInfo() { - yield [ - [], - [ - 'tables' => [ 'revision' ], - 'fields' => array_merge( - $this->getDefaultQueryFields(), - $this->getCommentQueryFields(), - $this->getActorQueryFields(), - $this->getContentHandlerQueryFields() - ), - 'joins' => [], - ] - ]; - yield [ - [ 'page', 'user', 'text' ], - [ - 'tables' => [ 'revision', 'page', 'user', 'text' ], - 'fields' => array_merge( - $this->getDefaultQueryFields(), - $this->getCommentQueryFields(), - $this->getActorQueryFields(), - $this->getContentHandlerQueryFields(), - [ - 'page_namespace', - 'page_title', - 'page_id', - 'page_latest', - 'page_is_redirect', - 'page_len', - 'user_name', - 'old_text', - 'old_flags' - ] - ), - 'joins' => [ - 'page' => [ 'INNER JOIN', [ 'page_id = rev_page' ] ], - 'user' => [ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ], - 'text' => [ 'INNER JOIN', [ 'rev_text_id=old_id' ] ], - ], - ] - ]; - } - - public function provideGetSlotsQueryInfo() { - $db = wfGetDB( DB_REPLICA ); - - yield [ - [], - [ - 'tables' => [ - 'slots' => 'revision', - ], - 'fields' => array_merge( - [ - 'slot_revision_id' => 'slots.rev_id', - 'slot_content_id' => 'NULL', - 'slot_origin' => 'slots.rev_id', - 'role_name' => $db->addQuotes( 'main' ), - ] - ), - 'joins' => [], - ] - ]; - yield [ - [ 'content' ], - [ - 'tables' => [ - 'slots' => 'revision', - ], - 'fields' => array_merge( - [ - 'slot_revision_id' => 'slots.rev_id', - 'slot_content_id' => 'NULL', - 'slot_origin' => 'slots.rev_id', - 'role_name' => $db->addQuotes( 'main' ), - 'content_size' => 'slots.rev_len', - 'content_sha1' => 'slots.rev_sha1', - 'content_address' => - $db->buildConcat( [ $db->addQuotes( 'tt:' ), 'slots.rev_text_id' ] ), - 'model_name' => 'slots.rev_content_model', - ] - ), - 'joins' => [], - ] - ]; - } - public function provideInsertRevisionOn_failures() { foreach ( parent::provideInsertRevisionOn_failures() as $case ) { yield $case; diff --git a/tests/phpunit/includes/Storage/RevisionQueryInfoTest.php b/tests/phpunit/includes/Storage/RevisionQueryInfoTest.php new file mode 100644 index 0000000000..7f56c3a8f8 --- /dev/null +++ b/tests/phpunit/includes/Storage/RevisionQueryInfoTest.php @@ -0,0 +1,1177 @@ + "{$prefix}_comment", + "{$prefix}_comment_data" => 'NULL', + "{$prefix}_comment_cid" => 'NULL', + ]; + } + + protected function getCompatCommentQueryFields( $prefix ) { + return [ + "{$prefix}_comment_text" + => "COALESCE( comment_{$prefix}_comment.comment_text, {$prefix}_comment )", + "{$prefix}_comment_data" => "comment_{$prefix}_comment.comment_data", + "{$prefix}_comment_cid" => "comment_{$prefix}_comment.comment_id", + ]; + } + + protected function getNewCommentQueryFields( $prefix ) { + return [ + "{$prefix}_comment_text" => "comment_{$prefix}_comment.comment_text", + "{$prefix}_comment_data" => "comment_{$prefix}_comment.comment_data", + "{$prefix}_comment_cid" => "comment_{$prefix}_comment.comment_id", + ]; + } + + protected function getOldActorQueryFields( $prefix ) { + return [ + "{$prefix}_user" => "{$prefix}_user", + "{$prefix}_user_text" => "{$prefix}_user_text", + "{$prefix}_actor" => 'NULL', + ]; + } + + protected function getNewActorQueryFields( $prefix, $tmp = false ) { + return [ + "{$prefix}_user" => "actor_{$prefix}_user.actor_user", + "{$prefix}_user_text" => "actor_{$prefix}_user.actor_name", + "{$prefix}_actor" => $tmp ?: "{$prefix}_actor", + ]; + } + + protected function getCompatActorQueryFields( $prefix, $tmp = false ) { + return [ + "{$prefix}_user" => "COALESCE( actor_{$prefix}_user.actor_user, {$prefix}_user )", + "{$prefix}_user_text" => "COALESCE( actor_{$prefix}_user.actor_name, {$prefix}_user_text )", + "{$prefix}_actor" => $tmp ?: "{$prefix}_actor", + ]; + } + + protected function getCompatActorJoins( $prefix ) { + return [ + "temp_{$prefix}_user" => [ + "LEFT JOIN", + "temp_{$prefix}_user.revactor_{$prefix} = {$prefix}_id", + ], + "actor_{$prefix}_user" => [ + "LEFT JOIN", + "actor_{$prefix}_user.actor_id = temp_{$prefix}_user.revactor_actor", + ], + ]; + } + + protected function getCompatCommentJoins( $prefix ) { + return [ + "temp_{$prefix}_comment" => [ + "LEFT JOIN", + "temp_{$prefix}_comment.revcomment_{$prefix} = {$prefix}_id", + ], + "comment_{$prefix}_comment" => [ + "LEFT JOIN", + "comment_{$prefix}_comment.comment_id = temp_{$prefix}_comment.revcomment_comment_id", + ], + ]; + } + + protected function getTextQueryFields() { + return [ + 'old_text', + 'old_flags', + ]; + } + + protected function getPageQueryFields() { + return [ + 'page_namespace', + 'page_title', + 'page_id', + 'page_latest', + 'page_is_redirect', + 'page_len', + ]; + } + + protected function getUserQueryFields() { + return [ + 'user_name', + ]; + } + + protected function getContentHandlerQueryFields( $prefix ) { + return [ + "{$prefix}_content_format", + "{$prefix}_content_model", + ]; + } + + public function provideArchiveQueryInfo() { + yield 'MCR, comment, actor' => [ + [ + 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_NEW, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_NEW, + 'wgActorTableSchemaMigrationStage' => MIGRATION_NEW, + ], + [ + 'tables' => [ + 'archive', + 'actor_ar_user' => 'actor', + 'comment_ar_comment' => 'comment', + ], + 'fields' => array_merge( + $this->getArchiveQueryFields( false ), + $this->getNewActorQueryFields( 'ar' ), + $this->getNewCommentQueryFields( 'ar' ) + ), + 'joins' => [ + 'comment_ar_comment' + => [ 'JOIN', 'comment_ar_comment.comment_id = ar_comment_id' ], + 'actor_ar_user' => [ 'JOIN', 'actor_ar_user.actor_id = ar_actor' ], + ], + ] + ]; + yield 'read-new MCR, comment, actor' => [ + [ + 'wgContentHandlerUseDB' => true, + 'wgMultiContentRevisionSchemaMigrationStage' + => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_NEW, + 'wgActorTableSchemaMigrationStage' => MIGRATION_WRITE_NEW, + ], + [ + 'tables' => [ + 'archive', + 'actor_ar_user' => 'actor', + 'comment_ar_comment' => 'comment', + ], + 'fields' => array_merge( + $this->getArchiveQueryFields( false ), + $this->getCompatActorQueryFields( 'ar' ), + $this->getCompatCommentQueryFields( 'ar' ) + ), + 'joins' => [ + 'comment_ar_comment' + => [ 'LEFT JOIN', 'comment_ar_comment.comment_id = ar_comment_id' ], + 'actor_ar_user' => [ 'LEFT JOIN', 'actor_ar_user.actor_id = ar_actor' ], + ], + ] + ]; + yield 'MCR write-both/read-old' => [ + [ + 'wgContentHandlerUseDB' => true, + 'wgMultiContentRevisionSchemaMigrationStage' + => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH, + 'wgActorTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH, + ], + [ + 'tables' => [ + 'archive', + 'actor_ar_user' => 'actor', + 'comment_ar_comment' => 'comment', + ], + 'fields' => array_merge( + $this->getArchiveQueryFields( true ), + $this->getContentHandlerQueryFields( 'ar' ), + $this->getCompatActorQueryFields( 'ar' ), + $this->getCompatCommentQueryFields( 'ar' ) + ), + 'joins' => [ + 'comment_ar_comment' + => [ 'LEFT JOIN', 'comment_ar_comment.comment_id = ar_comment_id' ], + 'actor_ar_user' => [ 'LEFT JOIN', 'actor_ar_user.actor_id = ar_actor' ], + ], + ] + ]; + yield 'pre-MCR, no model' => [ + [ + 'wgContentHandlerUseDB' => false, + 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD, + 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD, + ], + [ + 'tables' => [ + 'archive', + ], + 'fields' => array_merge( + $this->getArchiveQueryFields( true ), + $this->getOldActorQueryFields( 'ar' ), + $this->getOldCommentQueryFields( 'ar' ) + ), + 'joins' => [], + ] + ]; + } + + public function provideQueryInfo() { + // TODO: more option variations + yield 'MCR, page, user, comment, actor' => [ + [ + 'wgContentHandlerUseDB' => true, + 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_NEW, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_NEW, + 'wgActorTableSchemaMigrationStage' => MIGRATION_NEW, + ], + [ 'page', 'user' ], + [ + 'tables' => [ + 'revision', + 'page', + 'user', + 'temp_rev_user' => 'revision_actor_temp', + 'temp_rev_comment' => 'revision_comment_temp', + 'actor_rev_user' => 'actor', + 'comment_rev_comment' => 'comment', + ], + 'fields' => array_merge( + $this->getRevisionQueryFields( false ), + $this->getPageQueryFields(), + $this->getUserQueryFields(), + $this->getNewActorQueryFields( 'rev', 'temp_rev_user.revactor_actor' ), + $this->getNewCommentQueryFields( 'rev' ) + ), + 'joins' => [ + 'page' => [ 'INNER JOIN', [ 'page_id = rev_page' ] ], + 'user' => [ + 'LEFT JOIN', + [ 'actor_rev_user.actor_user != 0', 'user_id = actor_rev_user.actor_user' ], + ], + 'comment_rev_comment' => [ + 'JOIN', + 'comment_rev_comment.comment_id = temp_rev_comment.revcomment_comment_id', + ], + 'actor_rev_user' => [ + 'JOIN', + 'actor_rev_user.actor_id = temp_rev_user.revactor_actor', + ], + 'temp_rev_user' => [ 'JOIN', 'temp_rev_user.revactor_rev = rev_id' ], + 'temp_rev_comment' => [ 'JOIN', 'temp_rev_comment.revcomment_rev = rev_id' ], + ], + ] + ]; + yield 'MCR read-new, page, user, comment, actor' => [ + [ + 'wgContentHandlerUseDB' => true, + 'wgMultiContentRevisionSchemaMigrationStage' + => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_NEW, + 'wgActorTableSchemaMigrationStage' => MIGRATION_WRITE_NEW, + ], + [ 'page', 'user' ], + [ + 'tables' => [ + 'revision', + 'page', + 'user', + 'temp_rev_user' => 'revision_actor_temp', + 'temp_rev_comment' => 'revision_comment_temp', + 'actor_rev_user' => 'actor', + 'comment_rev_comment' => 'comment', + ], + 'fields' => array_merge( + $this->getRevisionQueryFields( false ), + $this->getPageQueryFields(), + $this->getUserQueryFields(), + $this->getCompatActorQueryFields( 'rev', 'temp_rev_user.revactor_actor' ), + $this->getCompatCommentQueryFields( 'rev' ) + ), + 'joins' => array_merge( + [ + 'page' => [ 'INNER JOIN', [ 'page_id = rev_page' ] ], + 'user' => [ + 'LEFT JOIN', + [ + 'COALESCE( actor_rev_user.actor_user, rev_user ) != 0', + 'user_id = COALESCE( actor_rev_user.actor_user, rev_user )' + ] + ], + ], + $this->getCompatActorJoins( 'rev' ), + $this->getCompatCommentJoins( 'rev' ) + ), + ] + ]; + yield 'MCR read-new' => [ + [ + 'wgContentHandlerUseDB' => true, + 'wgMultiContentRevisionSchemaMigrationStage' + => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_NEW, + 'wgActorTableSchemaMigrationStage' => MIGRATION_WRITE_NEW, + ], + [ 'page', 'user' ], + [ + 'tables' => [ + 'revision', + 'page', + 'user', + 'temp_rev_user' => 'revision_actor_temp', + 'temp_rev_comment' => 'revision_comment_temp', + 'actor_rev_user' => 'actor', + 'comment_rev_comment' => 'comment', + ], + 'fields' => array_merge( + $this->getRevisionQueryFields( false ), + $this->getPageQueryFields(), + $this->getUserQueryFields(), + $this->getCompatActorQueryFields( 'rev', 'temp_rev_user.revactor_actor' ), + $this->getCompatCommentQueryFields( 'rev' ) + ), + 'joins' => array_merge( + [ + 'page' => [ 'INNER JOIN', [ 'page_id = rev_page' ] ], + 'user' => [ + 'LEFT JOIN', + [ + 'COALESCE( actor_rev_user.actor_user, rev_user ) != 0', + 'user_id = COALESCE( actor_rev_user.actor_user, rev_user )' + ] + ], + ], + $this->getCompatActorJoins( 'rev' ), + $this->getCompatCommentJoins( 'rev' ) + ), + ] + ]; + yield 'MCR write-both/read-old' => [ + [ + 'wgContentHandlerUseDB' => true, + 'wgMultiContentRevisionSchemaMigrationStage' + => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH, + 'wgActorTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH, + ], + [], + [ + 'tables' => [ + 'revision', + 'temp_rev_user' => 'revision_actor_temp', + 'temp_rev_comment' => 'revision_comment_temp', + 'actor_rev_user' => 'actor', + 'comment_rev_comment' => 'comment', + ], + 'fields' => array_merge( + $this->getRevisionQueryFields( true ), + $this->getContentHandlerQueryFields( 'rev' ), + $this->getCompatActorQueryFields( 'rev', 'temp_rev_user.revactor_actor' ), + $this->getCompatCommentQueryFields( 'rev' ) + ), + 'joins' => array_merge( + $this->getCompatActorJoins( 'rev' ), + $this->getCompatCommentJoins( 'rev' ) + ), + ] + ]; + yield 'MCR write-both/read-old, page, user' => [ + [ + 'wgContentHandlerUseDB' => true, + 'wgMultiContentRevisionSchemaMigrationStage' + => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH, + 'wgActorTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH, + ], + [ 'page', 'user' ], + [ + 'tables' => [ + 'revision', + 'page', + 'user', + 'temp_rev_user' => 'revision_actor_temp', + 'temp_rev_comment' => 'revision_comment_temp', + 'actor_rev_user' => 'actor', + 'comment_rev_comment' => 'comment', + ], + 'fields' => array_merge( + $this->getRevisionQueryFields( true ), + $this->getContentHandlerQueryFields( 'rev' ), + $this->getUserQueryFields(), + $this->getPageQueryFields(), + $this->getCompatActorQueryFields( 'rev', 'temp_rev_user.revactor_actor' ), + $this->getCompatCommentQueryFields( 'rev' ) + ), + 'joins' => array_merge( + [ + 'page' => [ 'INNER JOIN', [ 'page_id = rev_page' ] ], + 'user' => [ + 'LEFT JOIN', + [ + 'COALESCE( actor_rev_user.actor_user, rev_user ) != 0', + 'user_id = COALESCE( actor_rev_user.actor_user, rev_user )' + ] + ], + ], + $this->getCompatActorJoins( 'rev' ), + $this->getCompatCommentJoins( 'rev' ) + ), + ] + ]; + yield 'pre-MCR' => [ + [ + 'wgContentHandlerUseDB' => true, + 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD, + 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD, + ], + [], + [ + 'tables' => [ 'revision' ], + 'fields' => array_merge( + $this->getRevisionQueryFields( true ), + $this->getContentHandlerQueryFields( 'rev' ), + $this->getOldActorQueryFields( 'rev' ), + $this->getOldCommentQueryFields( 'rev' ) + ), + 'joins' => [], + ] + ]; + yield 'pre-MCR, page, user' => [ + [ + 'wgContentHandlerUseDB' => true, + 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD, + 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD, + ], + [ 'page', 'user' ], + [ + 'tables' => [ 'revision', 'page', 'user' ], + 'fields' => array_merge( + $this->getRevisionQueryFields( true ), + $this->getContentHandlerQueryFields( 'rev' ), + $this->getPageQueryFields(), + $this->getUserQueryFields(), + $this->getOldActorQueryFields( 'rev' ), + $this->getOldCommentQueryFields( 'rev' ) + ), + 'joins' => [ + 'page' => [ 'INNER JOIN', [ 'page_id = rev_page' ] ], + 'user' => [ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ], + ], + ] + ]; + yield 'pre-MCR, no model' => [ + [ + 'wgContentHandlerUseDB' => false, + 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD, + 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD, + ], + [], + [ + 'tables' => [ 'revision' ], + 'fields' => array_merge( + $this->getRevisionQueryFields( true ), + $this->getOldActorQueryFields( 'rev' ), + $this->getOldCommentQueryFields( 'rev' ) + ), + 'joins' => [], + ], + ]; + yield 'pre-MCR, no model, page' => [ + [ + 'wgContentHandlerUseDB' => false, + 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD, + 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD, + ], + [ 'page' ], + [ + 'tables' => [ 'revision', 'page' ], + 'fields' => array_merge( + $this->getRevisionQueryFields( true ), + $this->getPageQueryFields(), + $this->getOldActorQueryFields( 'rev' ), + $this->getOldCommentQueryFields( 'rev' ) + ), + 'joins' => [ + 'page' => [ 'INNER JOIN', [ 'page_id = rev_page' ], ], + ], + ], + ]; + yield 'pre-MCR, no model, user' => [ + [ + 'wgContentHandlerUseDB' => false, + 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD, + 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD, + ], + [ 'user' ], + [ + 'tables' => [ 'revision', 'user' ], + 'fields' => array_merge( + $this->getRevisionQueryFields( true ), + $this->getUserQueryFields(), + $this->getOldActorQueryFields( 'rev' ), + $this->getOldCommentQueryFields( 'rev' ) + ), + 'joins' => [ + 'user' => [ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ], + ], + ], + ]; + yield 'pre-MCR, no model, text' => [ + [ + 'wgContentHandlerUseDB' => false, + 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD, + 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD, + ], + [ 'text' ], + [ + 'tables' => [ 'revision', 'text' ], + 'fields' => array_merge( + $this->getRevisionQueryFields( true ), + $this->getTextQueryFields(), + $this->getOldActorQueryFields( 'rev' ), + $this->getOldCommentQueryFields( 'rev' ) + ), + 'joins' => [ + 'text' => [ 'INNER JOIN', [ 'rev_text_id=old_id' ] ], + ], + ], + ]; + yield 'pre-MCR, no model, text, page, user' => [ + [ + 'wgContentHandlerUseDB' => false, + 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_OLD, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD, + 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD, + ], + [ 'text', 'page', 'user' ], + [ + 'tables' => [ + 'revision', 'page', 'user', 'text' + ], + 'fields' => array_merge( + $this->getRevisionQueryFields( true ), + $this->getPageQueryFields(), + $this->getUserQueryFields(), + $this->getTextQueryFields(), + $this->getOldActorQueryFields( 'rev' ), + $this->getOldCommentQueryFields( 'rev' ) + ), + 'joins' => [ + 'page' => [ + 'INNER JOIN', + [ 'page_id = rev_page' ], + ], + 'user' => [ + 'LEFT JOIN', + [ + 'rev_user != 0', + 'user_id = rev_user', + ], + ], + 'text' => [ + 'INNER JOIN', + [ 'rev_text_id=old_id' ], + ], + ], + ], + ]; + } + + public function provideSlotsQueryInfo() { + yield 'MCR, no options' => [ + [ + 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_NEW, + ], + [], + [ + 'tables' => [ + 'slots' + ], + 'fields' => [ + 'slot_revision_id', + 'slot_content_id', + 'slot_origin', + 'slot_role_id', + ], + 'joins' => [], + ] + ]; + yield 'MCR, role option' => [ + [ + 'wgMultiContentRevisionSchemaMigrationStage' => SCHEMA_COMPAT_NEW, + ], + [ 'role' ], + [ + 'tables' => [ + 'slots', + 'slot_roles', + ], + 'fields' => [ + 'slot_revision_id', + 'slot_content_id', + 'slot_origin', + 'slot_role_id', + 'role_name', + ], + 'joins' => [ + 'slot_roles' => [ 'LEFT JOIN', [ 'slot_role_id = role_id' ] ], + ], + ] + ]; + yield 'MCR read-new, content option' => [ + [ + 'wgMultiContentRevisionSchemaMigrationStage' + => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, + ], + [ 'content' ], + [ + 'tables' => [ + 'slots', + 'content', + ], + 'fields' => [ + 'slot_revision_id', + 'slot_content_id', + 'slot_origin', + 'slot_role_id', + 'content_size', + 'content_sha1', + 'content_address', + 'content_model', + ], + 'joins' => [ + 'content' => [ 'INNER JOIN', [ 'slot_content_id = content_id' ] ], + ], + ] + ]; + yield 'MCR read-new, content and model options' => [ + [ + 'wgMultiContentRevisionSchemaMigrationStage' + => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_NEW, + ], + [ 'content', 'model' ], + [ + 'tables' => [ + 'slots', + 'content', + 'content_models', + ], + 'fields' => [ + 'slot_revision_id', + 'slot_content_id', + 'slot_origin', + 'slot_role_id', + 'content_size', + 'content_sha1', + 'content_address', + 'content_model', + 'model_name', + ], + 'joins' => [ + 'content' => [ 'INNER JOIN', [ 'slot_content_id = content_id' ] ], + 'content_models' => [ 'LEFT JOIN', [ 'content_model = model_id' ] ], + ], + ] + ]; + + $db = wfGetDB( DB_REPLICA ); + + yield 'MCR write-both/read-old' => [ + [ + 'wgMultiContentRevisionSchemaMigrationStage' + => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, + ], + [], + [ + 'tables' => [ + 'slots' => 'revision', + ], + 'fields' => array_merge( + [ + 'slot_revision_id' => 'slots.rev_id', + 'slot_content_id' => 'NULL', + 'slot_origin' => 'slots.rev_id', + 'role_name' => $db->addQuotes( 'main' ), + ] + ), + 'joins' => [], + ] + ]; + yield 'MCR write-both/read-old, content' => [ + [ + 'wgMultiContentRevisionSchemaMigrationStage' + => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, + ], + [ 'content' ], + [ + 'tables' => [ + 'slots' => 'revision', + ], + 'fields' => array_merge( + [ + 'slot_revision_id' => 'slots.rev_id', + 'slot_content_id' => 'NULL', + 'slot_origin' => 'slots.rev_id', + 'role_name' => $db->addQuotes( 'main' ), + 'content_size' => 'slots.rev_len', + 'content_sha1' => 'slots.rev_sha1', + 'content_address' => $db->buildConcat( [ + $db->addQuotes( 'tt:' ), 'slots.rev_text_id' ] ), + 'model_name' => 'slots.rev_content_model', + ] + ), + 'joins' => [], + ] + ]; + yield 'MCR write-both/read-old, content, model, role' => [ + [ + 'wgMultiContentRevisionSchemaMigrationStage' + => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD, + ], + [ 'content', 'model', 'role' ], + [ + 'tables' => [ + 'slots' => 'revision', + ], + 'fields' => array_merge( + [ + 'slot_revision_id' => 'slots.rev_id', + 'slot_content_id' => 'NULL', + 'slot_origin' => 'slots.rev_id', + 'role_name' => $db->addQuotes( 'main' ), + 'content_size' => 'slots.rev_len', + 'content_sha1' => 'slots.rev_sha1', + 'content_address' => $db->buildConcat( [ + $db->addQuotes( 'tt:' ), 'slots.rev_text_id' ] ), + 'model_name' => 'slots.rev_content_model', + ] + ), + 'joins' => [], + ] + ]; + yield 'pre-MCR' => [ + [ + 'wgMultiContentRevisionSchemaMigrationStage' + => SCHEMA_COMPAT_OLD, + ], + [], + [ + 'tables' => [ + 'slots' => 'revision', + ], + 'fields' => array_merge( + [ + 'slot_revision_id' => 'slots.rev_id', + 'slot_content_id' => 'NULL', + 'slot_origin' => 'slots.rev_id', + 'role_name' => $db->addQuotes( 'main' ), + ] + ), + 'joins' => [], + ] + ]; + yield 'pre-MCR, content' => [ + [ + 'wgMultiContentRevisionSchemaMigrationStage' + => SCHEMA_COMPAT_OLD, + ], + [ 'content' ], + [ + 'tables' => [ + 'slots' => 'revision', + ], + 'fields' => array_merge( + [ + 'slot_revision_id' => 'slots.rev_id', + 'slot_content_id' => 'NULL', + 'slot_origin' => 'slots.rev_id', + 'role_name' => $db->addQuotes( 'main' ), + 'content_size' => 'slots.rev_len', + 'content_sha1' => 'slots.rev_sha1', + 'content_address' => + $db->buildConcat( [ $db->addQuotes( 'tt:' ), 'slots.rev_text_id' ] ), + 'model_name' => 'slots.rev_content_model', + ] + ), + 'joins' => [], + ] + ]; + } + + public function provideSelectFields() { + yield 'with model, comment, and actor' => [ + [ + 'wgContentHandlerUseDB' => true, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH, + 'wgActorTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH, + ], + 'fields' => array_merge( + [ + 'rev_id', + 'rev_page', + 'rev_text_id', + 'rev_timestamp', + 'rev_user_text', + 'rev_user', + 'rev_actor' => 'NULL', + 'rev_minor_edit', + 'rev_deleted', + 'rev_len', + 'rev_parent_id', + 'rev_sha1', + ], + $this->getContentHandlerQueryFields( 'rev' ), + [ + 'rev_comment_old' => 'rev_comment', + 'rev_comment_pk' => 'rev_id', + ] + ), + ]; + yield 'no mode, no comment, no actor' => [ + [ + 'wgContentHandlerUseDB' => false, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD, + 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD, + ], + 'fields' => array_merge( + [ + 'rev_id', + 'rev_page', + 'rev_text_id', + 'rev_timestamp', + 'rev_user_text', + 'rev_user', + 'rev_actor' => 'NULL', + 'rev_minor_edit', + 'rev_deleted', + 'rev_len', + 'rev_parent_id', + 'rev_sha1', + ], + $this->getOldCommentQueryFields( 'rev' ) + ), + ]; + } + + public function provideSelectArchiveFields() { + yield 'with model, comment, and actor' => [ + [ + 'wgContentHandlerUseDB' => true, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH, + 'wgActorTableSchemaMigrationStage' => MIGRATION_WRITE_BOTH, + ], + 'fields' => array_merge( + [ + 'ar_id', + 'ar_page_id', + 'ar_rev_id', + 'ar_text_id', + 'ar_timestamp', + 'ar_user_text', + 'ar_user', + 'ar_actor' => 'NULL', + 'ar_minor_edit', + 'ar_deleted', + 'ar_len', + 'ar_parent_id', + 'ar_sha1', + ], + $this->getContentHandlerQueryFields( 'ar' ), + [ + 'ar_comment_old' => 'ar_comment', + 'ar_comment_id' => 'ar_comment_id', + ] + ), + ]; + yield 'no mode, no comment, no actor' => [ + [ + 'wgContentHandlerUseDB' => false, + 'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD, + 'wgActorTableSchemaMigrationStage' => MIGRATION_OLD, + ], + 'fields' => array_merge( + [ + 'ar_id', + 'ar_page_id', + 'ar_rev_id', + 'ar_text_id', + 'ar_timestamp', + 'ar_user_text', + 'ar_user', + 'ar_actor' => 'NULL', + 'ar_minor_edit', + 'ar_deleted', + 'ar_len', + 'ar_parent_id', + 'ar_sha1', + ], + $this->getOldCommentQueryFields( 'ar' ) + ), + ]; + } + + /** + * @dataProvider provideSelectFields + * @covers Revision::selectFields + */ + public function testRevisionSelectFields( $migrationStageSettings, $expected ) { + $this->setMwGlobals( $migrationStageSettings ); + $this->overrideMwServices(); + + $this->hideDeprecated( 'Revision::selectFields' ); + $this->assertArrayEqualsIgnoringIntKeyOrder( $expected, Revision::selectFields() ); + } + + /** + * @dataProvider provideSelectArchiveFields + * @covers Revision::selectArchiveFields + */ + public function testRevisionSelectArchiveFields( $migrationStageSettings, $expected ) { + $this->setMwGlobals( $migrationStageSettings ); + $this->overrideMwServices(); + + $this->hideDeprecated( 'Revision::selectArchiveFields' ); + $this->assertArrayEqualsIgnoringIntKeyOrder( $expected, Revision::selectArchiveFields() ); + } + + /** + * @covers Revision::userJoinCond + */ + public function testRevisionUserJoinCond() { + $this->hideDeprecated( 'Revision::userJoinCond' ); + $this->setMwGlobals( 'wgActorTableSchemaMigrationStage', MIGRATION_OLD ); + $this->overrideMwServices(); + $this->assertEquals( + [ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ], + Revision::userJoinCond() + ); + } + + /** + * @covers Revision::pageJoinCond + */ + public function testRevisionPageJoinCond() { + $this->hideDeprecated( 'Revision::pageJoinCond' ); + $this->assertEquals( + [ 'INNER JOIN', [ 'page_id = rev_page' ] ], + Revision::pageJoinCond() + ); + } + + /** + * @covers Revision::selectTextFields + */ + public function testRevisionSelectTextFields() { + $this->hideDeprecated( 'Revision::selectTextFields' ); + $this->assertEquals( + $this->getTextQueryFields(), + Revision::selectTextFields() + ); + } + + /** + * @covers Revision::selectPageFields + */ + public function testRevisionSelectPageFields() { + $this->hideDeprecated( 'Revision::selectPageFields' ); + $this->assertEquals( + $this->getPageQueryFields(), + Revision::selectPageFields() + ); + } + + /** + * @covers Revision::selectUserFields + */ + public function testRevisionSelectUserFields() { + $this->hideDeprecated( 'Revision::selectUserFields' ); + $this->assertEquals( + $this->getUserQueryFields(), + Revision::selectUserFields() + ); + } + + /** + * @covers Revision::getArchiveQueryInfo + * @dataProvider provideArchiveQueryInfo + */ + public function testRevisionGetArchiveQueryInfo( $migrationStageSettings, $expected ) { + $this->setMwGlobals( $migrationStageSettings ); + $this->overrideMwServices(); + + $queryInfo = Revision::getArchiveQueryInfo(); + $this->assertQueryInfoEquals( $expected, $queryInfo ); + } + + /** + * @covers Revision::getQueryInfo + * @dataProvider provideQueryInfo + */ + public function testRevisionGetQueryInfo( $migrationStageSettings, $options, $expected ) { + $this->setMwGlobals( $migrationStageSettings ); + $this->overrideMwServices(); + + $queryInfo = Revision::getQueryInfo( $options ); + $this->assertQueryInfoEquals( $expected, $queryInfo ); + } + + /** + * @dataProvider provideQueryInfo + * @covers \MediaWiki\Storage\RevisionStore::getQueryInfo + */ + public function testRevisionStoreGetQueryInfo( $migrationStageSettings, $options, $expected ) { + $this->setMwGlobals( $migrationStageSettings ); + $this->overrideMwServices(); + + $store = MediaWikiServices::getInstance()->getRevisionStore(); + + $queryInfo = $store->getQueryInfo( $options ); + $this->assertQueryInfoEquals( $expected, $queryInfo ); + } + + /** + * @dataProvider provideSlotsQueryInfo + * @covers \MediaWiki\Storage\RevisionStore::getSlotsQueryInfo + */ + public function testRevisionStoreGetSlotsQueryInfo( + $migrationStageSettings, + $options, + $expected + ) { + $this->setMwGlobals( $migrationStageSettings ); + $this->overrideMwServices(); + + $store = MediaWikiServices::getInstance()->getRevisionStore(); + + $queryInfo = $store->getSlotsQueryInfo( $options ); + $this->assertQueryInfoEquals( $expected, $queryInfo ); + } + + /** + * @dataProvider provideArchiveQueryInfo + * @covers \MediaWiki\Storage\RevisionStore::getArchiveQueryInfo + */ + public function testRevisionStoreGetArchiveQueryInfo( $migrationStageSettings, $expected ) { + $this->setMwGlobals( $migrationStageSettings ); + $this->overrideMwServices(); + + $store = MediaWikiServices::getInstance()->getRevisionStore(); + + $queryInfo = $store->getArchiveQueryInfo(); + $this->assertQueryInfoEquals( $expected, $queryInfo ); + } + + private function assertQueryInfoEquals( $expected, $queryInfo ) { + $this->assertArrayEqualsIgnoringIntKeyOrder( + $expected['tables'], + $queryInfo['tables'], + 'tables' + ); + $this->assertArrayEqualsIgnoringIntKeyOrder( + $expected['fields'], + $queryInfo['fields'], + 'fields' + ); + $this->assertArrayEqualsIgnoringIntKeyOrder( + $expected['joins'], + $queryInfo['joins'], + 'joins' + ); + } + + /** + * Assert that the two arrays passed are equal, ignoring the order of the values that integer + * keys. + * + * Note: Failures of this assertion can be slightly confusing as the arrays are actually + * split into a string key array and an int key array before assertions occur. + * + * @param array $expected + * @param array $actual + */ + private function assertArrayEqualsIgnoringIntKeyOrder( + array $expected, + array $actual, + $message = null + ) { + $this->objectAssociativeSort( $expected ); + $this->objectAssociativeSort( $actual ); + + // Separate the int key values from the string key values so that assertion failures are + // easier to understand. + $expectedIntKeyValues = []; + $actualIntKeyValues = []; + + // Remove all int keys and re add them at the end after sorting by value + // This will result in all int keys being in the same order with same ints at the end of + // the array + foreach ( $expected as $key => $value ) { + if ( is_int( $key ) ) { + unset( $expected[$key] ); + $expectedIntKeyValues[] = $value; + } + } + foreach ( $actual as $key => $value ) { + if ( is_int( $key ) ) { + unset( $actual[$key] ); + $actualIntKeyValues[] = $value; + } + } + + $this->objectAssociativeSort( $expected ); + $this->objectAssociativeSort( $actual ); + + $this->objectAssociativeSort( $expectedIntKeyValues ); + $this->objectAssociativeSort( $actualIntKeyValues ); + + $this->assertEquals( $expected, $actual, $message ); + $this->assertEquals( $expectedIntKeyValues, $actualIntKeyValues, $message ); + } + +} diff --git a/tests/phpunit/includes/Storage/RevisionStoreDbTestBase.php b/tests/phpunit/includes/Storage/RevisionStoreDbTestBase.php index 667975458c..40e03add07 100644 --- a/tests/phpunit/includes/Storage/RevisionStoreDbTestBase.php +++ b/tests/phpunit/includes/Storage/RevisionStoreDbTestBase.php @@ -271,7 +271,7 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase { $this->assertEquals( $r1->getSha1(), $r2->getSha1() ); $this->assertEquals( $r1->getSize(), $r2->getSize() ); $this->assertEquals( $r1->getPageId(), $r2->getPageId() ); - $this->assertArrayEqualsIgnoringIntKeyOrder( $r1->getSlotRoles(), $r2->getSlotRoles() ); + $this->assertArrayEquals( $r1->getSlotRoles(), $r2->getSlotRoles() ); $this->assertEquals( $r1->getWikiId(), $r2->getWikiId() ); $this->assertEquals( $r1->isMinor(), $r2->isMinor() ); foreach ( $r1->getSlotRoles() as $role ) { @@ -617,7 +617,7 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase { $this->assertEquals( $user->getName(), $record->getUser()->getName() ); $this->assertEquals( $baseRev->getId(), $record->getParentId() ); - $this->assertArrayEqualsIgnoringIntKeyOrder( + $this->assertArrayEquals( $baseRev->getSlotRoles(), $record->getSlotRoles() ); @@ -887,6 +887,38 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase { } } + /** + * @covers \MediaWiki\Storage\RevisionStore::newRevisionFromRow + * @covers \MediaWiki\Storage\RevisionStore::getQueryInfo + */ + public function testNewRevisionFromRow_getQueryInfo() { + $page = $this->getTestPage(); + $text = __METHOD__ . 'a-ä'; + /** @var Revision $rev */ + $rev = $page->doEditContent( + new WikitextContent( $text ), + __METHOD__ . 'a' + )->value['revision']; + + $store = MediaWikiServices::getInstance()->getRevisionStore(); + $info = $store->getQueryInfo(); + $row = $this->db->selectRow( + $info['tables'], + $info['fields'], + [ 'rev_id' => $rev->getId() ], + __METHOD__, + [], + $info['joins'] + ); + $record = $store->newRevisionFromRow( + $row, + [], + $page->getTitle() + ); + $this->assertRevisionRecordMatchesRevision( $rev, $record ); + $this->assertSame( $text, $rev->getContent()->serialize() ); + } + /** * @covers \MediaWiki\Storage\RevisionStore::newRevisionFromRow */ @@ -960,8 +992,9 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase { /** * @covers \MediaWiki\Storage\RevisionStore::newRevisionFromArchiveRow + * @covers \MediaWiki\Storage\RevisionStore::getArchiveQueryInfo */ - public function testNewRevisionFromArchiveRow() { + public function testNewRevisionFromArchiveRow_getArchiveQueryInfo() { $store = MediaWikiServices::getInstance()->getRevisionStore(); $title = Title::newFromText( __METHOD__ ); $text = __METHOD__ . '-bä'; @@ -1545,182 +1578,4 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase { $this->testNewMutableRevisionFromArray( $array ); } - protected function getDefaultQueryFields( $returnTextIdField = true ) { - $fields = [ - 'rev_id', - 'rev_page', - 'rev_timestamp', - 'rev_minor_edit', - 'rev_deleted', - 'rev_len', - 'rev_parent_id', - 'rev_sha1', - ]; - if ( $returnTextIdField ) { - $fields[] = 'rev_text_id'; - } - return $fields; - } - - protected function getCommentQueryFields() { - return [ - 'rev_comment_text' => 'rev_comment', - 'rev_comment_data' => 'NULL', - 'rev_comment_cid' => 'NULL', - ]; - } - - protected function getActorQueryFields() { - return [ - 'rev_user' => 'rev_user', - 'rev_user_text' => 'rev_user_text', - 'rev_actor' => 'NULL', - ]; - } - - protected function getContentHandlerQueryFields() { - return [ - 'rev_content_format', - 'rev_content_model', - ]; - } - - abstract public function provideGetQueryInfo(); - - /** - * @dataProvider provideGetQueryInfo - * @covers \MediaWiki\Storage\RevisionStore::getQueryInfo - */ - public function testGetQueryInfo( $options, $expected ) { - $store = MediaWikiServices::getInstance()->getRevisionStore(); - - $queryInfo = $store->getQueryInfo( $options ); - - $this->assertArrayEqualsIgnoringIntKeyOrder( - $expected['tables'], - $queryInfo['tables'] - ); - $this->assertArrayEqualsIgnoringIntKeyOrder( - $expected['fields'], - $queryInfo['fields'] - ); - $this->assertArrayEqualsIgnoringIntKeyOrder( - $expected['joins'], - $queryInfo['joins'] - ); - } - - protected function getDefaultArchiveFields( $returnTextFields = true ) { - $fields = [ - 'ar_id', - 'ar_page_id', - 'ar_namespace', - 'ar_title', - 'ar_rev_id', - 'ar_timestamp', - 'ar_minor_edit', - 'ar_deleted', - 'ar_len', - 'ar_parent_id', - 'ar_sha1', - ]; - if ( $returnTextFields ) { - $fields[] = 'ar_text_id'; - } - return $fields; - } - - abstract public function provideGetArchiveQueryInfo(); - - /** - * @dataProvider provideGetArchiveQueryInfo - * @covers \MediaWiki\Storage\RevisionStore::getArchiveQueryInfo - */ - public function testGetArchiveQueryInfo( $expected ) { - $store = MediaWikiServices::getInstance()->getRevisionStore(); - - $archiveQueryInfo = $store->getArchiveQueryInfo(); - - $this->assertArrayEqualsIgnoringIntKeyOrder( - $expected['tables'], - $archiveQueryInfo['tables'] - ); - - $this->assertArrayEqualsIgnoringIntKeyOrder( - $expected['fields'], - $archiveQueryInfo['fields'] - ); - - $this->assertArrayEqualsIgnoringIntKeyOrder( - $expected['joins'], - $archiveQueryInfo['joins'] - ); - } - - abstract public function provideGetSlotsQueryInfo(); - - /** - * @dataProvider provideGetSlotsQueryInfo - * @covers \MediaWiki\Storage\RevisionStore::getSlotsQueryInfo - */ - public function testGetSlotsQueryInfo( $options, $expected ) { - $store = MediaWikiServices::getInstance()->getRevisionStore(); - - $archiveQueryInfo = $store->getSlotsQueryInfo( $options ); - - $this->assertArrayEqualsIgnoringIntKeyOrder( - $expected['tables'], - $archiveQueryInfo['tables'] - ); - - $this->assertArrayEqualsIgnoringIntKeyOrder( - $expected['fields'], - $archiveQueryInfo['fields'] - ); - - $this->assertArrayEqualsIgnoringIntKeyOrder( - $expected['joins'], - $archiveQueryInfo['joins'] - ); - } - - /** - * Assert that the two arrays passed are equal, ignoring the order of the values that integer - * keys. - * - * Note: Failures of this assertion can be slightly confusing as the arrays are actually - * split into a string key array and an int key array before assertions occur. - * - * @param array $expected - * @param array $actual - */ - private function assertArrayEqualsIgnoringIntKeyOrder( array $expected, array $actual ) { - $this->objectAssociativeSort( $expected ); - $this->objectAssociativeSort( $actual ); - - // Separate the int key values from the string key values so that assertion failures are - // easier to understand. - $expectedIntKeyValues = []; - $actualIntKeyValues = []; - - // Remove all int keys and re add them at the end after sorting by value - // This will result in all int keys being in the same order with same ints at the end of - // the array - foreach ( $expected as $key => $value ) { - if ( is_int( $key ) ) { - unset( $expected[$key] ); - $expectedIntKeyValues[] = $value; - } - } - foreach ( $actual as $key => $value ) { - if ( is_int( $key ) ) { - unset( $actual[$key] ); - $actualIntKeyValues[] = $value; - } - } - - $this->assertArrayEquals( $expected, $actual, false, true ); - $this->assertArrayEquals( $expectedIntKeyValues, $actualIntKeyValues, false, true ); - } - } -- 2.20.1