3 use MediaWiki\MediaWikiServices
;
4 use MediaWiki\Revision\RevisionRecord
;
7 * Base class for tests of PageArchive against different database schemas.
9 abstract class PageArchiveTestBase
extends MediaWikiTestCase
{
17 * @var PageArchive $archivedPage
19 protected $archivedPage;
22 * A logged out user who edited the page before it was archived.
23 * @var string $ipEditor
28 * Revision of the first (initial) edit
34 * Revision of the IP edit (the second edit)
39 function __construct( $name = null, array $data = [], $dataName = '' ) {
40 parent
::__construct( $name, $data, $dataName );
42 $this->tablesUsed
= array_merge(
47 'revision_comment_temp',
59 protected function addCoreDBData() {
60 // Blank out to avoid failures when schema overrides imposed by subclasses
61 // affect revision storage.
67 abstract protected function getMcrMigrationStage();
72 abstract protected function getMcrTablesToReset();
77 protected function getContentHandlerUseDB() {
81 protected function setUp() {
84 $this->tablesUsed +
= $this->getMcrTablesToReset();
86 $this->setMwGlobals( [
87 'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW
,
88 'wgContentHandlerUseDB' => $this->getContentHandlerUseDB(),
89 'wgMultiContentRevisionSchemaMigrationStage' => $this->getMcrMigrationStage(),
92 // First create our dummy page
93 $page = Title
::newFromText( 'PageArchiveTest_thePage' );
94 $page = new WikiPage( $page );
95 $content = ContentHandler
::makeContent(
98 CONTENT_MODEL_WIKITEXT
101 $user = $this->getTestUser()->getUser();
102 $page->doEditContent( $content, 'testing', EDIT_NEW
, false, $user );
104 $this->pageId
= $page->getId();
105 $this->firstRev
= $page->getRevision()->getRevisionRecord();
107 // Insert IP revision
108 $this->ipEditor
= '2001:db8::1';
110 $revisionStore = MediaWikiServices
::getInstance()->getRevisionStore();
112 $ipTimestamp = wfTimestamp(
114 wfTimestamp( TS_UNIX
, $this->firstRev
->getTimestamp() ) +
1
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,
125 $dbw = wfGetDB( DB_MASTER
);
126 $this->ipRev
= $revisionStore->insertRevisionOn( $rev, $dbw );
129 $page->doDeleteArticleReal( 'Just a test deletion' );
131 $this->archivedPage
= new PageArchive( $page->getTitle() );
135 * @covers PageArchive::undelete
136 * @covers PageArchive::undeleteRevisions
138 public function testUndeleteRevisions() {
139 // TODO: MCR: Test undeletion with multiple slots. Check that slots remain untouched.
141 // First make sure old revisions are archived
142 $dbr = wfGetDB( DB_REPLICA
);
143 $arQuery = Revision
::getArchiveQueryInfo();
144 $row = $dbr->selectRow(
147 [ 'ar_rev_id' => $this->ipRev
->getId() ],
152 $this->assertEquals( $this->ipEditor
, $row->ar_user_text
);
154 // Should not be in revision
155 $row = $dbr->selectRow( 'revision', '1', [ 'rev_id' => $this->ipRev
->getId() ] );
156 $this->assertFalse( $row );
158 // Should not be in ip_changes
159 $row = $dbr->selectRow( 'ip_changes', '1', [ 'ipc_rev_id' => $this->ipRev
->getId() ] );
160 $this->assertFalse( $row );
163 $this->archivedPage
->undelete( [] );
165 // Should be back in revision
166 $revQuery = Revision
::getQueryInfo();
167 $row = $dbr->selectRow(
170 [ 'rev_id' => $this->ipRev
->getId() ],
175 $this->assertNotFalse( $row, 'row exists in revision table' );
176 $this->assertEquals( $this->ipEditor
, $row->rev_user_text
);
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
);
184 abstract protected function getExpectedArchiveRows();
187 * @covers PageArchive::listRevisions
189 public function testListRevisions() {
190 $revisions = $this->archivedPage
->listRevisions();
191 $this->assertEquals( 2, $revisions->numRows() );
193 // Get the rows as arrays
194 $row0 = (array)$revisions->current();
195 $row1 = (array)$revisions->next();
197 $expectedRows = $this->getExpectedArchiveRows();
210 * @covers PageArchive::listPagesBySearch
212 public function testListPagesBySearch() {
213 $pages = PageArchive
::listPagesBySearch( 'PageArchiveTest_thePage' );
214 $this->assertSame( 1, $pages->numRows() );
216 $page = (array)$pages->current();
220 'ar_namespace' => '0',
221 'ar_title' => 'PageArchiveTest_thePage',
229 * @covers PageArchive::listPagesBySearch
231 public function testListPagesByPrefix() {
232 $pages = PageArchive
::listPagesByPrefix( 'PageArchiveTest' );
233 $this->assertSame( 1, $pages->numRows() );
235 $page = (array)$pages->current();
239 'ar_namespace' => '0',
240 'ar_title' => 'PageArchiveTest_thePage',
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' ] ];
255 * @covers PageArchive::getLastRevisionId
257 public function testGetLastRevisionId() {
258 $id = $this->archivedPage
->getLastRevisionId();
259 $this->assertSame( $this->ipRev
->getId(), $id );
263 * @covers PageArchive::isDeleted
265 public function testIsDeleted() {
266 $this->assertTrue( $this->archivedPage
->isDeleted() );
270 * @covers PageArchive::getRevision
272 public function testGetRevision() {
273 $rev = $this->archivedPage
->getRevision( $this->ipRev
->getTimestamp() );
274 $this->assertNotNull( $rev );
275 $this->assertSame( $this->pageId
, $rev->getPage() );
277 $rev = $this->archivedPage
->getRevision( '22991212115555' );
278 $this->assertNull( $rev );
282 * @covers PageArchive::getRevision
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() );
290 $rev = $this->archivedPage
->getArchivedRevision( 632546 );
291 $this->assertNull( $rev );
295 * @covers PageArchive::getPreviousRevision
297 public function testGetPreviousRevision() {
298 $rev = $this->archivedPage
->getPreviousRevision( $this->ipRev
->getTimestamp() );
299 $this->assertNotNull( $rev );
300 $this->assertSame( $this->firstRev
->getId(), $rev->getId() );
302 $rev = $this->archivedPage
->getPreviousRevision( $this->firstRev
->getTimestamp() );
303 $this->assertNull( $rev );
305 // Re-create our dummy page
306 $title = Title
::newFromText( 'PageArchiveTest_thePage' );
307 $page = new WikiPage( $title );
308 $content = ContentHandler
::makeContent(
311 CONTENT_MODEL_WIKITEXT
314 $user = $this->getTestUser()->getUser();
315 $status = $page->doEditContent( $content, 'testing', EDIT_NEW
, false, $user );
317 /** @var Revision $newRev */
318 $newRev = $status->value
['revision'];
320 // force the revision timestamp
321 $newTimestamp = wfTimestamp(
323 wfTimestamp( TS_UNIX
, $this->ipRev
->getTimestamp() ) +
1
328 [ 'rev_timestamp' => $this->db
->timestamp( $newTimestamp ) ],
329 [ 'rev_id' => $newRev->getId() ]
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() );
337 // check that we do get the existing revision when appropriate.
338 $afterNewTimestamp = wfTimestamp(
340 wfTimestamp( TS_UNIX
, $newTimestamp ) +
1
343 $rev = $this->archivedPage
->getPreviousRevision( $afterNewTimestamp );
344 $this->assertNotNull( $rev );
345 $this->assertSame( $newRev->getId(), $rev->getId() );