Merge "RevisionStoreDbTestBase, remove redundant needsDB override"
[lhc/web/wiklou.git] / tests / phpunit / includes / Storage / RevisionStoreDbTestBase.php
index 8137b27..5497d98 100644 (file)
@@ -17,6 +17,7 @@ use MediaWiki\Storage\RevisionRecord;
 use MediaWiki\Storage\RevisionStore;
 use MediaWiki\Storage\SlotRecord;
 use MediaWiki\Storage\SqlBlobStore;
+use MediaWiki\User\UserIdentityValue;
 use MediaWikiTestCase;
 use PHPUnit_Framework_MockObject_MockObject;
 use Revision;
@@ -64,10 +65,6 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
         */
        abstract protected function getMcrTablesToReset();
 
-       public function needsDB() {
-               return true;
-       }
-
        public function setUp() {
                parent::setUp();
                $this->tablesUsed[] = 'archive';
@@ -77,15 +74,12 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
 
                $this->tablesUsed += $this->getMcrTablesToReset();
 
-               $this->setMwGlobals(
-                       'wgMultiContentRevisionSchemaMigrationStage',
-                       $this->getMcrMigrationStage()
-               );
-
-               $this->setMwGlobals(
-                       'wgContentHandlerUseDB',
-                       $this->getContentHandlerUseDB()
-               );
+               $this->setMwGlobals( [
+                       'wgMultiContentRevisionSchemaMigrationStage' => $this->getMcrMigrationStage(),
+                       'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(),
+                       'wgCommentTableSchemaMigrationStage' => MIGRATION_OLD,
+                       'wgActorTableSchemaMigrationStage' => MIGRATION_OLD,
+               ] );
 
                $this->overrideMwServices();
        }
@@ -274,7 +268,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 ) {
@@ -397,9 +391,6 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
        public function testInsertRevisionOn_successes(
                array $revDetails = []
        ) {
-               // FIXME: fails under postgres
-               $this->markTestSkippedIfDbType( 'postgres' );
-
                $title = $this->getTestPageTitle();
                $rev = $this->getRevisionRecordFromDetailsArray( $revDetails );
 
@@ -620,7 +611,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()
                );
@@ -842,7 +833,7 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
                return (object)$fields;
        }
 
