*/
private $loadBalancer;
+ /**
+ * @var JobQueueGroup
+ */
+ private $queueGroup;
+
+ /**
+ * @var BagOStuff
+ */
+ private $stash;
+
/**
* @var ReadOnlyMode
*/
*/
private $cache;
+ /**
+ * @var HashBagOStuff
+ */
+ private $latestUpdateCache;
+
/**
* @var array[] Looks like $cacheIndex[Namespace ID][Target DB Key][User Id] => 'key'
* The index is needed so that on mass changes all relevant items can be un-cached.
/**
* @param ILBFactory $lbFactory
+ * @param JobQueueGroup $queueGroup
+ * @param BagOStuff $stash
* @param HashBagOStuff $cache
* @param ReadOnlyMode $readOnlyMode
* @param int $updateRowsPerQuery
*/
public function __construct(
ILBFactory $lbFactory,
+ JobQueueGroup $queueGroup,
+ BagOStuff $stash,
HashBagOStuff $cache,
ReadOnlyMode $readOnlyMode,
$updateRowsPerQuery
) {
$this->lbFactory = $lbFactory;
$this->loadBalancer = $lbFactory->getMainLB();
+ $this->queueGroup = $queueGroup;
+ $this->stash = $stash;
$this->cache = $cache;
$this->readOnlyMode = $readOnlyMode;
$this->stats = new NullStatsdDataFactory();
$this->revisionGetTimestampFromIdCallback =
[ Revision::class, 'getTimestampFromId' ];
$this->updateRowsPerQuery = $updateRowsPerQuery;
+
+ $this->latestUpdateCache = new HashBagOStuff( [ 'maxKeys' => 3 ] );
}
/**
*/
public function clearUserWatchedItemsUsingJobQueue( User $user ) {
$job = ClearUserWatchlistJob::newForUser( $user, $this->getMaxId() );
- // TODO inject me.
- JobQueueGroup::singleton()->push( $job );
+ $this->queueGroup->push( $job );
}
/**
}
$dbr = $this->getConnectionRef( DB_REPLICA );
+
$row = $dbr->selectRow(
'watchlist',
'wl_notificationtimestamp',
$item = new WatchedItem(
$user,
$target,
- wfTimestampOrNull( TS_MW, $row->wl_notificationtimestamp )
+ $this->getLatestNotificationTimestamp( $row->wl_notificationtimestamp, $user, $target )
);
$this->cache( $item );
$watchedItems = [];
foreach ( $res as $row ) {
+ $target = new TitleValue( (int)$row->wl_namespace, $row->wl_title );
// @todo: Should we add these to the process cache?
$watchedItems[] = new WatchedItem(
$user,
new TitleValue( (int)$row->wl_namespace, $row->wl_title ),
- $row->wl_notificationtimestamp
+ $this->getLatestNotificationTimestamp(
+ $row->wl_notificationtimestamp, $user, $target )
);
}
);
foreach ( $res as $row ) {
+ $target = new TitleValue( (int)$row->wl_namespace, $row->wl_title );
$timestamps[$row->wl_namespace][$row->wl_title] =
- wfTimestampOrNull( TS_MW, $row->wl_notificationtimestamp );
+ $this->getLatestNotificationTimestamp(
+ $row->wl_notificationtimestamp, $user, $target );
}
return $timestamps;
$timestamp = $dbw->timestamp( $timestamp );
}
- $success = $dbw->update(
+ $dbw->update(
'watchlist',
[ 'wl_notificationtimestamp' => $timestamp ],
$conds,
$this->uncacheUser( $user );
- return $success;
+ return true;
+ }
+
+ public function getLatestNotificationTimestamp( $timestamp, User $user, LinkTarget $target ) {
+ $timestamp = wfTimestampOrNull( TS_MW, $timestamp );
+ if ( $timestamp === null ) {
+ return null; // no notification
+ }
+
+ $seenTimestamps = $this->getPageSeenTimestamps( $user );
+ if (
+ $seenTimestamps &&
+ $seenTimestamps->get( $this->getPageSeenKey( $target ) ) >= $timestamp
+ ) {
+ // If a reset job did not yet run, then the "seen" timestamp will be higher
+ return null;
+ }
+
+ return $timestamp;
}
public function resetAllNotificationTimestampsForUser( User $user ) {
* @return bool
*/
public function resetNotificationTimestamp( User $user, Title $title, $force = '', $oldid = 0 ) {
+ $time = time();
+
// Only loggedin user can have a watchlist
if ( $this->readOnlyMode->isReadOnly() || $user->isAnon() ) {
return false;
}
}
+ // Mark the item as read immediately in lightweight storage
+ $this->stash->merge(
+ $this->getPageSeenTimestampsKey( $user ),
+ function ( $cache, $key, $current ) use ( $time, $title ) {
+ $value = $current ?: new MapCacheLRU( 300 );
+ $value->set( $this->getPageSeenKey( $title ), wfTimestamp( TS_MW, $time ) );
+
+ $this->latestUpdateCache->set( $key, $value, IExpiringStore::TTL_PROC_LONG );
+
+ return $value;
+ },
+ IExpiringStore::TTL_HOUR
+ );
+
// If the page is watched by the user (or may be watched), update the timestamp
$job = new ActivityUpdateJob(
$title,
'type' => 'updateWatchlistNotification',
'userid' => $user->getId(),
'notifTime' => $this->getNotificationTimestamp( $user, $title, $item, $force, $oldid ),
- 'curTime' => time()
+ 'curTime' => $time
]
);
+ // Try to enqueue this post-send
+ $this->queueGroup->lazyPush( $job );
- // Try to run this post-send
- // Calls DeferredUpdates::addCallableUpdate in normal operation
- call_user_func(
- $this->deferredUpdatesAddCallableUpdateCallback,
- function () use ( $job ) {
- $job->run();
+ $this->uncache( $user, $title );
+
+ return true;
+ }
+
+ /**
+ * @param User $user
+ * @return MapCacheLRU|null
+ */
+ private function getPageSeenTimestamps( User $user ) {
+ $key = $this->getPageSeenTimestampsKey( $user );
+
+ return $this->latestUpdateCache->getWithSetCallback(
+ $key,
+ IExpiringStore::TTL_PROC_LONG,
+ function () use ( $key ) {
+ return $this->stash->get( $key ) ?: null;
}
);
+ }
- $this->uncache( $user, $title );
+ /**
+ * @param User $user
+ * @return string
+ */
+ private function getPageSeenTimestampsKey( User $user ) {
+ return $this->stash->makeGlobalKey(
+ 'watchlist-recent-updates',
+ $this->lbFactory->getLocalDomainID(),
+ $user->getId()
+ );
+ }
- return true;
+ /**
+ * @param LinkTarget $target
+ * @return string
+ */
+ private function getPageSeenKey( LinkTarget $target ) {
+ return "{$target->getNamespace()}:{$target->getDBkey()}";
}
private function getNotificationTimestamp( User $user, Title $title, $item, $force, $oldid ) {
* @return int|bool
*/
public function countUnreadNotifications( User $user, $unreadLimit = null ) {
+ $dbr = $this->getConnectionRef( DB_REPLICA );
+
$queryOptions = [];
if ( $unreadLimit !== null ) {
$unreadLimit = (int)$unreadLimit;
$queryOptions['LIMIT'] = $unreadLimit;
}
- $dbr = $this->getConnectionRef( DB_REPLICA );
- $rowCount = $dbr->selectRowCount(
- 'watchlist',
- '1',
- [
- 'wl_user' => $user->getId(),
- 'wl_notificationtimestamp IS NOT NULL',
- ],
- __METHOD__,
- $queryOptions
- );
+ $conds = [
+ 'wl_user' => $user->getId(),
+ 'wl_notificationtimestamp IS NOT NULL'
+ ];
+
+ $rowCount = $dbr->selectRowCount( 'watchlist', '1', $conds, __METHOD__, $queryOptions );
- if ( !isset( $unreadLimit ) ) {
+ if ( $unreadLimit === null ) {
return $rowCount;
}
return $mock;
}
+ /**
+ * @return PHPUnit_Framework_MockObject_MockObject|JobQueueGroup
+ */
+ private function getMockJobQueueGroup() {
+ $mock = $this->getMockBuilder( JobQueueGroup::class )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $mock->expects( $this->any() )
+ ->method( 'push' )
+ ->will( $this->returnCallback( function ( Job $job ) {
+ $job->run();
+ } ) );
+ $mock->expects( $this->any() )
+ ->method( 'lazyPush' )
+ ->will( $this->returnCallback( function ( Job $job ) {
+ $job->run();
+ } ) );
+ return $mock;
+ }
+
/**
* @return PHPUnit_Framework_MockObject_MockObject|HashBagOStuff
*/
return $fakeRow;
}
- private function newWatchedItemStore( LBFactory $lbFactory, HashBagOStuff $cache,
+ private function newWatchedItemStore(
+ LBFactory $lbFactory,
+ JobQueueGroup $queueGroup,
+ HashBagOStuff $cache,
ReadOnlyMode $readOnlyMode
) {
return new WatchedItemStore(
$lbFactory,
+ $queueGroup,
+ new HashBagOStuff(),
$cache,
$readOnlyMode,
1000
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$this->getMockCache(),
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
public function testAddWatchBatchForUser_readOnlyDBReturnsFalse() {
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $this->getMockDb() ),
+ $this->getMockJobQueueGroup(),
$this->getMockCache(),
$this->getMockReadOnlyMode( true )
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$mockLoadBalancer,
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
public function testGetWatchedItemsForUser_badSortOptionThrowsException() {
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $this->getMockDb() ),
+ $this->getMockJobQueueGroup(),
$this->getMockCache(),
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
->method( 'delete' )
->with( '0:SomeDbKey:1' );
+ $mockQueueGroup = $this->getMockJobQueueGroup();
+ $mockQueueGroup->expects( $this->once() )
+ ->method( 'lazyPush' )
+ ->willReturnCallback( function ( ActivityUpdateJob $job ) {
+ // don't run
+ } );
+
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $mockQueueGroup,
$mockCache,
$this->getMockReadOnlyMode()
);
- // Note: This does not actually assert the job is correct
- $callableCallCounter = 0;
- $mockCallback = function ( $callable ) use ( &$callableCallCounter ) {
- $callableCallCounter++;
- $this->assertInternalType( 'callable', $callable );
- };
- $scopedOverride = $store->overrideDeferredUpdatesAddCallableUpdateCallback( $mockCallback );
-
$this->assertTrue(
$store->resetNotificationTimestamp(
$user,
$title
)
);
- $this->assertEquals( 1, $callableCallCounter );
-
- ScopedCallback::consume( $scopedOverride );
}
public function testResetNotificationTimestamp_noItemForced() {
->method( 'delete' )
->with( '0:SomeDbKey:1' );
+ $mockQueueGroup = $this->getMockJobQueueGroup();
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $mockQueueGroup,
$mockCache,
$this->getMockReadOnlyMode()
);
- // Note: This does not actually assert the job is correct
- $callableCallCounter = 0;
- $mockCallback = function ( $callable ) use ( &$callableCallCounter ) {
- $callableCallCounter++;
- $this->assertInternalType( 'callable', $callable );
- };
- $scopedOverride = $store->overrideDeferredUpdatesAddCallableUpdateCallback( $mockCallback );
+ $mockQueueGroup->expects( $this->any() )
+ ->method( 'lazyPush' )
+ ->will( $this->returnCallback( function ( ActivityUpdateJob $job ) {
+ // don't run
+ } ) );
$this->assertTrue(
$store->resetNotificationTimestamp(
'force'
)
);
- $this->assertEquals( 1, $callableCallCounter );
-
- ScopedCallback::consume( $scopedOverride );
}
/**
}
private function verifyCallbackJob(
- $callback,
+ ActivityUpdateJob $job,
LinkTarget $expectedTitle,
$expectedUserId,
callable $notificationTimestampCondition
) {
- $this->assertInternalType( 'callable', $callback );
-
- $callbackReflector = new ReflectionFunction( $callback );
- $vars = $callbackReflector->getStaticVariables();
- $this->assertArrayHasKey( 'job', $vars );
- $this->assertInstanceOf( ActivityUpdateJob::class, $vars['job'] );
-
- /** @var ActivityUpdateJob $job */
- $job = $vars['job'];
$this->assertEquals( $expectedTitle->getDBkey(), $job->getTitle()->getDBkey() );
$this->assertEquals( $expectedTitle->getNamespace(), $job->getTitle()->getNamespace() );
->method( 'delete' )
->with( '0:SomeTitle:1' );
+ $mockQueueGroup = $this->getMockJobQueueGroup();
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $mockQueueGroup,
$mockCache,
$this->getMockReadOnlyMode()
);
- $callableCallCounter = 0;
- $scopedOverride = $store->overrideDeferredUpdatesAddCallableUpdateCallback(
- function ( $callable ) use ( &$callableCallCounter, $title, $user ) {
- $callableCallCounter++;
- $this->verifyCallbackJob(
- $callable,
- $title,
- $user->getId(),
- function ( $time ) {
- return $time === null;
- }
- );
- }
- );
+ $mockQueueGroup->expects( $this->any() )
+ ->method( 'lazyPush' )
+ ->will( $this->returnCallback(
+ function ( ActivityUpdateJob $job ) use ( $title, $user ) {
+ $this->verifyCallbackJob(
+ $job,
+ $title,
+ $user->getId(),
+ function ( $time ) {
+ return $time === null;
+ }
+ );
+ }
+ ) );
$this->assertTrue(
$store->resetNotificationTimestamp(
$oldid
)
);
- $this->assertEquals( 1, $callableCallCounter );
-
- ScopedCallback::consume( $scopedOverride );
}
public function testResetNotificationTimestamp_oldidSpecifiedNotLatestRevisionForced() {
->method( 'delete' )
->with( '0:SomeDbKey:1' );
+ $mockQueueGroup = $this->getMockJobQueueGroup();
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $mockQueueGroup,
$mockCache,
$this->getMockReadOnlyMode()
);
- $addUpdateCallCounter = 0;
- $scopedOverrideDeferred = $store->overrideDeferredUpdatesAddCallableUpdateCallback(
- function ( $callable ) use ( &$addUpdateCallCounter, $title, $user ) {
- $addUpdateCallCounter++;
- $this->verifyCallbackJob(
- $callable,
- $title,
- $user->getId(),
- function ( $time ) {
- return $time !== null && $time > '20151212010101';
- }
- );
- }
- );
+ $mockQueueGroup->expects( $this->any() )
+ ->method( 'lazyPush' )
+ ->will( $this->returnCallback(
+ function ( ActivityUpdateJob $job ) use ( $title, $user ) {
+ $this->verifyCallbackJob(
+ $job,
+ $title,
+ $user->getId(),
+ function ( $time ) {
+ return $time !== null && $time > '20151212010101';
+ }
+ );
+ }
+ ) );
$getTimestampCallCounter = 0;
$scopedOverrideRevision = $store->overrideRevisionGetTimestampFromIdCallback(
$oldid
)
);
- $this->assertEquals( 1, $addUpdateCallCounter );
$this->assertEquals( 1, $getTimestampCallCounter );
- ScopedCallback::consume( $scopedOverrideDeferred );
ScopedCallback::consume( $scopedOverrideRevision );
}
->method( 'delete' )
->with( '0:SomeDbKey:1' );
+ $mockQueueGroup = $this->getMockJobQueueGroup();
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $mockQueueGroup,
$mockCache,
$this->getMockReadOnlyMode()
);
- $callableCallCounter = 0;
- $scopedOverride = $store->overrideDeferredUpdatesAddCallableUpdateCallback(
- function ( $callable ) use ( &$callableCallCounter, $title, $user ) {
- $callableCallCounter++;
- $this->verifyCallbackJob(
- $callable,
- $title,
- $user->getId(),
- function ( $time ) {
- return $time === null;
- }
- );
- }
- );
+ $mockQueueGroup->expects( $this->any() )
+ ->method( 'lazyPush' )
+ ->will( $this->returnCallback(
+ function ( ActivityUpdateJob $job ) use ( $title, $user ) {
+ $this->verifyCallbackJob(
+ $job,
+ $title,
+ $user->getId(),
+ function ( $time ) {
+ return $time === null;
+ }
+ );
+ }
+ ) );
$this->assertTrue(
$store->resetNotificationTimestamp(
$oldid
)
);
- $this->assertEquals( 1, $callableCallCounter );
-
- ScopedCallback::consume( $scopedOverride );
}
public function testResetNotificationTimestamp_futureNotificationTimestampForced() {
->method( 'delete' )
->with( '0:SomeDbKey:1' );
+ $mockQueueGroup = $this->getMockJobQueueGroup();
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $mockQueueGroup,
$mockCache,
$this->getMockReadOnlyMode()
);
- $addUpdateCallCounter = 0;
- $scopedOverrideDeferred = $store->overrideDeferredUpdatesAddCallableUpdateCallback(
- function ( $callable ) use ( &$addUpdateCallCounter, $title, $user ) {
- $addUpdateCallCounter++;
- $this->verifyCallbackJob(
- $callable,
- $title,
- $user->getId(),
- function ( $time ) {
- return $time === '30151212010101';
- }
- );
- }
- );
+ $mockQueueGroup->expects( $this->any() )
+ ->method( 'lazyPush' )
+ ->will( $this->returnCallback(
+ function ( ActivityUpdateJob $job ) use ( $title, $user ) {
+ $this->verifyCallbackJob(
+ $job,
+ $title,
+ $user->getId(),
+ function ( $time ) {
+ return $time === '30151212010101';
+ }
+ );
+ }
+ ) );
$getTimestampCallCounter = 0;
$scopedOverrideRevision = $store->overrideRevisionGetTimestampFromIdCallback(
$oldid
)
);
- $this->assertEquals( 1, $addUpdateCallCounter );
$this->assertEquals( 1, $getTimestampCallCounter );
- ScopedCallback::consume( $scopedOverrideDeferred );
ScopedCallback::consume( $scopedOverrideRevision );
}
->method( 'delete' )
->with( '0:SomeDbKey:1' );
+ $mockQueueGroup = $this->getMockJobQueueGroup();
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $mockQueueGroup,
$mockCache,
$this->getMockReadOnlyMode()
);
- $addUpdateCallCounter = 0;
- $scopedOverrideDeferred = $store->overrideDeferredUpdatesAddCallableUpdateCallback(
- function ( $callable ) use ( &$addUpdateCallCounter, $title, $user ) {
- $addUpdateCallCounter++;
- $this->verifyCallbackJob(
- $callable,
- $title,
- $user->getId(),
- function ( $time ) {
- return $time === false;
- }
- );
- }
- );
+ $mockQueueGroup->expects( $this->any() )
+ ->method( 'lazyPush' )
+ ->will( $this->returnCallback(
+ function ( ActivityUpdateJob $job ) use ( $title, $user ) {
+ $this->verifyCallbackJob(
+ $job,
+ $title,
+ $user->getId(),
+ function ( $time ) {
+ return $time === false;
+ }
+ );
+ }
+ ) );
$getTimestampCallCounter = 0;
$scopedOverrideRevision = $store->overrideRevisionGetTimestampFromIdCallback(
$oldid
)
);
- $this->assertEquals( 1, $addUpdateCallCounter );
$this->assertEquals( 1, $getTimestampCallCounter );
- ScopedCallback::consume( $scopedOverrideDeferred );
ScopedCallback::consume( $scopedOverrideRevision );
}
public function testSetNotificationTimestampsForUser_anonUser() {
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $this->getMockDb() ),
+ $this->getMockJobQueueGroup(),
$this->getMockCache(),
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$this->getMockCache(),
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$this->getMockCache(),
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$this->getMockCache(),
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);
$store = $this->newWatchedItemStore(
$this->getMockLBFactory( $mockDb ),
+ $this->getMockJobQueueGroup(),
$mockCache,
$this->getMockReadOnlyMode()
);