3 namespace MediaWiki\Tests\Maintenance
;
6 use MediaWiki\MainConfigNames
;
7 use MediaWiki\Password\PasswordFactory
;
8 use MediaWiki\SiteStats\SiteStats
;
9 use MediaWiki\User\User
;
12 * @covers \CreateAndPromote
16 class CreateAndPromoteTest
extends MaintenanceBaseTestCase
{
18 protected function getMaintenanceClass() {
19 return CreateAndPromote
::class;
22 /** @dataProvider provideExecuteForExistingAccount */
23 public function testExecuteForExistingAccount(
24 $options, $expectedGroupsAfterCall, $expectedOutputRegex, $shouldCreateLogEntry
26 $testUser = $this->getMutableTestUser()->getUser();
27 // Set the user as the test user and use 'force' because we are not creating a user.
28 $this->maintenance
->setArg( 'username', $testUser );
29 $this->maintenance
->setOption( 'force', true );
30 // Add the options from $options
31 foreach ( $options as $option => $value ) {
32 $this->maintenance
->setOption( $option, $value );
34 $this->maintenance
->execute();
35 // Verify that the user is now in the expected groups
36 $this->assertArrayEquals(
37 $expectedGroupsAfterCall,
38 $this->getServiceContainer()->getUserGroupManager()->getUserGroups( $testUser )
40 $this->expectOutputRegex( $expectedOutputRegex );
41 // Verify that the log entry was created, if that is expected
42 $queryBuilder = $this->newSelectQueryBuilder()
46 'log_actor' => $this->getServiceContainer()->getActorStore()
47 ->findActorIdByName( User
::MAINTENANCE_SCRIPT_USER
, $this->getDb() ),
48 'log_title' => $testUser->getUserPage()->getDBkey(),
49 'log_namespace' => NS_USER
,
50 'log_comment_id' => $this->getServiceContainer()->getCommentStore()
51 ->createComment( $this->getDb(), $options['reason'] ??
'' )->id
,
53 $this->assertSame( (int)$shouldCreateLogEntry, (int)$queryBuilder->fetchField() );
56 public static function provideExecuteForExistingAccount() {
58 'Assigning no rights' => [ [], [], "/Account exists and nothing to do.\n/", false ],
59 'Assigning sysop with reason provided' => [
60 [ 'sysop' => 1, 'reason' => 'testing' ], [ 'sysop' ], "/Promoting .* into sysop...\ndone/", true
62 'Assigning bot' => [ [ 'bot' => 1 ], [ 'bot' ], "/Promoting .* into bot...\ndone/", true ],
63 'Assigning suppress, bureaucrat, and interface-admin' => [
64 [ 'custom-groups' => 'suppress', 'bureaucrat' => 1, 'interface-admin' => 1 ],
65 [ 'suppress', 'bureaucrat', 'interface-admin' ],
66 "/Promoting .* into bureaucrat, interface-admin, suppress...\ndone/",
69 'Assigning unrecognised group' => [
70 [ 'custom-groups' => 'abctesting' ], [], "/Account exists and nothing to do.\n/", false,
75 public function testExecuteToSetPasswordForExistingUser() {
76 $password = PasswordFactory
::generateRandomPasswordString( 128 );
77 $testUser = $this->getMutableTestUser()->getUser();
78 // Set the username as our existing test user and set the password option.
79 $this->maintenance
->setArg( 'username', $testUser );
80 $this->maintenance
->setArg( 'password', $password );
81 $this->maintenance
->setOption( 'force', true );
82 $this->maintenance
->execute();
83 $this->expectOutputRegex( '/Password set/' );
84 // Check that the password for the $testUser matches the password we set
85 $actualPasswordHash = $this->newSelectQueryBuilder()
86 ->select( 'user_password' )
88 ->where( [ 'user_name' => $testUser->getName() ] )
91 $this->getServiceContainer()->getPasswordFactory()
92 ->newFromCiphertext( $actualPasswordHash )->verify( $password )
96 public function testExecuteForInvalidUsername() {
97 // Call the maintenance script with a username that is more than wgMaxNameChars, and so shouldn't be valid.
98 $this->overrideConfigValue( MainConfigNames
::MaxNameChars
, 2 );
99 $this->expectCallToFatalError();
100 $this->expectOutputRegex( '/invalid username/' );
101 $this->maintenance
->setArg( 'username', 'testing-username-1234' );
102 $this->maintenance
->execute();
105 public function testExecuteWhenUserExistsButForceOptionNotProvided() {
106 $this->expectCallToFatalError();
107 $this->expectOutputRegex( '/Account exists.*--force/' );
108 $this->maintenance
->setArg( 'username', $this->getTestUser()->getUserIdentity()->getName() );
109 $this->maintenance
->execute();
112 public function testExecuteWhenUserDoesNotExistAndNoPasswordSpecified() {
113 $this->expectCallToFatalError();
114 $this->expectOutputRegex( '/Argument <password> required/' );
115 $this->maintenance
->setName( 'createAndPromote.php' );
116 $this->maintenance
->setArg( 'username', 'NonExistingTestUser1234' );
117 $this->maintenance
->execute();
120 public function testExecuteForNewAccountButPasswordDoesNotMeetRequirements() {
121 $this->maintenance
->setArg( 'username', 'NewTestUser1234' );
122 // Use a very commonly used password "abc" and check that it rejects this
123 $this->maintenance
->setArg( 'password', 'abc' );
124 $this->expectCallToFatalError();
125 $this->expectOutputRegex( '/password entered is in a list of very commonly used passwords/' );
126 $this->maintenance
->execute();
129 public function testExecuteForNewAccountWhenReadOnly() {
130 $this->getServiceContainer()->getReadOnlyMode()->setReason( 'test' );
131 $this->maintenance
->setArg( 'username', 'NewTestUser1234' );
132 $this->maintenance
->setArg( 'password', PasswordFactory
::generateRandomPasswordString( 128 ) );
133 $this->expectCallToFatalError();
134 // Assert that the "readonlytext" message is displayed.
135 $this->expectOutputRegex( '/database is currently locked/' );
136 $this->maintenance
->execute();
139 public function testExecuteForNewAccount() {
140 $this->assertSame( 0, SiteStats
::users() );
141 $password = PasswordFactory
::generateRandomPasswordString( 128 );
142 // Run the maintenance script
143 $this->maintenance
->setArg( 'username', 'NewTestUser1234' );
144 $this->maintenance
->setArg( 'password', $password );
145 $this->maintenance
->setOption( 'sysop', 1 );
146 $this->maintenance
->execute();
147 $this->expectOutputRegex( '/Creating and promoting User:NewTestUser1234[\s\S]*done/' );
148 // Check that the new user exists and that the password matches
149 $actualPasswordHash = $this->newSelectQueryBuilder()
150 ->select( 'user_password' )
152 ->where( [ 'user_name' => 'NewTestUser1234' ] )
155 $this->getServiceContainer()->getPasswordFactory()
156 ->newFromCiphertext( $actualPasswordHash )->verify( $password )
158 // Check that the number of users has increased to 2, one for the new user and the other for the maintenance
160 $this->assertSame( 2, SiteStats
::users() );