7
7
use Doctrine \DBAL \Connection ;
8
8
use Doctrine \DBAL \Exception \ConnectionLost ;
9
9
use Doctrine \DBAL \Platforms \AbstractMySQLPlatform ;
10
+ use Doctrine \DBAL \Platforms \PostgreSQLPlatform ;
10
11
use Doctrine \DBAL \Schema \Table ;
11
12
use Doctrine \DBAL \Tests \FunctionalTestCase ;
13
+ use Doctrine \DBAL \Tests \TestUtil ;
12
14
use Doctrine \DBAL \Types \Types ;
13
15
14
16
use function func_get_args ;
15
17
use function restore_error_handler ;
16
18
use function set_error_handler ;
17
- use function sleep ;
18
19
19
20
use const E_WARNING ;
20
21
21
22
class TransactionTest extends FunctionalTestCase
22
23
{
24
+ public function testBeginTransactionFailure (): void
25
+ {
26
+ $ this ->expectConnectionLoss (static function (Connection $ connection ): void {
27
+ $ connection ->beginTransaction ();
28
+ });
29
+ }
30
+
23
31
public function testCommitFailure (): void
24
32
{
33
+ $ this ->connection ->beginTransaction ();
34
+
25
35
$ this ->expectConnectionLoss (static function (Connection $ connection ): void {
26
36
$ connection ->commit ();
27
37
});
28
38
}
29
39
30
40
public function testRollbackFailure (): void
31
41
{
42
+ $ this ->connection ->beginTransaction ();
43
+
32
44
$ this ->expectConnectionLoss (static function (Connection $ connection ): void {
33
45
$ connection ->rollBack ();
34
46
});
35
47
}
36
48
37
49
private function expectConnectionLoss (callable $ scenario ): void
38
50
{
39
- if (! $ this ->connection ->getDatabasePlatform () instanceof AbstractMySQLPlatform) {
40
- self ::markTestSkipped ('Restricted to MySQL. ' );
41
- }
42
-
43
- $ this ->connection ->executeStatement ('SET SESSION wait_timeout=1 ' );
44
- $ this ->connection ->beginTransaction ();
45
-
46
- // during the sleep MySQL will close the connection
47
- sleep (2 );
48
-
51
+ $ this ->killCurrentSession ();
49
52
$ this ->expectException (ConnectionLost::class);
50
53
51
54
// prevent the PHPUnit error handler from handling the "MySQL server has gone away" warning
@@ -65,6 +68,31 @@ private function expectConnectionLoss(callable $scenario): void
65
68
}
66
69
}
67
70
71
+ private function killCurrentSession (): void
72
+ {
73
+ $ this ->markConnectionNotReusable ();
74
+
75
+ $ databasePlatform = $ this ->connection ->getDatabasePlatform ();
76
+
77
+ [$ currentProcessQuery , $ killProcessStatement ] = match (true ) {
78
+ $ databasePlatform instanceof AbstractMySqlPlatform => [
79
+ 'SELECT CONNECTION_ID() ' ,
80
+ 'KILL ? ' ,
81
+ ],
82
+ $ databasePlatform instanceof PostgreSQLPlatform => [
83
+ 'SELECT pg_backend_pid() ' ,
84
+ 'SELECT pg_terminate_backend(?) ' ,
85
+ ],
86
+ default => self ::markTestSkipped ('Unsupported test platform. ' ),
87
+ };
88
+
89
+ $ privilegedConnection = TestUtil::getPrivilegedConnection ();
90
+ $ privilegedConnection ->executeStatement (
91
+ $ killProcessStatement ,
92
+ [$ this ->connection ->executeQuery ($ currentProcessQuery )->fetchOne ()],
93
+ );
94
+ }
95
+
68
96
public function testNestedTransactionWalkthrough (): void
69
97
{
70
98
if (! $ this ->connection ->getDatabasePlatform ()->supportsSavepoints ()) {
0 commit comments