wiki.techinc.nl/tests/phpunit/includes/api/query/ApiQueryWatchlistIntegrationTest.php
Bartosz Dziewoński 1048db795b API tests: Assert error codes, not error messages
Error messages are not guaranteed to be stable, and these tests
prevent us from improving them.

Error codes are supposed to be stable, so we should be asserting
that they do not change (especially since many of them are
dynamically generated by the dodgy code in ApiMessageTrait).

Introduce helpers assertApiErrorCode() and expectApiErrorCode()
to be used instead of the usual PHPUnit assertions/expectations
for this case.

Change-Id: I752f82f29bf5f9405ea117ebf9e5cf70335464ad
2023-04-26 19:36:29 +02:00

1596 lines
42 KiB
PHP

<?php
use MediaWiki\Linker\LinkTarget;
use MediaWiki\Permissions\Authority;
use MediaWiki\Revision\SlotRecord;
use MediaWiki\Title\Title;
/**
* @group medium
* @group API
* @group Database
*
* @covers ApiQueryWatchlist
*/
class ApiQueryWatchlistIntegrationTest extends ApiTestCase {
protected function setUp(): void {
parent::setUp();
$this->tablesUsed = array_unique(
array_merge( $this->tablesUsed, [ 'watchlist', 'recentchanges', 'page' ] )
);
self::$users['ApiQueryWatchlistIntegrationTestUser'] = $this->getMutableTestUser();
self::$users['ApiQueryWatchlistIntegrationTestUser2'] = $this->getMutableTestUser();
}
private function getLoggedInTestUser() {
return self::$users['ApiQueryWatchlistIntegrationTestUser']->getUser();
}
private function getNonLoggedInTestUser() {
return self::$users['ApiQueryWatchlistIntegrationTestUser2']->getUser();
}
private function doPageEdit( Authority $performer, LinkTarget $target, $content, $summary ) {
$this->editPage(
$target,
$content,
$summary,
NS_MAIN,
$performer
);
}
private function doMinorPageEdit( User $user, LinkTarget $target, $content, $summary ) {
$title = Title::newFromLinkTarget( $target );
$page = $this->getServiceContainer()->getWikiPageFactory()->newFromTitle( $title );
$page->doUserEditContent(
ContentHandler::makeContent( $content, $title ),
$user,
$summary,
EDIT_MINOR
);
}
private function doBotPageEdit( User $user, LinkTarget $target, $content, $summary ) {
$title = Title::newFromLinkTarget( $target );
$page = $this->getServiceContainer()->getWikiPageFactory()->newFromTitle( $title );
$page->doUserEditContent(
ContentHandler::makeContent( $content, $title ),
$user,
$summary,
EDIT_FORCE_BOT
);
}
private function doAnonPageEdit( LinkTarget $target, $content, $summary ) {
$this->editPage(
$target,
$content,
$summary,
NS_MAIN,
$this->getServiceContainer()->getUserFactory()->newAnonymous()
);
}
private function doPatrolledPageEdit(
User $user,
LinkTarget $target,
$content,
$summary,
User $patrollingUser
) {
$title = Title::newFromLinkTarget( $target );
$summary = CommentStoreComment::newUnsavedComment( trim( $summary ) );
$page = $this->getServiceContainer()->getWikiPageFactory()->newFromTitle( $title );
$updater = $page->newPageUpdater( $user );
$updater->setContent( SlotRecord::MAIN, ContentHandler::makeContent( $content, $title ) );
$rev = $updater->saveRevision( $summary );
$rc = $this->getServiceContainer()->getRevisionStore()->getRecentChange( $rev );
$rc->doMarkPatrolled( $patrollingUser, false, [] );
}
/**
* Performs a batch of page edits as a specified user
* @param User $user
* @param array $editData associative array, keys:
* - target => LinkTarget page to edit
* - content => string new content
* - summary => string edit summary
* - minorEdit => bool mark as minor edit if true (defaults to false)
* - botEdit => bool mark as bot edit if true (defaults to false)
*/
private function doPageEdits( User $user, array $editData ) {
foreach ( $editData as $singleEditData ) {
if ( array_key_exists( 'minorEdit', $singleEditData ) && $singleEditData['minorEdit'] ) {
$this->doMinorPageEdit(
$user,
$singleEditData['target'],
$singleEditData['content'],
$singleEditData['summary']
);
continue;
}
if ( array_key_exists( 'botEdit', $singleEditData ) && $singleEditData['botEdit'] ) {
$this->doBotPageEdit(
$user,
$singleEditData['target'],
$singleEditData['content'],
$singleEditData['summary']
);
continue;
}
$this->doPageEdit(
$user,
$singleEditData['target'],
$singleEditData['content'],
$singleEditData['summary']
);
}
}
private function getWatchedItemStore() {
return $this->getServiceContainer()->getWatchedItemStore();
}
/**
* @param User $user
* @param LinkTarget[] $targets
*/
private function watchPages( User $user, array $targets ) {
$store = $this->getWatchedItemStore();
$store->addWatchBatchForUser( $user, $targets );
}
private function doListWatchlistRequest( array $params = [], $user = null ) {
if ( $user === null ) {
$user = $this->getLoggedInTestUser();
}
return $this->doApiRequest(
array_merge(
[ 'action' => 'query', 'list' => 'watchlist' ],
$params
), null, false, $user
);
}
private function doGeneratorWatchlistRequest( array $params = [] ) {
return $this->doApiRequest(
array_merge(
[ 'action' => 'query', 'generator' => 'watchlist' ],
$params
), null, false, $this->getLoggedInTestUser()
);
}
private function getItemsFromApiResponse( array $response ) {
return $response[0]['query']['watchlist'];
}
/**
* Convenience method to assert that actual items array fetched from API is equal to the expected
* array, Unlike assertEquals this only checks if values of specified keys are equal in both
* arrays. This could be used e.g. not to compare IDs that could change between test run
* but only stable keys.
* Optionally this also checks that specified keys are present in the actual item without
* performing any checks on the related values.
*
* @param array $actualItems array of actual items (associative arrays)
* @param array $expectedItems array of expected items (associative arrays),
* those items have less keys than actual items
* @param array $keysUsedInValueComparison list of keys of the actual item that will be used
* in the comparison of values
* @param array $requiredKeys optional, list of keys that must be present in the
* actual items. Values of those keys are not checked.
*/
private function assertArraySubsetsEqual(
array $actualItems,
array $expectedItems,
array $keysUsedInValueComparison,
array $requiredKeys = []
) {
$this->assertCount( count( $expectedItems ), $actualItems );
// not checking values of all keys of the actual item, so removing unwanted keys from comparison
$actualItemsOnlyComparedValues = array_map(
static function ( array $item ) use ( $keysUsedInValueComparison ) {
return array_intersect_key( $item,
array_fill_keys( $keysUsedInValueComparison, true ) );
},
$actualItems
);
$this->assertEquals(
$expectedItems,
$actualItemsOnlyComparedValues
);
// Check that each item in $actualItems contains all of keys specified in $requiredKeys
$actualItemsKeysOnly = array_map( 'array_keys', $actualItems );
foreach ( $actualItemsKeysOnly as $keysOfTheItem ) {
$this->assertSame( [], array_diff( $requiredKeys, $keysOfTheItem ) );
}
}
private function getPrefixedText( LinkTarget $target ) {
return $this->getServiceContainer()->getTitleFormatter()->getPrefixedText( $target );
}
private function cleanTestUsersWatchlist() {
$user = $this->getLoggedInTestUser();
$store = $this->getWatchedItemStore();
$items = $store->getWatchedItemsForUser( $user );
foreach ( $items as $item ) {
$store->removeWatch( $user, $item->getTarget() );
}
}
public function testListWatchlist_returnsWatchedItemsWithRCInfo() {
// Clean up after previous tests that might have added something to the watchlist of
// the user with the same user ID as user used here as the test user
$this->cleanTestUsersWatchlist();
$user = $this->getLoggedInTestUser();
$target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdit(
$user,
$target,
'Some Content',
'Create the page'
);
$this->watchPages( $user, [ $target ] );
$result = $this->doListWatchlistRequest();
$this->assertArrayHasKey( 'query', $result[0] );
$this->assertArrayHasKey( 'watchlist', $result[0]['query'] );
$this->assertArraySubsetsEqual(
$this->getItemsFromApiResponse( $result ),
[
[
'type' => 'new',
'ns' => $target->getNamespace(),
'title' => $this->getPrefixedText( $target ),
'bot' => false,
'new' => true,
'minor' => false,
]
],
[ 'type', 'ns', 'title', 'bot', 'new', 'minor' ],
[ 'pageid', 'revid', 'old_revid' ]
);
}
public function testIdsPropParameter() {
$user = $this->getLoggedInTestUser();
$target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdit(
$user,
$target,
'Some Content',
'Create the page'
);
$this->watchPages( $user, [ $target ] );
$result = $this->doListWatchlistRequest( [ 'wlprop' => 'ids', ] );
$items = $this->getItemsFromApiResponse( $result );
$this->assertCount( 1, $items );
$this->assertArrayHasKey( 'pageid', $items[0] );
$this->assertArrayHasKey( 'revid', $items[0] );
$this->assertArrayHasKey( 'old_revid', $items[0] );
$this->assertEquals( 'new', $items[0]['type'] );
}
public function testTitlePropParameter() {
$user = $this->getLoggedInTestUser();
$subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdits(
$user,
[
[
'target' => $subjectTarget,
'content' => 'Some Content',
'summary' => 'Create the page',
],
[
'target' => $talkTarget,
'content' => 'Some Talk Page Content',
'summary' => 'Create Talk page',
],
]
);
$this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
$result = $this->doListWatchlistRequest( [ 'wlprop' => 'title', ] );
$this->assertEquals(
[
[
'type' => 'new',
'ns' => $talkTarget->getNamespace(),
'title' => $this->getPrefixedText( $talkTarget ),
],
[
'type' => 'new',
'ns' => $subjectTarget->getNamespace(),
'title' => $this->getPrefixedText( $subjectTarget ),
],
],
$this->getItemsFromApiResponse( $result )
);
}
public function testFlagsPropParameter() {
$user = $this->getLoggedInTestUser();
$normalEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$minorEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPageM' );
$botEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPageB' );
$this->doPageEdits(
$user,
[
[
'target' => $normalEditTarget,
'content' => 'Some Content',
'summary' => 'Create the page',
],
[
'target' => $minorEditTarget,
'content' => 'Some Content',
'summary' => 'Create the page',
],
[
'target' => $minorEditTarget,
'content' => 'Slightly Better Content',
'summary' => 'Change content',
'minorEdit' => true,
],
[
'target' => $botEditTarget,
'content' => 'Some Content',
'summary' => 'Create the page with a bot',
'botEdit' => true,
],
]
);
$this->watchPages( $user, [ $normalEditTarget, $minorEditTarget, $botEditTarget ] );
$result = $this->doListWatchlistRequest( [ 'wlprop' => 'flags', ] );
$this->assertEquals(
[
[
'type' => 'new',
'new' => true,
'minor' => false,
'bot' => true,
],
[
'type' => 'edit',
'new' => false,
'minor' => true,
'bot' => false,
],
[
'type' => 'new',
'new' => true,
'minor' => false,
'bot' => false,
],
],
$this->getItemsFromApiResponse( $result )
);
}
public function testUserPropParameter() {
$user = $this->getLoggedInTestUser();
$userEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$anonEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPageA' );
$this->doPageEdit(
$user,
$userEditTarget,
'Some Content',
'Create the page'
);
$this->doAnonPageEdit(
$anonEditTarget,
'Some Content',
'Create the page'
);
$this->watchPages( $user, [ $userEditTarget, $anonEditTarget ] );
$result = $this->doListWatchlistRequest( [ 'wlprop' => 'user', ] );
$this->assertEquals(
[
[
'type' => 'new',
'anon' => true,
'user' => User::newFromId( 0 )->getName(),
],
[
'type' => 'new',
'anon' => false,
'user' => $user->getName(),
],
],
$this->getItemsFromApiResponse( $result )
);
}
public function testUserIdPropParameter() {
$user = $this->getLoggedInTestUser();
$userEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$anonEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPageA' );
$this->doPageEdit(
$user,
$userEditTarget,
'Some Content',
'Create the page'
);
$this->doAnonPageEdit(
$anonEditTarget,
'Some Content',
'Create the page'
);
$this->watchPages( $user, [ $userEditTarget, $anonEditTarget ] );
$result = $this->doListWatchlistRequest( [ 'wlprop' => 'userid', ] );
$this->assertEquals(
[
[
'type' => 'new',
'anon' => true,
'user' => 0,
'userid' => 0,
],
[
'type' => 'new',
'anon' => false,
'user' => $user->getId(),
'userid' => $user->getId(),
],
],
$this->getItemsFromApiResponse( $result )
);
}
public function testCommentPropParameter() {
$user = $this->getLoggedInTestUser();
$target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdit(
$user,
$target,
'Some Content',
'Create the <b>page</b>'
);
$this->watchPages( $user, [ $target ] );
$result = $this->doListWatchlistRequest( [ 'wlprop' => 'comment', ] );
$this->assertEquals(
[
[
'type' => 'new',
'comment' => 'Create the <b>page</b>',
],
],
$this->getItemsFromApiResponse( $result )
);
}
public function testParsedCommentPropParameter() {
$user = $this->getLoggedInTestUser();
$target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdit(
$user,
$target,
'Some Content',
'Create the <b>page</b>'
);
$this->watchPages( $user, [ $target ] );
$result = $this->doListWatchlistRequest( [ 'wlprop' => 'parsedcomment', ] );
$this->assertEquals(
[
[
'type' => 'new',
'parsedcomment' => 'Create the &lt;b&gt;page&lt;/b&gt;',
],
],
$this->getItemsFromApiResponse( $result )
);
}
public function testTimestampPropParameter() {
$user = $this->getLoggedInTestUser();
$target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdit(
$user,
$target,
'Some Content',
'Create the page'
);
$this->watchPages( $user, [ $target ] );
$result = $this->doListWatchlistRequest( [ 'wlprop' => 'timestamp', ] );
$items = $this->getItemsFromApiResponse( $result );
$this->assertCount( 1, $items );
$this->assertArrayHasKey( 'timestamp', $items[0] );
$this->assertIsString( $items[0]['timestamp'] );
}
public function testSizesPropParameter() {
$user = $this->getLoggedInTestUser();
$target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdit(
$user,
$target,
'Some Content',
'Create the page'
);
$this->watchPages( $user, [ $target ] );
$result = $this->doListWatchlistRequest( [ 'wlprop' => 'sizes', ] );
$this->assertEquals(
[
[
'type' => 'new',
'oldlen' => 0,
'newlen' => 12,
],
],
$this->getItemsFromApiResponse( $result )
);
}
public function testNotificationTimestampPropParameter() {
$otherUser = $this->getNonLoggedInTestUser();
$target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdit(
$otherUser,
$target,
'Some Content',
'Create the page'
);
$store = $this->getWatchedItemStore();
$store->addWatch( $this->getLoggedInTestUser(), $target );
$store->updateNotificationTimestamp(
$otherUser,
$target,
'20151212010101'
);
$result = $this->doListWatchlistRequest( [ 'wlprop' => 'notificationtimestamp', ] );
$this->assertEquals(
[
[
'type' => 'new',
'notificationtimestamp' => '2015-12-12T01:01:01Z',
],
],
$this->getItemsFromApiResponse( $result )
);
}
private function setupPatrolledSpecificFixtures( User $user ) {
$target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPatrolledPageEdit(
$user,
$target,
'Some Content',
'Create the page (this gets patrolled)',
$user
);
$this->watchPages( $user, [ $target ] );
}
public function testPatrolPropParameter() {
$testUser = static::getTestSysop();
$user = $testUser->getUser();
$this->setupPatrolledSpecificFixtures( $user );
$result = $this->doListWatchlistRequest( [ 'wlprop' => 'patrol', ], $user );
$this->assertEquals(
[
[
'type' => 'new',
'patrolled' => true,
'unpatrolled' => false,
'autopatrolled' => false,
]
],
$this->getItemsFromApiResponse( $result )
);
}
private function createPageAndDeleteIt( LinkTarget $target ) {
$this->doPageEdit(
$this->getLoggedInTestUser(),
$target,
'Some Content',
'Create the page that will be deleted'
);
$wikiPage = $this->getServiceContainer()->getWikiPageFactory()->newFromLinkTarget( $target );
$this->deletePage( $wikiPage, 'Important Reason' );
}
public function testLoginfoPropParameter() {
$target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$this->createPageAndDeleteIt( $target );
$this->watchPages( $this->getLoggedInTestUser(), [ $target ] );
$result = $this->doListWatchlistRequest( [ 'wlprop' => 'loginfo', ] );
$this->assertArraySubsetsEqual(
$this->getItemsFromApiResponse( $result ),
[
[
'type' => 'log',
'logtype' => 'delete',
'logaction' => 'delete',
'logparams' => [],
],
],
[ 'type', 'logtype', 'logaction', 'logparams' ],
[ 'logid' ]
);
}
public function testEmptyPropParameter() {
$user = $this->getLoggedInTestUser();
$target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdit(
$user,
$target,
'Some Content',
'Create the page'
);
$this->watchPages( $user, [ $target ] );
$result = $this->doListWatchlistRequest( [ 'wlprop' => '', ] );
$this->assertEquals(
[
[
'type' => 'new',
]
],
$this->getItemsFromApiResponse( $result )
);
}
public function testNamespaceParam() {
$user = $this->getLoggedInTestUser();
$subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdits(
$user,
[
[
'target' => $subjectTarget,
'content' => 'Some Content',
'summary' => 'Create the page',
],
[
'target' => $talkTarget,
'content' => 'Some Content',
'summary' => 'Create the talk page',
],
]
);
$this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
$result = $this->doListWatchlistRequest( [ 'wlnamespace' => '0', ] );
$this->assertArraySubsetsEqual(
$this->getItemsFromApiResponse( $result ),
[
[
'ns' => 0,
'title' => $this->getPrefixedText( $subjectTarget ),
],
],
[ 'ns', 'title' ]
);
}
public function testUserParam() {
$user = $this->getLoggedInTestUser();
$otherUser = $this->getNonLoggedInTestUser();
$subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdit(
$user,
$subjectTarget,
'Some Content',
'Create the page'
);
$this->doPageEdit(
$otherUser,
$talkTarget,
'What is this page about?',
'Create the talk page'
);
$this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
$result = $this->doListWatchlistRequest( [
'wlprop' => 'user|title',
'wluser' => $otherUser->getName(),
] );
$this->assertEquals(
[
[
'type' => 'new',
'ns' => $talkTarget->getNamespace(),
'title' => $this->getPrefixedText( $talkTarget ),
'user' => $otherUser->getName(),
'anon' => false,
],
],
$this->getItemsFromApiResponse( $result )
);
}
public function testExcludeUserParam() {
$user = $this->getLoggedInTestUser();
$otherUser = $this->getNonLoggedInTestUser();
$subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdit(
$user,
$subjectTarget,
'Some Content',
'Create the page'
);
$this->doPageEdit(
$otherUser,
$talkTarget,
'What is this page about?',
'Create the talk page'
);
$this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
$result = $this->doListWatchlistRequest( [
'wlprop' => 'user|title',
'wlexcludeuser' => $otherUser->getName(),
] );
$this->assertEquals(
[
[
'type' => 'new',
'ns' => $subjectTarget->getNamespace(),
'title' => $this->getPrefixedText( $subjectTarget ),
'user' => $user->getName(),
'anon' => false,
]
],
$this->getItemsFromApiResponse( $result )
);
}
public function testShowMinorParams() {
$user = $this->getLoggedInTestUser();
$target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdits(
$user,
[
[
'target' => $target,
'content' => 'Some Content',
'summary' => 'Create the page',
],
[
'target' => $target,
'content' => 'Slightly Better Content',
'summary' => 'Change content',
'minorEdit' => true,
],
]
);
$this->watchPages( $user, [ $target ] );
$resultMinor = $this->doListWatchlistRequest( [
'wlshow' => WatchedItemQueryService::FILTER_MINOR,
'wlprop' => 'flags'
] );
$resultNotMinor = $this->doListWatchlistRequest( [
'wlshow' => WatchedItemQueryService::FILTER_NOT_MINOR, 'wlprop' => 'flags'
] );
$this->assertArraySubsetsEqual(
$this->getItemsFromApiResponse( $resultMinor ),
[
[ 'minor' => true, ]
],
[ 'minor' ]
);
$this->assertSame( [], $this->getItemsFromApiResponse( $resultNotMinor ) );
}
public function testShowBotParams() {
$user = $this->getLoggedInTestUser();
$target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doBotPageEdit(
$user,
$target,
'Some Content',
'Create the page'
);
$this->watchPages( $user, [ $target ] );
$resultBot = $this->doListWatchlistRequest( [
'wlshow' => WatchedItemQueryService::FILTER_BOT
] );
$resultNotBot = $this->doListWatchlistRequest( [
'wlshow' => WatchedItemQueryService::FILTER_NOT_BOT
] );
$this->assertArraySubsetsEqual(
$this->getItemsFromApiResponse( $resultBot ),
[
[ 'bot' => true ],
],
[ 'bot' ]
);
$this->assertSame( [], $this->getItemsFromApiResponse( $resultNotBot ) );
}
public function testShowAnonParams() {
$user = $this->getLoggedInTestUser();
$target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doAnonPageEdit(
$target,
'Some Content',
'Create the page'
);
$this->watchPages( $user, [ $target ] );
$resultAnon = $this->doListWatchlistRequest( [
'wlprop' => 'user',
'wlshow' => WatchedItemQueryService::FILTER_ANON
] );
$resultNotAnon = $this->doListWatchlistRequest( [
'wlprop' => 'user',
'wlshow' => WatchedItemQueryService::FILTER_NOT_ANON
] );
$this->assertArraySubsetsEqual(
$this->getItemsFromApiResponse( $resultAnon ),
[
[ 'anon' => true ],
],
[ 'anon' ]
);
$this->assertSame( [], $this->getItemsFromApiResponse( $resultNotAnon ) );
}
public function testShowUnreadParams() {
$user = $this->getLoggedInTestUser();
$otherUser = $this->getNonLoggedInTestUser();
$subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdit(
$user,
$subjectTarget,
'Some Content',
'Create the page'
);
$this->doPageEdit(
$otherUser,
$talkTarget,
'Some Content',
'Create the talk page'
);
$store = $this->getWatchedItemStore();
$store->addWatchBatchForUser( $user, [ $subjectTarget, $talkTarget ] );
$store->updateNotificationTimestamp(
$otherUser,
$talkTarget,
'20151212010101'
);
$resultUnread = $this->doListWatchlistRequest( [
'wlprop' => 'notificationtimestamp|title',
'wlshow' => WatchedItemQueryService::FILTER_UNREAD
] );
$resultNotUnread = $this->doListWatchlistRequest( [
'wlprop' => 'notificationtimestamp|title',
'wlshow' => WatchedItemQueryService::FILTER_NOT_UNREAD
] );
$this->assertEquals(
[
[
'type' => 'new',
'notificationtimestamp' => '2015-12-12T01:01:01Z',
'ns' => $talkTarget->getNamespace(),
'title' => $this->getPrefixedText( $talkTarget )
]
],
$this->getItemsFromApiResponse( $resultUnread )
);
$this->assertEquals(
[
[
'type' => 'new',
'notificationtimestamp' => '',
'ns' => $subjectTarget->getNamespace(),
'title' => $this->getPrefixedText( $subjectTarget )
]
],
$this->getItemsFromApiResponse( $resultNotUnread )
);
}
public function testShowPatrolledParams() {
$user = static::getTestSysop()->getUser();
$this->setupPatrolledSpecificFixtures( $user );
$resultPatrolled = $this->doListWatchlistRequest( [
'wlprop' => 'patrol',
'wlshow' => WatchedItemQueryService::FILTER_PATROLLED
], $user );
$resultNotPatrolled = $this->doListWatchlistRequest( [
'wlprop' => 'patrol',
'wlshow' => WatchedItemQueryService::FILTER_NOT_PATROLLED
], $user );
$this->assertEquals(
[
[
'type' => 'new',
'patrolled' => true,
'unpatrolled' => false,
'autopatrolled' => false,
]
],
$this->getItemsFromApiResponse( $resultPatrolled )
);
$this->assertSame( [], $this->getItemsFromApiResponse( $resultNotPatrolled ) );
}
public function testNewAndEditTypeParameters() {
$user = $this->getLoggedInTestUser();
$subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdits(
$user,
[
[
'target' => $subjectTarget,
'content' => 'Some Content',
'summary' => 'Create the page',
],
[
'target' => $subjectTarget,
'content' => 'Some Other Content',
'summary' => 'Change the content',
],
[
'target' => $talkTarget,
'content' => 'Some Talk Page Content',
'summary' => 'Create Talk page',
],
]
);
$this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
$resultNew = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'new' ] );
$resultEdit = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'edit' ] );
$this->assertEquals(
[
[
'type' => 'new',
'ns' => $talkTarget->getNamespace(),
'title' => $this->getPrefixedText( $talkTarget ),
],
],
$this->getItemsFromApiResponse( $resultNew )
);
$this->assertEquals(
[
[
'type' => 'edit',
'ns' => $subjectTarget->getNamespace(),
'title' => $this->getPrefixedText( $subjectTarget ),
],
],
$this->getItemsFromApiResponse( $resultEdit )
);
}
public function testLogTypeParameters() {
$user = $this->getLoggedInTestUser();
$subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
$this->createPageAndDeleteIt( $subjectTarget );
$this->doPageEdit(
$user,
$talkTarget,
'Some Talk Page Content',
'Create Talk page'
);
$this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
$result = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'log' ] );
$this->assertEquals(
[
[
'type' => 'log',
'ns' => $subjectTarget->getNamespace(),
'title' => $this->getPrefixedText( $subjectTarget ),
],
],
$this->getItemsFromApiResponse( $result )
);
}
private function getExternalRC( LinkTarget $target ) {
$title = Title::newFromLinkTarget( $target );
$rc = new RecentChange;
$rc->mAttribs = [
'rc_timestamp' => wfTimestamp( TS_MW ),
'rc_namespace' => $title->getNamespace(),
'rc_title' => $title->getDBkey(),
'rc_type' => RC_EXTERNAL,
'rc_source' => 'foo',
'rc_minor' => 0,
'rc_cur_id' => $title->getArticleID(),
'rc_user' => 0,
'rc_user_text' => 'ext>External User',
'rc_comment' => '',
'rc_comment_text' => '',
'rc_comment_data' => null,
'rc_this_oldid' => $title->getLatestRevID(),
'rc_last_oldid' => $title->getLatestRevID(),
'rc_bot' => 0,
'rc_ip' => '',
'rc_patrolled' => 0,
'rc_new' => 0,
'rc_old_len' => $title->getLength(),
'rc_new_len' => $title->getLength(),
'rc_deleted' => 0,
'rc_logid' => 0,
'rc_log_type' => null,
'rc_log_action' => '',
'rc_params' => '',
];
$rc->mExtra = [
'prefixedDBkey' => $title->getPrefixedDBkey(),
'lastTimestamp' => 0,
'oldSize' => $title->getLength(),
'newSize' => $title->getLength(),
'pageStatus' => 'changed'
];
return $rc;
}
public function testExternalTypeParameters() {
$user = $this->getLoggedInTestUser();
$subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdit(
$user,
$subjectTarget,
'Some Content',
'Create the page'
);
$this->doPageEdit(
$user,
$talkTarget,
'Some Talk Page Content',
'Create Talk page'
);
$rc = $this->getExternalRC( $subjectTarget );
$rc->save();
$this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
$result = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'external' ] );
$this->assertEquals(
[
[
'type' => 'external',
'ns' => $subjectTarget->getNamespace(),
'title' => $this->getPrefixedText( $subjectTarget ),
],
],
$this->getItemsFromApiResponse( $result )
);
}
public function testCategorizeTypeParameter() {
$user = $this->getLoggedInTestUser();
$subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$categoryTarget = new TitleValue( NS_CATEGORY, 'ApiQueryWatchlistIntegrationTestCategory' );
$this->doPageEdits(
$user,
[
[
'target' => $categoryTarget,
'content' => 'Some Content',
'summary' => 'Create the category',
],
[
'target' => $subjectTarget,
'content' => 'Some Content [[Category:ApiQueryWatchlistIntegrationTestCategory]]t',
'summary' => 'Create the page and add it to the category',
],
]
);
$title = Title::newFromLinkTarget( $subjectTarget );
$revision = $this->getServiceContainer()
->getRevisionLookup()
->getRevisionByTitle( $title );
$comment = $revision->getComment();
$rc = RecentChange::newForCategorization(
$revision->getTimestamp(),
Title::newFromLinkTarget( $categoryTarget ),
$user,
$comment ? $comment->text : '',
$title,
0,
$revision->getId(),
null,
false
);
$rc->save();
$this->watchPages( $user, [ $subjectTarget, $categoryTarget ] );
$result = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'categorize' ] );
$this->assertEquals(
[
[
'type' => 'categorize',
'ns' => $categoryTarget->getNamespace(),
'title' => $this->getPrefixedText( $categoryTarget ),
],
],
$this->getItemsFromApiResponse( $result )
);
}
public function testLimitParam() {
$user = $this->getLoggedInTestUser();
$target1 = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$target2 = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
$target3 = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage2' );
$this->doPageEdits(
$user,
[
[
'target' => $target1,
'content' => 'Some Content',
'summary' => 'Create the page',
],
[
'target' => $target2,
'content' => 'Some Talk Page Content',
'summary' => 'Create Talk page',
],
[
'target' => $target3,
'content' => 'Some Other Content',
'summary' => 'Create the page',
],
]
);
$this->watchPages( $user, [ $target1, $target2, $target3 ] );
$resultWithoutLimit = $this->doListWatchlistRequest( [ 'wlprop' => 'title' ] );
$resultWithLimit = $this->doListWatchlistRequest( [ 'wllimit' => 2, 'wlprop' => 'title' ] );
$this->assertEquals(
[
[
'type' => 'new',
'ns' => $target3->getNamespace(),
'title' => $this->getPrefixedText( $target3 )
],
[
'type' => 'new',
'ns' => $target2->getNamespace(),
'title' => $this->getPrefixedText( $target2 )
],
[
'type' => 'new',
'ns' => $target1->getNamespace(),
'title' => $this->getPrefixedText( $target1 )
],
],
$this->getItemsFromApiResponse( $resultWithoutLimit )
);
$this->assertEquals(
[
[
'type' => 'new',
'ns' => $target3->getNamespace(),
'title' => $this->getPrefixedText( $target3 )
],
[
'type' => 'new',
'ns' => $target2->getNamespace(),
'title' => $this->getPrefixedText( $target2 )
],
],
$this->getItemsFromApiResponse( $resultWithLimit )
);
$this->assertArrayHasKey( 'continue', $resultWithLimit[0] );
$this->assertArrayHasKey( 'wlcontinue', $resultWithLimit[0]['continue'] );
}
public function testAllRevParam() {
$user = $this->getLoggedInTestUser();
$target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdits(
$user,
[
[
'target' => $target,
'content' => 'Some Content',
'summary' => 'Create the page',
],
[
'target' => $target,
'content' => 'Some Other Content',
'summary' => 'Change the content',
],
]
);
$this->watchPages( $user, [ $target ] );
$resultAllRev = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wlallrev' => '', ] );
$resultNoAllRev = $this->doListWatchlistRequest( [ 'wlprop' => 'title' ] );
$this->assertEquals(
[
[
'type' => 'edit',
'ns' => $target->getNamespace(),
'title' => $this->getPrefixedText( $target ),
],
],
$this->getItemsFromApiResponse( $resultNoAllRev )
);
$this->assertEquals(
[
[
'type' => 'edit',
'ns' => $target->getNamespace(),
'title' => $this->getPrefixedText( $target ),
],
[
'type' => 'new',
'ns' => $target->getNamespace(),
'title' => $this->getPrefixedText( $target ),
],
],
$this->getItemsFromApiResponse( $resultAllRev )
);
}
public function testDirParams() {
$user = $this->getLoggedInTestUser();
$subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdits(
$user,
[
[
'target' => $subjectTarget,
'content' => 'Some Content',
'summary' => 'Create the page',
],
[
'target' => $talkTarget,
'content' => 'Some Talk Page Content',
'summary' => 'Create Talk page',
],
]
);
$this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
$resultDirOlder = $this->doListWatchlistRequest( [ 'wldir' => 'older', 'wlprop' => 'title' ] );
$resultDirNewer = $this->doListWatchlistRequest( [ 'wldir' => 'newer', 'wlprop' => 'title' ] );
$this->assertEquals(
[
[
'type' => 'new',
'ns' => $talkTarget->getNamespace(),
'title' => $this->getPrefixedText( $talkTarget )
],
[
'type' => 'new',
'ns' => $subjectTarget->getNamespace(),
'title' => $this->getPrefixedText( $subjectTarget )
],
],
$this->getItemsFromApiResponse( $resultDirOlder )
);
$this->assertEquals(
[
[
'type' => 'new',
'ns' => $subjectTarget->getNamespace(),
'title' => $this->getPrefixedText( $subjectTarget )
],
[
'type' => 'new',
'ns' => $talkTarget->getNamespace(),
'title' => $this->getPrefixedText( $talkTarget )
],
],
$this->getItemsFromApiResponse( $resultDirNewer )
);
}
public function testStartEndParams() {
$user = $this->getLoggedInTestUser();
$target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdit(
$user,
$target,
'Some Content',
'Create the page'
);
$this->watchPages( $user, [ $target ] );
$resultStart = $this->doListWatchlistRequest( [
'wlstart' => '20010115000000',
'wldir' => 'newer',
'wlprop' => 'title',
] );
$resultEnd = $this->doListWatchlistRequest( [
'wlend' => '20010115000000',
'wldir' => 'newer',
'wlprop' => 'title',
] );
$this->assertEquals(
[
[
'type' => 'new',
'ns' => $target->getNamespace(),
'title' => $this->getPrefixedText( $target ),
]
],
$this->getItemsFromApiResponse( $resultStart )
);
$this->assertSame( [], $this->getItemsFromApiResponse( $resultEnd ) );
}
public function testContinueParam() {
$user = $this->getLoggedInTestUser();
$target1 = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$target2 = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
$target3 = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage2' );
$this->doPageEdits(
$user,
[
[
'target' => $target1,
'content' => 'Some Content',
'summary' => 'Create the page',
],
[
'target' => $target2,
'content' => 'Some Talk Page Content',
'summary' => 'Create Talk page',
],
[
'target' => $target3,
'content' => 'Some Other Content',
'summary' => 'Create the page',
],
]
);
$this->watchPages( $user, [ $target1, $target2, $target3 ] );
$firstResult = $this->doListWatchlistRequest( [ 'wllimit' => 2, 'wlprop' => 'title' ] );
$this->assertArrayHasKey( 'continue', $firstResult[0] );
$this->assertArrayHasKey( 'wlcontinue', $firstResult[0]['continue'] );
$continuationParam = $firstResult[0]['continue']['wlcontinue'];
$continuedResult = $this->doListWatchlistRequest(
[ 'wlcontinue' => $continuationParam, 'wlprop' => 'title' ]
);
$this->assertEquals(
[
[
'type' => 'new',
'ns' => $target3->getNamespace(),
'title' => $this->getPrefixedText( $target3 ),
],
[
'type' => 'new',
'ns' => $target2->getNamespace(),
'title' => $this->getPrefixedText( $target2 ),
],
],
$this->getItemsFromApiResponse( $firstResult )
);
$this->assertEquals(
[
[
'type' => 'new',
'ns' => $target1->getNamespace(),
'title' => $this->getPrefixedText( $target1 )
]
],
$this->getItemsFromApiResponse( $continuedResult )
);
}
public function testOwnerAndTokenParams() {
$target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdit(
$this->getLoggedInTestUser(),
$target,
'Some Content',
'Create the page'
);
$userOptionsManager = $this->getServiceContainer()->getUserOptionsManager();
$otherUser = $this->getNonLoggedInTestUser();
$userOptionsManager->setOption( $otherUser, 'watchlisttoken', '1234567890' );
$otherUser->saveSettings();
$this->watchPages( $otherUser, [ $target ] );
$reloadedUser = User::newFromName( $otherUser->getName() );
$option = $userOptionsManager->getOption( $reloadedUser, 'watchlisttoken' );
$this->assertSame( '1234567890', $option );
$result = $this->doListWatchlistRequest( [
'wlowner' => $otherUser->getName(),
'wltoken' => '1234567890',
'wlprop' => 'title',
] );
$this->assertEquals(
[
[
'type' => 'new',
'ns' => $target->getNamespace(),
'title' => $this->getPrefixedText( $target )
]
],
$this->getItemsFromApiResponse( $result )
);
}
public function testOwnerAndTokenParams_wrongToken() {
$userOptionsManager = $this->getServiceContainer()->getUserOptionsManager();
$otherUser = $this->getNonLoggedInTestUser();
$userOptionsManager->setOption( $otherUser, 'watchlisttoken', '1234567890' );
$otherUser->saveSettings();
$this->expectApiErrorCode( 'bad_wltoken' );
$this->doListWatchlistRequest( [
'wlowner' => $otherUser->getName(),
'wltoken' => 'wrong-token',
] );
}
public function testOwnerAndTokenParams_noWatchlistTokenSet() {
$this->expectApiErrorCode( 'bad_wltoken' );
$this->doListWatchlistRequest( [
'wlowner' => $this->getNonLoggedInTestUser()->getName(),
'wltoken' => 'some-token',
] );
}
public function testGeneratorWatchlistPropInfo_returnsWatchedPages() {
$user = $this->getLoggedInTestUser();
$target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdit(
$user,
$target,
'Some Content',
'Create the page'
);
$this->watchPages( $user, [ $target ] );
$result = $this->doGeneratorWatchlistRequest( [ 'prop' => 'info' ] );
$this->assertArrayHasKey( 'query', $result[0] );
$this->assertArrayHasKey( 'pages', $result[0]['query'] );
// $result[0]['query']['pages'] uses page ids as keys. Page ids don't matter here, so drop them
$pages = array_values( $result[0]['query']['pages'] );
$this->assertArraySubsetsEqual(
$pages,
[
[
'ns' => $target->getNamespace(),
'title' => $this->getPrefixedText( $target ),
'new' => true,
]
],
[ 'ns', 'title', 'new' ]
);
}
public function testGeneratorWatchlistPropRevisions_returnsWatchedItemsRevisions() {
$user = $this->getLoggedInTestUser();
$target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
$this->doPageEdits(
$user,
[
[
'target' => $target,
'content' => 'Some Content',
'summary' => 'Create the page',
],
[
'target' => $target,
'content' => 'Some Other Content',
'summary' => 'Change the content',
],
]
);
$this->watchPages( $user, [ $target ] );
$result = $this->doGeneratorWatchlistRequest( [ 'prop' => 'revisions', 'gwlallrev' => '' ] );
$this->assertArrayHasKey( 'query', $result[0] );
$this->assertArrayHasKey( 'pages', $result[0]['query'] );
// $result[0]['query']['pages'] uses page ids as keys. Page ids don't matter here, so drop them
$pages = array_values( $result[0]['query']['pages'] );
$this->assertCount( 1, $pages );
$this->assertSame( 0, $pages[0]['ns'] );
$this->assertEquals( $this->getPrefixedText( $target ), $pages[0]['title'] );
$this->assertArraySubsetsEqual(
$pages[0]['revisions'],
[
[
'comment' => 'Create the page',
'user' => $user->getName(),
'minor' => false,
],
[
'comment' => 'Change the content',
'user' => $user->getName(),
'minor' => false,
],
],
[ 'comment', 'user', 'minor' ]
);
}
}