3 namespace MediaWiki\Tests\Maintenance
;
6 use MediaWiki\MainConfigNames
;
7 use MediaWiki\Tests\Unit\Permissions\MockAuthorityTrait
;
8 use MediaWiki\User\User
;
9 use MediaWiki\User\UserIdentity
;
16 class BlockUsersTest
extends MaintenanceBaseTestCase
{
17 use MockAuthorityTrait
;
19 protected function getMaintenanceClass() {
20 return BlockUsers
::class;
23 private function commonTestExecute( $options, $fileContents ) {
24 // Add the specified $options
25 foreach ( $options as $name => $value ) {
26 $this->maintenance
->setOption( $name, $value );
28 // Create a temporary file, write $fileContents to it, and then pass the filename in argv.
29 $file = $this->getNewTempFile();
30 file_put_contents( $file, $fileContents );
31 $this->maintenance
->setArg( 'file', $file );
33 $this->maintenance
->execute();
38 * @return UserIdentity[]
40 private function getTestUnblockedUsers( int $count ): array {
42 for ( $i = 0; $i < $count; $i++
) {
43 $returnArray[] = $this->getMutableTestUser()->getUserIdentity();
50 * @return UserIdentity[]
52 private function getTestBlockedUsers( int $count ): array {
53 $returnArray = $this->getTestUnblockedUsers( $count );
54 $blockManager = $this->getServiceContainer()->getBlockManager();
55 $blockUserFactory = $this->getServiceContainer()->getBlockUserFactory();
56 foreach ( $returnArray as $user ) {
57 $blockUserFactory->newBlockUser( $user, $this->mockRegisteredUltimateAuthority(), 'infinite', 'test' )
59 $this->assertNotNull( $blockManager->getBlock( $user, null ) );
64 /** @dataProvider provideExecuteForUnblock */
65 public function testExecuteForUnblock( $blockedUserCount, $notBlockedUserCount ) {
66 $blockedUsers = $this->getTestBlockedUsers( $blockedUserCount );
67 $unblockedUsers = $this->getTestUnblockedUsers( $notBlockedUserCount );
68 // Generate the file contents by combining the $blockedUsers and $unblockedUsers arrays
70 $expectedOutputRegex = '/';
71 foreach ( $blockedUsers as $user ) {
72 $fileContents .= $user->getName() . PHP_EOL
;
73 $userNameForRegex = preg_quote( $user->getName() );
74 $expectedOutputRegex .= ".*Unblocking '$userNameForRegex' succeeded.\n";
76 foreach ( $unblockedUsers as $user ) {
77 $fileContents .= $user->getName() . PHP_EOL
;
78 $userNameForRegex = preg_quote( $user->getName() );
79 $expectedOutputRegex .= ".*Unblocking '$userNameForRegex' failed.*\n";
81 $options['unblock'] = true;
82 $this->commonTestExecute( $options, $fileContents );
83 $this->expectOutputRegex( $expectedOutputRegex . '/' );
84 // Verify that the blocked users are no longer blocked.
85 $blockManager = $this->getServiceContainer()->getBlockManager();
86 foreach ( $blockedUsers as $user ) {
87 $blockManager->clearUserCache( $user );
88 $this->assertNull( $blockManager->getBlock( $user, null ), 'User was not actually unblocked.' );
92 public static function provideExecuteForUnblock() {
94 '2 blocked users and 1 unblocked user' => [ 2, 1 ],
95 '3 blocked users' => [ 3, 0 ],
99 /** @dataProvider provideExecuteForBlock */
100 public function testExecuteForBlock( $options, $blockedUserCount, $notBlockedUserCount ) {
101 $blockedUsers = $this->getTestBlockedUsers( $blockedUserCount );
102 $unblockedUsers = $this->getTestUnblockedUsers( $notBlockedUserCount );
103 // Generate the file contents by combining the $blockedUsers and $unblockedUsers arrays
105 $expectedOutputRegex = '/';
106 foreach ( $unblockedUsers as $user ) {
107 $fileContents .= $user->getName() . PHP_EOL
;
108 $userNameForRegex = preg_quote( $user->getName() );
109 $expectedOutputRegex .= ".*Blocking '$userNameForRegex' succeeded.\n";
111 foreach ( $blockedUsers as $user ) {
112 $fileContents .= $user->getName() . PHP_EOL
;
113 $userNameForRegex = preg_quote( $user->getName() );
114 $expectedOutputRegex .= ".*Blocking '$userNameForRegex' failed.*\n";
116 $this->commonTestExecute( $options, $fileContents );
117 $this->expectOutputRegex( $expectedOutputRegex . '/' );
118 // Verify that the blocked users are no longer blocked.
119 $blockManager = $this->getServiceContainer()->getBlockManager();
120 foreach ( $unblockedUsers as $user ) {
121 $blockManager->clearUserCache( $user );
122 $actualBlock = $blockManager->getBlock( $user, null );
123 $this->assertNotNull( $actualBlock, 'User was not blocked' );
124 // Verify that the block parameters are as expected.
125 $this->assertSame( $options['reason'] ??
'', $actualBlock->getReasonComment()->text
);
126 if ( !isset( $options['expiry'] ) ||
wfIsInfinity( $options['expiry'] ) ) {
127 $this->assertTrue( wfIsInfinity( $actualBlock->getExpiry() ) );
129 $this->assertSame( $options['expiry'], $actualBlock->getExpiry() );
132 $options['performer'] ?? User
::MAINTENANCE_SCRIPT_USER
,
133 $actualBlock->getBlocker()->getName()
136 'isCreateAccountBlocked' => !isset( $options['allow-createaccount'] ),
137 'isEmailBlocked' => !isset( $options['allow-email'] ),
138 'isUsertalkEditAllowed' => isset( $options['allow-talkedit'] ),
139 'isHardBlock' => !isset( $options['disable-hardblock'] ),
140 'isAutoblocking' => !isset( $options['disable-autoblock'] ),
142 foreach ( $blockParameters as $methodName => $expectedReturnValue ) {
144 $expectedReturnValue,
145 $actualBlock->$methodName(),
146 "::$methodName returned an unexpected value"
152 public static function provideExecuteForBlock() {
154 '2 blocked users and 1 unblocked user, with specified reason' => [ [ 'reason' => 'testing' ], 2, 1 ],
155 '3 unblocked users with most options set' => [
157 'allow-createaccount' => 1, 'allow-email' => 1, 'allow-talkedit' => 1, 'disable-hardblock' => 1,
158 'disable-autoblock' => 1,
165 public function testExecuteForBlockWithSpecifiedPerformer() {
166 $this->testExecuteForBlock( [ 'performer' => $this->getTestSysop()->getUserIdentity()->getName() ], 1, 0 );
169 public function testExecuteWhenPerformerNameInvalid() {
170 // Set wgMaxNameChars to 3, so that the performer username will be invalid
171 $this->overrideConfigValue( MainConfigNames
::MaxNameChars
, 3 );
172 $this->expectCallToFatalError();
173 $this->expectOutputRegex( '/Unable to parse.*username/' );
174 $this->commonTestExecute( [ 'performer' => 'Username-which-is-too-long' ], '' );