File: RenameUsersMatchingPatternTest.php

package info (click to toggle)
mediawiki 1%3A1.43.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 417,464 kB
  • sloc: php: 1,062,949; javascript: 664,290; sql: 9,714; python: 5,458; xml: 3,489; sh: 1,131; makefile: 64
file content (169 lines) | stat: -rw-r--r-- 7,541 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
<?php

namespace MediaWiki\Tests\Maintenance;

use MediaWiki\MainConfigNames;
use MediaWiki\Revision\SlotRecord;
use MediaWiki\Title\Title;
use MediaWiki\User\CentralId\CentralIdLookup;
use MediaWiki\User\CentralId\CentralIdLookupFactory;
use RenameUsersMatchingPattern;
use TestUser;

/**
 * @covers RenameUsersMatchingPattern
 * @group Database
 * @author Dreamy Jazz
 */
class RenameUsersMatchingPatternTest extends MaintenanceBaseTestCase {

	protected function setUp(): void {
		parent::setUp();
		// The tests only work if the local central ID provider is used. As such, force it to be the local provider in
		// case we are running this test while an extension is loaded that provides another provider.
		$this->overrideConfigValue( MainConfigNames::CentralIdLookupProvider, 'local' );
	}

	public function getMaintenanceClass() {
		return RenameUsersMatchingPattern::class;
	}

	public function testExecuteWhenNonLocalCentralIdAvailible() {
		$mockCentralIdLookupFactory = $this->createMock( CentralIdLookupFactory::class );
		$mockCentralIdLookupFactory->method( 'getNonLocalLookup' )
			->willReturn( $this->createMock( CentralIdLookup::class ) );
		$this->setService( 'CentralIdLookupFactory', $mockCentralIdLookupFactory );
		$this->expectCallToFatalError();
		$this->expectOutputRegex( '/This script cannot be run when CentralAuth is enabled/' );
		$this->maintenance->execute();
	}

	/** @dataProvider provideExecuteForFatalError */
	public function testExecuteForFatalError( $options, $expectedOutputRegex ) {
		foreach ( $options as $name => $value ) {
			$this->maintenance->setOption( $name, $value );
		}
		$this->expectCallToFatalError();
		$this->expectOutputRegex( $expectedOutputRegex );
		$this->maintenance->execute();
	}

	public static function provideExecuteForFatalError() {
		return [
			'Invalid performer username' => [
				[ 'performer' => 'Template:Testing#test', 'from' => '*$1', 'to' => '~$1' ],
				'/Unable to get performer account/',
			]
		];
	}

	public function testExecuteForInvalidNewName() {
		// Get a test user and add it to the database (so that we can query the user table).
		$testUser = $this->getMutableTestUser( [], 'Abc' )->getUser();
		$testUser->addToDatabase();
		// Run the maintenance script to attempt to rename to an invalid username, and expect that this fails.
		$this->maintenance->setOption( 'from', 'Abc$1' );
		$this->maintenance->setOption( 'to', 'Template:Test#testing_$1' );
		$this->expectOutputRegex(
			'/Cannot rename "' . preg_quote( $testUser, '/' ) . '" because.*not a valid title[\s\S]*' .
			"Renamed 0 user\(s\)/"
		);
		$this->maintenance->execute();
	}

	public function testExecuteNewUsernameAlreadyInUse() {
		// Get two users, with a different prefix but the same after the prefix.
		$testUser = new TestUser( "Abc MediaWikiIntegrationTestCase-already-in-use-username-test" );
		$testUser->getUser()->addToDatabase();
		$conflictingUser = new TestUser( "Def MediaWikiIntegrationTestCase-already-in-use-username-test" );
		$conflictingUser->getUser()->addToDatabase();
		// Run the maintenance script to attempt to rename a user to use a name already in use, and expect this fails.
		$this->maintenance->setOption( 'from', 'Abc$1' );
		$this->maintenance->setOption( 'to', 'Def$1' );
		$this->expectOutputRegex(
			'/Cannot rename "' . preg_quote( $testUser->getUser(), '/' ) . '" because "' .
			preg_quote( $conflictingUser->getUser(), '/' ) . '" already exists[\s\S]*' .
			"Renamed 0 user\(s\)/"
		);
		$this->maintenance->execute();
	}

