wiki.techinc.nl/tests/phpunit/includes/watcheditem/WatchedItemStoreIntegrationTest.php
Roan Kattouw 1da7573bb7 WatchedItemStore: Use batching in setNotificationTimestampsForUser
Update rows in batches, using the same logic as is used by
removeWatchBatchForUser().

Also remove the functionality for updating all rows, and move that to
resetAllNotificationTimestampsForUser() instead. To that end, add a
timestamp parameter to that method and to the job it uses, and make
setNotificationTimestampsForUser() behave like a backwards-compatibility
wrapper around resetAllNotificationTimestampsForUser() when no list of
titles is specified.

Bug: T207941
Change-Id: I58342257395de6fcfb4c392b3945b12883ca1680
Follows-Up: I2008ff89c95fe6f66a3fd789d2cef0e8fe52bd93
2019-03-21 04:41:42 +00:00

248 lines
8.8 KiB
PHP

<?php
use MediaWiki\MediaWikiServices;
use Wikimedia\TestingAccessWrapper;
/**
* @author Addshore
*
* @group Database
*
* @covers WatchedItemStore
*/
class WatchedItemStoreIntegrationTest extends MediaWikiTestCase {
public function setUp() {
parent::setUp();
self::$users['WatchedItemStoreIntegrationTestUser']
= new TestUser( 'WatchedItemStoreIntegrationTestUser' );
}
private function getUser() {
return self::$users['WatchedItemStoreIntegrationTestUser']->getUser();
}
public function testWatchAndUnWatchItem() {
$user = $this->getUser();
$title = Title::newFromText( 'WatchedItemStoreIntegrationTestPage' );
$store = MediaWikiServices::getInstance()->getWatchedItemStore();
// Cleanup after previous tests
$store->removeWatch( $user, $title );
$initialWatchers = $store->countWatchers( $title );
$initialUserWatchedItems = $store->countWatchedItems( $user );
$this->assertFalse(
$store->isWatched( $user, $title ),
'Page should not initially be watched'
);
$store->addWatch( $user, $title );
$this->assertTrue(
$store->isWatched( $user, $title ),
'Page should be watched'
);
$this->assertEquals( $initialUserWatchedItems + 1, $store->countWatchedItems( $user ) );
$watchedItemsForUser = $store->getWatchedItemsForUser( $user );
$this->assertCount( $initialUserWatchedItems + 1, $watchedItemsForUser );
$watchedItemsForUserHasExpectedItem = false;
foreach ( $watchedItemsForUser as $watchedItem ) {
if (
$watchedItem->getUser()->equals( $user ) &&
$watchedItem->getLinkTarget() == $title->getTitleValue()
) {
$watchedItemsForUserHasExpectedItem = true;
}
}
$this->assertTrue(
$watchedItemsForUserHasExpectedItem,
'getWatchedItemsForUser should contain the page'
);
$this->assertEquals( $initialWatchers + 1, $store->countWatchers( $title ) );
$this->assertEquals(
$initialWatchers + 1,
$store->countWatchersMultiple( [ $title ] )[$title->getNamespace()][$title->getDBkey()]
);
$this->assertEquals(
[ 0 => [ 'WatchedItemStoreIntegrationTestPage' => $initialWatchers + 1 ] ],
$store->countWatchersMultiple( [ $title ], [ 'minimumWatchers' => $initialWatchers + 1 ] )
);
$this->assertEquals(
[ 0 => [ 'WatchedItemStoreIntegrationTestPage' => 0 ] ],
$store->countWatchersMultiple( [ $title ], [ 'minimumWatchers' => $initialWatchers + 2 ] )
);
$this->assertEquals(
[ $title->getNamespace() => [ $title->getDBkey() => null ] ],
$store->getNotificationTimestampsBatch( $user, [ $title ] )
);
$store->removeWatch( $user, $title );
$this->assertFalse(
$store->isWatched( $user, $title ),
'Page should be unwatched'
);
$this->assertEquals( $initialUserWatchedItems, $store->countWatchedItems( $user ) );
$watchedItemsForUser = $store->getWatchedItemsForUser( $user );
$this->assertCount( $initialUserWatchedItems, $watchedItemsForUser );
$watchedItemsForUserHasExpectedItem = false;
foreach ( $watchedItemsForUser as $watchedItem ) {
if (
$watchedItem->getUser()->equals( $user ) &&
$watchedItem->getLinkTarget() == $title->getTitleValue()
) {
$watchedItemsForUserHasExpectedItem = true;
}
}
$this->assertFalse(
$watchedItemsForUserHasExpectedItem,
'getWatchedItemsForUser should not contain the page'
);
$this->assertEquals( $initialWatchers, $store->countWatchers( $title ) );
$this->assertEquals(
$initialWatchers,
$store->countWatchersMultiple( [ $title ] )[$title->getNamespace()][$title->getDBkey()]
);
$this->assertEquals(
[ $title->getNamespace() => [ $title->getDBkey() => false ] ],
$store->getNotificationTimestampsBatch( $user, [ $title ] )
);
}
public function testWatchBatchAndClearItems() {
$user = $this->getUser();
$title1 = Title::newFromText( 'WatchedItemStoreIntegrationTestPage1' );
$title2 = Title::newFromText( 'WatchedItemStoreIntegrationTestPage2' );
$store = MediaWikiServices::getInstance()->getWatchedItemStore();
$store->addWatchBatchForUser( $user, [ $title1, $title2 ] );
$this->assertTrue( $store->isWatched( $user, $title1 ) );
$this->assertTrue( $store->isWatched( $user, $title2 ) );
$store->clearUserWatchedItems( $user );
$this->assertFalse( $store->isWatched( $user, $title1 ) );
$this->assertFalse( $store->isWatched( $user, $title2 ) );
}
public function testUpdateResetAndSetNotificationTimestamp() {
$user = $this->getUser();
$otherUser = ( new TestUser( 'WatchedItemStoreIntegrationTestUser_otherUser' ) )->getUser();
$title = Title::newFromText( 'WatchedItemStoreIntegrationTestPage' );
$store = MediaWikiServices::getInstance()->getWatchedItemStore();
$store->addWatch( $user, $title );
$this->assertNull( $store->loadWatchedItem( $user, $title )->getNotificationTimestamp() );
$initialVisitingWatchers = $store->countVisitingWatchers( $title, '20150202020202' );
$initialUnreadNotifications = $store->countUnreadNotifications( $user );
$store->updateNotificationTimestamp( $otherUser, $title, '20150202010101' );
$this->assertEquals(
'20150202010101',
$store->loadWatchedItem( $user, $title )->getNotificationTimestamp()
);
$this->assertEquals(
[ $title->getNamespace() => [ $title->getDBkey() => '20150202010101' ] ],
$store->getNotificationTimestampsBatch( $user, [ $title ] )
);
$this->assertEquals(
$initialVisitingWatchers - 1,
$store->countVisitingWatchers( $title, '20150202020202' )
);
$this->assertEquals(
$initialVisitingWatchers - 1,
$store->countVisitingWatchersMultiple(
[ [ $title, '20150202020202' ] ]
)[$title->getNamespace()][$title->getDBkey()]
);
$this->assertEquals(
$initialUnreadNotifications + 1,
$store->countUnreadNotifications( $user )
);
$this->assertSame(
true,
$store->countUnreadNotifications( $user, $initialUnreadNotifications + 1 )
);
$this->assertTrue( $store->resetNotificationTimestamp( $user, $title ) );
$this->assertNull( $store->getWatchedItem( $user, $title )->getNotificationTimestamp() );
$this->assertEquals(
[ $title->getNamespace() => [ $title->getDBkey() => null ] ],
$store->getNotificationTimestampsBatch( $user, [ $title ] )
);
// Run the job queue
JobQueueGroup::destroySingletons();
$jobs = new RunJobs;
$jobs->loadParamsAndArgs( null, [ 'quiet' => true ], null );
$jobs->execute();
$this->assertEquals(
$initialVisitingWatchers,
$store->countVisitingWatchers( $title, '20150202020202' )
);
$this->assertEquals(
$initialVisitingWatchers,
$store->countVisitingWatchersMultiple(
[ [ $title, '20150202020202' ] ]
)[$title->getNamespace()][$title->getDBkey()]
);
$this->assertEquals(
[ 0 => [ 'WatchedItemStoreIntegrationTestPage' => $initialVisitingWatchers ] ],
$store->countVisitingWatchersMultiple(
[ [ $title, '20150202020202' ] ], $initialVisitingWatchers
)
);
$this->assertEquals(
[ 0 => [ 'WatchedItemStoreIntegrationTestPage' => 0 ] ],
$store->countVisitingWatchersMultiple(
[ [ $title, '20150202020202' ] ], $initialVisitingWatchers + 1
)
);
// setNotificationTimestampsForUser specifying a title
$this->assertTrue(
$store->setNotificationTimestampsForUser( $user, '20100202020202', [ $title ] )
);
$this->assertEquals(
'20100202020202',
$store->getWatchedItem( $user, $title )->getNotificationTimestamp()
);
// setNotificationTimestampsForUser not specifying a title
// This will try to use a DeferredUpdate; disable that
$mockCallback = function ( $callback ) {
$callback();
};
$scopedOverride = $store->overrideDeferredUpdatesAddCallableUpdateCallback( $mockCallback );
$this->assertTrue(
$store->setNotificationTimestampsForUser( $user, '20110202020202' )
);
// Because the operation above is normally deferred, it doesn't clear the cache
// Clear the cache manually
$wrappedStore = TestingAccessWrapper::newFromObject( $store );
$wrappedStore->uncacheUser( $user );
$this->assertEquals(
'20110202020202',
$store->getWatchedItem( $user, $title )->getNotificationTimestamp()
);
}
public function testDuplicateAllAssociatedEntries() {
$user = $this->getUser();
$titleOld = Title::newFromText( 'WatchedItemStoreIntegrationTestPageOld' );
$titleNew = Title::newFromText( 'WatchedItemStoreIntegrationTestPageNew' );
$store = MediaWikiServices::getInstance()->getWatchedItemStore();
$store->addWatch( $user, $titleOld->getSubjectPage() );
$store->addWatch( $user, $titleOld->getTalkPage() );
// Cleanup after previous tests
$store->removeWatch( $user, $titleNew->getSubjectPage() );
$store->removeWatch( $user, $titleNew->getTalkPage() );
$store->duplicateAllAssociatedEntries( $titleOld, $titleNew );
$this->assertTrue( $store->isWatched( $user, $titleOld->getSubjectPage() ) );
$this->assertTrue( $store->isWatched( $user, $titleOld->getTalkPage() ) );
$this->assertTrue( $store->isWatched( $user, $titleNew->getSubjectPage() ) );
$this->assertTrue( $store->isWatched( $user, $titleNew->getTalkPage() ) );
}
}