Failed Conditions
Push — master ( ac0e13...24dbc4 )
by Sergei
22s queued 15s
created

ConnectionTest::testPingDoesTriggersConnect()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\DBAL\Tests\Functional;
6
7
use Doctrine\DBAL\Connection;
8
use Doctrine\DBAL\ConnectionException;
9
use Doctrine\DBAL\Driver\PDOConnection;
10
use Doctrine\DBAL\DriverManager;
11
use Doctrine\DBAL\Platforms\SqlitePlatform;
12
use Doctrine\DBAL\Platforms\SQLServer2012Platform;
13
use Doctrine\DBAL\Tests\FunctionalTestCase;
14
use Doctrine\DBAL\Tests\TestUtil;
15
use Error;
16
use Exception;
17
use PDO;
18
use RuntimeException;
19
use Throwable;
20
use function file_exists;
21
use function in_array;
22
use function unlink;
23
24
class ConnectionTest extends FunctionalTestCase
25
{
26
    protected function setUp() : void
27
    {
28
        $this->resetSharedConn();
29
        parent::setUp();
30
    }
31
32
    protected function tearDown() : void
33
    {
34
        if (file_exists('/tmp/test_nesting.sqlite')) {
35
            unlink('/tmp/test_nesting.sqlite');
36
        }
37
38
        parent::tearDown();
39
        $this->resetSharedConn();
40
    }
41
42
    public function testCommitWithRollbackOnlyThrowsException() : void
43
    {
44
        $this->connection->beginTransaction();
45
        $this->connection->setRollbackOnly();
46
47
        $this->expectException(ConnectionException::class);
48
        $this->connection->commit();
49
    }
50
51
    public function testTransactionNestingBehavior() : void
52
    {
53
        try {
54
            $this->connection->beginTransaction();
55
            self::assertEquals(1, $this->connection->getTransactionNestingLevel());
56
57
            try {
58
                $this->connection->beginTransaction();
59
                self::assertEquals(2, $this->connection->getTransactionNestingLevel());
60
61
                throw new Exception();
62
            } catch (Throwable $e) {
63
                $this->connection->rollBack();
64
                self::assertEquals(1, $this->connection->getTransactionNestingLevel());
65
                //no rethrow
66
            }
67
68
            self::assertTrue($this->connection->isRollbackOnly());
69
70
            $this->connection->commit(); // should throw exception
71
            self::fail('Transaction commit after failed nested transaction should fail.');
72
        } catch (ConnectionException $e) {
73
            self::assertEquals(1, $this->connection->getTransactionNestingLevel());
74
            $this->connection->rollBack();
75
            self::assertEquals(0, $this->connection->getTransactionNestingLevel());
76
        }
77
78
        $this->connection->beginTransaction();
79
        $this->connection->close();
80
        $this->connection->beginTransaction();
81
        self::assertEquals(1, $this->connection->getTransactionNestingLevel());
82
    }
83
84
    public function testTransactionNestingLevelIsResetOnReconnect() : void
85
    {
86
        if ($this->connection->getDatabasePlatform()->getName() === 'sqlite') {
87
            $params           = $this->connection->getParams();
88
            $params['memory'] = false;
89
            $params['path']   = '/tmp/test_nesting.sqlite';
90
91
            $connection = DriverManager::getConnection(
92
                $params,
93
                $this->connection->getConfiguration(),
94
                $this->connection->getEventManager()
95
            );
96
        } else {
97
            $connection = $this->connection;
98
        }
99
100
        $connection->executeQuery('CREATE TABLE test_nesting(test int not null)');
101
102
        $this->connection->beginTransaction();
103
        $this->connection->beginTransaction();
104
        $connection->close(); // connection closed in runtime (for example if lost or another application logic)
105
106
        $connection->beginTransaction();
107
        $connection->executeQuery('insert into test_nesting values (33)');
108
        $connection->rollBack();
109
110
        self::assertEquals(0, $connection->fetchColumn('select count(*) from test_nesting'));
111
    }
112
113
    public function testTransactionNestingBehaviorWithSavepoints() : void
114
    {
115
        if (! $this->connection->getDatabasePlatform()->supportsSavepoints()) {
116
            self::markTestSkipped('This test requires the platform to support savepoints.');
117
        }
118
119
        $this->connection->setNestTransactionsWithSavepoints(true);
120
        try {
121
            $this->connection->beginTransaction();
122
            self::assertEquals(1, $this->connection->getTransactionNestingLevel());
123
124
            try {
125
                $this->connection->beginTransaction();
126
                self::assertEquals(2, $this->connection->getTransactionNestingLevel());
127
                $this->connection->beginTransaction();
128
                self::assertEquals(3, $this->connection->getTransactionNestingLevel());
129
                $this->connection->commit();
130
                self::assertEquals(2, $this->connection->getTransactionNestingLevel());
131
132
                throw new Exception();
133
            } catch (Throwable $e) {
134
                $this->connection->rollBack();
135
                self::assertEquals(1, $this->connection->getTransactionNestingLevel());
136
                //no rethrow
137
            }
138
139
            self::assertFalse($this->connection->isRollbackOnly());
140
            try {
141
                $this->connection->setNestTransactionsWithSavepoints(false);
142
                self::fail('Should not be able to disable savepoints in usage for nested transactions inside an open transaction.');
143
            } catch (ConnectionException $e) {
144
                self::assertTrue($this->connection->getNestTransactionsWithSavepoints());
145
            }
146
147
            $this->connection->commit(); // should not throw exception
148
        } catch (ConnectionException $e) {
149
            self::fail('Transaction commit after failed nested transaction should not fail when using savepoints.');
150
        }
151
    }
152
153
    public function testTransactionNestingBehaviorCantBeChangedInActiveTransaction() : void
154
    {
155
        if (! $this->connection->getDatabasePlatform()->supportsSavepoints()) {
156
            self::markTestSkipped('This test requires the platform to support savepoints.');
157
        }
158
159
        $this->connection->beginTransaction();
160
        $this->expectException(ConnectionException::class);
161
        $this->connection->setNestTransactionsWithSavepoints(true);
162
    }
163
164
    public function testSetNestedTransactionsThroughSavepointsNotSupportedThrowsException() : void
165
    {
166
        if ($this->connection->getDatabasePlatform()->supportsSavepoints()) {
167
            self::markTestSkipped('This test requires the platform not to support savepoints.');
168
        }
169
170
        $this->expectException(ConnectionException::class);
171
        $this->expectExceptionMessage('Savepoints are not supported by this driver.');
172
173
        $this->connection->setNestTransactionsWithSavepoints(true);
174
    }
175
176
    public function testCreateSavepointsNotSupportedThrowsException() : void
177
    {
178
        if ($this->connection->getDatabasePlatform()->supportsSavepoints()) {
179
            self::markTestSkipped('This test requires the platform not to support savepoints.');
180
        }
181
182
        $this->expectException(ConnectionException::class);
183
        $this->expectExceptionMessage('Savepoints are not supported by this driver.');
184
185
        $this->connection->createSavepoint('foo');
186
    }
187
188
    public function testReleaseSavepointsNotSupportedThrowsException() : void
189
    {
190
        if ($this->connection->getDatabasePlatform()->supportsSavepoints()) {
191
            self::markTestSkipped('This test requires the platform not to support savepoints.');
192
        }
193
194
        $this->expectException(ConnectionException::class);
195
        $this->expectExceptionMessage('Savepoints are not supported by this driver.');
196
197
        $this->connection->releaseSavepoint('foo');
198
    }
199
200
    public function testRollbackSavepointsNotSupportedThrowsException() : void
201
    {
202
        if ($this->connection->getDatabasePlatform()->supportsSavepoints()) {
203
            self::markTestSkipped('This test requires the platform not to support savepoints.');
204
        }
205
206
        $this->expectException(ConnectionException::class);
207
        $this->expectExceptionMessage('Savepoints are not supported by this driver.');
208
209
        $this->connection->rollbackSavepoint('foo');
210
    }
211
212
    public function testTransactionBehaviorWithRollback() : void
213
    {
214
        try {
215
            $this->connection->beginTransaction();
216
            self::assertEquals(1, $this->connection->getTransactionNestingLevel());
217
218
            throw new Exception();
219
        } catch (Throwable $e) {
220
            self::assertEquals(1, $this->connection->getTransactionNestingLevel());
221
            $this->connection->rollBack();
222
            self::assertEquals(0, $this->connection->getTransactionNestingLevel());
223
        }
224
    }
225
226
    public function testTransactionBehaviour() : void
227
    {
228
        try {
229
            $this->connection->beginTransaction();
230
            self::assertEquals(1, $this->connection->getTransactionNestingLevel());
231
            $this->connection->commit();
232
        } catch (Throwable $e) {
233
            $this->connection->rollBack();
234
            self::assertEquals(0, $this->connection->getTransactionNestingLevel());
235
        }
236
237
        self::assertEquals(0, $this->connection->getTransactionNestingLevel());
238
    }
239
240
    public function testTransactionalWithException() : void
241
    {
242
        try {
243
            $this->connection->transactional(static function ($conn) : void {
244
                /** @var Connection $conn */
245
                $conn->executeQuery($conn->getDatabasePlatform()->getDummySelectSQL());
246
247
                throw new RuntimeException('Ooops!');
248
            });
249
            self::fail('Expected exception');
250
        } catch (RuntimeException $expected) {
251
            self::assertEquals(0, $this->connection->getTransactionNestingLevel());
252
        }
253
    }
254
255
    public function testTransactionalWithThrowable() : void
256
    {
257
        try {
258
            $this->connection->transactional(static function ($conn) : void {
259
                /** @var Connection $conn */
260
                $conn->executeQuery($conn->getDatabasePlatform()->getDummySelectSQL());
261
262
                throw new Error('Ooops!');
263
            });
264
            self::fail('Expected exception');
265
        } catch (Error $expected) {
266
            self::assertEquals(0, $this->connection->getTransactionNestingLevel());
267
        }
268
    }
269
270
    public function testTransactional() : void
271
    {
272
        $res = $this->connection->transactional(static function ($conn) : void {
273
            /** @var Connection $conn */
274
            $conn->executeQuery($conn->getDatabasePlatform()->getDummySelectSQL());
275
        });
276
277
        self::assertNull($res);
278
    }
279
280
    public function testTransactionalReturnValue() : void
281
    {
282
        $res = $this->connection->transactional(static function () : int {
283
            return 42;
284
        });
285
286
        self::assertEquals(42, $res);
287
    }
288
289
    public function testPingDoesTriggersConnect() : void
290
    {
291
        $this->connection->close();
292
        self::assertFalse($this->connection->isConnected());
293
294
        $this->connection->ping();
295
        self::assertTrue($this->connection->isConnected());
296
    }
297
298
    /**
299
     * @group DBAL-1025
300
     */
301
    public function testConnectWithoutExplicitDatabaseName() : void
302
    {
303
        if (in_array($this->connection->getDatabasePlatform()->getName(), ['oracle', 'db2'], true)) {
304
            self::markTestSkipped('Platform does not support connecting without database name.');
305
        }
306
307
        $params = $this->connection->getParams();
308
        unset($params['dbname']);
309
310
        $connection = DriverManager::getConnection(
311
            $params,
312
            $this->connection->getConfiguration(),
313
            $this->connection->getEventManager()
314
        );
315
316
        $connection->connect();
317
318
        self::assertTrue($connection->isConnected());
319
320
        $connection->close();
321
    }
322
323
    /**
324
     * @group DBAL-990
325
     */
326
    public function testDeterminesDatabasePlatformWhenConnectingToNonExistentDatabase() : void
327
    {
328
        if (in_array($this->connection->getDatabasePlatform()->getName(), ['oracle', 'db2'], true)) {
329
            self::markTestSkipped('Platform does not support connecting without database name.');
330
        }
331
332
        $params = $this->connection->getParams();
333
334
        $params['dbname'] = 'foo_bar';
335
336
        $connection = DriverManager::getConnection(
337
            $params,
338
            $this->connection->getConfiguration(),
339
            $this->connection->getEventManager()
340
        );
341
342
        self::assertFalse($connection->isConnected());
343
        self::assertSame($params, $connection->getParams());
344
345
        $connection->close();
346
    }
347
348
    public function testPersistentConnection() : void
349
    {
350
        $platform = $this->connection->getDatabasePlatform();
351
352
        if ($platform instanceof SqlitePlatform
353
            || $platform instanceof SQLServer2012Platform) {
354
            self::markTestSkipped('The platform does not support persistent connections');
355
        }
356
357
        $params               = TestUtil::getConnectionParams();
358
        $params['persistent'] = true;
359
360
        $connection       = DriverManager::getConnection($params);
361
        $driverConnection = $connection->getWrappedConnection();
362
363
        if (! $driverConnection instanceof PDOConnection) {
364
            self::markTestSkipped('Unable to test if the connection is persistent');
365
        }
366
367
        $pdo = $driverConnection->getWrappedConnection();
368
369
        self::assertTrue($pdo->getAttribute(PDO::ATTR_PERSISTENT));
370
    }
371
}
372