wiki.techinc.nl/tests/phpunit/includes/user/TalkPageNotificationManagerTest.php
daniel 166b569444 Make use of the new PageUpdateStatus
PageUpdateStatus provides clean access the the newly created
RevisionRecord.

Depends-On: Ia08c586198082ea47e8313d0d41835f9830fb29e
Change-Id: Id6963842321c4eaa3d7d029ad0b769f73433c103
2022-11-30 17:56:58 +00:00

232 lines
8.6 KiB
PHP

<?php
use MediaWiki\Config\ServiceOptions;
use MediaWiki\Revision\MutableRevisionRecord;
use MediaWiki\Revision\RevisionLookup;
use MediaWiki\Revision\RevisionRecord;
use MediaWiki\Tests\Unit\DummyServicesTrait;
use MediaWiki\User\TalkPageNotificationManager;
use MediaWiki\User\UserIdentity;
use MediaWiki\User\UserIdentityValue;
use PHPUnit\Framework\AssertionFailedError;
/**
* @covers \MediaWiki\User\TalkPageNotificationManager
* @group Database
*/
class TalkPageNotificationManagerTest extends MediaWikiIntegrationTestCase {
use DummyServicesTrait;
protected function setUp(): void {
parent::setUp();
// tablesUsed don't clear up the database before the first test runs: T265033
$this->truncateTable( 'user_newtalk' );
$this->tablesUsed[] = 'user_newtalk';
}
private function editUserTalk( UserIdentity $user, string $text ): RevisionRecord {
// UserIdentity doesn't have getUserPage/getTalkPage, but we can easily recreate
// it, and its easier than needing to depend on a full user object
$userTalk = Title::makeTitle( NS_USER_TALK, $user->getName() );
$status = $this->editPage(
$userTalk->getPrefixedText(),
$text,
'',
NS_MAIN,
$this->getTestSysop()->getUser()
);
$this->assertStatusGood( $status, 'create revision of user talk' );
return $status->getNewRevision();
}
private function getManager(
bool $disableAnonTalk = false,
bool $isReadOnly = false,
RevisionLookup $revisionLookup = null
) {
$services = $this->getServiceContainer();
return new TalkPageNotificationManager(
new ServiceOptions(
TalkPageNotificationManager::CONSTRUCTOR_OPTIONS,
new HashConfig( [
'DisableAnonTalk' => $disableAnonTalk
] )
),
$services->getDBLoadBalancer(),
$this->getDummyReadOnlyMode( $isReadOnly ),
$revisionLookup ?? $services->getRevisionLookup(),
$this->createHookContainer(),
$services->getUserFactory()
);
}
public function provideUserHasNewMessages() {
yield 'Registered user' => [ UserIdentityValue::newRegistered( 123, 'MyName' ) ];
yield 'Anonymous user' => [ UserIdentityValue::newAnonymous( '1.2.3.4' ) ];
}
/**
* @dataProvider provideUserHasNewMessages
* @covers \MediaWiki\User\TalkPageNotificationManager::userHasNewMessages
* @covers \MediaWiki\User\TalkPageNotificationManager::setUserHasNewMessages
* @covers \MediaWiki\User\TalkPageNotificationManager::clearInstanceCache
* @covers \MediaWiki\User\TalkPageNotificationManager::removeUserHasNewMessages
*/
public function testUserHasNewMessages( UserIdentity $user ) {
$manager = $this->getManager();
$this->assertFalse( $manager->userHasNewMessages( $user ),
'Should be false before updated' );
$revRecord = $this->editUserTalk( $user, __METHOD__ );
$manager->setUserHasNewMessages( $user, $revRecord );
$this->assertTrue( $manager->userHasNewMessages( $user ),
'Should be true after updated' );
$manager->clearInstanceCache( $user );
$this->assertTrue( $manager->userHasNewMessages( $user ),
'Should be true after cache cleared' );
$manager->removeUserHasNewMessages( $user );
$this->assertFalse( $manager->userHasNewMessages( $user ),
'Should be false after updated' );
$manager->clearInstanceCache( $user );
$this->assertFalse( $manager->userHasNewMessages( $user ),
'Should be false after cache cleared' );
$manager->setUserHasNewMessages( $user, null );
$this->assertTrue( $manager->userHasNewMessages( $user ),
'Should be true after updated' );
$manager->removeUserHasNewMessages( $user );
$this->assertFalse( $manager->userHasNewMessages( $user ),
'Should be false after updated' );
}
/**
* @covers \MediaWiki\User\TalkPageNotificationManager::userHasNewMessages
* @covers \MediaWiki\User\TalkPageNotificationManager::setUserHasNewMessages
*/
public function testUserHasNewMessagesDisabledAnon() {
$user = new UserIdentityValue( 0, '1.2.3.4' );
$revRecord = $this->editUserTalk( $user, __METHOD__ );
$manager = $this->getManager( true );
$this->assertFalse( $manager->userHasNewMessages( $user ),
'New anon should have no new messages' );
$manager->setUserHasNewMessages( $user, $revRecord );
$this->assertFalse( $manager->userHasNewMessages( $user ),
'Must not set new messages for anon if disabled' );
$manager->clearInstanceCache( $user );
$this->assertFalse( $manager->userHasNewMessages( $user ),
'Must not set to database if anon messages disabled' );
}
/**
* @covers \MediaWiki\User\TalkPageNotificationManager::getLatestSeenMessageTimestamp
*/
public function testGetLatestSeenMessageTimestamp() {
$user = $this->getTestUser()->getUser();
$firstRev = $this->editUserTalk( $user, __METHOD__ . ' 1' );
$secondRev = $this->editUserTalk( $user, __METHOD__ . ' 2' );
$manager = $this->getManager();
$manager->setUserHasNewMessages( $user, $secondRev );
$this->assertSame( $firstRev->getTimestamp(), $manager->getLatestSeenMessageTimestamp( $user ) );
}
/**
* @covers \MediaWiki\User\TalkPageNotificationManager::getLatestSeenMessageTimestamp
*/
public function testGetLatestSeenMessageTimestampOutOfOrderRevision() {
$user = $this->getTestUser()->getUser();
$firstRev = $this->editUserTalk( $user, __METHOD__ . ' 1' );
$secondRev = $this->editUserTalk( $user, __METHOD__ . ' 2' );
$thirdRev = $this->editUserTalk( $user, __METHOD__ . ' 3' );
$veryOldTimestamp = MWTimestamp::convert( TS_MW, 1 );
$mockOldRev = $this->createMock( RevisionRecord::class );
$mockOldRev->method( 'getTimestamp' )
->willReturn( $veryOldTimestamp );
$mockRevLookup = $this->getMockForAbstractClass( RevisionLookup::class );
$mockRevLookup->method( 'getPreviousRevision' )
->willReturnCallback( static function ( RevisionRecord $rev )
use ( $firstRev, $secondRev, $thirdRev, $mockOldRev )
{
if ( $rev === $secondRev ) {
return $firstRev;
}
if ( $rev === $thirdRev ) {
return $mockOldRev;
}
throw new AssertionFailedError(
'RevisionLookup::getPreviousRevision called with wrong rev ' . $rev->getId()
);
} );
$manager = $this->getManager( false, false, $mockRevLookup );
$manager->setUserHasNewMessages( $user, $thirdRev );
$this->assertSame( $veryOldTimestamp, $manager->getLatestSeenMessageTimestamp( $user ) );
$manager->setUserHasNewMessages( $user, $secondRev );
$this->assertSame( $veryOldTimestamp, $manager->getLatestSeenMessageTimestamp( $user ) );
}
/**
* @covers \MediaWiki\User\TalkPageNotificationManager::getLatestSeenMessageTimestamp
*/
public function testGetLatestSeenMessageTimestampNoNewMessages() {
$user = $this->getTestUser()->getUser();
$manager = $this->getManager();
$this->assertNull( $manager->getLatestSeenMessageTimestamp( $user ),
'Must be null if no new messages' );
}
/**
* @covers \MediaWiki\User\TalkPageNotificationManager::userHasNewMessages
* @covers \MediaWiki\User\TalkPageNotificationManager::setUserHasNewMessages
* @covers \MediaWiki\User\TalkPageNotificationManager::removeUserHasNewMessages
*/
public function testDoesNotCrashOnReadOnly() {
$user = $this->getTestUser()->getUser();
$this->editUserTalk( $user, __METHOD__ );
$manager = $this->getManager( false, true );
$this->assertTrue( $manager->userHasNewMessages( $user ) );
$manager->removeUserHasNewMessages( $user );
$this->assertFalse( $manager->userHasNewMessages( $user ) );
}
/**
* @covers \MediaWiki\User\TalkPageNotificationManager::clearForPageView
*/
public function testClearForPageView() {
$user = $this->getTestUser()->getUser();
$title = $user->getTalkPage();
$revision = new MutableRevisionRecord( $title );
$revision->setPageId( 100 );
$revision->setId( 101 );
$manager = $this->getManager();
$manager->setUserHasNewMessages( $user );
$this->assertTrue( $manager->userHasNewMessages( $user ) );
// DB should have the notification
$this->assertSelect(
'user_newtalk',
'user_id',
[ 'user_id' => $user->getId() ],
[ [ $user->getId() ] ]
);
$this->db->startAtomic( __METHOD__ ); // let deferred updates queue up
$updateCountBefore = DeferredUpdates::pendingUpdatesCount();
$manager->clearForPageView( $user, $revision );
// Cache should already be updated
$this->assertFalse( $manager->userHasNewMessages( $user ) );
$updateCountAfter = DeferredUpdates::pendingUpdatesCount();
$this->assertGreaterThan( $updateCountBefore, $updateCountAfter, 'An update should have been queued' );
$this->db->endAtomic( __METHOD__ ); // run deferred updates
$this->assertSame( 0, DeferredUpdates::pendingUpdatesCount(), 'No pending updates' );
// Notification should have been deleted from the DB
$this->assertSelect(
'user_newtalk',
'user_id',
[ 'user_id' => $user->getId() ],
[]
);
}
}