Merge "Corrected grammatical error."
[lhc/web/wiklou.git] / tests / phpunit / includes / user / UserTest.php
index f84be3f..aeeae11 100644 (file)
@@ -5,6 +5,7 @@ define( 'NS_UNITTEST_TALK', 5601 );
 
 use MediaWiki\Block\Restriction\PageRestriction;
 use MediaWiki\Block\Restriction\NamespaceRestriction;
+use MediaWiki\Block\SystemBlock;
 use MediaWiki\MediaWikiServices;
 use MediaWiki\User\UserIdentityValue;
 use Wikimedia\TestingAccessWrapper;
@@ -28,7 +29,7 @@ class UserTest extends MediaWikiTestCase {
                $this->setMwGlobals( [
                        'wgGroupPermissions' => [],
                        'wgRevokePermissions' => [],
-                       'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
+                       'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_NEW,
                ] );
                $this->overrideMwServices();
 
@@ -504,20 +505,24 @@ class UserTest extends MediaWikiTestCase {
        }
 
        /**
+        * @covers User::isRegistered
         * @covers User::isLoggedIn
         * @covers User::isAnon
         */
        public function testLoggedIn() {
                $user = $this->getMutableTestUser()->getUser();
+               $this->assertTrue( $user->isRegistered() );
                $this->assertTrue( $user->isLoggedIn() );
                $this->assertFalse( $user->isAnon() );
 
                // Non-existent users are perceived as anonymous
                $user = User::newFromName( 'UTNonexistent' );
+               $this->assertFalse( $user->isRegistered() );
                $this->assertFalse( $user->isLoggedIn() );
                $this->assertTrue( $user->isAnon() );
 
                $user = new User;
+               $this->assertFalse( $user->isRegistered() );
                $this->assertFalse( $user->isLoggedIn() );
                $this->assertTrue( $user->isAnon() );
        }
@@ -617,7 +622,7 @@ class UserTest extends MediaWikiTestCase {
 
                // Confirm that the block has been applied as required.
                $this->assertTrue( $user1->isLoggedIn() );
-               $this->assertTrue( $user1->isBlocked() );
+               $this->assertInstanceOf( Block::class, $user1->getBlock() );
                $this->assertEquals( Block::TYPE_USER, $block->getType() );
                $this->assertTrue( $block->isAutoblocking() );
                $this->assertGreaterThanOrEqual( 1, $block->getId() );
@@ -638,7 +643,7 @@ class UserTest extends MediaWikiTestCase {
                $this->assertNotEquals( $user1->getToken(), $user2->getToken() );
                $this->assertTrue( $user2->isAnon() );
                $this->assertFalse( $user2->isLoggedIn() );
-               $this->assertTrue( $user2->isBlocked() );
+               $this->assertInstanceOf( Block::class, $user2->getBlock() );
                // Non-strict type-check.
                $this->assertEquals( true, $user2->getBlock()->isAutoblocking(), 'Autoblock does not work' );
                // Can't directly compare the objects because of member type differences.
@@ -654,7 +659,7 @@ class UserTest extends MediaWikiTestCase {
                $user3 = User::newFromSession( $request3 );
                $user3->load();
                $this->assertTrue( $user3->isLoggedIn() );
-               $this->assertTrue( $user3->isBlocked() );
+               $this->assertInstanceOf( Block::class, $user3->getBlock() );
                $this->assertEquals( true, $user3->getBlock()->isAutoblocking() ); // Non-strict type-check.
 
                // Clean up.
@@ -694,7 +699,7 @@ class UserTest extends MediaWikiTestCase {
 
                // 2. Test that the cookie IS NOT present.
                $this->assertTrue( $user->isLoggedIn() );
-               $this->assertTrue( $user->isBlocked() );
+               $this->assertInstanceOf( Block::class, $user->getBlock() );
                $this->assertEquals( Block::TYPE_USER, $block->getType() );
                $this->assertTrue( $block->isAutoblocking() );
                $this->assertGreaterThanOrEqual( 1, $user->getBlockId() );
@@ -739,7 +744,7 @@ class UserTest extends MediaWikiTestCase {
 
                // 2. Test the cookie's expiry timestamp.
                $this->assertTrue( $user1->isLoggedIn() );
-               $this->assertTrue( $user1->isBlocked() );
+               $this->assertInstanceOf( Block::class, $user1->getBlock() );
                $this->assertEquals( Block::TYPE_USER, $block->getType() );
                $this->assertTrue( $block->isAutoblocking() );
                $this->assertGreaterThanOrEqual( 1, $user1->getBlockId() );
@@ -783,6 +788,7 @@ class UserTest extends MediaWikiTestCase {
                        RequestContext::getMain()->setRequest( $request );
                        TestingAccessWrapper::newFromObject( $user )->mRequest = $request;
                        $request->getSession()->setUser( $user );
+                       $this->overrideMwServices();
                };
                $this->setMwGlobals( 'wgSoftBlockRanges', [ '10.0.0.0/8' ] );
 
@@ -799,7 +805,7 @@ class UserTest extends MediaWikiTestCase {
                $request->setIP( '10.20.30.40' );
                $setSessionUser( $wgUser, $request );
                $block = $wgUser->getBlock();
-               $this->assertInstanceOf( Block::class, $block );
+               $this->assertInstanceOf( SystemBlock::class, $block );
                $this->assertSame( 'wgSoftBlockRanges', $block->getSystemBlockType() );
 
                // Make sure the block is really soft
@@ -849,7 +855,7 @@ class UserTest extends MediaWikiTestCase {
                $user2->load();
                $this->assertTrue( $user2->isAnon() );
                $this->assertFalse( $user2->isLoggedIn() );
-               $this->assertFalse( $user2->isBlocked() );
+               $this->assertNull( $user2->getBlock() );
 
                // Clean up.
                $block->delete();
@@ -885,7 +891,7 @@ class UserTest extends MediaWikiTestCase {
                $user1 = User::newFromSession( $request1 );
                $user1->mBlock = $block;
                $user1->load();
-               $this->assertTrue( $user1->isBlocked() );
+               $this->assertInstanceOf( Block::class, $user1->getBlock() );
 
                // 2. Create a new request, set the cookie to just the block ID, and the user should
                // still get blocked when they log in again.
@@ -897,7 +903,7 @@ class UserTest extends MediaWikiTestCase {
                $this->assertNotEquals( $user1->getToken(), $user2->getToken() );
                $this->assertTrue( $user2->isAnon() );
                $this->assertFalse( $user2->isLoggedIn() );
-               $this->assertTrue( $user2->isBlocked() );
+               $this->assertInstanceOf( Block::class, $user2->getBlock() );
                $this->assertEquals( true, $user2->getBlock()->isAutoblocking() ); // Non-strict type-check.
 
                // Clean up.
@@ -980,7 +986,7 @@ class UserTest extends MediaWikiTestCase {
                $this->assertFalse( $user->getExperienceLevel() );
        }
 
-       public static function provideIsLocallBlockedProxy() {
+       public static function provideIsLocallyBlockedProxy() {
                return [
                        [ '1.2.3.4', '1.2.3.4' ],
                        [ '1.2.3.4', '1.2.3.0/16' ],
@@ -988,10 +994,12 @@ class UserTest extends MediaWikiTestCase {
        }
 
        /**
-        * @dataProvider provideIsLocallBlockedProxy
+        * @dataProvider provideIsLocallyBlockedProxy
         * @covers User::isLocallyBlockedProxy
         */
        public function testIsLocallyBlockedProxy( $ip, $blockListEntry ) {
+               $this->hideDeprecated( 'User::isLocallyBlockedProxy' );
+
                $this->setMwGlobals(
                        'wgProxyList', []
                );
@@ -1048,6 +1056,75 @@ class UserTest extends MediaWikiTestCase {
                $user = User::newFromId( $id );
                $this->assertTrue( $user->getActorId() > 0, 'Actor ID can be retrieved for user loaded by ID' );
 
+               $user2 = User::newFromActorId( $user->getActorId() );
+               $this->assertEquals( $user->getId(), $user2->getId(),
+                       'User::newFromActorId works for an existing user' );
+
+               $row = $this->db->selectRow( 'user', User::selectFields(), [ 'user_id' => $id ], __METHOD__ );
+               $user = User::newFromRow( $row );
+               $this->assertTrue( $user->getActorId() > 0,
+                       'Actor ID can be retrieved for user loaded with User::selectFields()' );
+
+               $user = User::newFromId( $id );
+               $user->setName( 'UserTestActorId4-renamed' );
+               $user->saveSettings();
+               $this->assertEquals(
+                       $user->getName(),
+                       $this->db->selectField(
+                               'actor', 'actor_name', [ 'actor_id' => $user->getActorId() ], __METHOD__
+                       ),
+                       'User::saveSettings updates actor table for name change'
+               );
+
+               // For sanity
+               $ip = '192.168.12.34';
+               $this->db->delete( 'actor', [ 'actor_name' => $ip ], __METHOD__ );
+
+               $user = User::newFromName( $ip, false );
+               $this->assertFalse( $user->getActorId() > 0, 'Anonymous user has no actor ID by default' );
+               $this->assertTrue( $user->getActorId( $this->db ) > 0,
+                       'Actor ID can be created for an anonymous user' );
+
+               $user = User::newFromName( $ip, false );
+               $this->assertTrue( $user->getActorId() > 0, 'Actor ID can be loaded for an anonymous user' );
+               $user2 = User::newFromActorId( $user->getActorId() );
+               $this->assertEquals( $user->getName(), $user2->getName(),
+                       'User::newFromActorId works for an anonymous user' );
+       }
+
+       /**
+        * Actor tests with SCHEMA_COMPAT_READ_OLD
+        *
+        * The only thing different from testActorId() is the behavior if the actor
+        * row doesn't exist in the DB, since with SCHEMA_COMPAT_READ_NEW that
+        * situation can't happen. But we copy all the other tests too just for good measure.
+        *
+        * @covers User::newFromActorId
+        */
+       public function testActorId_old() {
+               $this->setMwGlobals( [
+                       'wgActorTableSchemaMigrationStage' => SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD,
+               ] );
+               $this->overrideMwServices();
+
+               $domain = MediaWikiServices::getInstance()->getDBLoadBalancer()->getLocalDomainID();
+               $this->hideDeprecated( 'User::selectFields' );
+
+               // Newly-created user has an actor ID
+               $user = User::createNew( 'UserTestActorIdOld1' );
+               $id = $user->getId();
+               $this->assertTrue( $user->getActorId() > 0, 'User::createNew sets an actor ID' );
+
+               $user = User::newFromName( 'UserTestActorIdOld2' );
+               $user->addToDatabase();
+               $this->assertTrue( $user->getActorId() > 0, 'User::addToDatabase sets an actor ID' );
+
+               $user = User::newFromName( 'UserTestActorIdOld1' );
+               $this->assertTrue( $user->getActorId() > 0, 'Actor ID can be retrieved for user loaded by name' );
+
+               $user = User::newFromId( $id );
+               $this->assertTrue( $user->getActorId() > 0, 'Actor ID can be retrieved for user loaded by ID' );
+
                $user2 = User::newFromActorId( $user->getActorId() );
                $this->assertEquals( $user->getId(), $user2->getId(),
                        'User::newFromActorId works for an existing user' );
@@ -1066,7 +1143,7 @@ class UserTest extends MediaWikiTestCase {
                $this->assertFalse( $user->getActorId() > 0, 'No Actor ID by default if none in database' );
                $this->assertTrue( $user->getActorId( $this->db ) > 0, 'Actor ID can be created if none in db' );
 
-               $user->setName( 'UserTestActorId4-renamed' );
+               $user->setName( 'UserTestActorIdOld4-renamed' );
                $user->saveSettings();
                $this->assertEquals(
                        $user->getName(),
@@ -1129,6 +1206,15 @@ class UserTest extends MediaWikiTestCase {
                $this->assertSame( 'Bogus', $test->getName() );
                $this->assertSame( 654321, $test->getActorId() );
 
+               // Loading remote user by name from remote wiki should succeed
+               $test = User::newFromAnyId( null, 'Bogus', null, 'foo' );
+               $this->assertSame( 0, $test->getId() );
+               $this->assertSame( 'Bogus', $test->getName() );
+               $this->assertSame( 0, $test->getActorId() );
+               $test = User::newFromAnyId( 123456, 'Bogus', 654321, 'foo' );
+               $this->assertSame( 0, $test->getId() );
+               $this->assertSame( 0, $test->getActorId() );
+
                // Exceptional cases
                try {
                        User::newFromAnyId( null, null, null );
@@ -1140,6 +1226,13 @@ class UserTest extends MediaWikiTestCase {
                        $this->fail( 'Expected exception not thrown' );
                } catch ( InvalidArgumentException $ex ) {
                }
+
+               // Loading remote user by id from remote wiki should fail
+               try {
+                       User::newFromAnyId( 123456, null, 654321, 'foo' );
+                       $this->fail( 'Expected exception not thrown' );
+               } catch ( InvalidArgumentException $ex ) {
+               }
        }
 
        /**
@@ -1459,7 +1552,7 @@ class UserTest extends MediaWikiTestCase {
                $user = User::newFromSession( $request );
 
                // logged in users should be inmune to cookie block of type ip/range
-               $this->assertFalse( $user->isBlocked() );
+               $this->assertNull( $user->getBlock() );
 
                // cookie is being cleared
                $cookies = $request->response()->getCookies();
@@ -1506,4 +1599,38 @@ class UserTest extends MediaWikiTestCase {
                $updater->setContent( 'main', $content );
                return $updater->saveRevision( CommentStoreComment::newUnsavedComment( $comment ) );
        }
+
+       /**
+        * @covers User::idFromName
+        */
+       public function testExistingIdFromName() {
+               $this->assertTrue(
+                       array_key_exists( $this->user->getName(), User::$idCacheByName ),
+                       'Test user should already be in the id cache.'
+               );
+               $this->assertSame(
+                       $this->user->getId(), User::idFromName( $this->user->getName() ),
+                       'Id is correctly retreived from the cache.'
+               );
+               $this->assertSame(
+                       $this->user->getId(), User::idFromName( $this->user->getName(), User::READ_LATEST ),
+                       'Id is correctly retreived from the database.'
+               );
+       }
+
+       /**
+        * @covers User::idFromName
+        */
+       public function testNonExistingIdFromName() {
+               $this->assertFalse(
+                       array_key_exists( 'NotExisitngUser', User::$idCacheByName ),
+                       'Non exisitng user should not be in the id cache.'
+               );
+               $this->assertSame( null, User::idFromName( 'NotExisitngUser' ) );
+               $this->assertTrue(
+                       array_key_exists( 'NotExisitngUser', User::$idCacheByName ),
+                       'Username will be cached when requested once.'
+               );
+               $this->assertSame( null, User::idFromName( 'NotExisitngUser' ) );
+       }
 }