	public function testExecuteWithoutPageMoves() {
		// Get some testing users which have a common prefix
		$usersToBeRenamed = [];
		$userIdsUsedForTest = [];
		for ( $i = 0; $i < 3; $i++ ) {
			$testUser = $this->getMutableTestUser( [], 'Abc' );
			$testUser->getUser()->addToDatabase();
			$usersToBeRenamed[] = $testUser->getUserIdentity();
			$userIdsUsedForTest[] = $testUser->getUserIdentity()->getId();
		}
		// Get a user which does not use the common prefix, and therefore should not be renamed
		$testUserToNotBeRenamed = $this->getMutableTestUser( [], 'Def' )->getUser();
		$testUserToNotBeRenamed->addToDatabase();
		$userIdsUsedForTest[] = $testUserToNotBeRenamed->getId();
		// Run the maintenance script
		$this->maintenance->setOption( 'from', 'Abc$1' );
		$this->maintenance->setOption( 'to', 'Def$1' );
		$this->maintenance->setOption( 'skip-page-moves', true );
		$this->maintenance->execute();
		// Check that the output of the script is as expected, and generate a list of expected new usernames to check
		// against the DB.
		$expectedUsernamesAfterCall = [];
		$expectedOutputRegex = '/';
		foreach ( $usersToBeRenamed as $userIdentity ) {
			$expectedUsernameAfterCall = ucfirst( 'Def' . substr( $userIdentity->getName(), strlen( 'Abc' ) ) );
			$expectedOutputRegex .= preg_quote( $userIdentity->getName(), '/' ) .
				' was successfully renamed to ' . preg_quote( $expectedUsernameAfterCall, '/' ) . '[\s\S]*';
			$expectedUsernamesAfterCall[] = $expectedUsernameAfterCall;
		}
		$expectedOutputRegex .= 'Renamed 3 user\(s\)/';
		$this->expectOutputRegex( $expectedOutputRegex );
		// Check that the renames actually occurred
		$this->newSelectQueryBuilder()
			->select( 'user_name' )
			->from( 'user' )
			->where( [ 'user_id' => $userIdsUsedForTest ] )
			->assertFieldValues( array_merge( $expectedUsernamesAfterCall, [ $testUserToNotBeRenamed->getName() ] ) );
	}

	public function testExecuteWithPageMoves() {
		// Get one testing user, and create a user talk and user page for that user
		$testUser = $this->getMutableTestUser( [], 'Abc' );
		$testUser->getUser()->addToDatabase();
		$this->editPage( $testUser->getUser()->getUserPage(), 'user testing1234' );
		$userTalkPageBeforeRename = $testUser->getUser()->getUserPage()->getTalkPageIfDefined();
		$this->editPage( $userTalkPageBeforeRename, 'usertalk testing1234' );
		$this->editPage( Title::newFromText( $userTalkPageBeforeRename->getPrefixedText() . '/test' ), 'usertalk subpage' );
		$testUserIdentity = $testUser->getUserIdentity();
		// Run the maintenance script
		$this->maintenance->setOption( 'from', 'Abc$1' );
		$this->maintenance->setOption( 'to', 'Xyz$1' );
		$this->maintenance->execute();
		// Check that the output of the script is as expected
		$expectedUsernameAfterCall = ucfirst( 'Xyz' . substr( $testUserIdentity->getName(), strlen( 'Abc' ) ) );
		$this->expectOutputRegex(
			'/' . preg_quote( $testUserIdentity->getName(), '/' ) .
			' was successfully renamed to ' . preg_quote( $expectedUsernameAfterCall, '/' ) . '[\s\S]*'
			. 'Renamed 1 user\(s\)/'
		);
		// Check that the rename actually occurred
		$this->newSelectQueryBuilder()
			->select( 'user_name' )
			->from( 'user' )
			->where( [ 'user_id' => $testUserIdentity->getId() ] )
			->assertFieldValue( $expectedUsernameAfterCall );
		// Check that the user page, user talk page, and user talk subpage were actually moved.
		$expectedPageContent = [
			'user testing1234' => Title::newFromText( $expectedUsernameAfterCall, NS_USER ),
			'usertalk testing1234' => Title::newFromText( $expectedUsernameAfterCall, NS_USER_TALK ),
			'usertalk subpage' => Title::newFromText( "$expectedUsernameAfterCall/test", NS_USER_TALK ),
		];
		foreach ( $expectedPageContent as $expectedContent => $title ) {
			$userPageContent = $this->getServiceContainer()->getRevisionLookup()
				->getRevisionByTitle( $title )
				->getContent( SlotRecord::MAIN )->getWikitextForTransclusion();
			$this->assertSame( $expectedContent, $userPageContent );
		}
	}
}