diff --git a/tests/Doctrine/Tests/DBAL/Functional/LockModeTest.php b/tests/Doctrine/Tests/DBAL/Functional/LockModeTest.php index 2b61aaeea75..e1434406d9c 100644 --- a/tests/Doctrine/Tests/DBAL/Functional/LockModeTest.php +++ b/tests/Doctrine/Tests/DBAL/Functional/LockModeTest.php @@ -9,39 +9,50 @@ use Doctrine\DBAL\Exception; use Doctrine\DBAL\LockMode; use Doctrine\DBAL\Platforms\SqlitePlatform; +use Doctrine\DBAL\Platforms\SQLServerPlatform; use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\TransactionIsolationLevel; -use Doctrine\Tests\DbalTestCase; +use Doctrine\Tests\DbalFunctionalTestCase; use Doctrine\Tests\TestUtil; -class LockModeTest extends DbalTestCase +class LockModeTest extends DbalFunctionalTestCase { /** @var Connection */ - private $c1; - - /** @var Connection */ - private $c2; + private $connection2; public function setUp(): void { - $this->c1 = TestUtil::getConnection(); - $this->c2 = TestUtil::getConnection(); + parent::setUp(); - if ($this->c1->getDriver() instanceof OCI8\Driver) { + if ($this->connection->getDriver() instanceof OCI8\Driver) { // https://github.com/doctrine/dbal/issues/4417 self::markTestSkipped('This test fails on OCI8 for a currently unknown reason'); } + if ($this->connection->getDatabasePlatform() instanceof SQLServerPlatform) { + // Use row versioning instead of locking on SQL Server (if we don't, the second connection will block when + // attempting to read the row created by the first connection, instead of reading the previous version); + // for some reason we cannot set READ_COMMITTED_SNAPSHOT ON when not running this test in isolation, + // there may be another connection active at this point; temporarily forcing to SINGLE_USER does the trick. + $name = $this->connection->fetchOne('SELECT db_name()'); + $this->connection->executeStatement('ALTER DATABASE ' . $name . ' SET SINGLE_USER WITH ROLLBACK IMMEDIATE'); + $this->connection->executeStatement('ALTER DATABASE ' . $name . ' SET READ_COMMITTED_SNAPSHOT ON'); + $this->connection->executeStatement('ALTER DATABASE ' . $name . ' SET MULTI_USER'); + } + $table = new Table('users'); $table->addColumn('id', 'integer'); + $table->setPrimaryKey(['id']); + + $this->connection->getSchemaManager()->createTable($table); - $this->c1->getSchemaManager()->createTable($table); + $this->connection2 = TestUtil::getConnection(); - if ($this->c2->getSchemaManager()->tablesExist('users')) { + if ($this->connection2->getSchemaManager()->tablesExist('users')) { return; } - if ($this->c2->getDatabasePlatform() instanceof SqlitePlatform) { + if ($this->connection2->getDatabasePlatform() instanceof SqlitePlatform) { self::markTestSkipped('This test cannot run on SQLite using an in-memory database'); } @@ -50,32 +61,40 @@ public function setUp(): void public function tearDown(): void { - $this->c1->getSchemaManager()->dropTable('users'); + parent::tearDown(); + + $this->connection2->close(); + + $this->connection->getSchemaManager()->dropTable('users'); + + if (! $this->connection->getDatabasePlatform() instanceof SQLServerPlatform) { + return; + } - $this->c1->close(); - $this->c2->close(); + $name = $this->connection->fetchOne('SELECT db_name()'); + $this->connection->executeStatement('ALTER DATABASE ' . $name . ' SET READ_COMMITTED_SNAPSHOT OFF'); } public function testLockModeNoneDoesNotBreakTransactionIsolation(): void { try { - $this->c1->setTransactionIsolation(TransactionIsolationLevel::READ_COMMITTED); - $this->c2->setTransactionIsolation(TransactionIsolationLevel::READ_COMMITTED); + $this->connection->setTransactionIsolation(TransactionIsolationLevel::READ_COMMITTED); + $this->connection2->setTransactionIsolation(TransactionIsolationLevel::READ_COMMITTED); } catch (Exception $e) { self::markTestSkipped('This test must be able to set a transaction isolation level'); } - $this->c1->beginTransaction(); - $this->c2->beginTransaction(); + $this->connection->beginTransaction(); + $this->connection2->beginTransaction(); - $this->c1->insert('users', ['id' => 1]); + $this->connection->insert('users', ['id' => 1]); $query = 'SELECT id FROM users'; - $query = $this->c2->getDatabasePlatform()->appendLockHint($query, LockMode::NONE); + $query = $this->connection2->getDatabasePlatform()->appendLockHint($query, LockMode::NONE); - self::assertFalse($this->c2->fetchOne($query)); + self::assertSame([], $this->connection2->fetchAllNumeric($query)); - $this->c1->commit(); - $this->c2->commit(); + $this->connection->commit(); + $this->connection2->commit(); } }