Merge "Title: Title::getSubpage should not lose the interwiki prefix"
[lhc/web/wiklou.git] / tests / phpunit / includes / db / LoadBalancerTest.php
index 169e4bf..8510109 100644 (file)
@@ -30,6 +30,7 @@ use Wikimedia\TestingAccessWrapper;
 
 /**
  * @group Database
+ * @group medium
  * @covers \Wikimedia\Rdbms\LoadBalancer
  */
 class LoadBalancerTest extends MediaWikiTestCase {
@@ -50,8 +51,11 @@ class LoadBalancerTest extends MediaWikiTestCase {
        }
 
        /**
-        * @covers LoadBalancer::getLocalDomainID()
-        * @covers LoadBalancer::resolveDomainID()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getConnection()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getLocalDomainID()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::resolveDomainID()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::haveIndex()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::isNonZeroLoad()
         */
        public function testWithoutReplica() {
                global $wgDBname;
@@ -67,6 +71,15 @@ class LoadBalancerTest extends MediaWikiTestCase {
                        }
                ] );
 
+               $this->assertEquals( 1, $lb->getServerCount() );
+               $this->assertFalse( $lb->hasReplicaServers() );
+               $this->assertFalse( $lb->hasStreamingReplicaServers() );
+
+               $this->assertTrue( $lb->haveIndex( 0 ) );
+               $this->assertFalse( $lb->haveIndex( 1 ) );
+               $this->assertFalse( $lb->isNonZeroLoad( 0 ) );
+               $this->assertFalse( $lb->isNonZeroLoad( 1 ) );
+
                $ld = DatabaseDomain::newFromId( $lb->getLocalDomainID() );
                $this->assertEquals( $wgDBname, $ld->getDatabase(), 'local domain DB set' );
                $this->assertEquals( $this->dbPrefix(), $ld->getTablePrefix(), 'local domain prefix set' );
@@ -107,11 +120,38 @@ class LoadBalancerTest extends MediaWikiTestCase {
                $lb->closeAll();
        }
 
