Why:
* The blockUsers.php maintenance script can set the performer's
username as the username provided via the --performer option.
* The username is validated by the script, but the validation broke
in c106f679b0. This was because both:
** The check for whether the username was invalid changed to only
looking for 'null' values returned by User::newSystemUser /
User::newFromName.
** The User::newFromName method returns false on an invalid username.
* Replacing the deprecated User::newFromName with the call to
UserFactory::newFromName fixes this issue, as the replacement
method returns null on an invalid username.
** This also allows replacement of a deprecated method, which is
preferrable to changing the 'null' check to be a falsey check.
What:
* Replace the call to User::newFromName with UserFactory
::newFromName to fix this issue.
* Add a test to verify that this fix worked.
Bug: T371167
Change-Id: Ie181c16a1dda559a81b8ae4d53cd8f69b1af9b75
176 lines
6.4 KiB
PHP
176 lines
6.4 KiB
PHP
<?php
|
|
|
|
namespace MediaWiki\Tests\Maintenance;
|
|
|
|
use BlockUsers;
|
|
use MediaWiki\MainConfigNames;
|
|
use MediaWiki\Tests\Unit\Permissions\MockAuthorityTrait;
|
|
use MediaWiki\User\User;
|
|
use MediaWiki\User\UserIdentity;
|
|
|
|
/**
|
|
* @covers \BlockUsers
|
|
* @group Database
|
|
* @author Dreamy Jazz
|
|
*/
|
|
class BlockUsersTest extends MaintenanceBaseTestCase {
|
|
use MockAuthorityTrait;
|
|
|
|
protected function getMaintenanceClass() {
|
|
return BlockUsers::class;
|
|
}
|
|
|
|
private function commonTestExecute( $options, $fileContents ) {
|
|
// Add the specified $options
|
|
foreach ( $options as $name => $value ) {
|
|
$this->maintenance->setOption( $name, $value );
|
|
}
|
|
// Create a temporary file, write $fileContents to it, and then pass the filename in argv.
|
|
$file = $this->getNewTempFile();
|
|
file_put_contents( $file, $fileContents );
|
|
$this->maintenance->setArg( 'file', $file );
|
|
// Call ::execute
|
|
$this->maintenance->execute();
|
|
}
|
|
|
|
/**
|
|
* @param int $count
|
|
* @return UserIdentity[]
|
|
*/
|
|
private function getTestUnblockedUsers( int $count ): array {
|
|
$returnArray = [];
|
|
for ( $i = 0; $i < $count; $i++ ) {
|
|
$returnArray[] = $this->getMutableTestUser()->getUserIdentity();
|
|
}
|
|
return $returnArray;
|
|
}
|
|
|
|
/**
|
|
* @param int $count
|
|
* @return UserIdentity[]
|
|
*/
|
|
private function getTestBlockedUsers( int $count ): array {
|
|
$returnArray = $this->getTestUnblockedUsers( $count );
|
|
$blockManager = $this->getServiceContainer()->getBlockManager();
|
|
$blockUserFactory = $this->getServiceContainer()->getBlockUserFactory();
|
|
foreach ( $returnArray as $user ) {
|
|
$blockUserFactory->newBlockUser( $user, $this->mockRegisteredUltimateAuthority(), 'infinite', 'test' )
|
|
->placeBlock();
|
|
$this->assertNotNull( $blockManager->getBlock( $user, null ) );
|
|
}
|
|
return $returnArray;
|
|
}
|
|
|
|
/** @dataProvider provideExecuteForUnblock */
|
|
public function testExecuteForUnblock( $blockedUserCount, $notBlockedUserCount ) {
|
|
$blockedUsers = $this->getTestBlockedUsers( $blockedUserCount );
|
|
$unblockedUsers = $this->getTestUnblockedUsers( $notBlockedUserCount );
|
|
// Generate the file contents by combining the $blockedUsers and $unblockedUsers arrays
|
|
$fileContents = '';
|
|
$expectedOutputRegex = '/';
|
|
foreach ( $blockedUsers as $user ) {
|
|
$fileContents .= $user->getName() . PHP_EOL;
|
|
$userNameForRegex = preg_quote( $user->getName() );
|
|
$expectedOutputRegex .= ".*Unblocking '$userNameForRegex' succeeded.\n";
|
|
}
|
|
foreach ( $unblockedUsers as $user ) {
|
|
$fileContents .= $user->getName() . PHP_EOL;
|
|
$userNameForRegex = preg_quote( $user->getName() );
|
|
$expectedOutputRegex .= ".*Unblocking '$userNameForRegex' failed.*\n";
|
|
}
|
|
$options['unblock'] = true;
|
|
$this->commonTestExecute( $options, $fileContents );
|
|
$this->expectOutputRegex( $expectedOutputRegex . '/' );
|
|
// Verify that the blocked users are no longer blocked.
|
|
$blockManager = $this->getServiceContainer()->getBlockManager();
|
|
foreach ( $blockedUsers as $user ) {
|
|
$blockManager->clearUserCache( $user );
|
|
$this->assertNull( $blockManager->getBlock( $user, null ), 'User was not actually unblocked.' );
|
|
}
|
|
}
|
|
|
|
public static function provideExecuteForUnblock() {
|
|
return [
|
|
'2 blocked users and 1 unblocked user' => [ 2, 1 ],
|
|
'3 blocked users' => [ 3, 0 ],
|
|
];
|
|
}
|
|
|
|
/** @dataProvider provideExecuteForBlock */
|
|
public function testExecuteForBlock( $options, $blockedUserCount, $notBlockedUserCount ) {
|
|
$blockedUsers = $this->getTestBlockedUsers( $blockedUserCount );
|
|
$unblockedUsers = $this->getTestUnblockedUsers( $notBlockedUserCount );
|
|
// Generate the file contents by combining the $blockedUsers and $unblockedUsers arrays
|
|
$fileContents = '';
|
|
$expectedOutputRegex = '/';
|
|
foreach ( $unblockedUsers as $user ) {
|
|
$fileContents .= $user->getName() . PHP_EOL;
|
|
$userNameForRegex = preg_quote( $user->getName() );
|
|
$expectedOutputRegex .= ".*Blocking '$userNameForRegex' succeeded.\n";
|
|
}
|
|
foreach ( $blockedUsers as $user ) {
|
|
$fileContents .= $user->getName() . PHP_EOL;
|
|
$userNameForRegex = preg_quote( $user->getName() );
|
|
$expectedOutputRegex .= ".*Blocking '$userNameForRegex' failed.*\n";
|
|
}
|
|
$this->commonTestExecute( $options, $fileContents );
|
|
$this->expectOutputRegex( $expectedOutputRegex . '/' );
|
|
// Verify that the blocked users are no longer blocked.
|
|
$blockManager = $this->getServiceContainer()->getBlockManager();
|
|
foreach ( $unblockedUsers as $user ) {
|
|
$blockManager->clearUserCache( $user );
|
|
$actualBlock = $blockManager->getBlock( $user, null );
|
|
$this->assertNotNull( $actualBlock, 'User was not blocked' );
|
|
// Verify that the block parameters are as expected.
|
|
$this->assertSame( $options['reason'] ?? '', $actualBlock->getReasonComment()->text );
|
|
if ( !isset( $options['expiry'] ) || wfIsInfinity( $options['expiry'] ) ) {
|
|
$this->assertTrue( wfIsInfinity( $actualBlock->getExpiry() ) );
|
|
} else {
|
|
$this->assertSame( $options['expiry'], $actualBlock->getExpiry() );
|
|
}
|
|
$this->assertSame(
|
|
$options['performer'] ?? User::MAINTENANCE_SCRIPT_USER,
|
|
$actualBlock->getBlocker()->getName()
|
|
);
|
|
$blockParameters = [
|
|
'isCreateAccountBlocked' => !isset( $options['allow-createaccount'] ),
|
|
'isEmailBlocked' => !isset( $options['allow-email'] ),
|
|
'isUsertalkEditAllowed' => isset( $options['allow-talkedit'] ),
|
|
'isHardBlock' => !isset( $options['disable-hardblock'] ),
|
|
'isAutoblocking' => !isset( $options['disable-autoblock'] ),
|
|
];
|
|
foreach ( $blockParameters as $methodName => $expectedReturnValue ) {
|
|
$this->assertSame(
|
|
$expectedReturnValue,
|
|
$actualBlock->$methodName(),
|
|
"::$methodName returned an unexpected value"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static function provideExecuteForBlock() {
|
|
return [
|
|
'2 blocked users and 1 unblocked user, with specified reason' => [ [ 'reason' => 'testing' ], 2, 1 ],
|
|
'3 unblocked users with most options set' => [
|
|
[
|
|
'allow-createaccount' => 1, 'allow-email' => 1, 'allow-talkedit' => 1, 'disable-hardblock' => 1,
|
|
'disable-autoblock' => 1,
|
|
],
|
|
3, 0,
|
|
],
|
|
];
|
|
}
|
|
|
|
public function testExecuteForBlockWithSpecifiedPerformer() {
|
|
$this->testExecuteForBlock( [ 'performer' => $this->getTestSysop()->getUserIdentity()->getName() ], 1, 0 );
|
|
}
|
|
|
|
public function testExecuteWhenPerformerNameInvalid() {
|
|
// Set wgMaxNameChars to 3, so that the performer username will be invalid
|
|
$this->overrideConfigValue( MainConfigNames::MaxNameChars, 3 );
|
|
$this->expectCallToFatalError();
|
|
$this->expectOutputRegex( '/Unable to parse.*username/' );
|
|
$this->commonTestExecute( [ 'performer' => 'Username-which-is-too-long' ], '' );
|
|
}
|
|
}
|