X-Git-Url: http://git.cyclocoop.org/%7B%24www_url%7Dadmin/compta/categories/supprimer.php?a=blobdiff_plain;f=tests%2Fphpunit%2Fincludes%2FRevision%2FRevisionStoreDbTestBase.php;h=3467153a5587b42bad2e31038675062d22cd76bb;hb=1bd43b1bffffc3720e1ef743d802e88fdf849b0f;hp=018df481152a41fdcfa66c8d80fcba64073c3642;hpb=b6ee3e52534e0c76598383318a97a0c385dd3236;p=lhc%2Fweb%2Fwiklou.git diff --git a/tests/phpunit/includes/Revision/RevisionStoreDbTestBase.php b/tests/phpunit/includes/Revision/RevisionStoreDbTestBase.php index 018df48115..3467153a55 100644 --- a/tests/phpunit/includes/Revision/RevisionStoreDbTestBase.php +++ b/tests/phpunit/includes/Revision/RevisionStoreDbTestBase.php @@ -14,6 +14,7 @@ use MediaWiki\Revision\IncompleteRevisionException; use MediaWiki\Revision\MutableRevisionRecord; use MediaWiki\Revision\RevisionArchiveRecord; use MediaWiki\Revision\RevisionRecord; +use MediaWiki\Revision\RevisionStoreRecord; use MediaWiki\Revision\RevisionSlots; use MediaWiki\Revision\RevisionStore; use MediaWiki\Revision\SlotRecord; @@ -80,7 +81,7 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase { $this->setMwGlobals( [ 'wgMultiContentRevisionSchemaMigrationStage' => $this->getMcrMigrationStage(), 'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(), - 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_OLD, + 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW, ] ); $this->overrideMwServices(); @@ -437,9 +438,19 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase { $queryInfo = $store->getQueryInfo( [ 'user' ] ); $row = get_object_vars( $row ); + + // Use aliased fields from $queryInfo, e.g. rev_user + $keys = array_keys( $row ); + $keys = array_combine( $keys, $keys ); + $fields = array_intersect_key( $queryInfo['fields'], $keys ) + $keys; + + // assertSelect() fails unless the orders match. + ksort( $fields ); + ksort( $row ); + $this->assertSelect( $queryInfo['tables'], - array_keys( $row ), + $fields, [ 'rev_id' => $rev->getId() ], [ array_values( $row ) ], [], @@ -799,7 +810,7 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase { 'rev_page' => (string)$rev->getPage(), 'rev_timestamp' => $this->db->timestamp( $rev->getTimestamp() ), 'rev_user_text' => (string)$rev->getUserText(), - 'rev_user' => (string)$rev->getUser(), + 'rev_user' => (string)$rev->getUser() ?: null, 'rev_minor_edit' => $rev->isMinor() ? '1' : '0', 'rev_deleted' => (string)$rev->getVisibility(), 'rev_len' => (string)$rev->getSize(), @@ -1405,10 +1416,7 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase { ->value['revision']; $store = MediaWikiServices::getInstance()->getRevisionStore(); - $result = $store->getTimestampFromId( - $page->getTitle(), - $rev->getId() - ); + $result = $store->getTimestampFromId( $rev->getId() ); $this->assertSame( $rev->getTimestamp(), $result ); } @@ -1423,10 +1431,7 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase { ->value['revision']; $store = MediaWikiServices::getInstance()->getRevisionStore(); - $result = $store->getTimestampFromId( - $page->getTitle(), - $rev->getId() + 1 - ); + $result = $store->getTimestampFromId( $rev->getId() + 1 ); $this->assertFalse( $result ); } @@ -1705,4 +1710,198 @@ abstract class RevisionStoreDbTestBase extends MediaWikiTestCase { $this->testNewMutableRevisionFromArray( $array ); } + /** + * Creates a new revision for testing caching behavior + * + * @param WikiPage $page the page for the new revision + * @param RevisionStore $store store object to use for creating the revision + * @return bool|RevisionStoreRecord the revision created, or false if missing + */ + private function createRevisionStoreCacheRecord( $page, $store ) { + $user = MediaWikiTestCase::getMutableTestUser()->getUser(); + $updater = $page->newPageUpdater( $user ); + $updater->setContent( SlotRecord::MAIN, new WikitextContent( __METHOD__ ) ); + $summary = CommentStoreComment::newUnsavedComment( __METHOD__ ); + $rev = $updater->saveRevision( $summary, EDIT_NEW ); + return $store->getKnownCurrentRevision( $page->getTitle(), $rev->getId() ); + } + + /** + * @covers \MediaWiki\Revision\RevisionStore::getKnownCurrentRevision + */ + public function testGetKnownCurrentRevision_userNameChange() { + global $wgActorTableSchemaMigrationStage; + + $this->overrideMwServices(); + $cache = new WANObjectCache( [ 'cache' => new HashBagOStuff() ] ); + $this->setService( 'MainWANObjectCache', $cache ); + + $store = MediaWikiServices::getInstance()->getRevisionStore(); + $page = $this->getNonexistingTestPage(); + $rev = $this->createRevisionStoreCacheRecord( $page, $store ); + + // Grab the user name + $userNameBefore = $rev->getUser()->getName(); + + // Change the user name in the database, "behind the back" of the cache + $newUserName = "Renamed $userNameBefore"; + $this->db->update( 'revision', + [ 'rev_user_text' => $newUserName ], + [ 'rev_id' => $rev->getId() ] ); + $this->db->update( 'user', + [ 'user_name' => $newUserName ], + [ 'user_id' => $rev->getUser()->getId() ] ); + if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { + $this->db->update( 'actor', + [ 'actor_name' => $newUserName ], + [ 'actor_user' => $rev->getUser()->getId() ] ); + } + + // Reload the revision and regrab the user name. + $revAfter = $store->getKnownCurrentRevision( $page->getTitle(), $rev->getId() ); + $userNameAfter = $revAfter->getUser()->getName(); + + // The two user names should be different. + // If they are the same, we are seeing a cached value, which is bad. + $this->assertNotSame( $userNameBefore, $userNameAfter ); + + // This is implied by the above assertion, but explicitly check it, for completeness + $this->assertSame( $newUserName, $userNameAfter ); + } + + /** + * @covers \MediaWiki\Revision\RevisionStore::getKnownCurrentRevision + */ + public function testGetKnownCurrentRevision_revDelete() { + $this->overrideMwServices(); + $cache = new WANObjectCache( [ 'cache' => new HashBagOStuff() ] ); + $this->setService( 'MainWANObjectCache', $cache ); + + $store = MediaWikiServices::getInstance()->getRevisionStore(); + $page = $this->getNonexistingTestPage(); + $rev = $this->createRevisionStoreCacheRecord( $page, $store ); + + // Grab the deleted bitmask + $deletedBefore = $rev->getVisibility(); + + // Change the deleted bitmask in the database, "behind the back" of the cache + $this->db->update( 'revision', + [ 'rev_deleted' => RevisionRecord::DELETED_TEXT ], + [ 'rev_id' => $rev->getId() ] ); + + // Reload the revision and regrab the visibility flag. + $revAfter = $store->getKnownCurrentRevision( $page->getTitle(), $rev->getId() ); + $deletedAfter = $revAfter->getVisibility(); + + // The two deleted flags should be different. + // If they are the same, we are seeing a cached value, which is bad. + $this->assertNotSame( $deletedBefore, $deletedAfter ); + + // This is implied by the above assertion, but explicitly check it, for completeness + $this->assertSame( RevisionRecord::DELETED_TEXT, $deletedAfter ); + } + + /** + * @covers \MediaWiki\Revision\RevisionStore::newRevisionFromRow + */ + public function testNewRevisionFromRow_userNameChange() { + global $wgActorTableSchemaMigrationStage; + + $page = $this->getTestPage(); + $text = __METHOD__; + /** @var Revision $rev */ + $rev = $page->doEditContent( + new WikitextContent( $text ), + __METHOD__, + 0, + false, + $this->getMutableTestUser()->getUser() + )->value['revision']; + + $store = MediaWikiServices::getInstance()->getRevisionStore(); + $record = $store->newRevisionFromRow( + $this->revisionToRow( $rev ), + [], + $page->getTitle() + ); + + // Grab the user name + $userNameBefore = $record->getUser()->getName(); + + // Change the user name in the database + $newUserName = "Renamed $userNameBefore"; + $this->db->update( 'revision', + [ 'rev_user_text' => $newUserName ], + [ 'rev_id' => $record->getId() ] ); + $this->db->update( 'user', + [ 'user_name' => $newUserName ], + [ 'user_id' => $record->getUser()->getId() ] ); + if ( $wgActorTableSchemaMigrationStage & SCHEMA_COMPAT_WRITE_NEW ) { + $this->db->update( 'actor', + [ 'actor_name' => $newUserName ], + [ 'actor_user' => $record->getUser()->getId() ] ); + } + + // Reload the record, passing $fromCache as true to force fresh info from the db, + // and regrab the user name + $recordAfter = $store->newRevisionFromRow( + $this->revisionToRow( $rev ), + [], + $page->getTitle(), + true + ); + $userNameAfter = $recordAfter->getUser()->getName(); + + // The two user names should be different. + // If they are the same, we are seeing a cached value, which is bad. + $this->assertNotSame( $userNameBefore, $userNameAfter ); + + // This is implied by the above assertion, but explicitly check it, for completeness + $this->assertSame( $newUserName, $userNameAfter ); + } + + /** + * @covers \MediaWiki\Revision\RevisionStore::newRevisionFromRow + */ + public function testNewRevisionFromRow_revDelete() { + $page = $this->getTestPage(); + $text = __METHOD__; + /** @var Revision $rev */ + $rev = $page->doEditContent( + new WikitextContent( $text ), + __METHOD__ + )->value['revision']; + + $store = MediaWikiServices::getInstance()->getRevisionStore(); + $record = $store->newRevisionFromRow( + $this->revisionToRow( $rev ), + [], + $page->getTitle() + ); + + // Grab the deleted bitmask + $deletedBefore = $record->getVisibility(); + + // Change the deleted bitmask in the database + $this->db->update( 'revision', + [ 'rev_deleted' => RevisionRecord::DELETED_TEXT ], + [ 'rev_id' => $record->getId() ] ); + + // Reload the record, passing $fromCache as true to force fresh info from the db, + // and regrab the deleted bitmask + $recordAfter = $store->newRevisionFromRow( + $this->revisionToRow( $rev ), + [], + $page->getTitle(), + true + ); + $deletedAfter = $recordAfter->getVisibility(); + + // The two deleted flags should be different, because we modified the database. + $this->assertNotSame( $deletedBefore, $deletedAfter ); + + // This is implied by the above assertion, but explicitly check it, for completeness + $this->assertSame( RevisionRecord::DELETED_TEXT, $deletedAfter ); + } + }