3 namespace MediaWiki\Tests\Maintenance
;
5 use MediaWiki\Permissions\Authority
;
6 use MediaWiki\Revision\SlotRecord
;
7 use MediaWiki\Title\Title
;
9 use Wikimedia\Rdbms\IDBAccessObject
;
12 * @covers \RollbackEdits
16 class RollbackEditsTest
extends MaintenanceBaseTestCase
{
18 protected function getMaintenanceClass() {
19 return RollbackEdits
::class;
22 public function testExecuteForInvalidUserOption() {
23 $this->maintenance
->setOption( 'user', 'Template:Testing#test' );
24 $this->expectOutputRegex( '/Invalid username/' );
25 $this->expectCallToFatalError();
26 $this->maintenance
->execute();
29 public function testExecuteWhenUserHasNoPagesToRollback() {
30 $this->maintenance
->setOption( 'user', $this->getTestUser()->getUserIdentity()->getName() );
31 $this->maintenance
->execute();
32 $this->expectOutputRegex( "/No suitable titles to be rolled back./" );
35 public function testExecuteWhenAllTitlesInvalid() {
36 $this->maintenance
->setOption( 'titles', '::|~~~~' );
37 $this->maintenance
->setOption( 'user', $this->getTestUser()->getUserIdentity()->getName() );
38 $this->maintenance
->execute();
39 $this->expectOutputRegex( "/No suitable titles to be rolled back./" );
42 public function testExecuteForAllNonExistingTitles() {
43 $this->maintenance
->setOption( 'titles', 'Non-existing-test-page' );
44 $this->maintenance
->setOption( 'user', $this->getTestUser()->getUserIdentity()->getName() );
45 $this->maintenance
->execute();
46 $this->expectOutputRegex( "/Processing Non-existing-test-page...Failed!/" );
49 public function testExecuteForUnregisteredUsername() {
50 $this->maintenance
->setOption( 'titles', 'Non-existing-test-page' );
51 $this->maintenance
->setOption( 'user', 'NonExistingTestUser' );
52 $this->expectOutputRegex( '/Unknown user/' );
53 $this->expectCallToFatalError();
54 $this->maintenance
->execute();
61 private function getExistingTestPages( int $count ): array {
63 for ( $i = 0; $i < $count; $i++
) {
64 $returnArray[] = $this->getExistingTestPage()->getTitle();
70 * @param Title[] $titlesToBeRolledBack
71 * @param Authority $authority
72 * @param array $options
75 private function commonExecuteForSuccess( array $titlesToBeRolledBack, Authority
$authority, array $options ) {
76 $expectedOutputRegex = '/';
77 foreach ( $titlesToBeRolledBack as $title ) {
78 $this->editPage( $title, 'testing-12345', '', NS_MAIN
, $authority );
79 $expectedOutputRegex .= 'Processing ' . preg_quote( $title->getPrefixedText() ) . "\.\.\.Done!\n";
81 $this->maintenance
->setOption( 'user', $authority->getUser()->getName() );
82 foreach ( $options as $name => $value ) {
83 $this->maintenance
->setOption( $name, $value );
85 $this->maintenance
->execute();
86 $this->expectOutputRegex( $expectedOutputRegex . '/' );
88 foreach ( $titlesToBeRolledBack as $title ) {
89 // Assert that the content of the first revision and the latest revision are the same after the rollback.
90 $latestRevision = $this->getServiceContainer()->getRevisionLookup()
91 ->getRevisionById( $title->getLatestRevID( IDBAccessObject
::READ_LATEST
) );
92 $firstRevision = $this->getServiceContainer()->getRevisionLookup()
93 ->getFirstRevision( $title );
95 $firstRevision->getContent( SlotRecord
::MAIN
)->getWikitextForTransclusion(),
96 $latestRevision->getContent( SlotRecord
::MAIN
)->getWikitextForTransclusion()
98 // Assert the last revision is marked as a rollback
99 $this->assertContains( 'mw-rollback', $this->getServiceContainer()->getChangeTagsStore()->getTags( $this->getDb(), null, $latestRevision->getId() ) );
103 public function testExecuteForUser() {
104 $testUser = $this->getTestUser()->getAuthority();
105 $titles = $this->getExistingTestPages( 2 );
106 $this->commonExecuteForSuccess( $titles, $testUser, [] );
109 public function testExecuteForUserWithTitlesSet() {
110 $testUser = $this->getTestUser()->getAuthority();
111 $titles = $this->getExistingTestPages( 3 );
112 $titleNotToBeRolledBack = array_pop( $titles );
113 $this->editPage( $titleNotToBeRolledBack, 'testing-12345', '', NS_MAIN
, $testUser );
114 // Limit the rollbacks to only the specified pages.
115 $this->commonExecuteForSuccess(
116 $titles, $testUser, [ 'titles' => $titles[0]->getPrefixedText() . '|' . $titles[1]->getPrefixedText() ]
118 // Assert that the $titleNotToBeRolledBack was not rollbacked.
119 $latestRevision = $this->getServiceContainer()->getRevisionLookup()
120 ->getRevisionById( $titleNotToBeRolledBack->getLatestRevID() );
121 $firstRevision = $this->getServiceContainer()->getRevisionLookup()
122 ->getFirstRevision( $titleNotToBeRolledBack );
123 $this->assertNotSame(
124 $firstRevision->getContent( SlotRecord
::MAIN
)->getWikitextForTransclusion(),
125 $latestRevision->getContent( SlotRecord
::MAIN
)->getWikitextForTransclusion()
129 public function testExecuteForUserWithUncanonicalisedName() {
130 $contLang = $this->getServiceContainer()->getContentLanguage();
131 $testUser = $this->getTestUser()->getAuthority();
132 $titles = $this->getExistingTestPages( 2 );
133 $name = strtr( $contLang->lcfirst( $testUser->getUser()->getName() ), ' ', '_' );
134 $this->commonExecuteForSuccess( $titles, $testUser, [ 'user' => $name ] );