use Wikimedia\Rdbms\Database;
use Wikimedia\Rdbms\LoadBalancer;
use Wikimedia\Rdbms\LoadMonitorNull;
+use Wikimedia\TestingAccessWrapper;
/**
* @group Database
+ * @group medium
* @covers \Wikimedia\Rdbms\LoadBalancer
*/
class LoadBalancerTest extends MediaWikiTestCase {
- private function makeServerConfig() {
+ private function makeServerConfig( $flags = DBO_DEFAULT ) {
global $wgDBserver, $wgDBname, $wgDBuser, $wgDBpassword, $wgDBtype, $wgSQLiteDataDir;
return [
'type' => $wgDBtype,
'dbDirectory' => $wgSQLiteDataDir,
'load' => 0,
- 'flags' => DBO_TRX // REPEATABLE-READ for consistency
+ 'flags' => $flags
];
}
/**
- * @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;
$called = false;
$lb = new LoadBalancer( [
- 'servers' => [ $this->makeServerConfig() ],
+ // Simulate web request with DBO_TRX
+ 'servers' => [ $this->makeServerConfig( DBO_TRX ) ],
'queryLogger' => MediaWiki\Logger\LoggerFactory::getInstance( 'DBQuery' ),
'localDomain' => new DatabaseDomain( $wgDBname, null, $this->dbPrefix() ),
'chronologyCallback' => function () use ( &$called ) {
}
] );
+ $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' );
$this->assertSame( 'my_test_wiki', $lb->resolveDomainID( 'my_test_wiki' ) );
$this->assertSame( $ld->getId(), $lb->resolveDomainID( false ) );
$this->assertSame( $ld->getId(), $lb->resolveDomainID( $ld ) );
-
$this->assertFalse( $called );
+
$dbw = $lb->getConnection( DB_MASTER );
$this->assertTrue( $called );
$this->assertTrue( $dbw->getLBInfo( 'master' ), 'master shows as master' );
$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, $wgDBname, $wgDBuser, $wgDBpassword, $wgDBtype, $wgSQLiteDataDir;
+ global $wgDBserver;
- $servers = [
- [ // master
- 'host' => $wgDBserver,
- 'dbname' => $wgDBname,
- 'tablePrefix' => $this->dbPrefix(),
- 'user' => $wgDBuser,
- 'password' => $wgDBpassword,
- 'type' => $wgDBtype,
- 'dbDirectory' => $wgSQLiteDataDir,
- 'load' => 0,
- 'flags' => DBO_TRX // REPEATABLE-READ for consistency
- ],
- [ // emulated replica
- 'host' => $wgDBserver,
- 'dbname' => $wgDBname,
- 'tablePrefix' => $this->dbPrefix(),
- 'user' => $wgDBuser,
- 'password' => $wgDBpassword,
- 'type' => $wgDBtype,
- 'dbDirectory' => $wgSQLiteDataDir,
- 'load' => 100,
- 'flags' => DBO_TRX // REPEATABLE-READ for consistency
- ]
- ];
+ // Simulate web request with DBO_TRX
+ $lb = $this->newMultiServerLocalLoadBalancer( [], [ 'flags' => DBO_TRX ] );
- $lb = new LoadBalancer( [
- 'servers' => $servers,
- 'localDomain' => new DatabaseDomain( $wgDBname, null, $this->dbPrefix() ),
- 'queryLogger' => MediaWiki\Logger\LoggerFactory::getInstance( 'DBQuery' ),
- 'loadMonitorClass' => LoadMonitorNull::class
- ] );
+ $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' );
$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 );
$lb->closeAll();
}
+ private function newSingleServerLocalLoadBalancer() {
+ global $wgDBname;
+
+ return new LoadBalancer( [
+ 'servers' => [ $this->makeServerConfig() ],
+ 'localDomain' => new DatabaseDomain( $wgDBname, null, $this->dbPrefix() )
+ ] );
+ }
+
+ private function newMultiServerLocalLoadBalancer(
+ $lbExtra = [], $srvExtra = [], $masterOnly = false
+ ) {
+ global $wgDBserver, $wgDBname, $wgDBuser, $wgDBpassword, $wgDBtype, $wgSQLiteDataDir;
+
+ $servers = [
+ // Master DB
+ 0 => $srvExtra + [
+ 'host' => $wgDBserver,
+ 'dbname' => $wgDBname,
+ 'tablePrefix' => $this->dbPrefix(),
+ 'user' => $wgDBuser,
+ 'password' => $wgDBpassword,
+ 'type' => $wgDBtype,
+ 'dbDirectory' => $wgSQLiteDataDir,
+ 'load' => $masterOnly ? 100 : 0,
+ ],
+ // Main replica DBs
+ 1 => $srvExtra + [
+ 'host' => $wgDBserver,
+ 'dbname' => $wgDBname,
+ 'tablePrefix' => $this->dbPrefix(),
+ 'user' => $wgDBuser,
+ 'password' => $wgDBpassword,
+ 'type' => $wgDBtype,
+ 'dbDirectory' => $wgSQLiteDataDir,
+ 'load' => $masterOnly ? 0 : 100,
+ ],
+ 2 => $srvExtra + [
+ 'host' => $wgDBserver,
+ 'dbname' => $wgDBname,
+ 'tablePrefix' => $this->dbPrefix(),
+ 'user' => $wgDBuser,
+ 'password' => $wgDBpassword,
+ 'type' => $wgDBtype,
+ 'dbDirectory' => $wgSQLiteDataDir,
+ 'load' => $masterOnly ? 0 : 100,
+ ],
+ // RC replica DBs
+ 3 => $srvExtra + [
+ 'host' => $wgDBserver,
+ 'dbname' => $wgDBname,
+ 'tablePrefix' => $this->dbPrefix(),
+ 'user' => $wgDBuser,
+ 'password' => $wgDBpassword,
+ 'type' => $wgDBtype,
+ 'dbDirectory' => $wgSQLiteDataDir,
+ 'load' => 0,
+ 'groupLoads' => [
+ 'recentchanges' => 100,
+ 'watchlist' => 100
+ ],
+ ],
+ // Logging replica DBs
+ 4 => $srvExtra + [
+ 'host' => $wgDBserver,
+ 'dbname' => $wgDBname,
+ 'tablePrefix' => $this->dbPrefix(),
+ 'user' => $wgDBuser,
+ 'password' => $wgDBpassword,
+ 'type' => $wgDBtype,
+ 'dbDirectory' => $wgSQLiteDataDir,
+ 'load' => 0,
+ 'groupLoads' => [
+ 'logging' => 100
+ ],
+ ],
+ 5 => $srvExtra + [
+ 'host' => $wgDBserver,
+ 'dbname' => $wgDBname,
+ 'tablePrefix' => $this->dbPrefix(),
+ 'user' => $wgDBuser,
+ 'password' => $wgDBpassword,
+ 'type' => $wgDBtype,
+ 'dbDirectory' => $wgSQLiteDataDir,
+ 'load' => 0,
+ 'groupLoads' => [
+ 'logging' => 100
+ ],
+ ],
+ // Maintenance query replica DBs
+ 6 => $srvExtra + [
+ 'host' => $wgDBserver,
+ 'dbname' => $wgDBname,
+ 'tablePrefix' => $this->dbPrefix(),
+ 'user' => $wgDBuser,
+ 'password' => $wgDBpassword,
+ 'type' => $wgDBtype,
+ 'dbDirectory' => $wgSQLiteDataDir,
+ 'load' => 0,
+ 'groupLoads' => [
+ 'vslow' => 100
+ ],
+ ],
+ // 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( $lbExtra + [
+ 'servers' => $servers,
+ 'localDomain' => new DatabaseDomain( $wgDBname, null, $this->dbPrefix() ),
+ 'queryLogger' => MediaWiki\Logger\LoggerFactory::getInstance( 'DBQuery' ),
+ 'loadMonitorClass' => LoadMonitorNull::class
+ ] );
+ }
+
private function assertWriteForbidden( Database $db ) {
try {
$db->delete( 'some_table', [ 'id' => 57634126 ], __METHOD__ );
}
/**
- * @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() {
- global $wgDBname;
-
- $lb = new LoadBalancer( [
- 'servers' => [ $this->makeServerConfig() ],
- 'localDomain' => new DatabaseDomain( $wgDBname, null, $this->dbPrefix() )
- ] );
+ $lb = $this->newSingleServerLocalLoadBalancer();
$i = $lb->getWriterIndex();
$this->assertEquals( null, $lb->getAnyOpenConnection( $i ) );
+
$conn1 = $lb->getConnection( $i );
$this->assertNotEquals( null, $conn1 );
$this->assertEquals( $conn1, $lb->getAnyOpenConnection( $i ) );
+ $this->assertFalse( $conn1->getFlag( DBO_TRX ) );
+
$conn2 = $lb->getConnection( $i, [], false, $lb::CONN_TRX_AUTOCOMMIT );
$this->assertNotEquals( null, $conn2 );
+ $this->assertFalse( $conn2->getFlag( DBO_TRX ) );
+
if ( $lb->getServerAttributes( $i )[Database::ATTR_DB_LEVEL_LOCKING] ) {
$this->assertEquals( null,
$lb->getAnyOpenConnection( $i, $lb::CONN_TRX_AUTOCOMMIT ) );
$this->fail( "No exception thrown." );
} catch ( DBUnexpectedError $e ) {
$this->assertEquals(
- 'Wikimedia\Rdbms\LoadBalancer::openConnection: ' .
- 'CONN_TRX_AUTOCOMMIT handle has a transaction.',
+ 'Handle requested with CONN_TRX_AUTOCOMMIT yet it has a transaction',
$e->getMessage()
);
}
$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;
'type' => $wgDBtype,
'dbDirectory' => $wgSQLiteDataDir,
'load' => 0,
- 'flags' => DBO_TRX // REPEATABLE-READ for consistency
+ 'flags' => DBO_TRX // simulate a web request with DBO_TRX
],
];
$conn1->close();
$conn2->close();
}
+
+ /**
+ * @covers \Wikimedia\Rdbms\LoadBalancer::getConnectionRef
+ * @covers \Wikimedia\Rdbms\LoadBalancer::getConnection()
+ */
+ public function testDBConnRefReadsMasterAndReplicaRoles() {
+ $lb = $this->newSingleServerLocalLoadBalancer();
+
+ $rConn = $lb->getConnectionRef( DB_REPLICA );
+ $wConn = $lb->getConnectionRef( DB_MASTER );
+ $wConn2 = $lb->getConnectionRef( 0 );
+
+ $v = [ 'value' => '1', '1' ];
+ $sql = 'SELECT MAX(1) AS value';
+ foreach ( [ $rConn, $wConn, $wConn2 ] as $conn ) {
+ $conn->clearFlag( $conn::DBO_TRX );
+
+ $res = $conn->query( $sql, __METHOD__ );
+ $this->assertEquals( $v, $conn->fetchRow( $res ) );
+
+ $res = $conn->query( $sql, __METHOD__, $conn::QUERY_REPLICA_ROLE );
+ $this->assertEquals( $v, $conn->fetchRow( $res ) );
+ }
+
+ $wConn->getScopedLockAndFlush( 'key', __METHOD__, 1 );
+ $wConn2->getScopedLockAndFlush( 'key2', __METHOD__, 1 );
+ }
+
+ /**
+ * @covers \Wikimedia\Rdbms\LoadBalancer::getConnectionRef
+ * @expectedException \Wikimedia\Rdbms\DBReadOnlyRoleError
+ */
+ public function testDBConnRefWritesReplicaRole() {
+ $lb = $this->newSingleServerLocalLoadBalancer();
+
+ $rConn = $lb->getConnectionRef( DB_REPLICA );
+
+ $rConn->query( 'DELETE FROM sometesttable WHERE 1=0' );
+ }
+
+ /**
+ * @covers \Wikimedia\Rdbms\LoadBalancer::getConnectionRef
+ * @expectedException \Wikimedia\Rdbms\DBReadOnlyRoleError
+ */
+ public function testDBConnRefWritesReplicaRoleIndex() {
+ $lb = $this->newMultiServerLocalLoadBalancer();
+
+ $rConn = $lb->getConnectionRef( 1 );
+
+ $rConn->query( 'DELETE FROM sometesttable WHERE 1=0' );
+ }
+
+ /**
+ * @covers \Wikimedia\Rdbms\LoadBalancer::getConnectionRef
+ * @expectedException \Wikimedia\Rdbms\DBReadOnlyRoleError
+ */
+ public function testDBConnRefWritesReplicaRoleInsert() {
+ $lb = $this->newMultiServerLocalLoadBalancer();
+
+ $rConn = $lb->getConnectionRef( DB_REPLICA );
+
+ $rConn->insert( 'test', [ 't' => 1 ], __METHOD__ );
+ }
+
+ /**
+ * @covers \Wikimedia\Rdbms\LoadBalancer::getConnection()
+ */
+ public function testGetConnectionRefDefaultGroup() {
+ $lb = $this->newMultiServerLocalLoadBalancer( [ 'defaultGroup' => 'vslow' ] );
+ $lbWrapper = TestingAccessWrapper::newFromObject( $lb );
+
+ $rVslow = $lb->getConnectionRef( DB_REPLICA );
+ $vslowIndexPicked = $rVslow->getLBInfo( 'serverIndex' );
+
+ $this->assertSame( $vslowIndexPicked, $lbWrapper->getExistingReaderIndex( 'vslow' ) );
+ }
+
+ /**
+ * @covers \Wikimedia\Rdbms\LoadBalancer::getConnection()
+ */
+ public function testGetConnectionRefUnknownDefaultGroup() {
+ $lb = $this->newMultiServerLocalLoadBalancer( [ 'defaultGroup' => 'invalid' ] );
+
+ $this->assertInstanceOf(
+ IDatabase::class,
+ $lb->getConnectionRef( DB_REPLICA )
+ );
+ }
+
+ /**
+ * @covers \Wikimedia\Rdbms\LoadBalancer::getConnection()
+ * @covers \Wikimedia\Rdbms\LoadBalancer::getMaintenanceConnectionRef()
+ */
+ public function testQueryGroupIndex() {
+ $lb = $this->newMultiServerLocalLoadBalancer( [ 'defaultGroup' => false ] );
+ /** @var LoadBalancer $lbWrapper */
+ $lbWrapper = TestingAccessWrapper::newFromObject( $lb );
+
+ $rGeneric = $lb->getConnectionRef( DB_REPLICA );
+ $mainIndexPicked = $rGeneric->getLBInfo( 'serverIndex' );
+
+ $this->assertEquals(
+ $mainIndexPicked,
+ $lbWrapper->getExistingReaderIndex( $lb::GROUP_GENERIC )
+ );
+ $this->assertTrue( in_array( $mainIndexPicked, [ 1, 2 ] ) );
+ for ( $i = 0; $i < 300; ++$i ) {
+ $rLog = $lb->getConnectionRef( DB_REPLICA, [] );
+ $this->assertEquals(
+ $mainIndexPicked,
+ $rLog->getLBInfo( 'serverIndex' ),
+ "Main index unchanged" );
+ }
+
+ $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' );
+
+ $this->assertEquals( $logIndexPicked, $lbWrapper->getExistingReaderIndex( 'logging' ) );
+ $this->assertTrue( in_array( $logIndexPicked, [ 4, 5 ] ) );
+
+ for ( $i = 0; $i < 300; ++$i ) {
+ $rLog = $lb->getConnectionRef( DB_REPLICA, [ 'logging', 'watchlist' ] );
+ $this->assertEquals(
+ $logIndexPicked, $rLog->getLBInfo( 'serverIndex' ), "Index unchanged" );
+ }
+
+ $rVslow = $lb->getConnectionRef( DB_REPLICA, [ 'vslow', 'logging' ] );
+ $vslowIndexPicked = $rVslow->getLBInfo( 'serverIndex' );
+
+ $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 ) );
+ }
}