Passed
Branch dev (f56f10)
by Wilmer
04:41 queued 01:34
created

TestConnectionTrait::testEnableQueryLog()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 90
Code Lines 54

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 54
nc 3
nop 0
dl 0
loc 90
rs 9.0036
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\TestSupport;
6
7
use Yiisoft\Db\Connection\ConnectionInterface;
8
use Yiisoft\Db\Exception\Exception;
9
use Yiisoft\Db\Exception\NotSupportedException;
10
use Yiisoft\Db\Transaction\Transaction;
11
12
use function serialize;
13
use function unserialize;
14
15
trait TestConnectionTrait
16
{
17
    public function testSerialize(): void
18
    {
19
        $db = $this->getConnection();
0 ignored issues
show
Bug introduced by
It seems like getConnection() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

19
        /** @scrutinizer ignore-call */ 
20
        $db = $this->getConnection();
Loading history...
20
21
        $db->open();
22
23
        $serialized = serialize($db);
24
25
        $this->assertNotNull($db->getPDO());
0 ignored issues
show
Bug introduced by
It seems like assertNotNull() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

25
        $this->/** @scrutinizer ignore-call */ 
26
               assertNotNull($db->getPDO());
Loading history...
26
27
        $unserialized = unserialize($serialized);
28
29
        $this->assertInstanceOf(ConnectionInterface::class, $unserialized);
0 ignored issues
show
Bug introduced by
It seems like assertInstanceOf() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

29
        $this->/** @scrutinizer ignore-call */ 
30
               assertInstanceOf(ConnectionInterface::class, $unserialized);
Loading history...
30
        $this->assertNull($unserialized->getPDO());
0 ignored issues
show
Bug introduced by
It seems like assertNull() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

30
        $this->/** @scrutinizer ignore-call */ 
31
               assertNull($unserialized->getPDO());
Loading history...
31
        $this->assertEquals(123, $unserialized->createCommand('SELECT 123')->queryScalar());
0 ignored issues
show
Bug introduced by
It seems like assertEquals() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

31
        $this->/** @scrutinizer ignore-call */ 
32
               assertEquals(123, $unserialized->createCommand('SELECT 123')->queryScalar());
Loading history...
32
    }
33
34
    public function testTransaction(): void
35
    {
36
        $db = $this->getConnection();
37
38
        $this->assertNull($db->getTransaction());
39
40
        $transaction = $db->beginTransaction();
41
42
        $this->assertNotNull($db->getTransaction());
43
        $this->assertTrue($transaction->isActive());
0 ignored issues
show
Bug introduced by
It seems like assertTrue() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

43
        $this->/** @scrutinizer ignore-call */ 
44
               assertTrue($transaction->isActive());
Loading history...
44
45
        $db->createCommand()->insert('profile', ['description' => 'test transaction'])->execute();
46
47
        $transaction->rollBack();
48
49
        $this->assertFalse($transaction->isActive());
0 ignored issues
show
Bug introduced by
It seems like assertFalse() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

49
        $this->/** @scrutinizer ignore-call */ 
50
               assertFalse($transaction->isActive());
Loading history...
50
        $this->assertNull($db->getTransaction());
51
        $this->assertEquals(0, $db->createCommand(
52
            "SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'test transaction'"
53
        )->queryScalar());
54
55
        $transaction = $db->beginTransaction();
56
57
        $db->createCommand()->insert('profile', ['description' => 'test transaction'])->execute();
58
59
        $transaction->commit();
60
61
        $this->assertFalse($transaction->isActive());
62
        $this->assertNull($db->getTransaction());
63
        $this->assertEquals(1, $db->createCommand(
64
            "SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'test transaction'"
65
        )->queryScalar());
66
    }
67
68
    public function testTransactionShortcutException(): void
69
    {
70
        $db = $this->getConnection(true);
71
72
        $this->expectException(Exception::class);
0 ignored issues
show
Bug introduced by
It seems like expectException() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

72
        $this->/** @scrutinizer ignore-call */ 
73
               expectException(Exception::class);
Loading history...
73
74
        $db->transaction(function () use ($db) {
75
            $db->createCommand()->insert('profile', ['description' => 'test transaction shortcut'])->execute();
76
            throw new Exception('Exception in transaction shortcut');
77
        });
78
        $profilesCount = $db->createCommand(
79
            "SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'test transaction shortcut'"
80
        )->queryScalar();
81
        $this->assertEquals(0, $profilesCount, 'profile should not be inserted in transaction shortcut');
82
    }
83
84
    public function testTransactionShortcutCorrect(): void
85
    {
86
        $db = $this->getConnection(true);
87
88
        $result = $db->transaction(static function () use ($db) {
89
            $db->createCommand()->insert('profile', ['description' => 'test transaction shortcut'])->execute();
90
            return true;
91
        });
92
93
        $this->assertTrue($result, 'transaction shortcut valid value should be returned from callback');
94
95
        $profilesCount = $db->createCommand(
96
            "SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'test transaction shortcut'"
97
        )->queryScalar();
98
99
        $this->assertEquals(1, $profilesCount, 'profile should be inserted in transaction shortcut');
100
    }
101
102
    /**
103
     * Tests nested transactions with partial rollback.
104
     *
105
     * {@see https://github.com/yiisoft/yii2/issues/9851}
106
     */
107
    public function testNestedTransaction(): void
108
    {
109
        $db = $this->getConnection();
110
111
        $db->transaction(function (ConnectionInterface $db) {
112
            $this->assertNotNull($db->getTransaction());
113
114
            $db->transaction(function (ConnectionInterface $db) {
115
                $this->assertNotNull($db->getTransaction());
116
                $db->getTransaction()->rollBack();
117
            });
118
119
            $this->assertNotNull($db->getTransaction());
120
        });
121
    }
122
123
    public function testNestedTransactionNotSupported(): void
124
    {
125
        $db = $this->getConnection();
126
127
        $db->setEnableSavepoint(false);
128
129
        $db->transaction(function (ConnectionInterface $db) {
130
            $this->assertNotNull($db->getTransaction());
131
            $this->expectException(NotSupportedException::class);
132
            $db->beginTransaction();
133
        });
134
    }
135
136
    public function testEnableQueryLog(): void
137
    {
138
        $db = $this->getConnection();
139
140
        foreach (['qlog1', 'qlog2', 'qlog3', 'qlog4'] as $table) {
141
            if ($db->getTableSchema($table, true) !== null) {
142
                $db->createCommand()->dropTable($table)->execute();
143
            }
144
        }
145
146
        /* profiling and logging */
147
        $db->setLogger($this->logger);
148
        $db->setProfiler($this->profiler);
149
150
        $this->logger->flush();
151
        $this->profiler->flush();
152
153
        $db->createCommand()->createTable('qlog1', ['id' => 'pk'])->execute();
154
155
        $this->assertCount(1, $this->getInaccessibleProperty($this->logger, 'messages'));
0 ignored issues
show
Bug introduced by
It seems like assertCount() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

155
        $this->/** @scrutinizer ignore-call */ 
156
               assertCount(1, $this->getInaccessibleProperty($this->logger, 'messages'));
Loading history...
Bug introduced by
It seems like getInaccessibleProperty() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

155
        $this->assertCount(1, $this->/** @scrutinizer ignore-call */ getInaccessibleProperty($this->logger, 'messages'));
Loading history...
156
        $this->assertCount(1, $this->getInaccessibleProperty($this->profiler, 'messages'));
157
        $this->assertNotNull($db->getTableSchema('qlog1', true));
158
159
        $this->logger->flush();
160
        $this->profiler->flush();
161
162
        $db->createCommand('SELECT * FROM {{qlog1}}')->queryAll();
163
164
        $this->assertCount(1, $this->getInaccessibleProperty($this->logger, 'messages'));
165
        $this->assertCount(1, $this->getInaccessibleProperty($this->profiler, 'messages'));
166
167
        /* profiling only */
168
        $db->setLogger(null);
169
        $db->setProfiler($this->profiler);
170
171
        $this->logger->flush();
172
        $this->profiler->flush();
173
174
        $db->createCommand()->createTable('qlog2', ['id' => 'pk'])->execute();
175
176
        $this->assertCount(0, $this->getInaccessibleProperty($this->logger, 'messages'));
177
        $this->assertCount(1, $this->getInaccessibleProperty($this->profiler, 'messages'));
178
        $this->assertNotNull($db->getTableSchema('qlog2', true));
179
180
        $this->logger->flush();
181
        $this->profiler->flush();
182
183
        $db->createCommand('SELECT * FROM {{qlog2}}')->queryAll();
184
185
        $this->assertCount(0, $this->getInaccessibleProperty($this->logger, 'messages'));
186
        $this->assertCount(1, $this->getInaccessibleProperty($this->profiler, 'messages'));
187
188
        /* logging only */
189
        $db->setLogger($this->logger);
190
        $db->setProfiler(null);
191
192
        $this->logger->flush();
193
        $this->profiler->flush();
194
195
        $db->createCommand()->createTable('qlog3', ['id' => 'pk'])->execute();
196
197
        $this->assertCount(1, $this->getInaccessibleProperty($this->logger, 'messages'));
198
        $this->assertCount(0, $this->getInaccessibleProperty($this->profiler, 'messages'));
199
        $this->assertNotNull($db->getTableSchema('qlog3', true));
200
201
        $this->logger->flush();
202
        $this->profiler->flush();
203
204
        $db->createCommand('SELECT * FROM {{qlog3}}')->queryAll();
205
206
        $this->assertCount(1, $this->getInaccessibleProperty($this->logger, 'messages'));
207
        $this->assertCount(0, $this->getInaccessibleProperty($this->profiler, 'messages'));
208
209
        /* disabled */
210
        $db->setLogger(null);
211
        $db->setProfiler(null);
212
213
        $this->logger->flush();
214
        $this->profiler->flush();
215
216
        $db->createCommand()->createTable('qlog4', ['id' => 'pk'])->execute();
217
218
        $this->assertNotNull($db->getTableSchema('qlog4', true));
219
        $this->assertCount(0, $this->getInaccessibleProperty($this->logger, 'messages'));
220
        $this->assertCount(0, $this->getInaccessibleProperty($this->profiler, 'messages'));
221
222
        $db->createCommand('SELECT * FROM {{qlog4}}')->queryAll();
223
224
        $this->assertCount(0, $this->getInaccessibleProperty($this->logger, 'messages'));
225
        $this->assertCount(0, $this->getInaccessibleProperty($this->profiler, 'messages'));
226
    }
227
228
    public function testExceptionContainsRawQuery(): void
229
    {
230
        $db = $this->getConnection();
231
232
        if ($db->getTableSchema('qlog1', true) === null) {
233
            $db->createCommand()->createTable('qlog1', ['id' => 'pk'])->execute();
234
        }
235
236
        $db->setEmulatePrepare(true);
237
238
        /* profiling and logging */
239
        $db->setLogger($this->logger);
240
        $db->setProfiler($this->profiler);
241
242
        $this->runExceptionTest($db);
243
244
        /* profiling only */
245
        $db->setLogger(null);
246
        $db->setProfiler($this->profiler);
247
248
        $this->runExceptionTest($db);
249
250
        /* logging only */
251
        $db->setLogger($this->logger);
252
        $db->setProfiler(null);
253
254
        $this->runExceptionTest($db);
255
256
        /* disabled */
257
        $db->setLogger(null);
258
        $db->setProfiler(null);
259
260
        $this->runExceptionTest($db);
261
    }
262
263
    /**
264
     * @param ConnectionInterface $db
265
     */
266
    private function runExceptionTest(ConnectionInterface $db): void
267
    {
268
        $thrown = false;
269
270
        try {
271
            $db->createCommand('INSERT INTO qlog1(a) VALUES(:a);', [':a' => 1])->execute();
272
        } catch (Exception $e) {
273
            $this->assertStringContainsString(
0 ignored issues
show
Bug introduced by
It seems like assertStringContainsString() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

273
            $this->/** @scrutinizer ignore-call */ 
274
                   assertStringContainsString(
Loading history...
274
                'INSERT INTO qlog1(a) VALUES(1);',
275
                $e->getMessage(),
276
                'Exceptions message should contain raw SQL query: ' . (string) $e
277
            );
278
279
            $thrown = true;
280
        }
281
282
        $this->assertTrue($thrown, 'An exception should have been thrown by the command.');
283
284
        $thrown = false;
285
286
        try {
287
            $db->createCommand(
288
                'SELECT * FROM qlog1 WHERE id=:a ORDER BY nonexistingcolumn;',
289
                [':a' => 1]
290
            )->queryAll();
291
        } catch (Exception $e) {
292
            $this->assertStringContainsString(
293
                'SELECT * FROM qlog1 WHERE id=1 ORDER BY nonexistingcolumn;',
294
                $e->getMessage(),
295
                'Exceptions message should contain raw SQL query: ' . (string) $e
296
            );
297
298
            $thrown = true;
299
        }
300
301
        $this->assertTrue($thrown, 'An exception should have been thrown by the command.');
302
    }
303
304
    /**
305
     * Ensure database connection is reset on when a connection is cloned.
306
     *
307
     * Make sure each connection element has its own PDO instance i.e. own connection to the DB.
308
     * Also transaction elements should not be shared between two connections.
309
     */
310
    public function testClone(): void
311
    {
312
        $db = $this->getConnection();
313
314
        $this->assertNull($db->getTransaction());
315
        $this->assertNull($db->getPDO());
316
317
        $db->open();
318
319
        $this->assertNull($db->getTransaction());
320
        $this->assertNotNull($db->getPDO());
321
322
        $conn2 = clone $db;
323
324
        $this->assertNull($db->getTransaction());
325
        $this->assertNotNull($db->getPDO());
326
327
        $this->assertNull($conn2->getTransaction());
328
        $this->assertNull($conn2->getPDO());
329
330
        $db->beginTransaction();
331
332
        $this->assertNotNull($db->getTransaction());
333
        $this->assertNotNull($db->getPDO());
334
335
        $this->assertNull($conn2->getTransaction());
336
        $this->assertNull($conn2->getPDO());
337
338
        $conn3 = clone $db;
339
340
        $this->assertNotNull($db->getTransaction());
341
        $this->assertNotNull($db->getPDO());
342
        $this->assertNull($conn3->getTransaction());
343
        $this->assertNull($conn3->getPDO());
344
    }
345
}
346