Merge "[MCR] Introduce RevisionRenderer"
[lhc/web/wiklou.git] / tests / phpunit / includes / Storage / PageUpdaterTest.php
1 <?php
2
3 namespace MediaWiki\Tests\Storage;
4
5 use CommentStoreComment;
6 use Content;
7 use MediaWiki\MediaWikiServices;
8 use MediaWiki\Storage\RevisionRecord;
9 use MediaWikiTestCase;
10 use ParserOptions;
11 use RecentChange;
12 use Revision;
13 use TextContent;
14 use Title;
15 use WikiPage;
16
17 /**
18 * @covers \MediaWiki\Storage\PageUpdater
19 * @group Database
20 */
21 class PageUpdaterTest extends MediaWikiTestCase {
22
23 public static function setUpBeforeClass() {
24 parent::setUpBeforeClass();
25
26 // force service reset!
27 MediaWikiServices::getInstance()->resetServiceForTesting( 'RevisionStore' );
28 }
29
30 private function getDummyTitle( $method ) {
31 return Title::newFromText( $method, $this->getDefaultWikitextNS() );
32 }
33
34 /**
35 * @param int $revId
36 *
37 * @return null|RecentChange
38 */
39 private function getRecentChangeFor( $revId ) {
40 $qi = RecentChange::getQueryInfo();
41 $row = $this->db->selectRow(
42 $qi['tables'],
43 $qi['fields'],
44 [ 'rc_this_oldid' => $revId ],
45 __METHOD__,
46 [],
47 $qi['joins']
48 );
49
50 return $row ? RecentChange::newFromRow( $row ) : null;
51 }
52
53 // TODO: test setAjaxEditStash();
54
55 /**
56 * @covers \MediaWiki\Storage\PageUpdater::saveRevision()
57 * @covers \WikiPage::newPageUpdater()
58 */
59 public function testCreatePage() {
60 $user = $this->getTestUser()->getUser();
61
62 $title = $this->getDummyTitle( __METHOD__ );
63 $page = WikiPage::factory( $title );
64 $updater = $page->newPageUpdater( $user );
65
66 $oldStats = $this->db->selectRow( 'site_stats', '*', '1=1' );
67
68 $this->assertFalse( $updater->wasCommitted(), 'wasCommitted' );
69 $this->assertFalse( $updater->getOriginalRevisionId(), 'getOriginalRevisionId' );
70 $this->assertSame( 0, $updater->getUndidRevisionId(), 'getUndidRevisionId' );
71
72 $updater->addTag( 'foo' );
73 $updater->addTags( [ 'bar', 'qux' ] );
74
75 $tags = $updater->getExplicitTags();
76 sort( $tags );
77 $this->assertSame( [ 'bar', 'foo', 'qux' ], $tags, 'getExplicitTags' );
78
79 // TODO: MCR: test additional slots
80 $content = new TextContent( 'Lorem Ipsum' );
81 $updater->setContent( 'main', $content );
82
83 $parent = $updater->grabParentRevision();
84
85 $this->assertNull( $parent, 'getParentRevision' );
86 $this->assertFalse( $updater->wasCommitted(), 'wasCommitted' );
87
88 // TODO: test that hasEditConflict() grabs the parent revision
89 $this->assertFalse( $updater->hasEditConflict( 0 ), 'hasEditConflict' );
90 $this->assertTrue( $updater->hasEditConflict( 1 ), 'hasEditConflict' );
91
92 // TODO: test failure with EDIT_UPDATE
93 // TODO: test EDIT_MINOR, EDIT_BOT, etc
94 $summary = CommentStoreComment::newUnsavedComment( 'Just a test' );
95 $rev = $updater->saveRevision( $summary );
96
97 $this->assertNotNull( $rev );
98 $this->assertSame( 0, $rev->getParentId() );
99 $this->assertSame( $summary->text, $rev->getComment( RevisionRecord::RAW )->text );
100 $this->assertSame( $user->getName(), $rev->getUser( RevisionRecord::RAW )->getName() );
101
102 $this->assertTrue( $updater->wasCommitted(), 'wasCommitted()' );
103 $this->assertTrue( $updater->wasSuccessful(), 'wasSuccessful()' );
104 $this->assertTrue( $updater->getStatus()->isOK(), 'getStatus()->isOK()' );
105 $this->assertTrue( $updater->isNew(), 'isNew()' );
106 $this->assertFalse( $updater->isUnchanged(), 'isUnchanged()' );
107 $this->assertNotNull( $updater->getNewRevision(), 'getNewRevision()' );
108 $this->assertInstanceOf( Revision::class, $updater->getStatus()->value['revision'] );
109
110 $rev = $updater->getNewRevision();
111 $revContent = $rev->getContent( 'main' );
112 $this->assertSame( 'Lorem Ipsum', $revContent->serialize(), 'revision content' );
113
114 // were the WikiPage and Title objects updated?
115 $this->assertTrue( $page->exists(), 'WikiPage::exists()' );
116 $this->assertTrue( $title->exists(), 'Title::exists()' );
117 $this->assertSame( $rev->getId(), $page->getLatest(), 'WikiPage::getRevision()' );
118 $this->assertNotNull( $page->getRevision(), 'WikiPage::getRevision()' );
119
120 // re-load
121 $page2 = WikiPage::factory( $title );
122 $this->assertTrue( $page2->exists(), 'WikiPage::exists()' );
123 $this->assertSame( $rev->getId(), $page2->getLatest(), 'WikiPage::getRevision()' );
124 $this->assertNotNull( $page2->getRevision(), 'WikiPage::getRevision()' );
125
126 // Check RC entry
127 $rc = $this->getRecentChangeFor( $rev->getId() );
128 $this->assertNotNull( $rc, 'RecentChange' );
129
130 // check site stats - this asserts that derived data updates where run.
131 $stats = $this->db->selectRow( 'site_stats', '*', '1=1' );
132 $this->assertSame( $oldStats->ss_total_pages + 1, (int)$stats->ss_total_pages );
133 $this->assertSame( $oldStats->ss_total_edits + 1, (int)$stats->ss_total_edits );
134
135 // re-edit with same content - should be a "null-edit"
136 $updater = $page->newPageUpdater( $user );
137 $updater->setContent( 'main', $content );
138
139 $summary = CommentStoreComment::newUnsavedComment( 'to to re-edit' );
140 $rev = $updater->saveRevision( $summary );
141 $status = $updater->getStatus();
142
143 $this->assertNull( $rev, 'getNewRevision()' );
144 $this->assertNull( $updater->getNewRevision(), 'getNewRevision()' );
145 $this->assertTrue( $updater->isUnchanged(), 'isUnchanged' );
146 $this->assertTrue( $updater->wasSuccessful(), 'wasSuccessful()' );
147 $this->assertTrue( $status->isOK(), 'getStatus()->isOK()' );
148 $this->assertTrue( $status->hasMessage( 'edit-no-change' ), 'edit-no-change' );
149 }
150
151 /**
152 * @covers \MediaWiki\Storage\PageUpdater::saveRevision()
153 * @covers \WikiPage::newPageUpdater()
154 */
155 public function testUpdatePage() {
156 $user = $this->getTestUser()->getUser();
157
158 $title = $this->getDummyTitle( __METHOD__ );
159 $this->insertPage( $title );
160
161 $page = WikiPage::factory( $title );
162 $parentId = $page->getLatest();
163
164 $updater = $page->newPageUpdater( $user );
165
166 $oldStats = $this->db->selectRow( 'site_stats', '*', '1=1' );
167
168 $updater->setOriginalRevisionId( 7 );
169 $this->assertSame( 7, $updater->getOriginalRevisionId(), 'getOriginalRevisionId' );
170
171 $this->assertFalse( $updater->hasEditConflict( $parentId ), 'hasEditConflict' );
172 $this->assertTrue( $updater->hasEditConflict( $parentId - 1 ), 'hasEditConflict' );
173 $this->assertTrue( $updater->hasEditConflict( 0 ), 'hasEditConflict' );
174
175 // TODO: MCR: test additional slots
176 $updater->setContent( 'main', new TextContent( 'Lorem Ipsum' ) );
177
178 // TODO: test all flags for saveRevision()!
179 $summary = CommentStoreComment::newUnsavedComment( 'Just a test' );
180 $rev = $updater->saveRevision( $summary );
181
182 $this->assertNotNull( $rev );
183 $this->assertSame( $parentId, $rev->getParentId() );
184 $this->assertSame( $summary->text, $rev->getComment( RevisionRecord::RAW )->text );
185 $this->assertSame( $user->getName(), $rev->getUser( RevisionRecord::RAW )->getName() );
186
187 $this->assertTrue( $updater->wasCommitted(), 'wasCommitted()' );
188 $this->assertTrue( $updater->wasSuccessful(), 'wasSuccessful()' );
189 $this->assertTrue( $updater->getStatus()->isOK(), 'getStatus()->isOK()' );
190 $this->assertFalse( $updater->isNew(), 'isNew()' );
191 $this->assertNotNull( $updater->getNewRevision(), 'getNewRevision()' );
192 $this->assertInstanceOf( Revision::class, $updater->getStatus()->value['revision'] );
193 $this->assertFalse( $updater->isUnchanged(), 'isUnchanged()' );
194
195 // TODO: Test null revision (with different user): new revision!
196
197 $rev = $updater->getNewRevision();
198 $revContent = $rev->getContent( 'main' );
199 $this->assertSame( 'Lorem Ipsum', $revContent->serialize(), 'revision content' );
200
201 // were the WikiPage and Title objects updated?
202 $this->assertTrue( $page->exists(), 'WikiPage::exists()' );
203 $this->assertTrue( $title->exists(), 'Title::exists()' );
204 $this->assertSame( $rev->getId(), $page->getLatest(), 'WikiPage::getRevision()' );
205 $this->assertNotNull( $page->getRevision(), 'WikiPage::getRevision()' );
206
207 // re-load
208 $page2 = WikiPage::factory( $title );
209 $this->assertTrue( $page2->exists(), 'WikiPage::exists()' );
210 $this->assertSame( $rev->getId(), $page2->getLatest(), 'WikiPage::getRevision()' );
211 $this->assertNotNull( $page2->getRevision(), 'WikiPage::getRevision()' );
212
213 // Check RC entry
214 $rc = $this->getRecentChangeFor( $rev->getId() );
215 $this->assertNotNull( $rc, 'RecentChange' );
216
217 // re-edit
218 $updater = $page->newPageUpdater( $user );
219 $updater->setContent( 'main', new TextContent( 'dolor sit amet' ) );
220
221 $summary = CommentStoreComment::newUnsavedComment( 're-edit' );
222 $updater->saveRevision( $summary );
223 $this->assertTrue( $updater->wasSuccessful(), 'wasSuccessful()' );
224 $this->assertTrue( $updater->getStatus()->isOK(), 'getStatus()->isOK()' );
225
226 // check site stats - this asserts that derived data updates where run.
227 $stats = $this->db->selectRow( 'site_stats', '*', '1=1' );
228 $this->assertNotNull( $stats, 'site_stats' );
229 $this->assertSame( $oldStats->ss_total_pages + 0, (int)$stats->ss_total_pages );
230 $this->assertSame( $oldStats->ss_total_edits + 2, (int)$stats->ss_total_edits );
231 }
232
233 /**
234 * Creates a revision in the database.
235 *
236 * @param WikiPage $page
237 * @param $summary
238 * @param null|string|Content $content
239 *
240 * @return RevisionRecord|null
241 */
242 private function createRevision( WikiPage $page, $summary, $content = null ) {
243 $user = $this->getTestUser()->getUser();
244 $comment = CommentStoreComment::newUnsavedComment( $summary );
245
246 if ( !$content instanceof Content ) {
247 $content = new TextContent( $content ?? $summary );
248 }
249
250 $updater = $page->newPageUpdater( $user );
251 $updater->setContent( 'main', $content );
252 $rev = $updater->saveRevision( $comment );
253 return $rev;
254 }
255
256 /**
257 * @covers \MediaWiki\Storage\PageUpdater::grabParentRevision()
258 * @covers \MediaWiki\Storage\PageUpdater::saveRevision()
259 */
260 public function testCompareAndSwapFailure() {
261 $user = $this->getTestUser()->getUser();
262
263 $title = $this->getDummyTitle( __METHOD__ );
264
265 // start editing non-existing page
266 $page = WikiPage::factory( $title );
267 $updater = $page->newPageUpdater( $user );
268 $updater->grabParentRevision();
269
270 // create page concurrently
271 $concurrentPage = WikiPage::factory( $title );
272 $this->createRevision( $concurrentPage, __METHOD__ . '-one' );
273
274 // try creating the page - should trigger CAS failure.
275 $summary = CommentStoreComment::newUnsavedComment( 'create?!' );
276 $updater->setContent( 'main', new TextContent( 'Lorem ipsum' ) );
277 $updater->saveRevision( $summary );
278 $status = $updater->getStatus();
279
280 $this->assertFalse( $updater->wasSuccessful(), 'wasSuccessful()' );
281 $this->assertNull( $updater->getNewRevision(), 'getNewRevision()' );
282 $this->assertFalse( $status->isOK(), 'getStatus()->isOK()' );
283 $this->assertTrue( $status->hasMessage( 'edit-already-exists' ), 'edit-conflict' );
284
285 // start editing existing page
286 $page = WikiPage::factory( $title );
287 $updater = $page->newPageUpdater( $user );
288 $updater->grabParentRevision();
289
290 // update page concurrently
291 $concurrentPage = WikiPage::factory( $title );
292 $this->createRevision( $concurrentPage, __METHOD__ . '-two' );
293
294 // try creating the page - should trigger CAS failure.
295 $summary = CommentStoreComment::newUnsavedComment( 'edit?!' );
296 $updater->setContent( 'main', new TextContent( 'dolor sit amet' ) );
297 $updater->saveRevision( $summary );
298 $status = $updater->getStatus();
299
300 $this->assertFalse( $updater->wasSuccessful(), 'wasSuccessful()' );
301 $this->assertNull( $updater->getNewRevision(), 'getNewRevision()' );
302 $this->assertFalse( $status->isOK(), 'getStatus()->isOK()' );
303 $this->assertTrue( $status->hasMessage( 'edit-conflict' ), 'edit-conflict' );
304 }
305
306 /**
307 * @covers \MediaWiki\Storage\PageUpdater::saveRevision()
308 */
309 public function testFailureOnEditFlags() {
310 $user = $this->getTestUser()->getUser();
311
312 $title = $this->getDummyTitle( __METHOD__ );
313
314 // start editing non-existing page
315 $page = WikiPage::factory( $title );
316 $updater = $page->newPageUpdater( $user );
317
318 // update with EDIT_UPDATE flag should fail
319 $summary = CommentStoreComment::newUnsavedComment( 'udpate?!' );
320 $updater->setContent( 'main', new TextContent( 'Lorem ipsum' ) );
321 $updater->saveRevision( $summary, EDIT_UPDATE );
322 $status = $updater->getStatus();
323
324 $this->assertFalse( $updater->wasSuccessful(), 'wasSuccessful()' );
325 $this->assertNull( $updater->getNewRevision(), 'getNewRevision()' );
326 $this->assertFalse( $status->isOK(), 'getStatus()->isOK()' );
327 $this->assertTrue( $status->hasMessage( 'edit-gone-missing' ), 'edit-gone-missing' );
328
329 // create the page
330 $this->createRevision( $page, __METHOD__ );
331
332 // update with EDIT_NEW flag should fail
333 $summary = CommentStoreComment::newUnsavedComment( 'create?!' );
334 $updater = $page->newPageUpdater( $user );
335 $updater->setContent( 'main', new TextContent( 'dolor sit amet' ) );
336 $updater->saveRevision( $summary, EDIT_NEW );
337 $status = $updater->getStatus();
338
339 $this->assertFalse( $updater->wasSuccessful(), 'wasSuccessful()' );
340 $this->assertNull( $updater->getNewRevision(), 'getNewRevision()' );
341 $this->assertFalse( $status->isOK(), 'getStatus()->isOK()' );
342 $this->assertTrue( $status->hasMessage( 'edit-already-exists' ), 'edit-already-exists' );
343 }
344
345 public function provideSetRcPatrolStatus( $patrolled ) {
346 yield [ RecentChange::PRC_UNPATROLLED ];
347 yield [ RecentChange::PRC_AUTOPATROLLED ];
348 }
349
350 /**
351 * @dataProvider provideSetRcPatrolStatus
352 * @covers \MediaWiki\Storage\PageUpdater::setRcPatrolStatus()
353 */
354 public function testSetRcPatrolStatus( $patrolled ) {
355 $revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
356
357 $user = $this->getTestUser()->getUser();
358
359 $title = $this->getDummyTitle( __METHOD__ );
360
361 $page = WikiPage::factory( $title );
362 $updater = $page->newPageUpdater( $user );
363
364 $summary = CommentStoreComment::newUnsavedComment( 'Lorem ipsum ' . $patrolled );
365 $updater->setContent( 'main', new TextContent( 'Lorem ipsum ' . $patrolled ) );
366 $updater->setRcPatrolStatus( $patrolled );
367 $rev = $updater->saveRevision( $summary );
368
369 $rc = $revisionStore->getRecentChange( $rev );
370 $this->assertEquals( $patrolled, $rc->getAttribute( 'rc_patrolled' ) );
371 }
372
373 /**
374 * @covers \MediaWiki\Storage\PageUpdater::inheritSlot()
375 * @covers \MediaWiki\Storage\PageUpdater::setContent()
376 */
377 public function testInheritSlot() {
378 $user = $this->getTestUser()->getUser();
379 $title = $this->getDummyTitle( __METHOD__ );
380 $page = WikiPage::factory( $title );
381
382 $updater = $page->newPageUpdater( $user );
383 $summary = CommentStoreComment::newUnsavedComment( 'one' );
384 $updater->setContent( 'main', new TextContent( 'Lorem ipsum' ) );
385 $rev1 = $updater->saveRevision( $summary, EDIT_NEW );
386
387 $updater = $page->newPageUpdater( $user );
388 $summary = CommentStoreComment::newUnsavedComment( 'two' );
389 $updater->setContent( 'main', new TextContent( 'Foo Bar' ) );
390 $rev2 = $updater->saveRevision( $summary, EDIT_UPDATE );
391
392 $updater = $page->newPageUpdater( $user );
393 $summary = CommentStoreComment::newUnsavedComment( 'three' );
394 $updater->inheritSlot( $rev1->getSlot( 'main' ) );
395 $rev3 = $updater->saveRevision( $summary, EDIT_UPDATE );
396
397 $this->assertNotSame( $rev1->getId(), $rev3->getId() );
398 $this->assertNotSame( $rev2->getId(), $rev3->getId() );
399
400 $main1 = $rev1->getSlot( 'main' );
401 $main3 = $rev3->getSlot( 'main' );
402
403 $this->assertNotSame( $main1->getRevision(), $main3->getRevision() );
404 $this->assertSame( $main1->getAddress(), $main3->getAddress() );
405 $this->assertTrue( $main1->getContent()->equals( $main3->getContent() ) );
406 }
407
408 // TODO: MCR: test adding multiple slots, inheriting parent slots, and removing slots.
409
410 public function testSetUseAutomaticEditSummaries() {
411 $this->setContentLang( 'qqx' );
412 $user = $this->getTestUser()->getUser();
413
414 $title = $this->getDummyTitle( __METHOD__ );
415 $page = WikiPage::factory( $title );
416
417 $updater = $page->newPageUpdater( $user );
418 $updater->setUseAutomaticEditSummaries( true );
419 $updater->setContent( 'main', new TextContent( 'Lorem Ipsum' ) );
420
421 // empty comment triggers auto-summary
422 $summary = CommentStoreComment::newUnsavedComment( '' );
423 $updater->saveRevision( $summary, EDIT_AUTOSUMMARY );
424
425 $rev = $updater->getNewRevision();
426 $comment = $rev->getComment( RevisionRecord::RAW );
427 $this->assertSame( '(autosumm-new: Lorem Ipsum)', $comment->text, 'comment text' );
428
429 // check that this also works when blanking the page
430 $updater = $page->newPageUpdater( $user );
431 $updater->setUseAutomaticEditSummaries( true );
432 $updater->setContent( 'main', new TextContent( '' ) );
433
434 $summary = CommentStoreComment::newUnsavedComment( '' );
435 $updater->saveRevision( $summary, EDIT_AUTOSUMMARY );
436
437 $rev = $updater->getNewRevision();
438 $comment = $rev->getComment( RevisionRecord::RAW );
439 $this->assertSame( '(autosumm-blank)', $comment->text, 'comment text' );
440
441 // check that we can also disable edit-summaries
442 $title2 = $this->getDummyTitle( __METHOD__ . '/2' );
443 $page2 = WikiPage::factory( $title2 );
444
445 $updater = $page2->newPageUpdater( $user );
446 $updater->setUseAutomaticEditSummaries( false );
447 $updater->setContent( 'main', new TextContent( 'Lorem Ipsum' ) );
448
449 $summary = CommentStoreComment::newUnsavedComment( '' );
450 $updater->saveRevision( $summary, EDIT_AUTOSUMMARY );
451
452 $rev = $updater->getNewRevision();
453 $comment = $rev->getComment( RevisionRecord::RAW );
454 $this->assertSame( '', $comment->text, 'comment text should still be lank' );
455
456 // check that we don't do auto.summaries without the EDIT_AUTOSUMMARY flag
457 $updater = $page2->newPageUpdater( $user );
458 $updater->setUseAutomaticEditSummaries( true );
459 $updater->setContent( 'main', new TextContent( '' ) );
460
461 $summary = CommentStoreComment::newUnsavedComment( '' );
462 $updater->saveRevision( $summary, 0 );
463
464 $rev = $updater->getNewRevision();
465 $comment = $rev->getComment( RevisionRecord::RAW );
466 $this->assertSame( '', $comment->text, 'comment text' );
467 }
468
469 public function provideSetUsePageCreationLog() {
470 yield [ true, [ [ 'create', 'create' ] ] ];
471 yield [ false, [] ];
472 }
473
474 /**
475 * @dataProvider provideSetUsePageCreationLog
476 * @param bool $use
477 */
478 public function testSetUsePageCreationLog( $use, $expected ) {
479 $user = $this->getTestUser()->getUser();
480 $title = $this->getDummyTitle( __METHOD__ . ( $use ? '_logged' : '_unlogged' ) );
481 $page = WikiPage::factory( $title );
482
483 $updater = $page->newPageUpdater( $user );
484 $updater->setUsePageCreationLog( $use );
485 $summary = CommentStoreComment::newUnsavedComment( 'cmt' );
486 $updater->setContent( 'main', new TextContent( 'Lorem Ipsum' ) );
487 $updater->saveRevision( $summary, EDIT_NEW );
488
489 $rev = $updater->getNewRevision();
490 $this->assertSelect(
491 'logging',
492 [ 'log_type', 'log_action' ],
493 [ 'log_page' => $rev->getPageId() ],
494 $expected
495 );
496 }
497
498 public function provideMagicWords() {
499 yield 'PAGEID' => [
500 'Test {{PAGEID}} Test',
501 function ( RevisionRecord $rev ) {
502 return $rev->getPageId();
503 }
504 ];
505
506 yield 'REVISIONID' => [
507 'Test {{REVISIONID}} Test',
508 function ( RevisionRecord $rev ) {
509 return $rev->getId();
510 }
511 ];
512
513 yield 'REVISIONUSER' => [
514 'Test {{REVISIONUSER}} Test',
515 function ( RevisionRecord $rev ) {
516 return $rev->getUser()->getName();
517 }
518 ];
519
520 yield 'REVISIONTIMESTAMP' => [
521 'Test {{REVISIONTIMESTAMP}} Test',
522 function ( RevisionRecord $rev ) {
523 return $rev->getTimestamp();
524 }
525 ];
526 }
527
528 /**
529 * @covers \MediaWiki\Storage\PageUpdater::saveRevision()
530 *
531 * Integration test for PageUpdater, DerivedPageDataUpdater, RevisionRenderer
532 * and RenderedRevision, that ensures that magic words depending on revision meta-data
533 * are handled correctly. Note that each magic word needs to be tested separately,
534 * to assert correct behavior for each "vary" flag in the ParserOutput.
535 *
536 * @dataProvider provideMagicWords
537 */
538 public function testMagicWords( $wikitext, $callback ) {
539 $user = $this->getTestUser()->getUser();
540
541 $title = $this->getDummyTitle( __METHOD__ . '-' . $this->getName() );
542 $page = WikiPage::factory( $title );
543 $updater = $page->newPageUpdater( $user );
544
545 $updater->setContent( 'main', new \WikitextContent( $wikitext ) );
546
547 $summary = CommentStoreComment::newUnsavedComment( 'Just a test' );
548 $rev = $updater->saveRevision( $summary, EDIT_NEW );
549
550 if ( !$rev ) {
551 $this->fail( $updater->getStatus()->getWikiText() );
552 }
553
554 $expected = strval( $callback( $rev ) );
555
556 $cache = MediaWikiServices::getInstance()->getParserCache();
557 $output = $cache->get(
558 $page,
559 ParserOptions::newCanonical(
560 'canonical'
561 )
562 );
563
564 $this->assertNotNull( $output, 'ParserCache::get' );
565
566 $this->assertContains( $expected, $output->getText() );
567 }
568
569 }