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