diff options
author | jenkins-bot <jenkins-bot@gerrit.wikimedia.org> | 2022-04-14 15:33:50 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@wikimedia.org> | 2022-04-14 15:33:50 +0000 |
commit | bd8691818afc068d90c35457437862aef4913755 (patch) | |
tree | c6bb496202eb7f1c7c6664655d6ff7d950d3b71a /tests/phpunit | |
parent | 517fce893ccf6927c2f75a7f2d6f077d0b3a8b1f (diff) | |
parent | e8dbf5f80c029c4be52f1afd4ef91c59cfcd1185 (diff) | |
download | mediawikicore-bd8691818afc068d90c35457437862aef4913755.tar.gz mediawikicore-bd8691818afc068d90c35457437862aef4913755.zip |
Merge "TempUser infrastructure and services"
Diffstat (limited to 'tests/phpunit')
10 files changed, 590 insertions, 1 deletions
diff --git a/tests/phpunit/includes/user/UserTest.php b/tests/phpunit/includes/user/UserTest.php index 58dfd4534d0e..397070c935b8 100644 --- a/tests/phpunit/includes/user/UserTest.php +++ b/tests/phpunit/includes/user/UserTest.php @@ -2080,4 +2080,55 @@ class UserTest extends MediaWikiIntegrationTestCase { $this->assertSame( $user->getId(), $unserializedUser->getId() ); $this->assertSame( $isAllowed, $unserializedUser->isAllowed( 'read' ) ); } + + private function enableAutoCreateTempUser() { + $this->setMwGlobals( [ + 'wgAutoCreateTempUser' => [ + 'enabled' => true, + 'actions' => [ 'edit' ], + 'genPattern' => '*Unregistered $1', + 'matchPattern' => '*$1', + 'serialProvider' => [ 'type' => 'local' ], + 'serialMapping' => [ 'type' => 'plain-numeric' ], + ] + ] ); + } + + public static function provideIsTemp() { + return [ + [ '*Unregistered 1', true ], + [ 'Some user', false ] + ]; + } + + /** + * @covers User::isTemp + * @dataProvider provideIsTemp + */ + public function testIsTemp( $name, $expected ) { + $this->enableAutoCreateTempUser(); + $user = new User; + $user->setName( $name ); + $this->assertSame( $expected, $user->isTemp() ); + } + + /** + * @covers User::isNamed + */ + public function testIsNamed() { + $this->enableAutoCreateTempUser(); + + // Temp user is not named + $user = new User; + $user->setName( '*Unregistered 1' ); + $this->assertFalse( $user->isNamed() ); + + // Registered user is named + $user = $this->getMutableTestUser()->getUser(); + $this->assertTrue( $user->isNamed() ); + + // Anon is not named + $user = new User; + $this->assertFalse( $user->isNamed() ); + } } diff --git a/tests/phpunit/integration/includes/user/TempUser/LocalizedNumericSerialMappingTest.php b/tests/phpunit/integration/includes/user/TempUser/LocalizedNumericSerialMappingTest.php new file mode 100644 index 000000000000..5fced4ffc252 --- /dev/null +++ b/tests/phpunit/integration/includes/user/TempUser/LocalizedNumericSerialMappingTest.php @@ -0,0 +1,19 @@ +<?php + +namespace MediaWiki\Tests\User\TempUser; + +use MediaWiki\User\TempUser\LocalizedNumericSerialMapping; +use MediaWikiIntegrationTestCase; + +/** + * @covers \MediaWiki\User\TempUser\LocalizedNumericSerialMapping + */ +class LocalizedNumericSerialMappingTest extends MediaWikiIntegrationTestCase { + public function testGetSerialIdForIndex() { + $map = new LocalizedNumericSerialMapping( + [ 'language' => 'ar' ], + $this->getServiceContainer()->getLanguageFactory() + ); + $this->assertSame( '١٠', $map->getSerialIdForIndex( 10 ) ); + } +} diff --git a/tests/phpunit/integration/includes/user/TempUser/RealTempUserConfigTest.php b/tests/phpunit/integration/includes/user/TempUser/RealTempUserConfigTest.php new file mode 100644 index 000000000000..983c5dda135f --- /dev/null +++ b/tests/phpunit/integration/includes/user/TempUser/RealTempUserConfigTest.php @@ -0,0 +1,129 @@ +<?php + +namespace MediaWiki\Tests\User\TempUser; + +/** + * @covers \MediaWiki\User\TempUser\RealTempUserConfig + * @group Database + */ +class RealTempUserConfigTest extends \MediaWikiIntegrationTestCase { + /** This is meant to be the default config from DefaultSettings.php */ + private const DEFAULTS = [ + 'enabled' => false, + 'actions' => [ 'edit' ], + 'genPattern' => '*Unregistered $1', + 'matchPattern' => '*$1', + 'serialProvider' => [ 'type' => 'local' ], + 'serialMapping' => [ 'type' => 'plain-numeric' ] + ]; + + public static function provideIsAutoCreateAction() { + return [ + 'disabled' => [ + 'config' => [ + 'enabled' => false + ] + self::DEFAULTS, + 'action' => 'edit', + 'expected' => false + ], + 'disabled by action' => [ + 'config' => [ + 'enabled' => true, + 'actions' => [] + ] + self::DEFAULTS, + 'action' => 'edit', + 'expected' => false + ], + 'enabled' => [ + 'config' => [ + 'enabled' => true, + ] + self::DEFAULTS, + 'action' => 'edit', + 'expected' => true + ], + // Create isn't an action in the ActionFactory sense, but is is an + // action in PermissionManager + 'create' => [ + 'config' => [ + 'enabled' => true, + ] + self::DEFAULTS, + 'action' => 'create', + 'expected' => true + ], + 'unknown action' => [ + 'config' => [ + 'enabled' => true, + ] + self::DEFAULTS, + 'action' => 'foo', + 'expected' => false + ], + ]; + } + + /** + * @dataProvider provideIsAutoCreateAction + * @param array $config + * @param string $action + * @param bool $expected + */ + public function testIsAutoCreateAction( $config, $action, $expected ) { + $this->setMwGlobals( [ + 'wgAutoCreateTempUser' => $config + ] ); + $tuc = $this->getServiceContainer()->getTempUserConfig(); + $this->assertSame( $expected, $tuc->isAutoCreateAction( $action ) ); + } + + public static function provideIsReservedName() { + $defaults = [ + 'enabled' => true + ] + self::DEFAULTS; + return [ + 'disabled' => [ + 'config' => [ + 'enabled' => false + ] + $defaults, + 'name' => '*Some user', + 'expected' => false, + ], + 'default mismatch' => [ + 'config' => $defaults, + 'name' => 'Test', + 'expected' => false, + ], + 'default match' => [ + 'config' => $defaults, + 'name' => '*Some user', + 'expected' => true, + ] + ]; + } + + /** + * @dataProvider provideIsReservedName + * @param array $config + * @param string $name + * @param bool $expected + */ + public function testIsReservedName( $config, $name, $expected ) { + $this->setMwGlobals( [ + 'wgAutoCreateTempUser' => $config + ] ); + $tuc = $this->getServiceContainer()->getTempUserConfig(); + $this->assertSame( $expected, $tuc->isReservedName( $name ) ); + } + + private function getTempUserConfig() { + $this->setMwGlobals( [ + 'wgAutoCreateTempUser' => [ 'enabled' => true ] + self::DEFAULTS + ] ); + return $this->getServiceContainer()->getTempUserConfig(); + } + + public function testGetPlaceholderName() { + $this->assertSame( + '*Unregistered *', + $this->getTempUserConfig()->getPlaceholderName() + ); + } +} diff --git a/tests/phpunit/integration/includes/user/TempUser/TempUserCreatorTest.php b/tests/phpunit/integration/includes/user/TempUser/TempUserCreatorTest.php new file mode 100644 index 000000000000..afd151c3c740 --- /dev/null +++ b/tests/phpunit/integration/includes/user/TempUser/TempUserCreatorTest.php @@ -0,0 +1,156 @@ +<?php + +namespace MediaWiki\Tests\User\TempUser; + +use ExtensionRegistry; +use MediaWiki\Auth\AuthManager; +use MediaWiki\Session\Session; +use MediaWiki\User\TempUser\RealTempUserConfig; +use MediaWiki\User\TempUser\SerialMapping; +use MediaWiki\User\TempUser\SerialProvider; +use MediaWiki\User\TempUser\TempUserCreator; +use MediaWiki\User\UserFactory; +use Wikimedia\TestingAccessWrapper; + +/** + * @group Database + * @covers \MediaWiki\User\TempUser\DBSerialProvider + * @covers \MediaWiki\User\TempUser\LocalSerialProvider + * @covers \MediaWiki\User\TempUser\TempUserCreator + * @covers \MediaWiki\User\TempUser\CreateStatus + */ +class TempUserCreatorTest extends \MediaWikiIntegrationTestCase { + /** This is meant to be the default config from DefaultSettings.php */ + private const DEFAULTS = [ + 'enabled' => false, + 'actions' => [ 'edit' ], + 'genPattern' => '*Unregistered $1', + 'matchPattern' => '*$1', + 'serialProvider' => [ 'type' => 'local' ], + 'serialMapping' => [ 'type' => 'plain-numeric' ] + ]; + + public function testCreate() { + $this->tablesUsed[] = 'user'; + $this->tablesUsed[] = 'user_autocreate_serial'; + + $this->setMwGlobals( [ + 'wgAutoCreateTempUser' => [ + 'enabled' => true, + 'actions' => [ 'edit' ], + 'genPattern' => '*Unregistered $1', + 'matchPattern' => '*$1', + 'serialProvider' => [ 'type' => 'local' ], + 'serialMapping' => [ 'type' => 'plain-numeric' ] + ] + ] ); + $tuc = $this->getServiceContainer()->getTempUserCreator(); + $this->assertTrue( $tuc->isAutoCreateAction( 'edit' ) ); + $this->assertTrue( $tuc->isReservedName( '*Unregistered 1' ) ); + $status = $tuc->create(); + $this->assertSame( '*Unregistered 1', $status->getUser()->getName() ); + $status = $tuc->create(); + $this->assertSame( '*Unregistered 2', $status->getUser()->getName() ); + } + + private function getTempUserCreatorUnit() { + $scope1 = ExtensionRegistry::getInstance()->setAttributeForTest( + 'TempUserSerialProviders', + [ + 'test' => [ + 'factory' => static function () { + return new class implements SerialProvider { + public function acquireIndex(): int { + return 1; + } + }; + } + ], + ] + ); + $scope2 = ExtensionRegistry::getInstance()->setAttributeForTest( + 'TempUserSerialMappings', + [ + 'test' => [ + 'factory' => static function () { + return new class implements SerialMapping { + public function getSerialIdForIndex( int $index ): string { + $index--; + $adjective = (int)( $index / 2 ); + $animal = $index % 2; + return [ 'active' ][$adjective] . ' ' . [ 'aardvark' ][$animal]; + } + }; + } + ] + ] + ); + $config = new RealTempUserConfig( + [ + 'enabled' => true, + 'serialProvider' => [ 'type' => 'test' ], + 'serialMapping' => [ 'type' => 'test' ] + ] + self::DEFAULTS + ); + $creator = new TempUserCreator( + $config, + $this->createSimpleObjectFactory(), + $this->createMock( UserFactory::class ), + $this->createMock( AuthManager::class ), + null + ); + return [ $creator, [ $scope1, $scope2 ] ]; + } + + public function testAcquireName_unit() { + [ $creator, $scope ] = $this->getTempUserCreatorUnit(); + /** @var TempUserCreator $creator */ + $creator = TestingAccessWrapper::newFromObject( $creator ); + $this->assertSame( '*Unregistered active aardvark', $creator->acquireName() ); + } + + public function testAcquireName_db() { + $this->tablesUsed[] = 'user_autocreate_serial'; + $this->setMwGlobals( [ + 'wgAutoCreateTempUser' => [ + 'enabled' => true, + ] + self::DEFAULTS + ] ); + $tuc = TestingAccessWrapper::newFromObject( + $this->getServiceContainer()->getTempUserCreator() + ); + $this->assertSame( '*Unregistered 1', $tuc->acquireName() ); + $this->assertSame( '*Unregistered 2', $tuc->acquireName() ); + } + + public function testAcquireAndStashName() { + /** @var TempUserCreator $creator */ + [ $creator, $scope ] = $this->getTempUserCreatorUnit(); + + $session = new class extends Session { + private $data = []; + + public function __construct() { + } + + public function __destruct() { + } + + public function get( $key, $default = null ) { + return array_key_exists( $key, $this->data ) ? $this->data[$key] : $default; + } + + public function set( $key, $value ) { + $this->data[$key] = $value; + } + + public function save() { + } + }; + + $name = $creator->acquireAndStashName( $session ); + $this->assertSame( '*Unregistered active aardvark', $name ); + $name = $creator->acquireAndStashName( $session ); + $this->assertSame( '*Unregistered active aardvark', $name ); + } +} diff --git a/tests/phpunit/integration/includes/user/UserFactoryTest.php b/tests/phpunit/integration/includes/user/UserFactoryTest.php index c0aeaacea631..6007e520e55a 100644 --- a/tests/phpunit/integration/includes/user/UserFactoryTest.php +++ b/tests/phpunit/integration/includes/user/UserFactoryTest.php @@ -185,4 +185,38 @@ class UserFactoryTest extends MediaWikiIntegrationTestCase { $this->assertSame( 'Test', $user->getName() ); } + public function testNewTempPlaceholder() { + $this->setMwGlobals( [ + 'wgAutoCreateTempUser' => [ + 'enabled' => true, + 'actions' => [ 'edit' ], + 'genPattern' => '*Unregistered $1', + 'matchPattern' => '*$1', + 'serialProvider' => [ 'type' => 'local' ], + 'serialMapping' => [ 'type' => 'plain-numeric' ], + ] + ] ); + $user = $this->getUserFactory()->newTempPlaceholder(); + $this->assertTrue( $user->isTemp() ); + $this->assertFalse( $user->isRegistered() ); + $this->assertFalse( $user->isNamed() ); + $this->assertSame( 0, $user->getId() ); + } + + public function testNewUnsavedTempUser() { + $this->setMwGlobals( [ + 'wgAutoCreateTempUser' => [ + 'enabled' => true, + 'actions' => [ 'edit' ], + 'genPattern' => '*Unregistered $1', + 'matchPattern' => '*$1', + 'serialProvider' => [ 'type' => 'local' ], + 'serialMapping' => [ 'type' => 'plain-numeric' ], + ] + ] ); + $user = $this->getUserFactory()->newUnsavedTempUser( '*Unregistered 1234' ); + $this->assertTrue( $user->isTemp() ); + $this->assertFalse( $user->isNamed() ); + } + } diff --git a/tests/phpunit/mocks/DummyServicesTrait.php b/tests/phpunit/mocks/DummyServicesTrait.php index dcc86b28dc12..97fc9337223d 100644 --- a/tests/phpunit/mocks/DummyServicesTrait.php +++ b/tests/phpunit/mocks/DummyServicesTrait.php @@ -33,6 +33,7 @@ use MediaWiki\Config\ServiceOptions; use MediaWiki\Interwiki\InterwikiLookup; use MediaWiki\Linker\LinkTarget; use MediaWiki\Page\PageReference; +use MediaWiki\User\TempUser\RealTempUserConfig; use MediaWiki\User\UserIdentity; use MediaWiki\User\UserNameUtils; use MediaWikiTitleCodec; @@ -429,7 +430,15 @@ trait DummyServicesTrait { $logger, $titleParser, $textFormatter, - $options['hookContainer'] ?? $this->createHookContainer() + $options['hookContainer'] ?? $this->createHookContainer(), + new RealTempUserConfig( [ + 'enabled' => true, + 'actions' => [ 'edit' ], + 'serialProvider' => [ 'type' => 'local' ], + 'serialMapping' => [ 'type' => 'plain-numeric' ], + 'matchPattern' => '*$1', + 'genPattern' => '*Unregistered $1' + ] ) ); } diff --git a/tests/phpunit/unit/includes/user/TempUser/FilteredRadixSerialMappingTest.php b/tests/phpunit/unit/includes/user/TempUser/FilteredRadixSerialMappingTest.php new file mode 100644 index 000000000000..851e8df1255f --- /dev/null +++ b/tests/phpunit/unit/includes/user/TempUser/FilteredRadixSerialMappingTest.php @@ -0,0 +1,62 @@ +<?php + +namespace MediaWiki\Tests\User\TempUser; + +use MediaWiki\User\TempUser\FilteredRadixSerialMapping; +use PHPUnit\Framework\TestCase; + +/** + * @covers \MediaWiki\User\TempUser\FilteredRadixSerialMapping + */ +class FilteredRadixSerialMappingTest extends TestCase { + public static function provideGetSerialIdForIndex() { + return [ + [ + [ 'radix' => 10 ], + 16, + '16', + ], + [ + [ 'radix' => 16 ], + 10, + 'a', + ], + [ + [ 'radix' => 16, 'uppercase' => true ], + 10, + 'A', + ], + [ + [ 'radix' => 10, 'badIndexes' => [ 2 ] ], + 1, + '1' + ], + [ + [ 'radix' => 10, 'badIndexes' => [ 2 ] ], + 1, + '1' + ], + [ + [ 'radix' => 10, 'badIndexes' => [ 2 ] ], + 2, + '3' + ], + [ + [ 'radix' => 10, 'badIndexes' => [ 2 ] ], + 3, + '4' + ], + ]; + } + + /** + * @dataProvider provideGetSerialIdForIndex + * @param array $config + * @param int $id + * @param string $expected + */ + public function testGetSerialIdForIndex( $config, $id, $expected ) { + $map = new FilteredRadixSerialMapping( $config ); + $this->assertSame( $expected, $map->getSerialIdForIndex( $id ) ); + } +} diff --git a/tests/phpunit/unit/includes/user/TempUser/PatternTest.php b/tests/phpunit/unit/includes/user/TempUser/PatternTest.php new file mode 100644 index 000000000000..3766c029efb5 --- /dev/null +++ b/tests/phpunit/unit/includes/user/TempUser/PatternTest.php @@ -0,0 +1,94 @@ +<?php + +namespace MediaWiki\Tests\User\TempUser; + +use MediaWiki\User\TempUser\Pattern; +use PHPUnit\Framework\TestCase; + +/** + * @covers \MediaWiki\User\TempUser\Pattern + */ +class PatternTest extends TestCase { + public function testInvalid() { + $this->expectException( \MWException::class ); + $pattern = new Pattern( 'test', 'test' ); + $pattern->isMatch( 'test' ); + } + + public static function provideIsMatch() { + return [ + 'prefix mismatch' => [ + 'pattern' => '*$1', + 'name' => 'Test', + 'expected' => false, + ], + 'prefix match' => [ + 'pattern' => '*$1', + 'name' => '*Some user', + 'expected' => true, + ], + 'suffix only match' => [ + 'pattern' => '$1*', + 'name' => 'Some user*', + 'expected' => true, + ], + 'suffix only mismatch' => [ + 'pattern' => '$1*', + 'name' => 'Some user', + 'expected' => false, + ], + 'prefix and suffix match' => [ + 'pattern' => '*$1*', + 'name' => '*Unregistered 123*', + 'expected' => true, + ], + 'prefix and suffix mismatch' => [ + 'pattern' => '*$1*', + 'name' => 'Unregistered 123*', + 'expected' => false, + ], + 'prefix and suffix zero length match' => [ + 'pattern' => '*$1*', + 'name' => '**', + 'expected' => true, + ], + 'prefix and suffix overlapping' => [ + 'pattern' => '*$1*', + 'name' => '*', + 'expected' => false, + ], + ]; + } + + /** @dataProvider provideIsMatch */ + public function testIsMatch( $stringPattern, $name, $expected ) { + $pattern = new Pattern( 'test', $stringPattern ); + $this->assertSame( $expected, $pattern->isMatch( $name ) ); + } + + public static function provideGenerate() { + return [ + 'prefix' => [ + 'pattern' => 'x$1', + 'serial' => 'y', + 'expected' => 'xy', + ], + 'suffix' => [ + 'pattern' => '$1x', + 'serial' => 'y', + 'expected' => 'yx', + ], + 'both' => [ + 'pattern' => '*Unregistered $1*', + 'serial' => '123', + 'expected' => '*Unregistered 123*' + ] + ]; + } + + /** @dataProvider provideGenerate */ + public function testGenerate( $stringPattern, $serial, $expected ) { + $pattern = new Pattern( 'test', $stringPattern ); + $this->assertSame( $expected, $pattern->generate( $serial ) ); + } +} diff --git a/tests/phpunit/unit/includes/user/TempUser/PlainNumericSerialMappingTest.php b/tests/phpunit/unit/includes/user/TempUser/PlainNumericSerialMappingTest.php new file mode 100644 index 000000000000..ff3d185ef763 --- /dev/null +++ b/tests/phpunit/unit/includes/user/TempUser/PlainNumericSerialMappingTest.php @@ -0,0 +1,16 @@ +<?php + +namespace MediaWiki\Tests\User\TempUser; + +use MediaWiki\User\TempUser\PlainNumericSerialMapping; +use PHPUnit\Framework\TestCase; + +/** + * @covers \MediaWiki\User\TempUser\PlainNumericSerialMapping + */ +class PlainNumericSerialMappingTest extends TestCase { + public function testGetSerialIdForIndex() { + $map = new PlainNumericSerialMapping( [] ); + $this->assertSame( '111', $map->getSerialIdForIndex( 111 ) ); + } +} diff --git a/tests/phpunit/unit/includes/user/UserNameUtilsTest.php b/tests/phpunit/unit/includes/user/UserNameUtilsTest.php index 17574091bc9a..e6298a821745 100644 --- a/tests/phpunit/unit/includes/user/UserNameUtilsTest.php +++ b/tests/phpunit/unit/includes/user/UserNameUtilsTest.php @@ -120,6 +120,12 @@ class UserNameUtilsTest extends MediaWikiUnitTestCase { $utils->isCreatable( 'FooBar' ), 'User names with no issues can be created' ); + + $tempUserName = '*Unregistered 1234'; + $this->assertFalse( + $utils->isCreatable( $tempUserName ), + 'UI account creation with the temp user prefix needs to be prevented' + ); } /** @@ -302,4 +308,17 @@ class UserNameUtilsTest extends MediaWikiUnitTestCase { ]; } + public function testIsTemp() { + $utils = $this->getDummyUserNameUtils(); + $this->assertFalse( $utils->isTemp( 'Some user' ) ); + $this->assertTrue( $utils->isTemp( '*Unregistered 1234' ) ); + $this->assertTrue( $utils->isTemp( '*1234' ) ); + } + + public function testGetTempPlaceholder() { + $utils = $this->getDummyUserNameUtils(); + $name = $utils->getTempPlaceholder(); + $this->assertSame( '*Unregistered *', $name ); + } + } |