Merge "Drop cache interwiki"
[mediawiki.git] / tests / phpunit / includes / specials / DeletedContribsPagerTest.php
blob1f570780039afa09119c84232953e530bb3f6783
1 <?php
3 use MediaWiki\Cache\LinkBatchFactory;
4 use MediaWiki\CommentFormatter\CommentFormatter;
5 use MediaWiki\Context\RequestContext;
6 use MediaWiki\HookContainer\HookContainer;
7 use MediaWiki\Linker\LinkRenderer;
8 use MediaWiki\Pager\DeletedContribsPager;
9 use MediaWiki\Revision\RevisionRecord;
10 use MediaWiki\Revision\RevisionStore;
11 use MediaWiki\Title\NamespaceInfo;
12 use MediaWiki\Title\Title;
13 use MediaWiki\User\User;
14 use MediaWiki\User\UserFactory;
15 use MediaWiki\User\UserIdentityValue;
16 use Wikimedia\Rdbms\IConnectionProvider;
17 use Wikimedia\TestingAccessWrapper;
19 /**
20 * @group Database
21 * @covers \MediaWiki\Pager\DeletedContribsPager
23 class DeletedContribsPagerTest extends MediaWikiIntegrationTestCase {
24 private static User $user;
26 /** @var DeletedContribsPager */
27 private $pager;
29 /** @var HookContainer */
30 private $hookContainer;
32 /** @var LinkRenderer */
33 private $linkRenderer;
35 /** @var IConnectionProvider */
36 private $dbProvider;
38 /** @var RevisionStore */
39 private $revisionStore;
41 /** @var NamespaceInfo */
42 private $namespaceInfo;
44 /** @var CommentFormatter */
45 private $commentFormatter;
47 /** @var LinkBatchFactory */
48 private $linkBatchFactory;
50 /** @var UserFactory */
51 private $userFactory;
53 protected function setUp(): void {
54 parent::setUp();
56 $services = $this->getServiceContainer();
57 $this->hookContainer = $services->getHookContainer();
58 $this->linkRenderer = $services->getLinkRenderer();
59 $this->dbProvider = $services->getConnectionProvider();
60 $this->revisionStore = $services->getRevisionStore();
61 $this->namespaceInfo = $services->getNamespaceInfo();
62 $this->commentFormatter = $services->getCommentFormatter();
63 $this->linkBatchFactory = $services->getLinkBatchFactory();
64 $this->userFactory = $services->getUserFactory();
65 $this->pager = $this->getDeletedContribsPager();
68 private function getDeletedContribsPager( $target = 'Some test user', $namespace = 0 ) {
69 $target = UserIdentityValue::newAnonymous( $target );
71 return new DeletedContribsPager(
72 $this->hookContainer,
73 $this->linkRenderer,
74 $this->dbProvider,
75 $this->revisionStore,
76 $this->namespaceInfo,
77 $this->commentFormatter,
78 $this->linkBatchFactory,
79 $this->userFactory,
80 RequestContext::getMain(),
81 [ 'namespace' => $namespace ],
82 $target
86 /**
87 * Flow uses DeletedContribsPager::reallyDoQuery hook to provide something other then
88 * stdClass as a row, and then manually formats its own row in ContributionsLineEnding.
89 * Emulate this behaviour and check that it works.
91 public function testDeletedContribProvidedByHook() {
92 $this->setTemporaryHook( 'DeletedContribsPager::reallyDoQuery', static function ( &$data ) {
93 $data = [ [ new class() {
94 public $ar_timestamp = 12345;
95 public $testing = 'TESTING';
96 public $ar_namespace = NS_MAIN;
97 public $ar_title = 'Test';
98 public $ar_rev_id = null;
99 } ] ];
100 } );
101 $this->setTemporaryHook( 'DeletedContributionsLineEnding', function ( $pager, &$ret, $row ) {
102 $this->assertSame( 'TESTING', $row->testing );
103 $ret .= 'FROM_HOOK!';
104 } );
105 $pager = $this->getDeletedContribsPager();
106 $this->assertStringContainsString( 'FROM_HOOK!', $pager->getBody() );
109 public static function provideEmptyResultIntegration() {
110 $cases = [
111 [ 'target' => '', 'namespace' => '' ],
112 [ 'target' => '127.0.0.1', 'namespace' => '' ],
113 [ 'target' => 'UserWithNoEdits', 'namespace' => 1 ],
115 foreach ( $cases as $case ) {
116 yield [ $case ];
121 * Confirm that the query is valid for various filter options.
123 * @dataProvider provideEmptyResultIntegration
125 public function testEmptyResultIntegration( $options ) {
126 $pager = $this->getDeletedContribsPager(
127 $options['target'],
128 $options['namespace'],
130 $this->assertIsString( $pager->getBody() );
131 $this->assertSame( 0, $pager->getNumRows() );
134 public function testPopulatedIntegrationNoPermissions() {
135 $pager = $this->getDeletedContribsPager( self::$user->getName() );
137 $this->assertIsString( $pager->getBody() );
138 $this->assertSame( 1, $pager->getNumRows() );
141 public function testPopulatedIntegrationWithPermissions() {
142 $this->setGroupPermissions( [ '*' => [
143 'deletedhistory' => true,
144 'deletedtext' => true,
145 'undelete' => true,
146 ] ] );
148 $pager = $this->getDeletedContribsPager( self::$user->getName() );
149 $this->assertIsString( $pager->getBody() );
150 $this->assertSame( 2, $pager->getNumRows() );
151 $this->assertStringContainsString( '>+9<', $pager->getBody() );
154 public function testParentRevisionSizePreloading() {
155 $this->setGroupPermissions( [ '*' => [
156 'deletedhistory' => true,
157 'deletedtext' => true,
158 'undelete' => true,
159 ] ] );
161 $pager = $this->getDeletedContribsPager( self::$user->getName() );
162 // Make sure the query leaves (at least) one row unselected
163 // so that we can test loading from parent revision ids
164 TestingAccessWrapper::newFromObject( $pager )->deletedOnly = true;
165 $this->assertIsString( $pager->getBody() );
166 $this->assertSame( 1, $pager->getNumRows() );
167 $this->assertStringContainsString( '>+9<', $pager->getBody() );
170 public function addDBDataOnce() {
171 self::$user = $this->getTestUser()->getUser();
172 $title = Title::makeTitle( NS_MAIN, 'DeletedContribsPagerTest' );
174 // Make two edits (one will be revdel'd)
175 $this->editPage( $title, 'Test', '', NS_MAIN, self::$user );
176 $status = $this->editPage( $title, 'Test content.', '', NS_MAIN, self::$user );
178 // Delete the page where the edits were made
179 $page = $this->getServiceContainer()->getWikiPageFactory()->newFromTitle( $title );
180 $this->deletePage( $page );
182 // Suppress the second edit
183 $this->getDb()->newUpdateQueryBuilder()
184 ->update( 'archive' )
185 ->set( [
186 'ar_deleted' => RevisionRecord::DELETED_USER | RevisionRecord::DELETED_TEXT,
187 // This is to ensure the minor edits path doesn't encounter an error
188 'ar_minor_edit' => 1,
190 ->where( [
191 'ar_rev_id' => $status->getNewRevision()->getId()
193 ->execute();