Fix use of GenderCache in ApiPageSet::processTitlesArray
[lhc/web/wiklou.git] / tests / phpunit / includes / page / PageArchiveTestBase.php
1 <?php
2
3 use MediaWiki\MediaWikiServices;
4 use MediaWiki\Revision\RevisionRecord;
5
6 /**
7 * Base class for tests of PageArchive against different database schemas.
8 */
9 abstract class PageArchiveTestBase extends MediaWikiTestCase {
10
11 /**
12 * @var int
13 */
14 protected $pageId;
15
16 /**
17 * @var PageArchive $archivedPage
18 */
19 protected $archivedPage;
20
21 /**
22 * A logged out user who edited the page before it was archived.
23 * @var string $ipEditor
24 */
25 protected $ipEditor;
26
27 /**
28 * Revision of the first (initial) edit
29 * @var RevisionRecord
30 */
31 protected $firstRev;
32
33 /**
34 * Revision of the IP edit (the second edit)
35 * @var RevisionRecord
36 */
37 protected $ipRev;
38
39 function __construct( $name = null, array $data = [], $dataName = '' ) {
40 parent::__construct( $name, $data, $dataName );
41
42 $this->tablesUsed = array_merge(
43 $this->tablesUsed,
44 [
45 'page',
46 'revision',
47 'revision_comment_temp',
48 'ip_changes',
49 'text',
50 'archive',
51 'recentchanges',
52 'logging',
53 'page_props',
54 'comment',
55 ]
56 );
57 }
58
59 protected function addCoreDBData() {
60 // Blank out to avoid failures when schema overrides imposed by subclasses
61 // affect revision storage.
62 }
63
64 /**
65 * @return int
66 */
67 abstract protected function getMcrMigrationStage();
68
69 /**
70 * @return string[]
71 */
72 abstract protected function getMcrTablesToReset();
73
74 /**
75 * @return bool
76 */
77 protected function getContentHandlerUseDB() {
78 return true;
79 }
80
81 protected function setUp() {
82 parent::setUp();
83
84 $this->tablesUsed += $this->getMcrTablesToReset();
85
86 $this->setMwGlobals( [
87 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
88 'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(),
89 'wgMultiContentRevisionSchemaMigrationStage' => $this->getMcrMigrationStage(),
90 ] );
91
92 // First create our dummy page
93 $page = Title::newFromText( 'PageArchiveTest_thePage' );
94 $page = new WikiPage( $page );
95 $content = ContentHandler::makeContent(
96 'testing',
97 $page->getTitle(),
98 CONTENT_MODEL_WIKITEXT
99 );
100
101 $user = $this->getTestUser()->getUser();
102 $page->doEditContent( $content, 'testing', EDIT_NEW, false, $user );
103
104 $this->pageId = $page->getId();
105 $this->firstRev = $page->getRevision()->getRevisionRecord();
106
107 // Insert IP revision
108 $this->ipEditor = '2001:db8::1';
109
110 $revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
111
112 $ipTimestamp = wfTimestamp(
113 TS_MW,
114 wfTimestamp( TS_UNIX, $this->firstRev->getTimestamp() ) + 1
115 );
116
117 $rev = $revisionStore->newMutableRevisionFromArray( [
118 'text' => 'Lorem Ipsum',
119 'comment' => 'just a test',
120 'page' => $page->getId(),
121 'user_text' => $this->ipEditor,
122 'timestamp' => $ipTimestamp,
123 ] );
124
125 $dbw = wfGetDB( DB_MASTER );
126 $this->ipRev = $revisionStore->insertRevisionOn( $rev, $dbw );
127
128 // Delete the page
129 $page->doDeleteArticleReal( 'Just a test deletion' );
130
131 $this->archivedPage = new PageArchive( $page->getTitle() );
132 }
133
134 /**
135 * @covers PageArchive::undelete
136 * @covers PageArchive::undeleteRevisions
137 */
138 public function testUndeleteRevisions() {
139 // TODO: MCR: Test undeletion with multiple slots. Check that slots remain untouched.
140
141 // First make sure old revisions are archived
142 $dbr = wfGetDB( DB_REPLICA );
143 $arQuery = Revision::getArchiveQueryInfo();
144 $row = $dbr->selectRow(
145 $arQuery['tables'],
146 $arQuery['fields'],
147 [ 'ar_rev_id' => $this->ipRev->getId() ],
148 __METHOD__,
149 [],
150 $arQuery['joins']
151 );
152 $this->assertEquals( $this->ipEditor, $row->ar_user_text );
153
154 // Should not be in revision
155 $row = $dbr->selectRow( 'revision', '1', [ 'rev_id' => $this->ipRev->getId() ] );
156 $this->assertFalse( $row );
157
158 // Should not be in ip_changes
159 $row = $dbr->selectRow( 'ip_changes', '1', [ 'ipc_rev_id' => $this->ipRev->getId() ] );
160 $this->assertFalse( $row );
161
162 // Restore the page
163 $this->archivedPage->undelete( [] );
164
165 // Should be back in revision
166 $revQuery = Revision::getQueryInfo();
167 $row = $dbr->selectRow(
168 $revQuery['tables'],
169 $revQuery['fields'],
170 [ 'rev_id' => $this->ipRev->getId() ],
171 __METHOD__,
172 [],
173 $revQuery['joins']
174 );
175 $this->assertNotFalse( $row, 'row exists in revision table' );
176 $this->assertEquals( $this->ipEditor, $row->rev_user_text );
177
178 // Should be back in ip_changes
179 $row = $dbr->selectRow( 'ip_changes', [ 'ipc_hex' ], [ 'ipc_rev_id' => $this->ipRev->getId() ] );
180 $this->assertNotFalse( $row, 'row exists in ip_changes table' );
181 $this->assertEquals( IP::toHex( $this->ipEditor ), $row->ipc_hex );
182 }
183
184 abstract protected function getExpectedArchiveRows();
185
186 /**
187 * @covers PageArchive::listRevisions
188 */
189 public function testListRevisions() {
190 $revisions = $this->archivedPage->listRevisions();
191 $this->assertEquals( 2, $revisions->numRows() );
192
193 // Get the rows as arrays
194 $row0 = (array)$revisions->current();
195 $row1 = (array)$revisions->next();
196
197 $expectedRows = $this->getExpectedArchiveRows();
198
199 $this->assertEquals(
200 $expectedRows[0],
201 $row0
202 );
203 $this->assertEquals(
204 $expectedRows[1],
205 $row1
206 );
207 }
208
209 /**
210 * @covers PageArchive::listPagesBySearch
211 */
212 public function testListPagesBySearch() {
213 $pages = PageArchive::listPagesBySearch( 'PageArchiveTest_thePage' );
214 $this->assertSame( 1, $pages->numRows() );
215
216 $page = (array)$pages->current();
217
218 $this->assertSame(
219 [
220 'ar_namespace' => '0',
221 'ar_title' => 'PageArchiveTest_thePage',
222 'count' => '2',
223 ],
224 $page
225 );
226 }
227
228 /**
229 * @covers PageArchive::listPagesBySearch
230 */
231 public function testListPagesByPrefix() {
232 $pages = PageArchive::listPagesByPrefix( 'PageArchiveTest' );
233 $this->assertSame( 1, $pages->numRows() );
234
235 $page = (array)$pages->current();
236
237 $this->assertSame(
238 [
239 'ar_namespace' => '0',
240 'ar_title' => 'PageArchiveTest_thePage',
241 'count' => '2',
242 ],
243 $page
244 );
245 }
246
247 public function provideGetTextFromRowThrowsInvalidArgumentException() {
248 yield 'missing ar_text_id field' => [ [] ];
249 yield 'ar_text_id is null' => [ [ 'ar_text_id' => null ] ];
250 yield 'ar_text_id is zero' => [ [ 'ar_text_id' => 0 ] ];
251 yield 'ar_text_id is "0"' => [ [ 'ar_text_id' => '0' ] ];
252 }
253
254 /**
255 * @covers PageArchive::getLastRevisionId
256 */
257 public function testGetLastRevisionId() {
258 $id = $this->archivedPage->getLastRevisionId();
259 $this->assertSame( $this->ipRev->getId(), $id );
260 }
261
262 /**
263 * @covers PageArchive::isDeleted
264 */
265 public function testIsDeleted() {
266 $this->assertTrue( $this->archivedPage->isDeleted() );
267 }
268
269 /**
270 * @covers PageArchive::getRevision
271 */
272 public function testGetRevision() {
273 $rev = $this->archivedPage->getRevision( $this->ipRev->getTimestamp() );
274 $this->assertNotNull( $rev );
275 $this->assertSame( $this->pageId, $rev->getPage() );
276
277 $rev = $this->archivedPage->getRevision( '22991212115555' );
278 $this->assertNull( $rev );
279 }
280
281 /**
282 * @covers PageArchive::getRevision
283 */
284 public function testGetArchivedRevision() {
285 $rev = $this->archivedPage->getArchivedRevision( $this->ipRev->getId() );
286 $this->assertNotNull( $rev );
287 $this->assertSame( $this->ipRev->getTimestamp(), $rev->getTimestamp() );
288 $this->assertSame( $this->pageId, $rev->getPage() );
289
290 $rev = $this->archivedPage->getArchivedRevision( 632546 );
291 $this->assertNull( $rev );
292 }
293
294 /**
295 * @covers PageArchive::getPreviousRevision
296 */
297 public function testGetPreviousRevision() {
298 $rev = $this->archivedPage->getPreviousRevision( $this->ipRev->getTimestamp() );
299 $this->assertNotNull( $rev );
300 $this->assertSame( $this->firstRev->getId(), $rev->getId() );
301
302 $rev = $this->archivedPage->getPreviousRevision( $this->firstRev->getTimestamp() );
303 $this->assertNull( $rev );
304
305 // Re-create our dummy page
306 $title = Title::newFromText( 'PageArchiveTest_thePage' );
307 $page = new WikiPage( $title );
308 $content = ContentHandler::makeContent(
309 'testing again',
310 $page->getTitle(),
311 CONTENT_MODEL_WIKITEXT
312 );
313
314 $user = $this->getTestUser()->getUser();
315 $status = $page->doEditContent( $content, 'testing', EDIT_NEW, false, $user );
316
317 /** @var Revision $newRev */
318 $newRev = $status->value['revision'];
319
320 // force the revision timestamp
321 $newTimestamp = wfTimestamp(
322 TS_MW,
323 wfTimestamp( TS_UNIX, $this->ipRev->getTimestamp() ) + 1
324 );
325
326 $this->db->update(
327 'revision',
328 [ 'rev_timestamp' => $this->db->timestamp( $newTimestamp ) ],
329 [ 'rev_id' => $newRev->getId() ]
330 );
331
332 // check that we don't get the existing revision too soon.
333 $rev = $this->archivedPage->getPreviousRevision( $newTimestamp );
334 $this->assertNotNull( $rev );
335 $this->assertSame( $this->ipRev->getId(), $rev->getId() );
336
337 // check that we do get the existing revision when appropriate.
338 $afterNewTimestamp = wfTimestamp(
339 TS_MW,
340 wfTimestamp( TS_UNIX, $newTimestamp ) + 1
341 );
342
343 $rev = $this->archivedPage->getPreviousRevision( $afterNewTimestamp );
344 $this->assertNotNull( $rev );
345 $this->assertSame( $newRev->getId(), $rev->getId() );
346 }
347
348 }