62 'queryLogger' =>
MediaWiki\Logger\LoggerFactory::getInstance(
'DBQuery' ),
64 'chronologyCallback' =>
function ()
use ( &
$called ) {
69 $ld = DatabaseDomain::newFromId( $lb->getLocalDomainID() );
70 $this->assertEquals(
$wgDBname, $ld->getDatabase(),
'local domain DB set' );
71 $this->assertEquals( $this->
dbPrefix(), $ld->getTablePrefix(),
'local domain prefix set' );
72 $this->assertSame(
'my_test_wiki', $lb->resolveDomainID(
'my_test_wiki' ) );
79 $this->assertTrue( $dbw->getLBInfo(
'master' ),
'master shows as master' );
80 $this->assertTrue( $dbw->getFlag(
$dbw::DBO_TRX ),
"DBO_TRX set on master" );
84 $this->assertTrue(
$dbr->getLBInfo(
'master' ),
'DB_REPLICA also gets the master' );
87 if ( !$lb->getServerAttributes( $lb->getWriterIndex() )[$dbw::ATTR_DB_LEVEL_LOCKING] ) {
88 $dbwAuto = $lb->getConnection(
DB_MASTER, [],
false, $lb::CONN_TRX_AUTOCOMMIT );
90 $dbwAuto->getFlag(
$dbw::DBO_TRX ),
"No DBO_TRX with CONN_TRX_AUTOCOMMIT" );
91 $this->assertTrue( $dbw->getFlag(
$dbw::DBO_TRX ),
"DBO_TRX still set on master" );
92 $this->assertNotEquals(
93 $dbw, $dbwAuto,
"CONN_TRX_AUTOCOMMIT uses separate connection" );
95 $dbrAuto = $lb->getConnection(
DB_REPLICA, [],
false, $lb::CONN_TRX_AUTOCOMMIT );
97 $dbrAuto->getFlag(
$dbw::DBO_TRX ),
"No DBO_TRX with CONN_TRX_AUTOCOMMIT" );
98 $this->assertTrue(
$dbr->getFlag(
$dbw::DBO_TRX ),
"DBO_TRX still set on replica" );
99 $this->assertNotEquals(
100 $dbr, $dbrAuto,
"CONN_TRX_AUTOCOMMIT uses separate connection" );
102 $dbwAuto2 = $lb->getConnection(
DB_MASTER, [],
false, $lb::CONN_TRX_AUTOCOMMIT );
103 $this->assertEquals( $dbwAuto2, $dbwAuto,
"CONN_TRX_AUTOCOMMIT reuses connections" );
116 $this->assertTrue( $dbw->getLBInfo(
'master' ),
'master shows as master' );
119 $dbw->getLBInfo(
'clusterMasterHost' ),
120 'cluster master set' );
121 $this->assertTrue( $dbw->getFlag(
$dbw::DBO_TRX ),
"DBO_TRX set on master" );
125 $this->assertTrue(
$dbr->getLBInfo(
'replica' ),
'replica shows as replica' );
128 $dbr->getLBInfo(
'clusterMasterHost' ),
129 'cluster master set' );
133 if ( !$lb->getServerAttributes( $lb->getWriterIndex() )[$dbw::ATTR_DB_LEVEL_LOCKING] ) {
134 $dbwAuto = $lb->getConnection(
DB_MASTER, [],
false, $lb::CONN_TRX_AUTOCOMMIT );
136 $dbwAuto->getFlag(
$dbw::DBO_TRX ),
"No DBO_TRX with CONN_TRX_AUTOCOMMIT" );
137 $this->assertTrue( $dbw->getFlag(
$dbw::DBO_TRX ),
"DBO_TRX still set on master" );
138 $this->assertNotEquals(
139 $dbw, $dbwAuto,
"CONN_TRX_AUTOCOMMIT uses separate connection" );
141 $dbrAuto = $lb->getConnection(
DB_REPLICA, [],
false, $lb::CONN_TRX_AUTOCOMMIT );
143 $dbrAuto->getFlag(
$dbw::DBO_TRX ),
"No DBO_TRX with CONN_TRX_AUTOCOMMIT" );
144 $this->assertTrue(
$dbr->getFlag(
$dbw::DBO_TRX ),
"DBO_TRX still set on replica" );
145 $this->assertNotEquals(
146 $dbr, $dbrAuto,
"CONN_TRX_AUTOCOMMIT uses separate connection" );
148 $dbwAuto2 = $lb->getConnection(
DB_MASTER, [],
false, $lb::CONN_TRX_AUTOCOMMIT );
149 $this->assertEquals( $dbwAuto2, $dbwAuto,
"CONN_TRX_AUTOCOMMIT reuses connections" );
193 'servers' => $servers,
195 'queryLogger' =>
MediaWiki\Logger\LoggerFactory::getInstance(
'DBQuery' ),
202 $db->
delete(
'some_table', [
'id' => 57634126 ], __METHOD__ );
203 $this->fail(
'Write operation should have failed!' );
206 $constraint =
new PHPUnit_Framework_Constraint_StringContains(
'Write operation' );
208 if ( !$constraint->evaluate( $ex->getMessage(),
'',
true ) ) {
220 $useAtomicSection = in_array(
$db->
getType(), [
'sqlite',
'postgres',
'mssql' ],
true );
223 $this->assertNotEquals( $db::STATUS_TRX_ERROR,
$db->
trxStatus() );
225 if ( $useAtomicSection ) {
229 $this->assertNotSame(
231 $db->
query(
"CREATE TABLE $table (id INT, time INT)", __METHOD__ ),
234 $this->assertNotEquals( $db::STATUS_TRX_ERROR,
$db->
trxStatus() );
235 $this->assertNotSame(
237 $db->
query(
"DELETE FROM $table WHERE id=57634126", __METHOD__ ),
240 $this->assertNotEquals( $db::STATUS_TRX_ERROR,
$db->
trxStatus() );
242 if ( !$useAtomicSection ) {
248 $this->assertNotEquals( $db::STATUS_TRX_ERROR,
$db->
trxStatus() );
255 'dbname' =>
'my_unittest_wiki',
256 'tablePrefix' =>
'unittest_',
258 'dbDirectory' =>
"some_directory",
264 'servers' => $servers,
265 'localDomain' =>
new DatabaseDomain(
'my_unittest_wiki',
null,
'unittest_' ),
269 $this->assertTrue( $lb->getServerAttributes( 0 )[Database::ATTR_DB_LEVEL_LOCKING] );
274 'user' =>
'wikiuser',
275 'password' =>
'none',
276 'dbname' =>
'my_unittest_wiki',
277 'tablePrefix' =>
'unittest_',
283 'user' =>
'wikiuser',
284 'password' =>
'none',
285 'dbname' =>
'my_unittest_wiki',
286 'tablePrefix' =>
'unittest_',
293 'servers' => $servers,
294 'localDomain' =>
new DatabaseDomain(
'my_unittest_wiki',
null,
'unittest_' ),
298 $this->assertFalse( $lb->getServerAttributes( 1 )[Database::ATTR_DB_LEVEL_LOCKING] );
308 $i = $lb->getWriterIndex();
309 $this->assertEquals(
null, $lb->getAnyOpenConnection( $i ) );
311 $conn1 = $lb->getConnection( $i );
312 $this->assertNotEquals(
null, $conn1 );
313 $this->assertEquals( $conn1, $lb->getAnyOpenConnection( $i ) );
314 $this->assertFalse( $conn1->getFlag(
DBO_TRX ) );
316 $conn2 = $lb->getConnection( $i, [],
false, $lb::CONN_TRX_AUTOCOMMIT );
317 $this->assertNotEquals(
null, $conn2 );
318 $this->assertFalse( $conn2->getFlag(
DBO_TRX ) );
320 if ( $lb->getServerAttributes( $i )[Database::ATTR_DB_LEVEL_LOCKING] ) {
321 $this->assertEquals(
null,
322 $lb->getAnyOpenConnection( $i, $lb::CONN_TRX_AUTOCOMMIT ) );
323 $this->assertEquals( $conn1,
325 $i, [],
false, $lb::CONN_TRX_AUTOCOMMIT ), $lb::CONN_TRX_AUTOCOMMIT );
327 $this->assertEquals( $conn2,
328 $lb->getAnyOpenConnection( $i, $lb::CONN_TRX_AUTOCOMMIT ) );
329 $this->assertEquals( $conn2,
330 $lb->getConnection( $i, [],
false, $lb::CONN_TRX_AUTOCOMMIT ) );
332 $conn2->startAtomic( __METHOD__ );
334 $lb->getConnection( $i, [],
false, $lb::CONN_TRX_AUTOCOMMIT );
335 $conn2->endAtomic( __METHOD__ );
336 $this->fail(
"No exception thrown." );
337 }
catch ( DBUnexpectedError
$e ) {
339 'Wikimedia\Rdbms\LoadBalancer::openConnection: ' .
340 'CONN_TRX_AUTOCOMMIT handle has a transaction.',
344 $conn2->endAtomic( __METHOD__ );
368 'servers' => $servers,
372 $conn1 = $lb->openConnection( $lb->getWriterIndex(),
false );
373 $conn2 = $lb->openConnection( $lb->getWriterIndex(),
'' );
376 $lb->forEachOpenMasterConnection(
function ()
use ( &$count ) {
379 $this->assertEquals( 2, $count,
'Connection handle count' );
382 $lb->setTransactionListener(
'test-listener',
function ()
use ( &$tlCalls ) {
386 $lb->beginMasterChanges( __METHOD__ );
387 $bc = array_fill_keys( [
'a',
'b',
'c',
'd' ], 0 );
388 $conn1->onTransactionPreCommitOrIdle(
function ()
use ( &$bc, $conn1, $conn2 ) {
390 $conn2->onTransactionPreCommitOrIdle(
function ()
use ( &$bc, $conn1, $conn2 ) {
392 $conn1->onTransactionPreCommitOrIdle(
function ()
use ( &$bc, $conn1, $conn2 ) {
394 $conn1->onTransactionPreCommitOrIdle(
function ()
use ( &$bc, $conn1, $conn2 ) {
400 $lb->finalizeMasterChanges();
401 $lb->approveMasterChanges( [] );
402 $lb->commitMasterChanges( __METHOD__ );
403 $lb->runMasterTransactionIdleCallbacks();
404 $lb->runMasterTransactionListenerCallbacks();
406 $this->assertEquals( array_fill_keys( [
'a',
'b',
'c',
'd' ], 1 ), $bc );
407 $this->assertEquals( 2, $tlCalls );
410 $lb->beginMasterChanges( __METHOD__ );
411 $ac = array_fill_keys( [
'a',
'b',
'c',
'd' ], 0 );
412 $conn1->onTransactionCommitOrIdle(
function ()
use ( &$ac, $conn1, $conn2 ) {
414 $conn2->onTransactionCommitOrIdle(
function ()
use ( &$ac, $conn1, $conn2 ) {
416 $conn1->onTransactionCommitOrIdle(
function ()
use ( &$ac, $conn1, $conn2 ) {
418 $conn1->onTransactionCommitOrIdle(
function ()
use ( &$ac, $conn1, $conn2 ) {
424 $lb->finalizeMasterChanges();
425 $lb->approveMasterChanges( [] );
426 $lb->commitMasterChanges( __METHOD__ );
427 $lb->runMasterTransactionIdleCallbacks();
428 $lb->runMasterTransactionListenerCallbacks();
430 $this->assertEquals( array_fill_keys( [
'a',
'b',
'c',
'd' ], 1 ), $ac );
431 $this->assertEquals( 2, $tlCalls );
441 $wConn = $lb->getConnectionRef(
DB_MASTER );
442 $wConn2 = $lb->getConnectionRef( 0 );
444 $v = [
'value' =>
'1',
'1' ];
445 $sql =
'SELECT MAX(1) AS value';
446 foreach ( [ $rConn, $wConn, $wConn2 ]
as $conn ) {
449 $res = $conn->query( $sql, __METHOD__ );
450 $this->assertEquals( $v, $conn->fetchRow(
$res ) );
452 $res = $conn->query( $sql, __METHOD__, $conn::QUERY_REPLICA_ROLE );
453 $this->assertEquals( $v, $conn->fetchRow(
$res ) );
456 $wConn->getScopedLockAndFlush(
'key', __METHOD__, 1 );
457 $wConn2->getScopedLockAndFlush(
'key2', __METHOD__, 1 );
468 $rConn->query(
'DELETE FROM sometesttable WHERE 1=0' );
477 $rConn = $lb->getConnectionRef( 1 );
479 $rConn->query(
'DELETE FROM sometesttable WHERE 1=0' );
490 $rConn->insert(
'test', [
't' => 1 ], __METHOD__ );