X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=tests%2Fphpunit%2Fincludes%2Fdb%2FLBFactoryTest.php;h=0395bff2b4158282f0b37c6af91cb1175d0e076a;hb=52af356cad3799ebec3826e1e4743d76a114da3e;hp=4097760ad6154bf76b296aa90e0a088cf7182498;hpb=61aab0ff9912221d51b7e40d508a8e733257aadb;p=lhc%2Fweb%2Fwiklou.git diff --git a/tests/phpunit/includes/db/LBFactoryTest.php b/tests/phpunit/includes/db/LBFactoryTest.php index 4097760ad6..0395bff2b4 100644 --- a/tests/phpunit/includes/db/LBFactoryTest.php +++ b/tests/phpunit/includes/db/LBFactoryTest.php @@ -153,53 +153,132 @@ class LBFactoryTest extends MediaWikiTestCase { $lb->closeAll(); } - public function testLBFactoryMulti() { + public function testLBFactoryMultiConns() { + $factory = $this->newLBFactoryMultiLBs(); + + $dbw = $factory->getMainLB()->getConnection( DB_MASTER ); + $this->assertTrue( $dbw->getLBInfo( 'master' ), 'master shows as master' ); + + $dbr = $factory->getMainLB()->getConnection( DB_REPLICA ); + $this->assertTrue( $dbr->getLBInfo( 'replica' ), 'slave shows as slave' ); + + // Destructor should trigger without round stage errors + unset( $factory ); + } + + public function testLBFactoryMultiRoundCallbacks() { + $called = 0; + $countLBsFunc = function ( LBFactoryMulti $factory ) { + $count = 0; + $factory->forEachLB( function () use ( &$count ) { + ++$count; + } ); + + return $count; + }; + + $factory = $this->newLBFactoryMultiLBs(); + $this->assertEquals( 0, $countLBsFunc( $factory ) ); + $dbw = $factory->getMainLB()->getConnection( DB_MASTER ); + $this->assertEquals( 1, $countLBsFunc( $factory ) ); + // Test that LoadBalancer instances made during pre-commit callbacks in do not + // throw DBTransactionError due to transaction ROUND_* stages being mismatched. + $factory->beginMasterChanges( __METHOD__ ); + $dbw->onTransactionPreCommitOrIdle( function () use ( $factory, &$called ) { + ++$called; + // Trigger s1 LoadBalancer instantiation during "finalize" stage. + // There is no s1wiki DB to select so it is not in getConnection(), + // but this fools getMainLB() at least. + $factory->getMainLB( 's1wiki' )->getConnection( DB_MASTER ); + } ); + $factory->commitMasterChanges( __METHOD__ ); + $this->assertEquals( 1, $called ); + $this->assertEquals( 2, $countLBsFunc( $factory ) ); + $factory->shutdown(); + $factory->closeAll(); + + $called = 0; + $factory = $this->newLBFactoryMultiLBs(); + $this->assertEquals( 0, $countLBsFunc( $factory ) ); + $dbw = $factory->getMainLB()->getConnection( DB_MASTER ); + $this->assertEquals( 1, $countLBsFunc( $factory ) ); + // Test that LoadBalancer instances made during pre-commit callbacks in do not + // throw DBTransactionError due to transaction ROUND_* stages being mismatched.hrow + // DBTransactionError due to transaction ROUND_* stages being mismatched. + $factory->beginMasterChanges( __METHOD__ ); + $dbw->query( "SELECT 1 as t", __METHOD__ ); + $dbw->onTransactionResolution( function () use ( $factory, &$called ) { + ++$called; + // Trigger s1 LoadBalancer instantiation during "finalize" stage. + // There is no s1wiki DB to select so it is not in getConnection(), + // but this fools getMainLB() at least. + $factory->getMainLB( 's1wiki' )->getConnection( DB_MASTER ); + } ); + $factory->commitMasterChanges( __METHOD__ ); + $this->assertEquals( 1, $called ); + $this->assertEquals( 2, $countLBsFunc( $factory ) ); + $factory->shutdown(); + $factory->closeAll(); + + $factory = $this->newLBFactoryMultiLBs(); + $dbw = $factory->getMainLB()->getConnection( DB_MASTER ); + // DBTransactionError should not be thrown + $ran = 0; + $dbw->onTransactionPreCommitOrIdle( function () use ( &$ran ) { + ++$ran; + } ); + $factory->commitAll( __METHOD__ ); + $this->assertEquals( 1, $ran ); + + $factory->shutdown(); + $factory->closeAll(); + } + + private function newLBFactoryMultiLBs() { global $wgDBserver, $wgDBname, $wgDBuser, $wgDBpassword, $wgDBtype, $wgSQLiteDataDir; - $factory = new LBFactoryMulti( [ - 'sectionsByDB' => [], + return new LBFactoryMulti( [ + 'sectionsByDB' => [ + 's1wiki' => 's1', + ], 'sectionLoads' => [ + 's1' => [ + 'test-db3' => 0, + 'test-db4' => 100, + ], 'DEFAULT' => [ 'test-db1' => 0, 'test-db2' => 100, - ], + ] ], 'serverTemplate' => [ - 'dbname' => $wgDBname, - 'user' => $wgDBuser, - 'password' => $wgDBpassword, - 'type' => $wgDBtype, + 'dbname' => $wgDBname, + 'user' => $wgDBuser, + 'password' => $wgDBpassword, + 'type' => $wgDBtype, 'dbDirectory' => $wgSQLiteDataDir, - 'flags' => DBO_DEFAULT + 'flags' => DBO_DEFAULT ], 'hostsByName' => [ - 'test-db1' => $wgDBserver, - 'test-db2' => $wgDBserver + 'test-db1' => $wgDBserver, + 'test-db2' => $wgDBserver, + 'test-db3' => $wgDBserver, + 'test-db4' => $wgDBserver ], 'loadMonitorClass' => LoadMonitorNull::class ] ); - $lb = $factory->getMainLB(); - - $dbw = $lb->getConnection( DB_MASTER ); - $this->assertTrue( $dbw->getLBInfo( 'master' ), 'master shows as master' ); - - $dbr = $lb->getConnection( DB_REPLICA ); - $this->assertTrue( $dbr->getLBInfo( 'replica' ), 'slave shows as slave' ); - - $factory->shutdown(); - $lb->closeAll(); } /** * @covers \Wikimedia\Rdbms\ChronologyProtector */ public function testChronologyProtector() { - // (a) First HTTP request - $m1Pos = new MySQLMasterPos( 'db1034-bin.000976', '843431247' ); - $m2Pos = new MySQLMasterPos( 'db1064-bin.002400', '794074907' ); - $now = microtime( true ); + // (a) First HTTP request + $m1Pos = new MySQLMasterPos( 'db1034-bin.000976/843431247', $now ); + $m2Pos = new MySQLMasterPos( 'db1064-bin.002400/794074907', $now ); + // Master DB 1 $mockDB1 = $this->getMockBuilder( DatabaseMysqli::class ) ->disableOriginalConstructor() @@ -345,32 +424,25 @@ class LBFactoryTest extends MediaWikiTestCase { } public function testNiceDomains() { - global $wgDBname, $wgDBtype; - - if ( $wgDBtype === 'sqlite' ) { - $tmpDir = $this->getNewTempDirectory(); - $dbPath = "$tmpDir/unit_test_db.sqlite"; - file_put_contents( $dbPath, '' ); - $tempFsFile = new TempFSFile( $dbPath ); - $tempFsFile->autocollect(); - } else { - $dbPath = null; + global $wgDBname; + + if ( wfGetDB( DB_MASTER )->databasesAreIndependent() ) { + self::markTestSkipped( "Skipping tests about selecting DBs: not applicable" ); + return; } $factory = $this->newLBFactoryMulti( [], - [ 'dbFilePath' => $dbPath ] + [] ); $lb = $factory->getMainLB(); - if ( $wgDBtype !== 'sqlite' ) { - $db = $lb->getConnectionRef( DB_MASTER ); - $this->assertEquals( - wfWikiID(), - $db->getDomainID() - ); - unset( $db ); - } + $db = $lb->getConnectionRef( DB_MASTER ); + $this->assertEquals( + wfWikiID(), + $db->getDomainID() + ); + unset( $db ); /** @var Database $db */ $db = $lb->getConnection( DB_MASTER, [], '' ); @@ -411,6 +483,7 @@ class LBFactoryTest extends MediaWikiTestCase { $db = $lb->getConnection( DB_MASTER ); // local domain connection $factory->setDomainPrefix( 'my_' ); + $this->assertEquals( $wgDBname, $db->getDBname() ); $this->assertEquals( "$wgDBname-my_", $db->getDomainID() @@ -431,23 +504,17 @@ class LBFactoryTest extends MediaWikiTestCase { } public function testTrickyDomain() { - global $wgDBtype, $wgDBname; - - if ( $wgDBtype === 'sqlite' ) { - $tmpDir = $this->getNewTempDirectory(); - $dbPath = "$tmpDir/unit_test_db.sqlite"; - file_put_contents( $dbPath, '' ); - $tempFsFile = new TempFSFile( $dbPath ); - $tempFsFile->autocollect(); - } else { - $dbPath = null; + global $wgDBname; + + if ( wfGetDB( DB_MASTER )->databasesAreIndependent() ) { + self::markTestSkipped( "Skipping tests about selecting DBs: not applicable" ); + return; } $dbname = 'unittest-domain'; // explodes if DB is selected $factory = $this->newLBFactoryMulti( [ 'localDomain' => ( new DatabaseDomain( $dbname, null, '' ) )->getId() ], [ - 'dbFilePath' => $dbPath, 'dbName' => 'do_not_select_me' // explodes if DB is selected ] ); @@ -496,7 +563,27 @@ class LBFactoryTest extends MediaWikiTestCase { "Correct full table name" ); - if ( $db->databasesAreIndependent() ) { + $lb->reuseConnection( $db ); // don't care + + $factory->closeAll(); + $factory->destroy(); + } + + public function testInvalidSelectDB() { + $dbname = 'unittest-domain'; // explodes if DB is selected + $factory = $this->newLBFactoryMulti( + [ 'localDomain' => ( new DatabaseDomain( $dbname, null, '' ) )->getId() ], + [ + 'dbName' => 'do_not_select_me' // explodes if DB is selected + ] + ); + $lb = $factory->getMainLB(); + /** @var Database $db */ + $db = $lb->getConnection( DB_MASTER, [], '' ); + + if ( $db->getType() === 'sqlite' ) { + $this->assertFalse( $db->selectDB( 'garbage-db' ) ); + } elseif ( $db->databasesAreIndependent() ) { try { $e = null; $db->selectDB( 'garbage-db' ); @@ -510,11 +597,6 @@ class LBFactoryTest extends MediaWikiTestCase { $this->assertFalse( $db->selectDB( 'garbage-db' ) ); \Wikimedia\restoreWarnings(); } - - $lb->reuseConnection( $db ); // don't care - - $factory->closeAll(); - $factory->destroy(); } private function quoteTable( Database $db, $table ) { @@ -524,4 +606,38 @@ class LBFactoryTest extends MediaWikiTestCase { return $db->addIdentifierQuotes( $table ); } } + + /** + * @covers \Wikimedia\Rdbms\LBFactory::makeCookieValueFromCPIndex() + * @covers \Wikimedia\Rdbms\LBFactory::getCPIndexFromCookieValue() + */ + public function testCPPosIndexCookieValues() { + $this->assertEquals( '3@542', LBFactory::makeCookieValueFromCPIndex( 3, 542 ) ); + + $time = 1526522031; + $this->assertSame( + 5, + LBFactory::getCPIndexFromCookieValue( "5", $time - 10 ) + ); + $this->assertSame( + null, + LBFactory::getCPIndexFromCookieValue( "0", $time - 10 ) + ); + $this->assertSame( + 2, + LBFactory::getCPIndexFromCookieValue( "2@$time", $time - 10 ) + ); + $this->assertSame( + 2, + LBFactory::getCPIndexFromCookieValue( "2@$time", $time + 9 - 10 ) + ); + $this->assertSame( + null, + LBFactory::getCPIndexFromCookieValue( "0@$time", $time + 9 - 10 ) + ); + $this->assertSame( + null, + LBFactory::getCPIndexFromCookieValue( "2@$time", $time + 11 - 10 ) + ); + } }