<?php
+use Wikimedia\Rdbms\Database;
use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\DatabaseMysqli;
use Wikimedia\Rdbms\LBFactorySingle;
use Wikimedia\Rdbms\TransactionProfiler;
use Wikimedia\TestingAccessWrapper;
+use Wikimedia\Rdbms\DatabaseSqlite;
+use Wikimedia\Rdbms\DatabasePostgres;
+use Wikimedia\Rdbms\DatabaseMssql;
class DatabaseTest extends PHPUnit\Framework\TestCase {
$this->db = new DatabaseTestHelper( __CLASS__ . '::' . $this->getName() );
}
+ /**
+ * @dataProvider provideAddQuotes
+ * @covers Wikimedia\Rdbms\Database::factory
+ */
+ public function testFactory() {
+ $m = Database::NEW_UNCONNECTED; // no-connect mode
+ $p = [ 'host' => 'localhost', 'user' => 'me', 'password' => 'myself', 'dbname' => 'i' ];
+
+ $this->assertInstanceOf( DatabaseMysqli::class, Database::factory( 'mysqli', $p, $m ) );
+ $this->assertInstanceOf( DatabaseMysqli::class, Database::factory( 'MySqli', $p, $m ) );
+ $this->assertInstanceOf( DatabaseMysqli::class, Database::factory( 'MySQLi', $p, $m ) );
+ $this->assertInstanceOf( DatabasePostgres::class, Database::factory( 'postgres', $p, $m ) );
+ $this->assertInstanceOf( DatabasePostgres::class, Database::factory( 'Postgres', $p, $m ) );
+
+ $x = $p + [ 'port' => 10000, 'UseWindowsAuth' => false ];
+ $this->assertInstanceOf( DatabaseMssql::class, Database::factory( 'mssql', $x, $m ) );
+
+ $x = $p + [ 'dbFilePath' => 'some/file.sqlite' ];
+ $this->assertInstanceOf( DatabaseSqlite::class, Database::factory( 'sqlite', $x, $m ) );
+ $x = $p + [ 'dbDirectory' => 'some/file' ];
+ $this->assertInstanceOf( DatabaseSqlite::class, Database::factory( 'sqlite', $x, $m ) );
+ }
+
public static function provideAddQuotes() {
return [
[ null, 'NULL' ],
public function testTransactionIdle() {
$db = $this->db;
- $db->setFlag( DBO_TRX );
+ $db->clearFlag( DBO_TRX );
$called = false;
$flagSet = null;
- $db->onTransactionIdle(
- function () use ( $db, &$flagSet, &$called ) {
- $called = true;
- $flagSet = $db->getFlag( DBO_TRX );
- },
- __METHOD__
- );
- $this->assertFalse( $flagSet, 'DBO_TRX off in callback' );
- $this->assertTrue( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
+ $callback = function () use ( $db, &$flagSet, &$called ) {
+ $called = true;
+ $flagSet = $db->getFlag( DBO_TRX );
+ };
+
+ $db->onTransactionIdle( $callback, __METHOD__ );
$this->assertTrue( $called, 'Callback reached' );
+ $this->assertFalse( $flagSet, 'DBO_TRX off in callback' );
+ $this->assertFalse( $db->getFlag( DBO_TRX ), 'DBO_TRX still default' );
- $db->clearFlag( DBO_TRX );
$flagSet = null;
- $db->onTransactionIdle(
- function () use ( $db, &$flagSet ) {
- $flagSet = $db->getFlag( DBO_TRX );
- },
- __METHOD__
- );
+ $called = false;
+ $db->startAtomic( __METHOD__ );
+ $db->onTransactionIdle( $callback, __METHOD__ );
+ $this->assertFalse( $called, 'Callback not reached during TRX' );
+ $db->endAtomic( __METHOD__ );
+
+ $this->assertTrue( $called, 'Callback reached after COMMIT' );
$this->assertFalse( $flagSet, 'DBO_TRX off in callback' );
$this->assertFalse( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
$this->assertFalse( $db->getFlag( DBO_TRX ), 'DBO_TRX restored to default' );
}
+ /**
+ * @covers Wikimedia\Rdbms\Database::onTransactionIdle
+ * @covers Wikimedia\Rdbms\Database::runOnTransactionIdleCallbacks
+ */
+ public function testTransactionIdle_TRX() {
+ $db = $this->getMockDB( [ 'isOpen', 'ping' ] );
+ $db->method( 'isOpen' )->willReturn( true );
+ $db->method( 'ping' )->willReturn( true );
+ $db->setFlag( DBO_TRX );
+
+ $lbFactory = LBFactorySingle::newFromConnection( $db );
+ // Ask for the connection so that LB sets internal state
+ // about this connection being the master connection
+ $lb = $lbFactory->getMainLB();
+ $conn = $lb->openConnection( $lb->getWriterIndex() );
+ $this->assertSame( $db, $conn, 'Same DB instance' );
+ $this->assertTrue( $db->getFlag( DBO_TRX ), 'DBO_TRX is set' );
+
+ $called = false;
+ $flagSet = null;
+ $callback = function () use ( $db, &$flagSet, &$called ) {
+ $called = true;
+ $flagSet = $db->getFlag( DBO_TRX );
+ };
+
+ $db->onTransactionIdle( $callback, __METHOD__ );
+ $this->assertTrue( $called, 'Called when idle if DBO_TRX is set' );
+ $this->assertFalse( $flagSet, 'DBO_TRX off in callback' );
+ $this->assertTrue( $db->getFlag( DBO_TRX ), 'DBO_TRX still default' );
+
+ $called = false;
+ $lbFactory->beginMasterChanges( __METHOD__ );
+ $db->onTransactionIdle( $callback, __METHOD__ );
+ $this->assertFalse( $called, 'Not called when lb-transaction is active' );
+
+ $lbFactory->commitMasterChanges( __METHOD__ );
+ $this->assertTrue( $called, 'Called when lb-transaction is committed' );
+
+ $called = false;
+ $lbFactory->beginMasterChanges( __METHOD__ );
+ $db->onTransactionIdle( $callback, __METHOD__ );
+ $this->assertFalse( $called, 'Not called when lb-transaction is active' );
+
+ $lbFactory->rollbackMasterChanges( __METHOD__ );
+ $this->assertFalse( $called, 'Not called when lb-transaction is rolled back' );
+
+ $lbFactory->commitMasterChanges( __METHOD__ );
+ $this->assertFalse( $called, 'Not called in next round commit' );
+ }
+
/**
* @covers Wikimedia\Rdbms\Database::onTransactionPreCommitOrIdle
* @covers Wikimedia\Rdbms\Database::runOnTransactionPreCommitCallbacks
* @covers Wikimedia\Rdbms\Database::runOnTransactionPreCommitCallbacks
*/
public function testTransactionPreCommitOrIdle_TRX() {
- $db = $this->getMockDB( [ 'isOpen' ] );
+ $db = $this->getMockDB( [ 'isOpen', 'ping' ] );
$db->method( 'isOpen' )->willReturn( true );
+ $db->method( 'ping' )->willReturn( true );
$db->setFlag( DBO_TRX );
$lbFactory = LBFactorySingle::newFromConnection( $db );
- // Ask for the connectin so that LB sets internal state
+ // Ask for the connection so that LB sets internal state
// about this connection being the master connection
$lb = $lbFactory->getMainLB();
$conn = $lb->openConnection( $lb->getWriterIndex() );
$this->assertSame( $db, $conn, 'Same DB instance' );
+
+ $this->assertFalse( $lb->hasMasterChanges() );
$this->assertTrue( $db->getFlag( DBO_TRX ), 'DBO_TRX is set' );
+ $called = false;
+ $callback = function () use ( &$called ) {
+ $called = true;
+ };
+ $db->onTransactionPreCommitOrIdle( $callback, __METHOD__ );
+ $this->assertTrue( $called, 'Called when idle if DBO_TRX is set' );
+ $called = false;
+ $lbFactory->commitMasterChanges();
+ $this->assertFalse( $called );
$called = false;
- $db->onTransactionPreCommitOrIdle(
- function () use ( &$called ) {
- $called = true;
- }
- );
- $this->assertFalse( $called, 'Not called when idle if DBO_TRX is set' );
+ $lbFactory->beginMasterChanges( __METHOD__ );
+ $db->onTransactionPreCommitOrIdle( $callback, __METHOD__ );
+ $this->assertFalse( $called, 'Not called when lb-transaction is active' );
+ $lbFactory->commitMasterChanges( __METHOD__ );
+ $this->assertTrue( $called, 'Called when lb-transaction is committed' );
+ $called = false;
$lbFactory->beginMasterChanges( __METHOD__ );
+ $db->onTransactionPreCommitOrIdle( $callback, __METHOD__ );
$this->assertFalse( $called, 'Not called when lb-transaction is active' );
+ $lbFactory->rollbackMasterChanges( __METHOD__ );
+ $this->assertFalse( $called, 'Not called when lb-transaction is rolled back' );
+
$lbFactory->commitMasterChanges( __METHOD__ );
- $this->assertTrue( $called, 'Called when lb-transaction is committed' );
+ $this->assertFalse( $called, 'Not called in next round commit' );
}
/**
$this->assertEquals( $origTrx, $db->getFlag( DBO_TRX ) );
}
+ /**
+ * @expectedException UnexpectedValueException
+ * @covers Wikimedia\Rdbms\Database::setFlag
+ */
+ public function testDBOIgnoreSet() {
+ $db = $this->getMockBuilder( DatabaseMysqli::class )
+ ->disableOriginalConstructor()
+ ->setMethods( null )
+ ->getMock();
+
+ $db->setFlag( Database::DBO_IGNORE );
+ }
+
+ /**
+ * @expectedException UnexpectedValueException
+ * @covers Wikimedia\Rdbms\Database::clearFlag
+ */
+ public function testDBOIgnoreClear() {
+ $db = $this->getMockBuilder( DatabaseMysqli::class )
+ ->disableOriginalConstructor()
+ ->setMethods( null )
+ ->getMock();
+
+ $db->clearFlag( Database::DBO_IGNORE );
+ }
+
/**
* @covers Wikimedia\Rdbms\Database::tablePrefix
* @covers Wikimedia\Rdbms\Database::dbSchema
$this->db->dbSchema( $old );
$this->assertNotEquals( 'xxx', $this->db->dbSchema() );
}
+
}