Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert driver exceptions when starting transactions #6812

Open
wants to merge 4 commits into
base: 4.2.x
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 25 additions & 10 deletions tests/Functional/TransactionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,43 +9,40 @@
use Doctrine\DBAL\Platforms\AbstractMySQLPlatform;
use Doctrine\DBAL\Schema\Table;
use Doctrine\DBAL\Tests\FunctionalTestCase;
use Doctrine\DBAL\Tests\TestUtil;
use Doctrine\DBAL\Types\Types;

use function func_get_args;
use function restore_error_handler;
use function set_error_handler;
use function sleep;
use function sprintf;

use const E_WARNING;

class TransactionTest extends FunctionalTestCase
{
public function testCommitFailure(): void
{
$this->markConnectionNotReusable();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marking as not reusable as I didn't want for a failure in one test to leak into the other


$this->expectConnectionLoss(static function (Connection $connection): void {
$connection->commit();
});
}

public function testRollbackFailure(): void
{
$this->markConnectionNotReusable();

$this->expectConnectionLoss(static function (Connection $connection): void {
$connection->rollBack();
});
}

private function expectConnectionLoss(callable $scenario): void
{
if (! $this->connection->getDatabasePlatform() instanceof AbstractMySQLPlatform) {
self::markTestSkipped('Restricted to MySQL.');
}

$this->connection->executeStatement('SET SESSION wait_timeout=1');
$this->connection->beginTransaction();

// during the sleep MySQL will close the connection
sleep(2);

$this->killCurrentSession();
$this->expectException(ConnectionLost::class);

// prevent the PHPUnit error handler from handling the "MySQL server has gone away" warning
Expand All @@ -65,6 +62,24 @@ private function expectConnectionLoss(callable $scenario): void
}
}

private function killCurrentSession(): void
{
$databasePlatform = $this->connection->getDatabasePlatform();

[$currentProcessQuery, $killProcessStatement] = match (true) {
$databasePlatform instanceof AbstractMySqlPlatform => ['SELECT CONNECTION_ID()', 'KILL %s'],
default => self::markTestSkipped('Unsupported test platform.'),
};

$privilegedConnection = TestUtil::getPrivilegedConnection();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using priviledged connection here, assuming that's a requirement for other platforms (maybe oracle or SQL server?)

$privilegedConnection->executeStatement(
sprintf(
$killProcessStatement,
$this->connection->executeQuery($currentProcessQuery)->fetchOne(),
),
);
}

public function testNestedTransactionWalkthrough(): void
{
if (! $this->connection->getDatabasePlatform()->supportsSavepoints()) {
Expand Down