Failed Conditions
Pull Request — develop (#3367)
by Benjamin
12:25
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
namespace Doctrine\Tests\DBAL\Functional;
4
5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\ConnectionException;
7
use Doctrine\DBAL\Driver\Connection as DriverConnection;
8
use Doctrine\DBAL\DriverManager;
9
use Doctrine\DBAL\Platforms\AbstractPlatform;
10
use Doctrine\Tests\DbalFunctionalTestCase;
11
use Error;
12
use Exception;
13
use RuntimeException;
14
use Throwable;
15
use function in_array;
16
17
class ConnectionTest extends DbalFunctionalTestCase
18
{
19
    protected function setUp()
20
    {
21
        $this->resetSharedConn();
22
        parent::setUp();
23
    }
24
25
    protected function tearDown()
26
    {
27
        parent::tearDown();
28
        $this->resetSharedConn();
29
    }
30
31
    public function testGetWrappedConnection()
32
    {
33
        self::assertInstanceOf(DriverConnection::class, $this->connection->getWrappedConnection());
34
    }
35
36
    public function testCommitWithRollbackOnlyThrowsException()
37
    {
38
        $this->connection->beginTransaction();
39
        $this->connection->setRollbackOnly();
40
41
        $this->expectException(ConnectionException::class);
42
        $this->connection->commit();
43
    }
44
45
    public function testTransactionNestingBehavior()
46
    {
47
        try {
48
            $this->connection->beginTransaction();
49
            self::assertEquals(1, $this->connection->getTransactionNestingLevel());
50
51
            try {
52
                $this->connection->beginTransaction();
53
                self::assertEquals(2, $this->connection->getTransactionNestingLevel());
54
                throw new Exception();
55
                $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...
56
            } catch (Throwable $e) {
57
                $this->connection->rollBack();
58
                self::assertEquals(1, $this->connection->getTransactionNestingLevel());
59
                //no rethrow
60
            }
61
            self::assertTrue($this->connection->isRollbackOnly());
62
63
            $this->connection->commit(); // should throw exception
64
            $this->fail('Transaction commit after failed nested transaction should fail.');
65
        } catch (ConnectionException $e) {
66
            self::assertEquals(1, $this->connection->getTransactionNestingLevel());
67
            $this->connection->rollBack();
68
            self::assertEquals(0, $this->connection->getTransactionNestingLevel());
69
        }
70
    }
71
72
    public function testTransactionNestingBehaviorWithSavepoints()
73
    {
74
        if (! $this->connection->getDatabasePlatform()->supportsSavepoints()) {
75
            $this->markTestSkipped('This test requires the platform to support savepoints.');
76
        }
77
78
        $this->connection->setNestTransactionsWithSavepoints(true);
79
        try {
80
            $this->connection->beginTransaction();
81
            self::assertEquals(1, $this->connection->getTransactionNestingLevel());
82
83
            try {
84
                $this->connection->beginTransaction();
85
                self::assertEquals(2, $this->connection->getTransactionNestingLevel());
86
                $this->connection->beginTransaction();
87
                self::assertEquals(3, $this->connection->getTransactionNestingLevel());
88
                $this->connection->commit();
89
                self::assertEquals(2, $this->connection->getTransactionNestingLevel());
90
                throw new Exception();
91
                $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...
92
            } catch (Throwable $e) {
93
                $this->connection->rollBack();
94
                self::assertEquals(1, $this->connection->getTransactionNestingLevel());
95
                //no rethrow
96
            }
97
            self::assertFalse($this->connection->isRollbackOnly());
98
            try {
99
                $this->connection->setNestTransactionsWithSavepoints(false);
100
                $this->fail('Should not be able to disable savepoints in usage for nested transactions inside an open transaction.');
101
            } catch (ConnectionException $e) {
102
                self::assertTrue($this->connection->getNestTransactionsWithSavepoints());
103
            }
104
            $this->connection->commit(); // should not throw exception
105
        } catch (ConnectionException $e) {
106
            $this->fail('Transaction commit after failed nested transaction should not fail when using savepoints.');
107
            $this->connection->rollBack();
108
        }
109
    }
110
111
    public function testTransactionNestingBehaviorCantBeChangedInActiveTransaction()
112
    {
113
        if (! $this->connection->getDatabasePlatform()->supportsSavepoints()) {
114
            $this->markTestSkipped('This test requires the platform to support savepoints.');
115
        }
116
117
        $this->connection->beginTransaction();
118
        $this->expectException(ConnectionException::class);
119
        $this->connection->setNestTransactionsWithSavepoints(true);
120
    }
121
122
    public function testSetNestedTransactionsThroughSavepointsNotSupportedThrowsException()
123
    {
124
        if ($this->connection->getDatabasePlatform()->supportsSavepoints()) {
125
            $this->markTestSkipped('This test requires the platform not to support savepoints.');
126
        }
127
128
        $this->expectException(ConnectionException::class);
129
        $this->expectExceptionMessage('Savepoints are not supported by this driver.');
130
131
        $this->connection->setNestTransactionsWithSavepoints(true);
132
    }
133
134
    public function testCreateSavepointsNotSupportedThrowsException()
135
    {
136
        if ($this->connection->getDatabasePlatform()->supportsSavepoints()) {
137
            $this->markTestSkipped('This test requires the platform not to support savepoints.');
138
        }
139
140
        $this->expectException(ConnectionException::class);
141
        $this->expectExceptionMessage('Savepoints are not supported by this driver.');
142
143
        $this->connection->createSavepoint('foo');
144
    }
145
146
    public function testReleaseSavepointsNotSupportedThrowsException()
147
    {
148
        if ($this->connection->getDatabasePlatform()->supportsSavepoints()) {
149
            $this->markTestSkipped('This test requires the platform not to support savepoints.');
150
        }
151
152
        $this->expectException(ConnectionException::class);
153
        $this->expectExceptionMessage('Savepoints are not supported by this driver.');
154
155
        $this->connection->releaseSavepoint('foo');
156
    }
157
158
    public function testRollbackSavepointsNotSupportedThrowsException()
159
    {
160
        if ($this->connection->getDatabasePlatform()->supportsSavepoints()) {
161
            $this->markTestSkipped('This test requires the platform not to support savepoints.');
162
        }
163
164
        $this->expectException(ConnectionException::class);
165
        $this->expectExceptionMessage('Savepoints are not supported by this driver.');
166
167
        $this->connection->rollbackSavepoint('foo');
168
    }
169
170
    public function testTransactionBehaviorWithRollback()
171
    {
172
        try {
173
            $this->connection->beginTransaction();
174
            self::assertEquals(1, $this->connection->getTransactionNestingLevel());
175
176
            throw new Exception();
177
178
            $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...
179
        } catch (Throwable $e) {
180
            self::assertEquals(1, $this->connection->getTransactionNestingLevel());
181
            $this->connection->rollBack();
182
            self::assertEquals(0, $this->connection->getTransactionNestingLevel());
183
        }
184
    }
185
186
    public function testTransactionBehaviour()
187
    {
188
        try {
189
            $this->connection->beginTransaction();
190
            self::assertEquals(1, $this->connection->getTransactionNestingLevel());
191
            $this->connection->commit();
192
        } catch (Throwable $e) {
193
            $this->connection->rollBack();
194
            self::assertEquals(0, $this->connection->getTransactionNestingLevel());
195
        }
196
197
        self::assertEquals(0, $this->connection->getTransactionNestingLevel());
198
    }
199
200
    public function testTransactionalWithException()
201
    {
202
        try {
203
            $this->connection->transactional(static function ($conn) {
204
                /** @var Connection $conn */
205
                $conn->executeQuery($conn->getDatabasePlatform()->getDummySelectSQL());
206
                throw new RuntimeException('Ooops!');
207
            });
208
            $this->fail('Expected exception');
209
        } catch (RuntimeException $expected) {
210
            self::assertEquals(0, $this->connection->getTransactionNestingLevel());
211
        }
212
    }
213
214
    public function testTransactionalWithThrowable()
215
    {
216
        try {
217
            $this->connection->transactional(static function ($conn) {
218
                /** @var Connection $conn */
219
                $conn->executeQuery($conn->getDatabasePlatform()->getDummySelectSQL());
220
                throw new Error('Ooops!');
221
            });
222
            $this->fail('Expected exception');
223
        } catch (Error $expected) {
224
            self::assertEquals(0, $this->connection->getTransactionNestingLevel());
225
        }
226
    }
227
228
    public function testTransactional()
229
    {
230
        $res = $this->connection->transactional(static function ($conn) {
231
            /** @var Connection $conn */
232
            $conn->executeQuery($conn->getDatabasePlatform()->getDummySelectSQL());
233
        });
234
235
        self::assertNull($res);
236
    }
237
238
    public function testTransactionalReturnValue()
239
    {
240
        $res = $this->connection->transactional(static function () {
241
            return 42;
242
        });
243
244
        self::assertEquals(42, $res);
245
    }
246
247
    public function testPingDoesTriggersConnect()
248
    {
249
        self::assertTrue($this->connection->ping());
250
        self::assertTrue($this->connection->isConnected());
251
    }
252
253
    /**
254
     * @group DBAL-1025
255
     */
256
    public function testConnectWithoutExplicitDatabaseName()
257
    {
258
        if (in_array($this->connection->getDatabasePlatform()->getName(), ['oracle', 'db2'], true)) {
259
            $this->markTestSkipped('Platform does not support connecting without database name.');
260
        }
261
262
        $params = $this->connection->getParams();
263
        unset($params['dbname']);
264
265
        $connection = DriverManager::getConnection(
266
            $params,
267
            $this->connection->getConfiguration(),
268
            $this->connection->getEventManager()
269
        );
270
271
        self::assertTrue($connection->connect());
272
273
        $connection->close();
274
    }
275
276
    /**
277
     * @group DBAL-990
278
     */
279
    public function testDeterminesDatabasePlatformWhenConnectingToNonExistentDatabase()
280
    {
281
        if (in_array($this->connection->getDatabasePlatform()->getName(), ['oracle', 'db2'], true)) {
282
            $this->markTestSkipped('Platform does not support connecting without database name.');
283
        }
284
285
        $params = $this->connection->getParams();
286
287
        $params['dbname'] = 'foo_bar';
288
289
        $connection = DriverManager::getConnection(
290
            $params,
291
            $this->connection->getConfiguration(),
292
            $this->connection->getEventManager()
293
        );
294
295
        self::assertInstanceOf(AbstractPlatform::class, $connection->getDatabasePlatform());
296
        self::assertFalse($connection->isConnected());
297
        self::assertSame($params, $connection->getParams());
298
299
        $connection->close();
300
    }
301
}
302