rdbms: fix LBFactory::commitAll() round handling
[lhc/web/wiklou.git] / tests / phpunit / includes / db / LBFactoryTest.php
index fa1cfc9..a84cc04 100644 (file)
@@ -157,12 +157,18 @@ class LBFactoryTest extends MediaWikiTestCase {
                global $wgDBserver, $wgDBname, $wgDBuser, $wgDBpassword, $wgDBtype, $wgSQLiteDataDir;
 
                $factory = new LBFactoryMulti( [
-                       'sectionsByDB' => [],
+                       'sectionsByDB' => [
+                               's1wiki' => 's1',
+                       ],
                        'sectionLoads' => [
+                               's1' => [
+                                       'test-db3' => 0,
+                                       'test-db4' => 100,
+                               ],
                                'DEFAULT' => [
                                        'test-db1' => 0,
                                        'test-db2' => 100,
-                               ],
+                               ]
                        ],
                        'serverTemplate' => [
                                'dbname'      => $wgDBname,
@@ -174,7 +180,9 @@ class LBFactoryTest extends MediaWikiTestCase {
                        ],
                        'hostsByName' => [
                                'test-db1'  => $wgDBserver,
-                               'test-db2'  => $wgDBserver
+                               'test-db2'  => $wgDBserver,
+                               'test-db3'  => $wgDBserver,
+                               'test-db4'  => $wgDBserver
                        ],
                        'loadMonitorClass' => LoadMonitorNull::class
                ] );
@@ -186,20 +194,45 @@ class LBFactoryTest extends MediaWikiTestCase {
                $dbr = $lb->getConnection( DB_REPLICA );
                $this->assertTrue( $dbr->getLBInfo( 'replica' ), 'slave shows as slave' );
 
+               // Test that LoadBalancer instances made during commitMasterChanges() do not throw
+               // DBTransactionError due to transaction ROUND_* stages being mismatched.
+               $factory->beginMasterChanges( __METHOD__ );
+               $dbw->onTransactionPreCommitOrIdle( function () use ( $factory ) {
+                       // 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__ );
+
+               $count = 0;
+               $factory->forEachLB( function () use ( &$count ) {
+                       ++$count;
+               } );
+               $this->assertEquals( 2, $count );
+
+               // DBTransactionError should not be thrown
+               $ran = 0;
+               $dbw->onTransactionPreCommitOrIdle( function () use ( &$ran ) {
+                       ++$ran;
+               } );
+               $factory->commitAll( __METHOD__ );
+               $this->assertEquals( 1, $ran );
+
                $factory->shutdown();
-               $lb->closeAll();
+               $factory->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,45 +378,38 @@ 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, [], '' );
 
                $this->assertEquals(
-                       $wgDBname,
+                       '',
                        $db->getDomainId(),
-                       'Main domain ID handle used; same DB name'
+                       'Null domain ID handle used'
                );
                $this->assertEquals(
-                       $wgDBname,
+                       '',
                        $db->getDBname(),
-                       'Main domain ID handle used; same DB name'
+                       'Null domain ID handle used'
                );
                $this->assertEquals(
                        '',
@@ -411,6 +437,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,31 +458,25 @@ 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
+                       ]
                );
                $lb = $factory->getMainLB();
                /** @var Database $db */
                $db = $lb->getConnection( DB_MASTER, [], '' );
 
-               $this->assertEquals(
-                       $wgDBname,
-                       $db->getDomainID()
-               );
+               $this->assertEquals( '', $db->getDomainID(), "Null domain used" );
 
                $this->assertEquals(
                        $this->quoteTable( $db, 'page' ),
@@ -496,7 +517,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' );
@@ -506,15 +547,10 @@ class LBFactoryTest extends MediaWikiTestCase {
                        $this->assertInstanceOf( \Wikimedia\Rdbms\DBConnectionError::class, $e );
                        $this->assertFalse( $db->isOpen() );
                } else {
-                       \MediaWiki\suppressWarnings();
+                       \Wikimedia\suppressWarnings();
                        $this->assertFalse( $db->selectDB( 'garbage-db' ) );
-                       \MediaWiki\restoreWarnings();
+                       \Wikimedia\restoreWarnings();
                }
-
-               $lb->reuseConnection( $db ); // don't care
-
-               $factory->closeAll();
-               $factory->destroy();
        }
 
        private function quoteTable( Database $db, $table ) {