From 761e704d6e59b611241e6c83ea37dca3ab90e9e0 Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Mon, 29 Apr 2019 20:25:13 +0300 Subject: [PATCH] Convert WatchedItem and friends to LinkTarget There is no longer any reference to Title in WatchedItem classes or their unit tests except for one hook that keeps Title for compat. Happy side effects include getting rid of $revisionGetTimestampFromIdCallback, and a net reduction of 143 LOC. Change-Id: Id998c6f336ed808f7259e4f8359bcf8d6c0210d6 --- includes/ServiceWiring.php | 4 +- includes/Title.php | 10 +- includes/jobqueue/jobs/ActivityUpdateJob.php | 6 +- .../watcheditem/NoWriteWatchedItemStore.php | 2 +- includes/watcheditem/WatchedItemStore.php | 105 ++- .../watcheditem/WatchedItemStoreInterface.php | 4 +- .../NoWriteWatchedItemStoreUnitTest.php | 2 +- .../watcheditem/WatchedItemStoreUnitTest.php | 774 ++++++++---------- 8 files changed, 390 insertions(+), 517 deletions(-) diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php index 9836736394..40e54b5b9a 100644 --- a/includes/ServiceWiring.php +++ b/includes/ServiceWiring.php @@ -707,7 +707,9 @@ return [ $services->getMainObjectStash(), new HashBagOStuff( [ 'maxKeys' => 100 ] ), $services->getReadOnlyMode(), - $services->getMainConfig()->get( 'UpdateRowsPerQuery' ) + $services->getMainConfig()->get( 'UpdateRowsPerQuery' ), + $services->getNamespaceInfo(), + $services->getRevisionLookup() ); $store->setStatsdDataFactory( $services->getStatsdDataFactory() ); diff --git a/includes/Title.php b/includes/Title.php index dc5400e8e4..ad6c167937 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -3982,14 +3982,14 @@ class Title implements LinkTarget, IDBAccessObject { /** * Compare with another title. * - * @param Title $title + * @param LinkTarget $title * @return bool */ - public function equals( Title $title ) { + public function equals( LinkTarget $title ) { // Note: === is necessary for proper matching of number-like titles. - return $this->mInterwiki === $title->mInterwiki - && $this->mNamespace == $title->mNamespace - && $this->mDbkeyform === $title->mDbkeyform; + return $this->mInterwiki === $title->getInterwiki() + && $this->mNamespace == $title->getNamespace() + && $this->mDbkeyform === $title->getDBkey(); } /** diff --git a/includes/jobqueue/jobs/ActivityUpdateJob.php b/includes/jobqueue/jobs/ActivityUpdateJob.php index 8cc14e51e8..9b085108be 100644 --- a/includes/jobqueue/jobs/ActivityUpdateJob.php +++ b/includes/jobqueue/jobs/ActivityUpdateJob.php @@ -19,6 +19,8 @@ * @ingroup JobQueue */ +use MediaWiki\Linker\LinkTarget; + /** * Job for updating user activity like "last viewed" timestamps * @@ -32,7 +34,9 @@ * @since 1.26 */ class ActivityUpdateJob extends Job { - function __construct( Title $title, array $params ) { + function __construct( LinkTarget $title, array $params ) { + $title = Title::newFromLinkTarget( $title ); + parent::__construct( 'activityUpdateJob', $title, $params ); static $required = [ 'type', 'userid', 'notifTime', 'curTime' ]; diff --git a/includes/watcheditem/NoWriteWatchedItemStore.php b/includes/watcheditem/NoWriteWatchedItemStore.php index d5d175cac5..72f6086dfb 100644 --- a/includes/watcheditem/NoWriteWatchedItemStore.php +++ b/includes/watcheditem/NoWriteWatchedItemStore.php @@ -134,7 +134,7 @@ class NoWriteWatchedItemStore implements WatchedItemStoreInterface { public function resetNotificationTimestamp( UserIdentity $user, - Title $title, + LinkTarget $title, $force = '', $oldid = 0 ) { diff --git a/includes/watcheditem/WatchedItemStore.php b/includes/watcheditem/WatchedItemStore.php index b7e5559a55..bd4360eb85 100644 --- a/includes/watcheditem/WatchedItemStore.php +++ b/includes/watcheditem/WatchedItemStore.php @@ -2,6 +2,7 @@ use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface; use MediaWiki\Linker\LinkTarget; +use MediaWiki\Revision\RevisionLookup; use MediaWiki\User\UserIdentity; use Wikimedia\Assert\Assert; use Wikimedia\Rdbms\IDatabase; @@ -68,14 +69,19 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac private $deferredUpdatesAddCallableUpdateCallback; /** - * @var callable|null + * @var int */ - private $revisionGetTimestampFromIdCallback; + private $updateRowsPerQuery; /** - * @var int + * @var NamespaceInfo */ - private $updateRowsPerQuery; + private $nsInfo; + + /** + * @var RevisionLookup + */ + private $revisionLookup; /** * @var StatsdDataFactoryInterface @@ -89,6 +95,8 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac * @param HashBagOStuff $cache * @param ReadOnlyMode $readOnlyMode * @param int $updateRowsPerQuery + * @param NamespaceInfo $nsInfo + * @param RevisionLookup $revisionLookup */ public function __construct( ILBFactory $lbFactory, @@ -96,7 +104,9 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac BagOStuff $stash, HashBagOStuff $cache, ReadOnlyMode $readOnlyMode, - $updateRowsPerQuery + $updateRowsPerQuery, + NamespaceInfo $nsInfo, + RevisionLookup $revisionLookup ) { $this->lbFactory = $lbFactory; $this->loadBalancer = $lbFactory->getMainLB(); @@ -107,9 +117,9 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac $this->stats = new NullStatsdDataFactory(); $this->deferredUpdatesAddCallableUpdateCallback = [ DeferredUpdates::class, 'addCallableUpdate' ]; - $this->revisionGetTimestampFromIdCallback = - [ Revision::class, 'getTimestampFromId' ]; $this->updateRowsPerQuery = $updateRowsPerQuery; + $this->nsInfo = $nsInfo; + $this->revisionLookup = $revisionLookup; $this->latestUpdateCache = new HashBagOStuff( [ 'maxKeys' => 3 ] ); } @@ -145,29 +155,6 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac } ); } - /** - * Overrides the Revision::getTimestampFromId callback - * This is intended for use while testing and will fail if MW_PHPUNIT_TEST is not defined. - * - * @param callable $callback - * @see Revision::getTimestampFromId for callback signiture - * - * @return ScopedCallback to reset the overridden value - * @throws MWException - */ - public function overrideRevisionGetTimestampFromIdCallback( callable $callback ) { - if ( !defined( 'MW_PHPUNIT_TEST' ) ) { - throw new MWException( - 'Cannot override Revision::getTimestampFromId callback in operation.' - ); - } - $previousValue = $this->revisionGetTimestampFromIdCallback; - $this->revisionGetTimestampFromIdCallback = $callback; - return new ScopedCallback( function () use ( $previousValue ) { - $this->revisionGetTimestampFromIdCallback = $previousValue; - } ); - } - private function getCacheKey( UserIdentity $user, LinkTarget $target ) { return $this->cache->makeKey( (string)$target->getNamespace(), @@ -985,13 +972,13 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac /** * @since 1.27 * @param UserIdentity $user - * @param Title $title + * @param LinkTarget $title * @param string $force * @param int $oldid * @return bool */ public function resetNotificationTimestamp( - UserIdentity $user, Title $title, $force = '', $oldid = 0 + UserIdentity $user, LinkTarget $title, $force = '', $oldid = 0 ) { $time = time(); @@ -1000,16 +987,20 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac return false; } - // Hook expects User, not UserIdentity + // Hook expects User and Title, not UserIdentity and LinkTarget $userObj = User::newFromId( $user->getId() ); + $titleObj = Title::castFromLinkTarget( $title ); if ( !Hooks::run( 'BeforeResetNotificationTimestamp', - [ &$userObj, &$title, $force, &$oldid ] ) + [ &$userObj, &$titleObj, $force, &$oldid ] ) ) { return false; } if ( !$userObj->equals( $user ) ) { $user = $userObj; } + if ( !$titleObj->equals( $title ) ) { + $title = $titleObj; + } $item = null; if ( $force != 'force' ) { @@ -1020,11 +1011,19 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac } // Get the timestamp (TS_MW) of this revision to track the latest one seen - $seenTime = call_user_func( - $this->revisionGetTimestampFromIdCallback, - $title, - $oldid ?: $title->getLatestRevID() - ); + $id = $oldid; + $seenTime = null; + if ( !$id ) { + $latestRev = $this->revisionLookup->getRevisionByTitle( $title ); + if ( $latestRev ) { + $id = $latestRev->getId(); + // Save a DB query + $seenTime = $latestRev->getTimestamp(); + } + } + if ( $seenTime === null ) { + $seenTime = $this->revisionLookup->getTimestampFromId( $id ); + } // Mark the item as read immediately in lightweight storage $this->stash->merge( @@ -1105,14 +1104,15 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac } private function getNotificationTimestamp( - UserIdentity $user, Title $title, $item, $force, $oldid + UserIdentity $user, LinkTarget $title, $item, $force, $oldid ) { if ( !$oldid ) { // No oldid given, assuming latest revision; clear the timestamp. return null; } - if ( !$title->getNextRevisionID( $oldid ) ) { + $oldRev = $this->revisionLookup->getRevisionById( $oldid ); + if ( !$this->revisionLookup->getNextRevision( $oldRev, $title ) ) { // Oldid given and is the latest revision for this title; clear the timestamp. return null; } @@ -1128,12 +1128,7 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac // Oldid given and isn't the latest; update the timestamp. // This will result in no further notification emails being sent! - // Calls Revision::getTimestampFromId in normal operation - $notificationTimestamp = call_user_func( - $this->revisionGetTimestampFromIdCallback, - $title, - $oldid - ); + $notificationTimestamp = $this->revisionLookup->getTimestampFromId( $oldid ); // We need to go one second to the future because of various strict comparisons // throughout the codebase @@ -1192,11 +1187,15 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac * @param LinkTarget $newTarget */ public function duplicateAllAssociatedEntries( LinkTarget $oldTarget, LinkTarget $newTarget ) { - $oldTarget = Title::newFromLinkTarget( $oldTarget ); - $newTarget = Title::newFromLinkTarget( $newTarget ); - - $this->duplicateEntry( $oldTarget->getSubjectPage(), $newTarget->getSubjectPage() ); - $this->duplicateEntry( $oldTarget->getTalkPage(), $newTarget->getTalkPage() ); + // Duplicate first the subject page, then the talk page + $this->duplicateEntry( + $this->nsInfo->getSubjectPage( $oldTarget ), + $this->nsInfo->getSubjectPage( $newTarget ) + ); + $this->duplicateEntry( + $this->nsInfo->getTalkPage( $oldTarget ), + $this->nsInfo->getTalkPage( $newTarget ) + ); } /** @@ -1260,7 +1259,7 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac /** * @param UserIdentity $user - * @param Title[] $titles + * @param LinkTarget[] $titles */ private function uncacheTitlesForUser( UserIdentity $user, array $titles ) { foreach ( $titles as $title ) { diff --git a/includes/watcheditem/WatchedItemStoreInterface.php b/includes/watcheditem/WatchedItemStoreInterface.php index 299c22209b..54c02d7bca 100644 --- a/includes/watcheditem/WatchedItemStoreInterface.php +++ b/includes/watcheditem/WatchedItemStoreInterface.php @@ -252,7 +252,7 @@ interface WatchedItemStoreInterface { * @since 1.31 * * @param UserIdentity $user - * @param Title $title + * @param LinkTarget $title * @param string $force Whether to force the write query to be executed even if the * page is not watched or the notification timestamp is already NULL. * 'force' in order to force @@ -262,7 +262,7 @@ interface WatchedItemStoreInterface { * @return bool success Whether a job was enqueued */ public function resetNotificationTimestamp( - UserIdentity $user, Title $title, $force = '', $oldid = 0 ); + UserIdentity $user, LinkTarget $title, $force = '', $oldid = 0 ); /** * @since 1.31 diff --git a/tests/phpunit/includes/watcheditem/NoWriteWatchedItemStoreUnitTest.php b/tests/phpunit/includes/watcheditem/NoWriteWatchedItemStoreUnitTest.php index cc60899153..f424b21b3e 100644 --- a/tests/phpunit/includes/watcheditem/NoWriteWatchedItemStoreUnitTest.php +++ b/tests/phpunit/includes/watcheditem/NoWriteWatchedItemStoreUnitTest.php @@ -78,7 +78,7 @@ class NoWriteWatchedItemStoreUnitTest extends MediaWikiTestCase { $this->setExpectedException( DBReadOnlyError::class ); $noWriteService->resetNotificationTimestamp( new UserIdentityValue( 1, 'MockUser', 0 ), - Title::newFromText( 'Foo' ) + new TitleValue( 0, 'Foo' ) ); } diff --git a/tests/phpunit/includes/watcheditem/WatchedItemStoreUnitTest.php b/tests/phpunit/includes/watcheditem/WatchedItemStoreUnitTest.php index ca5ae3e4c8..82308de4ea 100644 --- a/tests/phpunit/includes/watcheditem/WatchedItemStoreUnitTest.php +++ b/tests/phpunit/includes/watcheditem/WatchedItemStoreUnitTest.php @@ -1,9 +1,10 @@ createMock( NamespaceInfo::class ); + $mock->method( 'getSubjectPage' )->will( $this->returnArgument( 0 ) ); + $mock->method( 'getTalkPage' )->will( $this->returnCallback( + function ( $target ) { + return new TitleValue( 1, $target->getDbKey() ); + } + ) ); + $mock->expects( $this->never() ) + ->method( $this->anythingBut( 'getSubjectPage', 'getTalkPage' ) ); + return $mock; + } + + /** + * No methods may be called except provided callbacks, if any. + * + * @param array $callbacks Keys are method names, values are callbacks + * @param array $counts Keys are method names, values are expected number of times to be called + * (default is any number is okay) + */ + private function getMockRevisionLookup( + array $callbacks = [], array $counts = [] + ) : RevisionLookup { + $mock = $this->createMock( RevisionLookup::class ); + foreach ( $callbacks as $method => $callback ) { + $count = isset( $counts[$method] ) ? $this->exactly( $counts[$method] ) : $this->any(); + $mock->expects( $count ) + ->method( $method ) + ->will( $this->returnCallback( $callbacks[$method] ) ); + } + $mock->expects( $this->never() ) + ->method( $this->anythingBut( ...array_keys( $callbacks ) ) ); + return $mock; + } + private function getFakeRow( array $rowValues ) { $fakeRow = new stdClass(); foreach ( $rowValues as $valueName => $value ) { @@ -117,19 +157,28 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { return $fakeRow; } - private function newWatchedItemStore( - LBFactory $lbFactory, - JobQueueGroup $queueGroup, - HashBagOStuff $cache, - ReadOnlyMode $readOnlyMode - ) { + /** + * @param array $mocks Associative array providing mocks to use when constructing the + * WatchedItemStore. Anything not provided will fall back to a default. Valid keys: + * * lbFactory + * * db + * * queueGroup + * * cache + * * readOnlyMode + * * nsInfo + * * revisionLookup + */ + private function newWatchedItemStore( array $mocks = [] ) : WatchedItemStore { return new WatchedItemStore( - $lbFactory, - $queueGroup, + $mocks['lbFactory'] ?? + $this->getMockLBFactory( $mocks['db'] ?? $this->getMockDb() ), + $mocks['queueGroup'] ?? $this->getMockJobQueueGroup(), new HashBagOStuff(), - $cache, - $readOnlyMode, - 1000 + $mocks['cache'] ?? $this->getMockCache(), + $mocks['readOnlyMode'] ?? $this->getMockReadOnlyMode(), + 1000, + $mocks['nsInfo'] ?? $this->getMockNsInfo(), + $mocks['revisionLookup'] ?? $this->getMockRevisionLookup() ); } @@ -163,12 +212,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { ->method( 'delete' ) ->with( 'RM-KEY' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); TestingAccessWrapper::newFromObject( $store ) ->cacheIndex = [ 0 => [ 'F' => [ 7 => 'RM-KEY', 9 => 'KEEP-KEY' ] ] ]; @@ -196,12 +240,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'set' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertFalse( $store->clearUserWatchedItems( $user ) ); } @@ -227,12 +266,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'set' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertEquals( 12, $store->countWatchedItems( $user ) ); } @@ -259,12 +293,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'set' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertEquals( 7, $store->countWatchers( $titleValue ) ); } @@ -312,12 +341,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'set' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $expected = [ 0 => [ 'SomeDbKey' => 100, 'OtherDbKey' => 300 ], @@ -380,12 +404,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'set' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $expected = [ 0 => [ 'SomeDbKey' => 100, 'OtherDbKey' => 300 ], @@ -430,12 +449,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'get' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertEquals( 7, $store->countVisitingWatchers( $titleValue, '111' ) ); } @@ -513,12 +527,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'set' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $expected = [ 0 => [ 'SomeDbKey' => 100, 'OtherDbKey' => 300 ], @@ -619,12 +628,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'set' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $expected = [ 0 => [ @@ -674,12 +678,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'set' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $expected = [ 0 => [ 'SomeDbKey' => 0, 'OtherDbKey' => 0 ], @@ -713,12 +712,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'get' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertEquals( 9, $store->countUnreadNotifications( $user ) ); } @@ -749,12 +743,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'get' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertSame( true, @@ -788,12 +777,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'get' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertEquals( 9, @@ -820,12 +804,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { ) ->will( $this->returnValue( new FakeResultWrapper( [] ) ) ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $this->getMockCache(), - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb ] ); $store->duplicateEntry( new TitleValue( 0, 'Old_Title' ), @@ -880,12 +859,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'get' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $store->duplicateEntry( new TitleValue( 0, 'Old_Title' ), @@ -928,12 +902,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'get' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $store->duplicateAllAssociatedEntries( new TitleValue( 0, 'Old_Title' ), @@ -1023,12 +992,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'get' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $store->duplicateAllAssociatedEntries( $oldTarget, @@ -1057,12 +1021,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { ->method( 'delete' ) ->with( '0:Some_Page:1' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $store->addWatch( new UserIdentityValue( 1, 'MockUser', 0 ), @@ -1079,12 +1038,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() ) ->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $store->addWatch( new UserIdentityValue( 0, 'AnonUser', 0 ), @@ -1094,11 +1048,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { public function testAddWatchBatchForUser_readOnlyDBReturnsFalse() { $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $this->getMockDb() ), - $this->getMockJobQueueGroup(), - $this->getMockCache(), - $this->getMockReadOnlyMode( true ) - ); + [ 'readOnlyMode' => $this->getMockReadOnlyMode( true ) ] ); $this->assertFalse( $store->addWatchBatchForUser( @@ -1144,12 +1094,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { ->method( 'delete' ) ->with( '1:Some_Page:1' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $mockUser = new UserIdentityValue( 1, 'MockUser', 0 ); @@ -1170,12 +1115,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() ) ->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertFalse( $store->addWatchBatchForUser( @@ -1195,12 +1135,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() ) ->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertTrue( $store->addWatchBatchForUser( $user, [] ) @@ -1231,12 +1166,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { '0:SomeDbKey:1' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $watchedItem = $store->loadWatchedItem( new UserIdentityValue( 1, 'MockUser', 0 ), @@ -1267,12 +1197,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'get' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertFalse( $store->loadWatchedItem( @@ -1291,12 +1216,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'get' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertFalse( $store->loadWatchedItem( @@ -1341,12 +1261,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { [ '1:SomeDbKey:1' ] ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertTrue( $store->removeWatch( @@ -1392,12 +1307,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { [ '1:SomeDbKey:1' ] ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertFalse( $store->removeWatch( @@ -1417,12 +1327,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() ) ->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertFalse( $store->removeWatch( @@ -1463,12 +1368,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { '0:SomeDbKey:1' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $watchedItem = $store->getWatchedItem( new UserIdentityValue( 1, 'MockUser', 0 ), @@ -1499,12 +1399,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { ) ->will( $this->returnValue( $cachedItem ) ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertEquals( $cachedItem, @@ -1538,12 +1433,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { ->with( '0:SomeDbKey:1' ) ->will( $this->returnValue( false ) ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertFalse( $store->getWatchedItem( @@ -1563,12 +1453,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'get' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertFalse( $store->getWatchedItem( @@ -1605,12 +1490,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'get' ); $mockCache->expects( $this->never() )->method( 'set' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $user = new UserIdentityValue( 1, 'MockUser', 0 ); $watchedItems = $store->getWatchedItemsForUser( $user ); @@ -1658,11 +1538,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { ->will( $this->returnValue( [] ) ); $store = $this->newWatchedItemStore( - $mockLoadBalancer, - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + [ 'lbFactory' => $mockLoadBalancer, 'cache' => $mockCache ] ); $watchedItems = $store->getWatchedItemsForUser( $user, @@ -1672,12 +1548,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { } public function testGetWatchedItemsForUser_badSortOptionThrowsException() { - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $this->getMockDb() ), - $this->getMockJobQueueGroup(), - $this->getMockCache(), - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore(); $this->setExpectedException( InvalidArgumentException::class ); $store->getWatchedItemsForUser( @@ -1715,12 +1586,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { '0:SomeDbKey:1' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertTrue( $store->isWatched( @@ -1753,12 +1619,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { ->with( '0:SomeDbKey:1' ) ->will( $this->returnValue( false ) ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertFalse( $store->isWatched( @@ -1778,12 +1639,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'get' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertFalse( $store->isWatched( @@ -1847,12 +1703,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'set' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertEquals( [ @@ -1900,12 +1751,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'set' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertEquals( [ @@ -1964,12 +1810,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'set' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertEquals( [ @@ -2006,12 +1847,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'set' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertEquals( [ @@ -2034,12 +1870,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache = $this->getMockCache(); $mockCache->expects( $this->never() )->method( $this->anything() ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertEquals( [ @@ -2061,17 +1892,12 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'set' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertFalse( $store->resetNotificationTimestamp( new UserIdentityValue( 0, 'AnonUser', 0 ), - Title::newFromText( 'SomeDbKey' ) + new TitleValue( 0, 'SomeDbKey' ) ) ); } @@ -2096,24 +1922,19 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'set' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertFalse( $store->resetNotificationTimestamp( new UserIdentityValue( 1, 'MockUser', 0 ), - Title::newFromText( 'SomeDbKey' ) + new TitleValue( 0, 'SomeDbKey' ) ) ); } public function testResetNotificationTimestamp_item() { $user = new UserIdentityValue( 1, 'MockUser', 0 ); - $title = Title::newFromText( 'SomeDbKey' ); + $title = new TitleValue( 0, 'SomeDbKey' ); $mockDb = $this->getMockDb(); $mockDb->expects( $this->once() ) @@ -2150,12 +1971,22 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { // don't run } ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $mockQueueGroup, - $mockCache, - $this->getMockReadOnlyMode() - ); + // We don't care if these methods actually do anything here + $mockRevisionLookup = $this->getMockRevisionLookup( [ + 'getRevisionByTitle' => function () { + return null; + }, + 'getTimestampFromId' => function () { + return '00000000000000'; + }, + ] ); + + $store = $this->newWatchedItemStore( [ + 'db' => $mockDb, + 'queueGroup' => $mockQueueGroup, + 'cache' => $mockCache, + 'revisionLookup' => $mockRevisionLookup, + ] ); $this->assertTrue( $store->resetNotificationTimestamp( @@ -2167,7 +1998,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { public function testResetNotificationTimestamp_noItemForced() { $user = new UserIdentityValue( 1, 'MockUser', 0 ); - $title = Title::newFromText( 'SomeDbKey' ); + $title = new TitleValue( 0, 'SomeDbKey' ); $mockDb = $this->getMockDb(); $mockDb->expects( $this->never() ) @@ -2181,12 +2012,23 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { ->with( '0:SomeDbKey:1' ); $mockQueueGroup = $this->getMockJobQueueGroup(); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $mockQueueGroup, - $mockCache, - $this->getMockReadOnlyMode() - ); + + // We don't care if these methods actually do anything here + $mockRevisionLookup = $this->getMockRevisionLookup( [ + 'getRevisionByTitle' => function () { + return null; + }, + 'getTimestampFromId' => function () { + return '00000000000000'; + }, + ] ); + + $store = $this->newWatchedItemStore( [ + 'db' => $mockDb, + 'queueGroup' => $mockQueueGroup, + 'cache' => $mockCache, + 'revisionLookup' => $mockRevisionLookup, + ] ); $mockQueueGroup->expects( $this->any() ) ->method( 'lazyPush' ) @@ -2203,26 +2045,6 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { ); } - /** - * @param string $text - * @param int $ns - * - * @return PHPUnit_Framework_MockObject_MockObject|Title - */ - private function getMockTitle( $text, $ns = 0 ) { - $title = $this->createMock( Title::class ); - $title->expects( $this->any() ) - ->method( 'getText' ) - ->will( $this->returnValue( str_replace( '_', ' ', $text ) ) ); - $title->expects( $this->any() ) - ->method( 'getDbKey' ) - ->will( $this->returnValue( str_replace( '_', ' ', $text ) ) ); - $title->expects( $this->any() ) - ->method( 'getNamespace' ) - ->will( $this->returnValue( $ns ) ); - return $title; - } - private function verifyCallbackJob( ActivityUpdateJob $job, LinkTarget $expectedTitle, @@ -2244,11 +2066,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { public function testResetNotificationTimestamp_oldidSpecifiedLatestRevisionForced() { $user = new UserIdentityValue( 1, 'MockUser', 0 ); $oldid = 22; - $title = $this->getMockTitle( 'SomeTitle' ); - $title->expects( $this->once() ) - ->method( 'getNextRevisionID' ) - ->with( $oldid ) - ->will( $this->returnValue( false ) ); + $title = new TitleValue( 0, 'SomeTitle' ); $mockDb = $this->getMockDb(); $mockDb->expects( $this->never() ) @@ -2262,12 +2080,35 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { ->with( '0:SomeTitle:1' ); $mockQueueGroup = $this->getMockJobQueueGroup(); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $mockQueueGroup, - $mockCache, - $this->getMockReadOnlyMode() - ); + + $mockRevisionRecord = $this->createMock( RevisionRecord::class ); + $mockRevisionRecord->expects( $this->never() )->method( $this->anything() ); + + $mockRevisionLookup = $this->getMockRevisionLookup( [ + 'getTimestampFromId' => function () { + return '00000000000000'; + }, + 'getRevisionById' => function ( $id, $flags ) use ( $oldid, $mockRevisionRecord ) { + $this->assertSame( $oldid, $id ); + $this->assertSame( 0, $flags ); + return $mockRevisionRecord; + }, + 'getNextRevision' => + function ( $oldRev, $titleArg ) use ( $mockRevisionRecord, $title ) { + $this->assertSame( $mockRevisionRecord, $oldRev ); + $this->assertSame( $title, $titleArg ); + return false; + }, + ], [ + 'getNextRevision' => 1, + ] ); + + $store = $this->newWatchedItemStore( [ + 'db' => $mockDb, + 'queueGroup' => $mockQueueGroup, + 'cache' => $mockCache, + 'revisionLookup' => $mockRevisionLookup, + ] ); $mockQueueGroup->expects( $this->any() ) ->method( 'lazyPush' ) @@ -2297,11 +2138,13 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { public function testResetNotificationTimestamp_oldidSpecifiedNotLatestRevisionForced() { $user = new UserIdentityValue( 1, 'MockUser', 0 ); $oldid = 22; - $title = $this->getMockTitle( 'SomeDbKey' ); - $title->expects( $this->once() ) - ->method( 'getNextRevisionID' ) - ->with( $oldid ) - ->will( $this->returnValue( 33 ) ); + $title = new TitleValue( 0, 'SomeDbKey' ); + + $mockRevision = $this->createMock( RevisionRecord::class ); + $mockRevision->expects( $this->never() )->method( $this->anything() ); + + $mockNextRevision = $this->createMock( RevisionRecord::class ); + $mockNextRevision->expects( $this->never() )->method( $this->anything() ); $mockDb = $this->getMockDb(); $mockDb->expects( $this->once() ) @@ -2329,12 +2172,34 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { ->with( '0:SomeDbKey:1' ); $mockQueueGroup = $this->getMockJobQueueGroup(); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $mockQueueGroup, - $mockCache, - $this->getMockReadOnlyMode() - ); + + $mockRevisionLookup = $this->getMockRevisionLookup( + [ + 'getTimestampFromId' => function ( $oldidParam ) use ( $oldid ) { + $this->assertSame( $oldid, $oldidParam ); + }, + 'getRevisionById' => function ( $id ) use ( $oldid, $mockRevision ) { + $this->assertSame( $oldid, $id ); + return $mockRevision; + }, + 'getNextRevision' => + function ( RevisionRecord $rev ) use ( $mockRevision, $mockNextRevision ) { + $this->assertSame( $mockRevision, $rev ); + return $mockNextRevision; + }, + ], + [ + 'getTimestampFromId' => 2, + 'getRevisionById' => 1, + 'getNextRevision' => 1, + ] + ); + $store = $this->newWatchedItemStore( [ + 'db' => $mockDb, + 'queueGroup' => $mockQueueGroup, + 'cache' => $mockCache, + 'revisionLookup' => $mockRevisionLookup, + ] ); $mockQueueGroup->expects( $this->any() ) ->method( 'lazyPush' ) @@ -2351,15 +2216,6 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { } ) ); - $getTimestampCallCounter = 0; - $scopedOverrideRevision = $store->overrideRevisionGetTimestampFromIdCallback( - function ( $titleParam, $oldidParam ) use ( &$getTimestampCallCounter, $title, $oldid ) { - $getTimestampCallCounter++; - $this->assertEquals( $title, $titleParam ); - $this->assertEquals( $oldid, $oldidParam ); - } - ); - $this->assertTrue( $store->resetNotificationTimestamp( $user, @@ -2368,19 +2224,12 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $oldid ) ); - $this->assertEquals( 2, $getTimestampCallCounter ); - - ScopedCallback::consume( $scopedOverrideRevision ); } public function testResetNotificationTimestamp_notWatchedPageForced() { $user = new UserIdentityValue( 1, 'MockUser', 0 ); $oldid = 22; - $title = $this->getMockTitle( 'SomeDbKey' ); - $title->expects( $this->once() ) - ->method( 'getNextRevisionID' ) - ->with( $oldid ) - ->will( $this->returnValue( 33 ) ); + $title = new TitleValue( 0, 'SomeDbKey' ); $mockDb = $this->getMockDb(); $mockDb->expects( $this->once() ) @@ -2404,13 +2253,42 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { ->with( '0:SomeDbKey:1' ); $mockQueueGroup = $this->getMockJobQueueGroup(); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $mockQueueGroup, - $mockCache, - $this->getMockReadOnlyMode() + + $mockRevision = $this->createMock( RevisionRecord::class ); + $mockRevision->expects( $this->never() )->method( $this->anything() ); + + $mockNextRevision = $this->createMock( RevisionRecord::class ); + $mockNextRevision->expects( $this->never() )->method( $this->anything() ); + + $mockRevisionLookup = $this->getMockRevisionLookup( + [ + 'getTimestampFromId' => function ( $oldidParam ) use ( $oldid ) { + $this->assertSame( $oldid, $oldidParam ); + }, + 'getRevisionById' => function ( $id ) use ( $oldid, $mockRevision ) { + $this->assertSame( $oldid, $id ); + return $mockRevision; + }, + 'getNextRevision' => + function ( RevisionRecord $rev ) use ( $mockRevision, $mockNextRevision ) { + $this->assertSame( $mockRevision, $rev ); + return $mockNextRevision; + }, + ], + [ + 'getTimestampFromId' => 1, + 'getRevisionById' => 1, + 'getNextRevision' => 1, + ] ); + $store = $this->newWatchedItemStore( [ + 'db' => $mockDb, + 'queueGroup' => $mockQueueGroup, + 'cache' => $mockCache, + 'revisionLookup' => $mockRevisionLookup, + ] ); + $mockQueueGroup->expects( $this->any() ) ->method( 'lazyPush' ) ->will( $this->returnCallback( @@ -2439,11 +2317,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { public function testResetNotificationTimestamp_futureNotificationTimestampForced() { $user = new UserIdentityValue( 1, 'MockUser', 0 ); $oldid = 22; - $title = $this->getMockTitle( 'SomeDbKey' ); - $title->expects( $this->once() ) - ->method( 'getNextRevisionID' ) - ->with( $oldid ) - ->will( $this->returnValue( 33 ) ); + $title = new TitleValue( 0, 'SomeDbKey' ); $mockDb = $this->getMockDb(); $mockDb->expects( $this->once() ) @@ -2471,13 +2345,42 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { ->with( '0:SomeDbKey:1' ); $mockQueueGroup = $this->getMockJobQueueGroup(); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $mockQueueGroup, - $mockCache, - $this->getMockReadOnlyMode() + + $mockRevision = $this->createMock( RevisionRecord::class ); + $mockRevision->expects( $this->never() )->method( $this->anything() ); + + $mockNextRevision = $this->createMock( RevisionRecord::class ); + $mockNextRevision->expects( $this->never() )->method( $this->anything() ); + + $mockRevisionLookup = $this->getMockRevisionLookup( + [ + 'getTimestampFromId' => function ( $oldidParam ) use ( $oldid ) { + $this->assertEquals( $oldid, $oldidParam ); + }, + 'getRevisionById' => function ( $id ) use ( $oldid, $mockRevision ) { + $this->assertSame( $oldid, $id ); + return $mockRevision; + }, + 'getNextRevision' => + function ( RevisionRecord $rev ) use ( $mockRevision, $mockNextRevision ) { + $this->assertSame( $mockRevision, $rev ); + return $mockNextRevision; + }, + ], + [ + 'getTimestampFromId' => 2, + 'getRevisionById' => 1, + 'getNextRevision' => 1, + ] ); + $store = $this->newWatchedItemStore( [ + 'db' => $mockDb, + 'queueGroup' => $mockQueueGroup, + 'cache' => $mockCache, + 'revisionLookup' => $mockRevisionLookup, + ] ); + $mockQueueGroup->expects( $this->any() ) ->method( 'lazyPush' ) ->will( $this->returnCallback( @@ -2493,15 +2396,6 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { } ) ); - $getTimestampCallCounter = 0; - $scopedOverrideRevision = $store->overrideRevisionGetTimestampFromIdCallback( - function ( $titleParam, $oldidParam ) use ( &$getTimestampCallCounter, $title, $oldid ) { - $getTimestampCallCounter++; - $this->assertEquals( $title, $titleParam ); - $this->assertEquals( $oldid, $oldidParam ); - } - ); - $this->assertTrue( $store->resetNotificationTimestamp( $user, @@ -2510,19 +2404,12 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $oldid ) ); - $this->assertEquals( 2, $getTimestampCallCounter ); - - ScopedCallback::consume( $scopedOverrideRevision ); } public function testResetNotificationTimestamp_futureNotificationTimestampNotForced() { $user = new UserIdentityValue( 1, 'MockUser', 0 ); $oldid = 22; - $title = $this->getMockTitle( 'SomeDbKey' ); - $title->expects( $this->once() ) - ->method( 'getNextRevisionID' ) - ->with( $oldid ) - ->will( $this->returnValue( 33 ) ); + $title = new TitleValue( 0, 'SomeDbKey' ); $mockDb = $this->getMockDb(); $mockDb->expects( $this->once() ) @@ -2550,12 +2437,40 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { ->with( '0:SomeDbKey:1' ); $mockQueueGroup = $this->getMockJobQueueGroup(); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $mockQueueGroup, - $mockCache, - $this->getMockReadOnlyMode() - ); + + $mockRevision = $this->createMock( RevisionRecord::class ); + $mockRevision->expects( $this->never() )->method( $this->anything() ); + + $mockNextRevision = $this->createMock( RevisionRecord::class ); + $mockNextRevision->expects( $this->never() )->method( $this->anything() ); + + $mockRevisionLookup = $this->getMockRevisionLookup( + [ + 'getTimestampFromId' => function ( $oldidParam ) use ( $oldid ) { + $this->assertEquals( $oldid, $oldidParam ); + }, + 'getRevisionById' => function ( $id ) use ( $oldid, $mockRevision ) { + $this->assertSame( $oldid, $id ); + return $mockRevision; + }, + 'getNextRevision' => + function ( RevisionRecord $rev ) use ( $mockRevision, $mockNextRevision ) { + $this->assertSame( $mockRevision, $rev ); + return $mockNextRevision; + }, + ], + [ + 'getTimestampFromId' => 2, + 'getRevisionById' => 1, + 'getNextRevision' => 1, + ] + ); + $store = $this->newWatchedItemStore( [ + 'db' => $mockDb, + 'queueGroup' => $mockQueueGroup, + 'cache' => $mockCache, + 'revisionLookup' => $mockRevisionLookup, + ] ); $mockQueueGroup->expects( $this->any() ) ->method( 'lazyPush' ) @@ -2572,15 +2487,6 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { } ) ); - $getTimestampCallCounter = 0; - $scopedOverrideRevision = $store->overrideRevisionGetTimestampFromIdCallback( - function ( $titleParam, $oldidParam ) use ( &$getTimestampCallCounter, $title, $oldid ) { - $getTimestampCallCounter++; - $this->assertEquals( $title, $titleParam ); - $this->assertEquals( $oldid, $oldidParam ); - } - ); - $this->assertTrue( $store->resetNotificationTimestamp( $user, @@ -2589,18 +2495,10 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $oldid ) ); - $this->assertEquals( 2, $getTimestampCallCounter ); - - ScopedCallback::consume( $scopedOverrideRevision ); } public function testSetNotificationTimestampsForUser_anonUser() { - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $this->getMockDb() ), - $this->getMockJobQueueGroup(), - $this->getMockCache(), - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore(); $this->assertFalse( $store->setNotificationTimestampsForUser( new UserIdentityValue( 0, 'AnonUser', 0 ), '' ) ); } @@ -2609,12 +2507,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $user = new UserIdentityValue( 1, 'MockUser', 0 ); $timestamp = '20100101010101'; - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $this->getMockDb() ), - $this->getMockJobQueueGroup(), - $this->getMockCache(), - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore(); // Note: This does not actually assert the job is correct $callableCallCounter = 0; @@ -2634,12 +2527,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $user = new UserIdentityValue( 1, 'MockUser', 0 ); $timestamp = null; - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $this->getMockDb() ), - $this->getMockJobQueueGroup(), - $this->getMockCache(), - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore(); // Note: This does not actually assert the job is correct $callableCallCounter = 0; @@ -2677,12 +2565,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { ->method( 'affectedRows' ) ->will( $this->returnValue( 2 ) ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $this->getMockCache(), - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb ] ); $this->assertTrue( $store->setNotificationTimestampsForUser( $user, $timestamp, $targets ) @@ -2721,12 +2604,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'get' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $this->assertEquals( [ 2, 3 ], @@ -2763,12 +2641,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { $mockCache->expects( $this->never() )->method( 'get' ); $mockCache->expects( $this->never() )->method( 'delete' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); $watchers = $store->updateNotificationTimestamp( new UserIdentityValue( 1, 'MockUser', 0 ), @@ -2808,12 +2681,7 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase { ->method( 'delete' ) ->with( '0:SomeDbKey:1' ); - $store = $this->newWatchedItemStore( - $this->getMockLBFactory( $mockDb ), - $this->getMockJobQueueGroup(), - $mockCache, - $this->getMockReadOnlyMode() - ); + $store = $this->newWatchedItemStore( [ 'db' => $mockDb, 'cache' => $mockCache ] ); // This will add the item to the cache $store->getWatchedItem( $user, $titleValue ); -- 2.20.1