Passed
Pull Request — master (#3120)
by Sergei
12:25
created

ConnectionTest::testTransactionNestingBehaviorWithSavepoints()   B

Complexity

Conditions 5
Paths 200

Size

Total Lines 36
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

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