-       private function assertRevisionRecordMatchesRevision(
+       protected function assertRevisionRecordMatchesRevision(
                Revision $rev,
                RevisionRecord $record
        ) {
@@ -890,6 +881,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
         */
@@ -923,7 +946,7 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
                /** @var Revision $rev */
                $rev = $page->doEditContent(
                        new WikitextContent( $text ),
-                       __METHOD__. 'a'
+                       __METHOD__ . 'a'
                )->value['revision'];
 
                $store = MediaWikiServices::getInstance()->getRevisionStore();
@@ -963,8 +986,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ä';
@@ -1021,10 +1045,89 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
                $this->assertSame( $text, $record->getContent( 'main' )->serialize() );
        }
 
+       /**
+        * @covers \MediaWiki\Storage\RevisionStore::newRevisionFromArchiveRow
+        */
+       public function testNewRevisionFromArchiveRow_no_user() {
+               $store = MediaWikiServices::getInstance()->getRevisionStore();
+
+               $row = (object)[
+                       'ar_id' => '1',
+                       'ar_page_id' => '2',
+                       'ar_namespace' => '0',
+                       'ar_title' => 'Something',
+                       'ar_rev_id' => '2',
+                       'ar_text_id' => '47',
+                       'ar_timestamp' => '20180528192356',
+                       'ar_minor_edit' => '0',
+                       'ar_deleted' => '0',
+                       'ar_len' => '78',
+                       'ar_parent_id' => '0',
+                       'ar_sha1' => 'deadbeef',
+                       'ar_comment_text' => 'whatever',
+                       'ar_comment_data' => null,
+                       'ar_comment_cid' => null,
+                       'ar_user' => '0',
+                       'ar_user_text' => '', // this is the important bit
+                       'ar_actor' => null,
+                       'ar_content_format' => null,
+                       'ar_content_model' => null,
+               ];
+
+               \Wikimedia\suppressWarnings();
+               $record = $store->newRevisionFromArchiveRow( $row );
+               \Wikimedia\suppressWarnings( true );
+
+               $this->assertInstanceOf( RevisionRecord::class, $record );
+               $this->assertInstanceOf( UserIdentityValue::class, $record->getUser() );
+               $this->assertSame( 'Unknown user', $record->getUser()->getName() );
+       }
+
+       /**
+        * @covers \MediaWiki\Storage\RevisionStore::newRevisionFromRow
+        */
+       public function testNewRevisionFromRow_no_user() {
+               $store = MediaWikiServices::getInstance()->getRevisionStore();
+               $title = Title::newFromText( __METHOD__ );
+
+               $row = (object)[
+                       'rev_id' => '2',
+                       'rev_page' => '2',
+                       'page_namespace' => '0',
+                       'page_title' => $title->getText(),
+                       'rev_text_id' => '47',
+                       'rev_timestamp' => '20180528192356',
+                       'rev_minor_edit' => '0',
+                       'rev_deleted' => '0',
+                       'rev_len' => '78',
+                       'rev_parent_id' => '0',
+                       'rev_sha1' => 'deadbeef',
+                       'rev_comment_text' => 'whatever',
+                       'rev_comment_data' => null,
+                       'rev_comment_cid' => null,
+                       'rev_user' => '0',
+                       'rev_user_text' => '', // this is the important bit
+                       'rev_actor' => null,
+                       'rev_content_format' => null,
+                       'rev_content_model' => null,
+               ];
+
+               \Wikimedia\suppressWarnings();
+               $record = $store->newRevisionFromRow( $row, 0, $title );
+               \Wikimedia\suppressWarnings( true );
+
+               $this->assertNotNull( $record );
+               $this->assertNotNull( $record->getUser() );
+               $this->assertNotEmpty( $record->getUser()->getName() );
+       }
+
        /**
         * @covers \MediaWiki\Storage\RevisionStore::insertRevisionOn
         */
        public function testInsertRevisionOn_archive() {
+               // This is a round trip test for deletion and undeletion of a
+               // revision row via the archive table.
+
                $store = MediaWikiServices::getInstance()->getRevisionStore();
                $title = Title::newFromText( __METHOD__ );
 
@@ -1036,6 +1139,9 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
                $orig = $origRev->getRevisionRecord();
                $page->doDeleteArticle( __METHOD__ );
 
+               // re-create page, so we can later load revisions for it
+               $page->doEditContent( new WikitextContent( 'Two' ), __METHOD__ );
+
                $db = wfGetDB( DB_MASTER );
                $arQuery = $store->getArchiveQueryInfo();
                $row = $db->selectRow(
@@ -1043,34 +1149,37 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase {
                        __METHOD__, [], $arQuery['joins']
                );
 
-               $record = $store->newRevisionFromArchiveRow( $row );
+               $this->assertNotFalse( $row, 'query failed' );
+
+               $record = $store->newRevisionFromArchiveRow(
+                       $row,
+                       0,
+                       $title,
+                       [ 'page_id' => $title->getArticleID() ]
+               );
 
                $restored = $store->insertRevisionOn( $record, $db );
-               $this->assertSame( $orig->getPageId(), $restored->getPageId() );
-               $this->assertSame( $orig->getId(), $restored->getId() );
-               $this->assertSame( $orig->getComment()->text, $restored->getComment()->text );
 
-               $origMain = $orig->getSlot( 'main' );
-               $restoredMain = $restored->getSlot( 'main' );
-               $this->assertSame(
-                       $origMain->getOrigin(),
-                       $restoredMain->getOrigin()
-               );
+               // is the new revision correct?
+               $this->assertRevisionCompleteness( $restored );
+               $this->assertRevisionRecordsEqual( $record, $restored );
 
-               if ( $origMain->hasContentId() ) {
-                       $this->assertSame(
-                               $origMain->getContentId(),
-                               $restoredMain->getContentId()
-                       );
-               }
+               // does the new revision use the original slot?
+               $recMain = $record->getSlot( 'main' );
+               $restMain = $restored->getSlot( 'main' );
+               $this->assertSame( $recMain->getAddress(), $restMain->getAddress() );
+               $this->assertSame( $recMain->getContentId(), $restMain->getContentId() );
+               $this->assertSame( $recMain->getOrigin(), $restMain->getOrigin() );
+               $this->assertSame( 'Foo', $restMain->getContent()->serialize() );
 
-               // NOTE: we didn't restore the page row, so we can't use RevisionStore::getRevisionById
-               $this->assertSelect(
-                       'revision',
-                       [ 'rev_id' ],
-                       [ 'rev_id' => $orig->getId() ],
-                       [ [ $orig->getId() ] ]
-               );
+               // can we load it from the store?
+               $loaded = $store->getRevisionById( $restored->getId() );
+               $this->assertNotNull( $loaded );
+               $this->assertRevisionCompleteness( $loaded );
+               $this->assertRevisionRecordsEqual( $restored, $loaded );
+
+               // can we find it directly in the database?
+               $this->assertRevisionExistsInDatabase( $restored );
        }
 
        /**
@@ -1548,182 +1657,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 );
-       }
-
 }