Failed Conditions
Pull Request — develop (#3348)
by Sergei
65:23
created

ConnectionTest::testQuote()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\Tests\DBAL\Functional;
6
7
use Doctrine\DBAL\Connection;
8
use Doctrine\DBAL\ConnectionException;
9
use Doctrine\DBAL\Driver\Connection as DriverConnection;
10
use Doctrine\DBAL\DriverManager;
11
use Doctrine\DBAL\Platforms\AbstractPlatform;
12
use Doctrine\Tests\DbalFunctionalTestCase;
13
use Error;
14
use Exception;
15
use RuntimeException;
16
use Throwable;
17
use function in_array;
18
19
class ConnectionTest extends DbalFunctionalTestCase
20
{
21
    protected function setUp() : void
22
    {
23
        $this->resetSharedConn();
24
        parent::setUp();
25
    }
26
27
    protected function tearDown() : void
28
    {
29
        parent::tearDown();
30
        $this->resetSharedConn();
31
    }
32
33
    public function testGetWrappedConnection() : void
34
    {
35
        self::assertInstanceOf(DriverConnection::class, $this->connection->getWrappedConnection());
36
    }
37
38
    public function testCommitWithRollbackOnlyThrowsException() : void
39
    {
40
        $this->connection->beginTransaction();
41
        $this->connection->setRollbackOnly();
42
43
        $this->expectException(ConnectionException::class);
44
        $this->connection->commit();
45
    }
46
47
    public function testTransactionNestingBehavior() : void
48
    {
49
        try {
50
            $this->connection->beginTransaction();
51
            self::assertEquals(1, $this->connection->getTransactionNestingLevel());
52
53
            try {
54
                $this->connection->beginTransaction();
55
                self::assertEquals(2, $this->connection->getTransactionNestingLevel());
56
                throw new Exception();
57
                $this->connection->commit(); // never reached
0 ignored issues
show
Unused Code introduced by
$this->connection->commit() is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
58
            } catch (Throwable $e) {
59
                $this->connection->rollBack();
60
                self::assertEquals(1, $this->connection->getTransactionNestingLevel());
61
                //no rethrow
62
            }
63
            self::assertTrue($this->connection->isRollbackOnly());
64
65
            $this->connection->commit(); // should throw exception
66
            $this->fail('Transaction commit after failed nested transaction should fail.');
67
        } catch (ConnectionException $e) {
68
            self::assertEquals(1, $this->connection->getTransactionNestingLevel());
69
            $this->connection->rollBack();
70
            self::assertEquals(0, $this->connection->getTransactionNestingLevel());
71
        }
72
    }
73
74
    public function testTransactionNestingBehaviorWithSavepoints() : void
75
    {
76
        if (! $this->connection->getDatabasePlatform()->supportsSavepoints()) {
77
            $this->markTestSkipped('This test requires the platform to support savepoints.');
78
        }
79
80
        $this->connection->setNestTransactionsWithSavepoints(true);
81
        try {
82
            $this->connection->beginTransaction();
83
            self::assertEquals(1, $this->connection->getTransactionNestingLevel());
84
85
            try {
86
                $this->connection->beginTransaction();
87
                self::assertEquals(2, $this->connection->getTransactionNestingLevel());
88
                $this->connection->beginTransaction();
89
                self::assertEquals(3, $this->connection->getTransactionNestingLevel());
90
                $this->connection->commit();
91
                self::assertEquals(2, $this->connection->getTransactionNestingLevel());
92
                throw new Exception();
93
                $this->connection->commit(); // never reached
0 ignored issues
show
Unused Code introduced by
$this->connection->commit() is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
94
            } catch (Throwable $e) {
95
                $this->connection->rollBack();
96
                self::assertEquals(1, $this->connection->getTransactionNestingLevel());
97
                //no rethrow
98
            }
99
            self::assertFalse($this->connection->isRollbackOnly());
100
            try {
101
                $this->connection->setNestTransactionsWithSavepoints(false);
102
                $this->fail('Should not be able to disable savepoints in usage for nested transactions inside an open transaction.');
103
            } catch (ConnectionException $e) {
104
                self::assertTrue($this->connection->getNestTransactionsWithSavepoints());
105
            }
106
            $this->connection->commit(); // should not throw exception
107
        } catch (ConnectionException $e) {
108
            $this->fail('Transaction commit after failed nested transaction should not fail when using savepoints.');
109
            $this->connection->rollBack();
110
        }
111
    }
112
113
    public function testTransactionNestingBehaviorCantBeChangedInActiveTransaction() : void
114
    {
115
        if (! $this->connection->getDatabasePlatform()->supportsSavepoints()) {
116
            $this->markTestSkipped('This test requires the platform to support savepoints.');
117
        }
118
119
        $this->connection->beginTransaction();
120
        $this->expectException(ConnectionException::class);
121
        $this->connection->setNestTransactionsWithSavepoints(true);
122
    }
123
124
    public function testSetNestedTransactionsThroughSavepointsNotSupportedThrowsException() : void
125
    {
126
        if ($this->connection->getDatabasePlatform()->supportsSavepoints()) {
127
            $this->markTestSkipped('This test requires the platform not to support savepoints.');
128
        }
129
130
        $this->expectException(ConnectionException::class);
131
        $this->expectExceptionMessage('Savepoints are not supported by this driver.');
132
133
        $this->connection->setNestTransactionsWithSavepoints(true);
134
    }
135
136
    public function testCreateSavepointsNotSupportedThrowsException() : void
137
    {
138
        if ($this->connection->getDatabasePlatform()->supportsSavepoints()) {
139
            $this->markTestSkipped('This test requires the platform not to support savepoints.');
140
        }
141
142
        $this->expectException(ConnectionException::class);
143
        $this->expectExceptionMessage('Savepoints are not supported by this driver.');
144
145
        $this->connection->createSavepoint('foo');
146
    }
147
148
    public function testReleaseSavepointsNotSupportedThrowsException() : void
149
    {
150
        if ($this->connection->getDatabasePlatform()->supportsSavepoints()) {
151
            $this->markTestSkipped('This test requires the platform not to support savepoints.');
152
        }
153
154
        $this->expectException(ConnectionException::class);
155
        $this->expectExceptionMessage('Savepoints are not supported by this driver.');
156
157
        $this->connection->releaseSavepoint('foo');
158
    }
159
160
    public function testRollbackSavepointsNotSupportedThrowsException() : void
161
    {
162
        if ($this->connection->getDatabasePlatform()->supportsSavepoints()) {
163
            $this->markTestSkipped('This test requires the platform not to support savepoints.');
164
        }
165
166
        $this->expectException(ConnectionException::class);
167
        $this->expectExceptionMessage('Savepoints are not supported by this driver.');
168
169
        $this->connection->rollbackSavepoint('foo');
170
    }
171
172
    public function testTransactionBehaviorWithRollback() : void
173
    {
174
        try {
175
            $this->connection->beginTransaction();
176
            self::assertEquals(1, $this->connection->getTransactionNestingLevel());
177
178
            throw new Exception();
179
180
            $this->connection->commit(); // never reached
0 ignored issues
show
Unused Code introduced by
$this->connection->commit() is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
181
        } catch (Throwable $e) {
182
            self::assertEquals(1, $this->connection->getTransactionNestingLevel());
183
            $this->connection->rollBack();
184
            self::assertEquals(0, $this->connection->getTransactionNestingLevel());
185
        }
186
    }
187
188
    public function testTransactionBehaviour() : void
189
    {
190
        try {
191
            $this->connection->beginTransaction();
192
            self::assertEquals(1, $this->connection->getTransactionNestingLevel());
193
            $this->connection->commit();
194
        } catch (Throwable $e) {
195
            $this->connection->rollBack();
196
            self::assertEquals(0, $this->connection->getTransactionNestingLevel());
197
        }
198
199
        self::assertEquals(0, $this->connection->getTransactionNestingLevel());
200
    }
201
202
    public function testTransactionalWithException() : void
203
    {
204
        try {
205
            $this->connection->transactional(static function ($conn) : void {
206
                /** @var Connection $conn */
207
                $conn->executeQuery($conn->getDatabasePlatform()->getDummySelectSQL());
208
                throw new RuntimeException('Ooops!');
209
            });
210
            $this->fail('Expected exception');
211
        } catch (RuntimeException $expected) {
212
            self::assertEquals(0, $this->connection->getTransactionNestingLevel());
213
        }
214
    }
215
216
    public function testTransactionalWithThrowable() : void
217
    {
218
        try {
219
            $this->connection->transactional(static function ($conn) : void {
220
                /** @var Connection $conn */
221
                $conn->executeQuery($conn->getDatabasePlatform()->getDummySelectSQL());
222
                throw new Error('Ooops!');
223
            });
224
            $this->fail('Expected exception');
225
        } catch (Error $expected) {
226
            self::assertEquals(0, $this->connection->getTransactionNestingLevel());
227
        }
228
    }
229
230
    public function testTransactional() : void
231
    {
232
        $res = $this->connection->transactional(static function ($conn) : void {
233
            /** @var Connection $conn */
234
            $conn->executeQuery($conn->getDatabasePlatform()->getDummySelectSQL());
235
        });
236
237
        self::assertNull($res);
238
    }
239
240
    public function testTransactionalReturnValue() : void
241
    {
242
        $res = $this->connection->transactional(static function () {
243
            return 42;
244
        });
245
246
        self::assertEquals(42, $res);
247
    }
248
249
    public function testPingDoesTriggersConnect() : void
250
    {
251
        self::assertTrue($this->connection->ping());
252
        self::assertTrue($this->connection->isConnected());
253
    }
254
255
    /**
256
     * @group DBAL-1025
257
     */
258
    public function testConnectWithoutExplicitDatabaseName() : void
259
    {
260
        if (in_array($this->connection->getDatabasePlatform()->getName(), ['oracle', 'db2'], true)) {
261
            $this->markTestSkipped('Platform does not support connecting without database name.');
262
        }
263
264
        $params = $this->connection->getParams();
265
        unset($params['dbname']);
266
267
        $connection = DriverManager::getConnection(
268
            $params,
269
            $this->connection->getConfiguration(),
270
            $this->connection->getEventManager()
271
        );
272
273
        $connection->connect();
274
275
        self::assertTrue($connection->isConnected());
276
277
        $connection->close();
278
    }
279
280
    /**
281
     * @group DBAL-990
282
     */
283
    public function testDeterminesDatabasePlatformWhenConnectingToNonExistentDatabase() : void
284
    {
285
        if (in_array($this->connection->getDatabasePlatform()->getName(), ['oracle', 'db2'], true)) {
286
            $this->markTestSkipped('Platform does not support connecting without database name.');
287
        }
288
289
        $params = $this->connection->getParams();
290
291
        $params['dbname'] = 'foo_bar';
292
293
        $connection = DriverManager::getConnection(
294
            $params,
295
            $this->connection->getConfiguration(),
296
            $this->connection->getEventManager()
297
        );
298
299
        self::assertInstanceOf(AbstractPlatform::class, $connection->getDatabasePlatform());
300
        self::assertFalse($connection->isConnected());
301
        self::assertSame($params, $connection->getParams());
302
303
        $connection->close();
304
    }
305
}
306