wiki.techinc.nl/tests/phpunit/integration/includes/user/ActorStoreTest.php
Petr Pchelko 021206c232 User: use ActorNormalization to insert actor
While creating users, we have several interesting corner cases:

- When creating a new User, we actually rely on the 'unique'
constraint on actor_name. This is important if something calls
'User::createNew' with a name that is already occupied by an
existing anon actor with no user. This is quite a weird corner case,
but there's a test for that. We could probably assimilate this
nicly in actor store by checking whether the user id in the database
for the actor we found is the same as user id in the passed in user identity.
- Even more interesting use-case is 'subsuming' existing actors with
reserved user names. When we call User::newSystemUser, and there is
already an actor with the same reserved name, we 'subsume' that actor
and take over it's actor_id for our new system user. This can now be
done with an upsert. This state of having reserved actor with no user
is not easy to cause, but imports or updating from old MW versions
seem to be able to produce this state. Archeology revealed that
'subsuming' existing actor was added for installer.

Change-Id: I16b2f088217db0283215fc2ef5fb04a3742e1626
2021-04-15 13:42:39 -07:00

844 lines
26 KiB
PHP

<?php
namespace MediaWiki\Tests\User;
use CannotCreateActorException;
use IDatabase;
use InvalidArgumentException;
use MediaWiki\DAO\WikiAwareEntity;
use MediaWiki\MediaWikiServices;
use MediaWiki\User\ActorStore;
use MediaWiki\User\UserIdentity;
use MediaWiki\User\UserIdentityValue;
use MediaWiki\User\UserNameUtils;
use MediaWiki\User\UserSelectQueryBuilder;
use stdClass;
use User;
use Wikimedia\Assert\PreconditionException;
/**
* @covers \MediaWiki\User\ActorStore
* @coversDefaultClass \MediaWiki\User\ActorStore
* @group Database
*/
class ActorStoreTest extends ActorStoreTestBase {
public function provideGetActorById() {
yield 'getActorById, registered' => [
42, // $argument
new UserIdentityValue( 24, 'TestUser' ), // $expected
];
yield 'getActorById, anon' => [
43, // $argument
new UserIdentityValue( 0, self::IP ), // $expected
];
yield 'getActorById, non-existent' => [
4321231, // $argument
null, // $expected
];
yield 'getActorById, zero' => [
0, // $argument
null, // $expected
];
}
/**
* @dataProvider provideGetActorById
* @covers ::getActorById
*/
public function testGetActorById( $argument, ?UserIdentity $expected ) {
$actor = $this->getStore()->getActorById( $argument, $this->db );
if ( $expected ) {
$this->assertNotNull( $actor );
$this->assertSameActors( $expected, $actor );
// test caching
$cachedActor = $this->getStore()->getActorById( $argument, $this->db );
$this->assertSame( $actor, $cachedActor );
} else {
$this->assertNull( $actor );
}
}
public function provideGetActorByMethods() {
yield 'getUserIdentityByName, registered' => [
'getUserIdentityByName', // $method
'TestUser', // $argument
new UserIdentityValue( 24, 'TestUser' ), // $expected
];
yield 'getUserIdentityByName, non-existent' => [
'getUserIdentityByName', // $method
'TestUser_I_Do_Not_Exist', // $argument
null, // $expected
];
yield 'getUserIdentityByName, anon' => [
'getUserIdentityByName', // $method
self::IP, // $argument
new UserIdentityValue( 0, self::IP ), // $expected
];
yield 'getUserIdentityByName, anon, non-canonicalized IP' => [
'getUserIdentityByName', // $method
strtolower( self::IP ), // $argument
new UserIdentityValue( 0, self::IP ), // $expected
];
yield 'getUserIdentityByName, user name 0' => [
'getUserIdentityByName', // $method
'0', // $argument
new UserIdentityValue( 26, '0' ), // $expected
];
yield 'getUserIdentityByUserId, registered' => [
'getUserIdentityByUserId', // $method
24, // $argument
new UserIdentityValue( 24, 'TestUser' ), // $expected
];
yield 'getUserIdentityByUserId, non-exitent' => [
'getUserIdentityByUserId', // $method
2412312, // $argument
null, // $expected
];
yield 'getUserIdentityByUserId, zero' => [
'getUserIdentityByUserId', // $method
0, // $argument
null, // $expected
];
}
/**
* @dataProvider provideGetActorByMethods
* @covers ::getActorById
* @covers ::getUserIdentityByName
* @covers ::getUserIdentityByUserId
*/
public function testGetActorByMethods( string $method, $argument, ?UserIdentity $expected ) {
$actor = $this->getStore()->$method( $argument );
if ( $expected ) {
$this->assertNotNull( $actor );
$this->assertSameActors( $expected, $actor );
// test caching
$cachedActor = $this->getStore()->$method( $argument );
$this->assertSame( $actor, $cachedActor );
} else {
$this->assertNull( $actor );
}
}
public function provideUserIdentityValues() {
yield [ new UserIdentityValue( 24, 'TestUser' ) ];
yield [ new UserIdentityValue( 0, self::IP ) ];
}
/**
* @dataProvider provideUserIdentityValues
* @covers ::findActorId
* @covers ::getActorById
* @covers ::getUserIdentityByName
* @covers ::getUserIdentityByUserId
* @param UserIdentity $expected
*/
public function testSequentialCacheRetrieval( UserIdentity $expected ) {
// ensure UserIdentity is cached
$actorId = $this->getStore()->findActorId( $expected, $this->db );
$cachedActorId = $this->getStore()->findActorId( $expected, $this->db );
$this->assertSame( $actorId, $cachedActorId );
$cachedActorId = $this->getStore()->acquireActorId( $expected, $this->db );
$this->assertSame( $actorId, $cachedActorId );
$cached = $this->getStore()->getActorById( $actorId, $this->db );
$this->assertNotNull( $cached );
$this->assertSameActors( $expected, $cached );
$cached = $this->getStore()->getUserIdentityByName( $expected->getName() );
$this->assertNotNull( $cached );
$this->assertSameActors( $expected, $cached );
$userId = $expected->getId();
if ( $userId ) {
$cached = $this->getStore()->getUserIdentityByUserId( $userId );
$this->assertNotNull( $cached );
$this->assertSameActors( $expected, $cached );
}
}
/**
* @covers ::getActorById
*/
public function testGetActorByIdRealUser() {
$user = $this->getTestUser()->getUser();
$actor = $this->getStore()->getActorById( $user->getActorId(), $this->db );
$this->assertSameActors( $user, $actor );
}
/**
* @covers ::getUserIdentityByName
*/
public function testgetUserIdentityByNameRealUser() {
$user = $this->getTestUser()->getUser();
$actor = $this->getStore()->getUserIdentityByName( $user->getName() );
$this->assertSameActors( $user, $actor );
}
/**
* @covers ::getUserIdentityByUserId
*/
public function testGetUserIdentityByUserIdRealUser() {
$user = $this->getTestUser()->getUser();
$actor = $this->getStore()->getUserIdentityByUserId( $user->getId() );
$this->assertSameActors( $user, $actor );
}
public function provideGetUserIdentityByName_exception() {
yield 'empty' => [
'', // $name
];
}
/**
* @dataProvider provideGetUserIdentityByName_exception
* @covers ::getUserIdentityByName
*/
public function testGetUserIdentityByName_exception( string $name ) {
$this->expectException( InvalidArgumentException::class );
$this->getStore()->getUserIdentityByName( $name );
}
public function provideNewActorFromRow() {
yield 'full row' => [
UserIdentity::LOCAL, // $wikiId
(object)[ 'actor_id' => 42, 'actor_name' => 'TestUser', 'actor_user' => 24 ], // $row
new UserIdentityValue( 24, 'TestUser' ), // $expected
];
yield 'full row, strings' => [
UserIdentity::LOCAL, // $wikiId
(object)[ 'actor_id' => '42', 'actor_name' => 'TestUser', 'actor_user' => '24' ], // $row
new UserIdentityValue( 24, 'TestUser' ), // $expected
];
yield 'null user' => [
UserIdentity::LOCAL, // $wikiId
(object)[ 'actor_id' => '42', 'actor_name' => 'TestUser', 'actor_user' => null ], // $row
new UserIdentityValue( 0, 'TestUser' ), // $expected
];
yield 'zero user' => [
UserIdentity::LOCAL, // $wikiId
(object)[ 'actor_id' => '42', 'actor_name' => 'TestUser', 'actor_user' => 0 ], // $row
new UserIdentityValue( 0, 'TestUser' ), // $expected
];
yield 'cross-wiki' => [
'acmewiki', // $wikiId
(object)[ 'actor_id' => 42, 'actor_name' => 'TestUser', 'actor_user' => 24 ], // $row
new UserIdentityValue( 24, 'TestUser', 'acmewiki' ), // $expected
];
yield 'user name 0' => [
UserIdentity::LOCAL, // $wikiId
(object)[ 'actor_id' => '46', 'actor_name' => '0', 'actor_user' => 26 ], // $row
new UserIdentityValue( 26, '0' ), // $expected
];
}
/**
* @dataProvider provideNewActorFromRow
* @covers ::newActorFromRow
*/
public function testNewActorFromRow( $wikiId, stdClass $row, UserIdentity $expected ) {
$actor = $this->getStore( $wikiId )->newActorFromRow( $row );
$this->assertSameActors( $expected, $actor, $wikiId );
}
public function provideNewActorFromRow_exception() {
yield 'null actor' => [
(object)[ 'actor_id' => '0', 'actor_name' => 'TestUser', 'actor_user' => 0 ], // $row
];
yield 'zero actor' => [
(object)[ 'actor_id' => null, 'actor_name' => 'TestUser', 'actor_user' => 0 ], // $row
];
yield 'empty name' => [
(object)[ 'actor_id' => '10', 'actor_name' => '', 'actor_user' => 15 ], // $row
];
}
/**
* @dataProvider provideNewActorFromRow_exception
* @covers ::newActorFromRow
*/
public function testNewActorFromRow_exception( stdClass $row ) {
$this->expectException( InvalidArgumentException::class );
$this->getStore()->newActorFromRow( $row );
}
public function provideNewActorFromRowFields() {
yield 'full row' => [
UserIdentity::LOCAL, // $wikiId
42, // $actorId
'TestUser', // $name
24, // $userId
new UserIdentityValue( 24, 'TestUser' ), // $expected
];
yield 'full row, strings' => [
UserIdentity::LOCAL, // $wikiId
'42', // $actorId
'TestUser', // $name
'24', // $userId
new UserIdentityValue( 24, 'TestUser' ), // $expected
];
yield 'null user' => [
UserIdentity::LOCAL, // $wikiId
42, // $actorId
'TestUser', // $name
null, // $userId
new UserIdentityValue( 0, 'TestUser' ), // $expected
];
yield 'zero user' => [
UserIdentity::LOCAL, // $wikiId
42, // $actorId
'TestUser', // $name
0, // $userId
new UserIdentityValue( 0, 'TestUser' ), // $expected
];
yield 'user name 0' => [
UserIdentity::LOCAL, // $wikiId
46, // $actorId
'0', // $name
26, // $userId
new UserIdentityValue( 26, '0' ), // $expected
];
yield 'cross-wiki' => [
'acmewiki', // $wikiId
42, // $actorId
'TestUser', // $name
0, // $userId
new UserIdentityValue( 0, 'TestUser', 'acmewiki' ), // $expected
];
}
/**
* @dataProvider provideNewActorFromRowFields
* @covers ::newActorFromRowFields
*/
public function testNewActorFromRowFields( $wikiId, $actorId, $name, $userId, UserIdentity $expected ) {
$actor = $this->getStore( $wikiId )->newActorFromRowFields( $userId, $name, $actorId );
$this->assertSameActors( $expected, $actor, $wikiId );
}
public function provideNewActorFromRowFields_exception() {
yield 'empty name' => [
42, // $actorId
'', // $name
24, // $userId
];
yield 'null name' => [
42, // $actorId
null, // $name
24, // $userId
];
yield 'null actor' => [
null, // $actorId
'TestUser', // $name
null, // $userId
];
yield 'zero actor' => [
0, // $actorId
'TestUser', // $name
null, // $userId
];
}
/**
* @dataProvider provideNewActorFromRowFields_exception
* @covers ::newActorFromRowFields
*/
public function testNewActorFromRowFields_exception( $actorId, $name, $userId ) {
$this->expectException( InvalidArgumentException::class );
$this->getStore()->newActorFromRowFields( $userId, $name, $actorId );
}
public function provideFindActorId() {
yield 'anon, local' => [
static function () {
return new UserIdentityValue( 0, self::IP );
}, // $actorCallback
43, // $expected
];
yield 'anon, non-canonical, local' => [
static function () {
return new UserIdentityValue( 0, strtolower( self::IP ) );
}, // $actorCallback
43, // $expected
];
yield 'registered, local' => [
static function () {
return new UserIdentityValue( 24, 'TestUser' );
}, // $actorCallback
42, // $expected
];
yield 'registered, zero user name' => [
static function () {
return new UserIdentityValue( 26, '0', 0 );
}, // $actorCallback
46, // $expected
];
yield 'anon, non-existent, local' => [
static function () {
return new UserIdentityValue( 0, '127.1.2.3' );
}, // $actorCallback
null, // $expected
];
yield 'registered, non-existent, local' => [
static function () {
return new UserIdentityValue( 51, 'DoNotExist' );
}, // $actorCallback
null, // $expected
];
yield 'external, local' => [
static function () {
return new UserIdentityValue( 0, 'acme>TestUser' );
}, // $actorCallback
45, // $expected
];
yield 'anon User, local' => [
static function ( MediaWikiServices $serviceContainer ) {
return $serviceContainer->getUserFactory()->newAnonymous( self::IP );
}, // $actorCallback
43, // $expected
];
yield 'anon User, non-canonical, local' => [
static function ( MediaWikiServices $serviceContainer ) {
return $serviceContainer->getUserFactory()->newAnonymous( strtolower( self::IP ) );
}, // $actorCallback
43, // $expected
];
yield 'anon User, non-existent, local' => [
static function ( MediaWikiServices $serviceContainer ) {
return $serviceContainer->getUserFactory()->newAnonymous( '127.1.2.3' );
}, // $actorCallback
null, // $expected
];
yield 'anon, foreign' => [
static function () {
return new UserIdentityValue( 0, self::IP, 'acmewiki' );
}, // $actorCallback
43, // $expected
'acmewiki', // $wikiId
];
yield 'registered, foreign' => [
static function () {
return new UserIdentityValue( 24, 'TestUser', 'acmewiki' );
}, // $actorCallback
42, // $expected
'acmewiki', // $wikiId
];
}
/**
* @dataProvider provideFindActorId
* @covers ::findActorId
*/
public function testFindActorId( callable $actorCallback, $expected, $wikiId = WikiAwareEntity::LOCAL ) {
$actor = $actorCallback( $this->getServiceContainer() );
if ( $wikiId ) {
$this->executeWithForeignStore(
$wikiId,
function ( ActorStore $store ) use ( $expected, $actor ) {
$this->assertSame( $expected, $store->findActorId( $actor, $this->db ) );
if ( $actor instanceof User ) {
$this->assertSame( $expected ?: 0, $actor->getActorId() );
}
}
);
} else {
$this->assertSame( $expected, $this->getStore()->findActorId( $actor, $this->db ) );
if ( $actor instanceof User ) {
$this->assertSame( $expected ?: 0, $actor->getActorId() );
}
}
}
/**
* @covers ::findActorId
*/
public function testFindActorId_wikiMismatch() {
$this->markTestSkipped();
$this->expectException( PreconditionException::class );
$this->getStore()->findActorId(
new UserIdentityValue( 0, self::IP, 'acmewiki' ),
$this->db
);
}
public function provideFindActorIdByName() {
yield 'anon' => [
self::IP, // $actorCallback
43, // $expected
];
yield 'anon, non-canonical' => [
strtolower( self::IP ), // $actorCallback
43, // $expected
];
yield 'registered' => [
'TestUser', // $actorCallback
42, // $expected
];
yield 'registered, unnormalized' => [
'testUser', // $actorCallback
42, // $expected
];
yield 'registered, 0 user name' => [
'0', // $actorCallback
46, // $expected
];
yield 'external, local' => [
'acme>TestUser',
45, // $expected
];
yield 'anon, non-existent' => [
'127.1.2.3', // $actorCallback
null, // $expected
];
yield 'registered, non-existent' => [
'DoNotExist', // $actorCallback
null, // $expected
];
yield 'invalid' => [
'#', // $actorCallback
null, // $expected
];
}
/**
* @dataProvider provideFindActorIdByName
* @covers ::findActorId
*/
public function testFindActorIdByName( $name, $expected ) {
$this->assertSame( $expected, $this->getStore()->findActorIdByName( $name, $this->db ) );
}
public function provideAcquireActorId() {
yield 'anon' => [ static function () {
return new UserIdentityValue( 0, '127.3.2.1' );
} ];
yield 'registered' => [ static function () {
return new UserIdentityValue( 15, 'MyUser' );
} ];
yield 'User object' => [ static function ( $serviceContainer ) {
return $serviceContainer->getUserFactory()->newAnonymous( '127.4.3.2' );
} ];
}
/**
* @dataProvider provideAcquireActorId
* @covers ::acquireActorId
*/
public function testAcquireActorId( callable $userCallback ) {
$user = $userCallback( $this->getServiceContainer() );
$actorId = $this->getStore()->acquireActorId( $user, $this->db );
$this->assertTrue( $actorId > 0 );
if ( $user instanceof User ) {
$this->assertSame( $actorId, $user->getActorId() );
}
}
public function provideAcquireActorId_foreign() {
yield 'anon' => [
'userCallback' => static function () {
return new UserIdentityValue( 0, '127.3.2.1', 'acmewiki' );
},
'method' => 'acquireActorId'
];
yield 'registered' => [
'userCallback' => static function () {
return new UserIdentityValue( 15, 'MyUser', 'acmewiki' );
},
'method' => 'acquireActorId'
];
yield 'anon, new' => [
'userCallback' => static function () {
return new UserIdentityValue( 0, '128.9.8.7', 'acmewiki' );
},
'method' => 'createNewActor'
];
yield 'registered, new' => [
'userCallback' => static function () {
return new UserIdentityValue( 15, 'New MyUser', 'acmewiki' );
},
'method' => 'createNewActor'
];
}
/**
* @dataProvider provideAcquireActorId_foreign
* @covers ::acquireActorId
* @covers ::createNewActor
*/
public function testAcquireActorId_foreign( callable $userCallback, string $method ) {
$user = $userCallback( $this->getServiceContainer() );
$this->executeWithForeignStore(
'acmewiki',
function ( ActorStore $store ) use ( $user, $method ) {
$actorId = $store->$method( $user, $this->db );
$this->assertTrue( $actorId > 0 );
if ( $user instanceof User ) {
$this->assertSame( $actorId, $user->getActorId() );
}
}
);
}
/**
* @dataProvider provideAcquireActorId_foreign
* @covers ::acquireActorId
* @covers ::createNewActor
*/
public function testAcquireActorId_foreign_withDBConnection( callable $userCallback, string $method ) {
$user = $userCallback( $this->getServiceContainer() );
$this->executeWithForeignStore(
'acmewiki',
function ( ActorStore $store, IDatabase $dbw ) use ( $user, $method ) {
$actorId = $store->$method( $user, $dbw );
$this->assertTrue( $actorId > 0 );
if ( $user instanceof User ) {
$this->assertSame( $actorId, $user->getActorId() );
}
}
);
}
public function provideAcquireActorId_canNotCreate() {
yield 'usable name' => [
'actor' => new UserIdentityValue( 0, 'MyFancyUser' ),
'method' => 'acquireActorId'
];
yield 'empty name' => [
'actor' => new UserIdentityValue( 15, '' ),
'method' => 'acquireActorId'
];
yield 'usable name, new' => [
'actor' => new UserIdentityValue( 0, 'MyFancyUser' ),
'method' => 'createNewActor'
];
yield 'empty name, new' => [
'actor' => new UserIdentityValue( 15, '' ),
'method' => 'createNewActor'
];
yield 'usable name, replace' => [
'actor' => new UserIdentityValue( 0, 'MyFancyUser' ),
'method' => 'acquireSystemActorId'
];
yield 'empty name, replace' => [
'actor' => new UserIdentityValue( 15, '' ),
'method' => 'acquireSystemActorId'
];
yield 'existing non-anon, replace' => [
'actor' => new UserIdentityValue( 25, 'TestUser' ),
'method' => 'acquireSystemActorId'
];
}
/**
* @dataProvider provideAcquireActorId_canNotCreate
* @covers ::acquireActorId
* @covers ::createNewActor
* @covers ::acquireSystemActorId
*/
public function testAcquireActorId_canNotCreate( UserIdentityValue $actor, string $method ) {
// We rely on DB to protect against duplicates when inserting new actor
$this->setNullLogger( 'DBQuery' );
$this->expectException( CannotCreateActorException::class );
$this->getStore()->$method( $actor, $this->db );
}
/**
* @covers ::createNewActor
*/
public function testAcquireNowActorId_existing() {
// We rely on DB to protect against duplicates when inserting new actor
$this->setNullLogger( 'DBQuery' );
$this->expectException( CannotCreateActorException::class );
$this->getStore()->createNewActor( new UserIdentityValue( 24, 'TestUser' ), $this->db );
}
public function provideAcquireActorId_existing() {
yield 'anon' => [
new UserIdentityValue( 0, self::IP ), // $actor
43, // $expected
];
yield 'registered' => [
new UserIdentityValue( 24, 'TestUser' ), // $actor
42, // $expected
];
yield 'registered, 0 user name' => [
new UserIdentityValue( 26, '0' ), // $actor
46, // $expected
];
}
/**
* @dataProvider provideAcquireActorId_existing
* @covers ::acquireActorId
*/
public function testAcquireActorId_existing( UserIdentityValue $actor, int $expected ) {
$this->assertSame( $expected, $this->getStore()->acquireActorId( $actor, $this->db ) );
}
public function testAcquireActorId_domain_mismatch() {
$this->expectException( InvalidArgumentException::class );
$this->getStore( 'fancywiki' )->acquireActorId(
new UserIdentityValue( 15, 'Test', 'fancywiki' ),
$this->db
);
}
public function testcreateNewActor_domain_mismatch() {
$this->expectException( InvalidArgumentException::class );
$this->getStore( 'fancywiki' )->createNewActor(
new UserIdentityValue( 15, 'Test', 'fancywiki' ),
$this->db
);
}
public function testAcquireSystemActorId_domain_mismatch() {
$this->expectException( InvalidArgumentException::class );
$this->getStore( 'fancywiki' )->acquireSystemActorId(
new UserIdentityValue( 15, 'Test', 'fancywiki' ),
$this->db
);
}
/**
* @covers ::acquireActorId
*/
public function testAcquireActorId_wikiMismatch() {
$this->markTestSkipped();
$this->expectException( PreconditionException::class );
$this->getStore()->acquireActorId(
new UserIdentityValue( 0, self::IP, 'acmewiki' ),
$this->db
);
}
/**
* @covers ::acquireActorId
*/
public function testAcquireActorId_clearCacheOnRollback() {
$rolledBackActor = new UserIdentityValue( 0, '127.0.0.10' );
$store = $this->getStore();
$this->db->startAtomic( __METHOD__ );
$rolledBackActorId = $store->acquireActorId( $rolledBackActor, $this->db );
$this->assertTrue( $rolledBackActorId > 0 );
$foundActorId = $store->findActorId( $rolledBackActor, $this->db );
$this->assertSame( $rolledBackActorId, $foundActorId );
$this->db->rollback( __METHOD__ );
// Insert some other user identity using another store
// so that we take over the rolled back actor ID.
$anotherActor = new UserIdentityValue( 0, '127.0.0.11' );
$anotherActorId = $this->getStore()->acquireActorId( $anotherActor, $this->db );
// Make sure no actor ID associated with rolled back actor.
$foundActorIdAfterRollback = $store->findActorId( $rolledBackActor, $this->db );
$this->assertNull( $foundActorIdAfterRollback );
// Make sure we can acquire new actor ID for the rolled back actor
$newActorId = $store->acquireActorId( $rolledBackActor, $this->db );
$this->assertTrue( $newActorId > 0 );
$this->assertNotSame( $newActorId, $rolledBackActorId );
// Make sure we find correct actor by rolled back actor ID
$this->assertSameActors( $anotherActor, $store->getActorById( $anotherActorId, $this->db ) );
}
/**
* @covers ::acquireSystemActorId
*/
public function testAcquireSystemActorId() {
$store = $this->getStore();
$originalActor = new UserIdentityValue( 0, '129.0.0.1' );
$actorId = $store->createNewActor( $originalActor, $this->db );
$this->assertTrue( $actorId > 0, 'Sanity: acquired new actor ID' );
$updatedActor = new UserIdentityValue( 56789, '129.0.0.1' );
$this->assertSame( $actorId, $store->acquireSystemActorId( $updatedActor, $this->db ) );
$this->assertSame( 56789, $store->getActorById( $actorId, $this->db )->getId() );
// Try with another store to verify not just cache was updated
$this->assertSame( 56789, $this->getStore()->getActorById( $actorId, $this->db )->getId() );
}
/**
* @covers ::acquireSystemActorId
*/
public function testAcquireSystemActorId_replaceReserved() {
$this->setMwGlobals( [
'wgReservedUsernames' => [ 'RESERVED' ],
] );
$store = $this->getStore();
$originalActor = new UserIdentityValue( 0, 'RESERVED' );
$actorId = $store->createNewActor( $originalActor, $this->db );
$this->assertTrue( $actorId > 0, 'Sanity: acquired new actor ID' );
$updatedActor = new UserIdentityValue( 80, 'RESERVED' );
$this->assertSame( $actorId, $store->acquireSystemActorId( $updatedActor, $this->db ) );
$this->assertSame( 80, $store->getActorById( $actorId, $this->db )->getId() );
// Try with another store to verify not just cache was updated
$this->assertSame( 80, $this->getStore()->getActorById( $actorId, $this->db )->getId() );
}
/**
* @covers ::acquireSystemActorId
*/
public function testAcquireSystemActorId_assignsNew() {
$store = $this->getStore();
$newActor = new UserIdentityValue( 456789, '129.0.0.2' );
$newActorId = $store->acquireSystemActorId( $newActor, $this->db );
$this->assertTrue( $newActorId > 0 );
$this->assertSame( 456789, $store->getActorById( $newActorId, $this->db )->getId() );
// Try with another store to verify not just cache was updated
$this->assertSame( 456789, $this->getStore()->getActorById( $newActorId, $this->db )->getId() );
}
/**
* @covers ::getUnknownActor
*/
public function testGetUnknownActor() {
$store = $this->getStore();
$unknownActor = $store->getUnknownActor();
$this->assertInstanceOf( UserIdentity::class, $unknownActor );
$this->assertSame( ActorStore::UNKNOWN_USER_NAME, $unknownActor->getName() );
$this->assertSameActors( $unknownActor, $store->getUnknownActor() );
}
public function provideNormalizeUserName() {
yield [ strtolower( self::IP ), UserNameUtils::RIGOR_NONE, self::IP ];
yield [ 'acme>test', UserNameUtils::RIGOR_VALID, 'acme>test' ];
yield [ 'test_this', UserNameUtils::RIGOR_VALID, 'Test this' ];
yield [ 'foo#bar', UserNameUtils::RIGOR_VALID, null ];
yield [ 'foo|bar', UserNameUtils::RIGOR_VALID, null ];
yield [ '_', UserNameUtils::RIGOR_NONE, '_' ];
yield [ 'test', UserNameUtils::RIGOR_NONE, 'test' ];
yield [ '', UserNameUtils::RIGOR_NONE, null ];
yield [ '0', UserNameUtils::RIGOR_NONE, '0' ];
}
/**
* @dataProvider provideNormalizeUserName
*/
public function testNormalizeUserName( $name, $rigor, $expected ) {
$store = $this->getStore();
$this->assertSame( $expected, $store->normalizeUserName( $name, $rigor ) );
}
public function testNewSelectQueryBuilderWithoutDB() {
$store = $this->getStore();
$queryBuilder = $store->newSelectQueryBuilder();
$this->assertInstanceOf( UserSelectQueryBuilder::class, $queryBuilder );
}
public function testNewSelectQueryBuilderWithDB() {
$store = $this->getStore();
$queryBuilder = $store->newSelectQueryBuilder( $this->db );
$this->assertInstanceOf( UserSelectQueryBuilder::class, $queryBuilder );
}
}