+       /**
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getConnection()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getReaderIndex()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getWriterIndex()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::haveIndex()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::isNonZeroLoad()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getServerName()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getServerInfo()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getServerType()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getServerAttributes()
+        */
        public function testWithReplica() {
                global $wgDBserver;
 
                // Simulate web request with DBO_TRX
-               $lb = $this->newMultiServerLocalLoadBalancer( DBO_TRX );
+               $lb = $this->newMultiServerLocalLoadBalancer( [], [ 'flags' => DBO_TRX ] );
+
+               $this->assertEquals( 8, $lb->getServerCount() );
+               $this->assertTrue( $lb->hasReplicaServers() );
+               $this->assertTrue( $lb->hasStreamingReplicaServers() );
+
+               $this->assertTrue( $lb->haveIndex( 0 ) );
+               $this->assertTrue( $lb->haveIndex( 1 ) );
+               $this->assertFalse( $lb->isNonZeroLoad( 0 ) );
+               $this->assertTrue( $lb->isNonZeroLoad( 1 ) );
+
+               for ( $i = 0; $i < $lb->getServerCount(); ++$i ) {
+                       $this->assertType( 'string', $lb->getServerName( $i ) );
+                       $this->assertType( 'array', $lb->getServerInfo( $i ) );
+                       $this->assertType( 'string', $lb->getServerType( $i ) );
+                       $this->assertType( 'array', $lb->getServerAttributes( $i ) );
+               }
 
                $dbw = $lb->getConnection( DB_MASTER );
                $this->assertTrue( $dbw->getLBInfo( 'master' ), 'master shows as master' );
@@ -124,12 +164,14 @@ class LoadBalancerTest extends MediaWikiTestCase {
 
                $dbr = $lb->getConnection( DB_REPLICA );
                $this->assertTrue( $dbr->getLBInfo( 'replica' ), 'replica shows as replica' );
+               $this->assertTrue( $dbr->isReadOnly(), 'replica shows as replica' );
                $this->assertEquals(
                        ( $wgDBserver != '' ) ? $wgDBserver : 'localhost',
                        $dbr->getLBInfo( 'clusterMasterHost' ),
                        'cluster master set' );
                $this->assertTrue( $dbr->getFlag( $dbw::DBO_TRX ), "DBO_TRX set on replica" );
                $this->assertWriteForbidden( $dbr );
+               $this->assertEquals( $dbr->getLBInfo( 'serverIndex' ), $lb->getReaderIndex() );
 
                if ( !$lb->getServerAttributes( $lb->getWriterIndex() )[$dbw::ATTR_DB_LEVEL_LOCKING] ) {
                        $dbwAuto = $lb->getConnection( DB_MASTER, [], false, $lb::CONN_TRX_AUTOCOMMIT );
@@ -162,12 +204,14 @@ class LoadBalancerTest extends MediaWikiTestCase {
                ] );
        }
 
-       private function newMultiServerLocalLoadBalancer( $flags = DBO_DEFAULT ) {
+       private function newMultiServerLocalLoadBalancer(
+               $lbExtra = [], $srvExtra = [], $masterOnly = false
+       ) {
                global $wgDBserver, $wgDBname, $wgDBuser, $wgDBpassword, $wgDBtype, $wgSQLiteDataDir;
 
                $servers = [
                        // Master DB
-                       0 => [
+                       0 => $srvExtra + [
                                'host' => $wgDBserver,
                                'dbname' => $wgDBname,
                                'tablePrefix' => $this->dbPrefix(),
@@ -175,11 +219,10 @@ class LoadBalancerTest extends MediaWikiTestCase {
                                'password' => $wgDBpassword,
                                'type' => $wgDBtype,
                                'dbDirectory' => $wgSQLiteDataDir,
-                               'load' => 0,
-                               'flags' => $flags
+                               'load' => $masterOnly ? 100 : 0,
                        ],
                        // Main replica DBs
-                       1 => [
+                       1 => $srvExtra + [
                                'host' => $wgDBserver,
                                'dbname' => $wgDBname,
                                'tablePrefix' => $this->dbPrefix(),
@@ -187,10 +230,9 @@ class LoadBalancerTest extends MediaWikiTestCase {
                                'password' => $wgDBpassword,
                                'type' => $wgDBtype,
                                'dbDirectory' => $wgSQLiteDataDir,
-                               'load' => 100,
-                               'flags' => $flags
+                               'load' => $masterOnly ? 0 : 100,
                        ],
-                       2 => [
+                       2 => $srvExtra + [
                                'host' => $wgDBserver,
                                'dbname' => $wgDBname,
                                'tablePrefix' => $this->dbPrefix(),
@@ -198,11 +240,10 @@ class LoadBalancerTest extends MediaWikiTestCase {
                                'password' => $wgDBpassword,
                                'type' => $wgDBtype,
                                'dbDirectory' => $wgSQLiteDataDir,
-                               'load' => 100,
-                               'flags' => $flags
+                               'load' => $masterOnly ? 0 : 100,
                        ],
                        // RC replica DBs
-                       3 => [
+                       3 => $srvExtra + [
                                'host' => $wgDBserver,
                                'dbname' => $wgDBname,
                                'tablePrefix' => $this->dbPrefix(),
@@ -215,10 +256,9 @@ class LoadBalancerTest extends MediaWikiTestCase {
                                        'recentchanges' => 100,
                                        'watchlist' => 100
                                ],
-                               'flags' => $flags
                        ],
                        // Logging replica DBs
-                       4 => [
+                       4 => $srvExtra + [
                                'host' => $wgDBserver,
                                'dbname' => $wgDBname,
                                'tablePrefix' => $this->dbPrefix(),
@@ -230,9 +270,8 @@ class LoadBalancerTest extends MediaWikiTestCase {
                                'groupLoads' => [
                                        'logging' => 100
                                ],
-                               'flags' => $flags
                        ],
-                       5 => [
+                       5 => $srvExtra + [
                                'host' => $wgDBserver,
                                'dbname' => $wgDBname,
                                'tablePrefix' => $this->dbPrefix(),
@@ -244,10 +283,9 @@ class LoadBalancerTest extends MediaWikiTestCase {
                                'groupLoads' => [
                                        'logging' => 100
                                ],
-                               'flags' => $flags
                        ],
                        // Maintenance query replica DBs
-                       6 => [
+                       6 => $srvExtra + [
                                'host' => $wgDBserver,
                                'dbname' => $wgDBname,
                                'tablePrefix' => $this->dbPrefix(),
@@ -259,11 +297,25 @@ class LoadBalancerTest extends MediaWikiTestCase {
                                'groupLoads' => [
                                        'vslow' => 100
                                ],
-                               'flags' => $flags
+                       ],
+                       // Replica DB that only has a copy of some static tables
+                       7 => $srvExtra + [
+                               'host' => $wgDBserver,
+                               'dbname' => $wgDBname,
+                               'tablePrefix' => $this->dbPrefix(),
+                               'user' => $wgDBuser,
+                               'password' => $wgDBpassword,
+                               'type' => $wgDBtype,
+                               'dbDirectory' => $wgSQLiteDataDir,
+                               'load' => 0,
+                               'groupLoads' => [
+                                       'archive' => 100
+                               ],
+                               'is static' => true
                        ]
                ];
 
-               return new LoadBalancer( [
+               return new LoadBalancer( $lbExtra + [
                        'servers' => $servers,
                        'localDomain' => new DatabaseDomain( $wgDBname, null, $this->dbPrefix() ),
                        'queryLogger' => MediaWiki\Logger\LoggerFactory::getInstance( 'DBQuery' ),
@@ -373,8 +425,10 @@ class LoadBalancerTest extends MediaWikiTestCase {
        }
 
        /**
-        * @covers LoadBalancer::openConnection()
-        * @covers LoadBalancer::getAnyOpenConnection()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getConnection()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::openConnection()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getAnyOpenConnection()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getWriterIndex()
         */
        function testOpenConnection() {
                $lb = $this->newSingleServerLocalLoadBalancer();
@@ -420,6 +474,18 @@ class LoadBalancerTest extends MediaWikiTestCase {
                $lb->closeAll();
        }
 
+       /**
+        * @covers \Wikimedia\Rdbms\LoadBalancer::openConnection()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getWriterIndex()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::forEachOpenMasterConnection()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::setTransactionListener()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::beginMasterChanges()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::finalizeMasterChanges()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::approveMasterChanges()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::commitMasterChanges()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::runMasterTransactionIdleCallbacks()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::runMasterTransactionListenerCallbacks()
+        */
        public function testTransactionCallbackChains() {
                global $wgDBserver, $wgDBname, $wgDBuser, $wgDBpassword, $wgDBtype, $wgSQLiteDataDir;
 
@@ -507,6 +573,10 @@ class LoadBalancerTest extends MediaWikiTestCase {
                $conn2->close();
        }
 
+       /**
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getConnectionRef
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getConnection()
+        */
        public function testDBConnRefReadsMasterAndReplicaRoles() {
                $lb = $this->newSingleServerLocalLoadBalancer();
 
@@ -531,6 +601,7 @@ class LoadBalancerTest extends MediaWikiTestCase {
        }
 
        /**
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getConnectionRef
         * @expectedException \Wikimedia\Rdbms\DBReadOnlyRoleError
         */
        public function testDBConnRefWritesReplicaRole() {
@@ -542,6 +613,7 @@ class LoadBalancerTest extends MediaWikiTestCase {
        }
 
        /**
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getConnectionRef
         * @expectedException \Wikimedia\Rdbms\DBReadOnlyRoleError
         */
        public function testDBConnRefWritesReplicaRoleIndex() {
@@ -553,6 +625,7 @@ class LoadBalancerTest extends MediaWikiTestCase {
        }
 
        /**
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getConnectionRef
         * @expectedException \Wikimedia\Rdbms\DBReadOnlyRoleError
         */
        public function testDBConnRefWritesReplicaRoleInsert() {
@@ -563,8 +636,12 @@ class LoadBalancerTest extends MediaWikiTestCase {
                $rConn->insert( 'test', [ 't' => 1 ], __METHOD__ );
        }
 
+       /**
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getConnection()
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getMaintenanceConnectionRef()
+        */
        public function testQueryGroupIndex() {
-               $lb = $this->newMultiServerLocalLoadBalancer();
+               $lb = $this->newMultiServerLocalLoadBalancer( [ 'defaultGroup' => false ] );
                /** @var LoadBalancer $lbWrapper */
                $lbWrapper = TestingAccessWrapper::newFromObject( $lb );
 
@@ -583,9 +660,13 @@ class LoadBalancerTest extends MediaWikiTestCase {
 
                $rRC = $lb->getConnectionRef( DB_REPLICA, [ 'recentchanges' ] );
                $rWL = $lb->getConnectionRef( DB_REPLICA, [ 'watchlist' ] );
+               $rRCMaint = $lb->getMaintenanceConnectionRef( DB_REPLICA, [ 'recentchanges' ] );
+               $rWLMaint = $lb->getMaintenanceConnectionRef( DB_REPLICA, [ 'watchlist' ] );
 
                $this->assertEquals( 3, $rRC->getLBInfo( 'serverIndex' ) );
                $this->assertEquals( 3, $rWL->getLBInfo( 'serverIndex' ) );
+               $this->assertEquals( 3, $rRCMaint->getLBInfo( 'serverIndex' ) );
+               $this->assertEquals( 3, $rWLMaint->getLBInfo( 'serverIndex' ) );
 
                $rLog = $lb->getConnectionRef( DB_REPLICA, [ 'logging', 'watchlist' ] );
                $logIndexPicked = $rLog->getLBInfo( 'serverIndex' );
@@ -605,4 +686,37 @@ class LoadBalancerTest extends MediaWikiTestCase {
                $this->assertEquals( $vslowIndexPicked, $lbWrapper->getExistingReaderIndex( 'vslow' ) );
                $this->assertEquals( 6, $vslowIndexPicked );
        }
+
+       public function testNonZeroMasterLoad() {
+               $lb = $this->newMultiServerLocalLoadBalancer( [], [ 'flags' => DBO_DEFAULT ], true );
+               // Make sure that no infinite loop occurs (T226678)
+               $rGeneric = $lb->getConnectionRef( DB_REPLICA );
+               $this->assertEquals( $lb->getWriterIndex(), $rGeneric->getLBInfo( 'serverIndex' ) );
+       }
+
+       /**
+        * @covers \Wikimedia\Rdbms\LoadBalancer::getLazyConnectionRef
+        */
+       public function testGetLazyConnectionRef() {
+               $lb = $this->newMultiServerLocalLoadBalancer();
+
+               $rMaster = $lb->getLazyConnectionRef( DB_MASTER );
+               $rReplica = $lb->getLazyConnectionRef( 1 );
+               $this->assertFalse( $lb->getAnyOpenConnection( 0 ) );
+               $this->assertFalse( $lb->getAnyOpenConnection( 1 ) );
+
+               $rMaster->getType();
+               $rReplica->getType();
+               $rMaster->getDomainID();
+               $rReplica->getDomainID();
+               $this->assertFalse( $lb->getAnyOpenConnection( 0 ) );
+               $this->assertFalse( $lb->getAnyOpenConnection( 1 ) );
+
+               $rMaster->query( "SELECT 1", __METHOD__ );
+               $this->assertNotFalse( $lb->getAnyOpenConnection( 0 ) );
+
+               $rReplica->query( "SELECT 1", __METHOD__ );
+               $this->assertNotFalse( $lb->getAnyOpenConnection( 0 ) );
+               $this->assertNotFalse( $lb->getAnyOpenConnection( 1 ) );
+       }
 }