Passed
Pull Request — master (#380)
by Wilmer
02:50
created

CommonConnectionTest   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 393
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 240
dl 0
loc 393
rs 10
c 2
b 0
f 0
wmc 17

10 Methods

Rating   Name   Duplication   Size   Complexity  
A testTransactionShortcutCorrect() 0 16 1
A testPartialRollbackTransactionsWithSavePoints() 0 49 1
A testRollbackTransactionsWithSavePoints() 0 33 1
A testExecute() 0 24 1
A testExceptionContainsRawQuery() 0 37 2
A testGetTableSchema() 0 5 1
B testLoggerProfiler() 0 85 3
A testTransaction() 0 40 1
A runExceptionTest() 0 53 3
A testNotProfiler() 0 23 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Tests\Common;
6
7
use Psr\Log\NullLogger;
8
use Yiisoft\Db\Connection\ConnectionInterface;
9
use Yiisoft\Db\Exception\Exception;
10
use Yiisoft\Db\Tests\AbstractConnectionTest;
11
use Yiisoft\Db\Tests\Support\Assert;
12
use Yiisoft\Db\Tests\Support\TestTrait;
13
14
/**
15
 * @group mssql
16
 * @group mysql
17
 * @group pgsql
18
 * @group oracle
19
 * @group sqlite
20
 */
21
abstract class CommonConnectionTest extends AbstractConnectionTest
22
{
23
    use TestTrait;
24
25
    /**
26
     * @dataProvider \Yiisoft\Db\Tests\Provider\ConnectionProvider::execute()
27
     */
28
    public function testExecute(string $expected): void
29
    {
30
        $db = $this->getConnectionWithData();
31
32
        $sql = <<<SQL
33
        INSERT INTO {{customer}}([[email]], [[name]], [[address]]) VALUES ('[email protected]', 'user4', 'address4')
34
        SQL;
35
        $command = $db->createCommand($sql);
36
37
        $this->assertSame(1, $command->execute());
38
39
        $sql = <<<SQL
40
        SELECT COUNT(*) FROM {{customer}} WHERE [[name]] = 'user4'
41
        SQL;
42
        $command = $db->createCommand($sql);
43
44
        $this->assertEquals(1, $command->queryScalar());
45
46
        $command = $db->createCommand('bad SQL');
47
48
        $this->expectException(Exception::class);
49
        $this->expectExceptionMessage($expected);
50
51
        $command->execute();
52
    }
53
54
    public function testExceptionContainsRawQuery(): void
55
    {
56
        $db = $this->getConnection();
57
58
        $command = $db->createCommand();
59
60
        if ($db->getTableSchema('qlog1', true) !== null) {
61
            $command->dropTable('qlog1')->execute();
62
        }
63
64
        /* profiling and logging */
65
        $command->createTable('qlog1', ['id' => 'pk'])->execute();
66
        $db->setEmulatePrepare(true);
67
        $logger = $this->getLogger();
68
        $profiler = $this->getProfiler();
69
        $db->setLogger($logger);
70
        $db->setProfiler($profiler);
71
72
        $this->runExceptionTest($db);
73
74
        /* profiling only */
75
        $db->setLogger(new NullLogger());
76
        $db->setProfiler($profiler);
77
78
        $this->runExceptionTest($db);
79
80
        /* logging only */
81
        $db->setLogger($logger);
82
        $db->notProfiler();
83
84
        $this->runExceptionTest($db);
85
86
        /* disabled */
87
        $db->setLogger(new NullLogger());
88
        $db->notProfiler();
89
90
        $this->runExceptionTest($db);
91
    }
92
93
    public function testGetTableSchema(): void
94
    {
95
        $db = $this->getConnection();
96
97
        $this->assertNull($db->getTableSchema('non_existing_table'));
98
    }
99
100
    public function testLoggerProfiler(): void
101
    {
102
        $db = $this->getConnection();
103
104
        foreach (['qlog1', 'qlog2', 'qlog3', 'qlog4'] as $table) {
105
            if ($db->getTableSchema($table, true) !== null) {
106
                $db->createCommand()->dropTable($table)->execute();
107
            }
108
        }
109
110
        $logger = $this->getLogger();
111
        $profiler = $this->getProfiler();
112
        /* profiling and logging */
113
        $db->setLogger($logger);
114
        $db->setProfiler($profiler);
115
116
        $this->assertNotNull($logger);
117
        $this->assertNotNull($profiler);
118
119
        $logger->flush();
120
        $profiler->flush();
121
        $db->createCommand()->createTable('qlog1', ['id' => 'pk'])->execute();
122
123
        $this->assertCount(1, Assert::getInaccessibleProperty($logger, 'messages'));
124
        $this->assertCount(1, Assert::getInaccessibleProperty($profiler, 'messages'));
125
        $this->assertNotNull($db->getTableSchema('qlog1', true));
126
127
        $logger->flush();
128
        $profiler->flush();
129
        $db->createCommand('SELECT * FROM {{qlog1}}')->queryAll();
130
131
        $this->assertCount(1, Assert::getInaccessibleProperty($logger, 'messages'));
132
        $this->assertCount(1, Assert::getInaccessibleProperty($profiler, 'messages'));
133
134
        /* profiling only */
135
        $db->setLogger(new NullLogger());
136
        $db->setProfiler($profiler);
137
        $logger->flush();
138
        $profiler->flush();
139
        $db->createCommand()->createTable('qlog2', ['id' => 'pk'])->execute();
140
141
        $this->assertCount(0, Assert::getInaccessibleProperty($logger, 'messages'));
142
        $this->assertCount(1, Assert::getInaccessibleProperty($profiler, 'messages'));
143
        $this->assertNotNull($db->getTableSchema('qlog2', true));
144
145
        $logger->flush();
146
        $profiler->flush();
147
        $db->createCommand('SELECT * FROM {{qlog2}}')->queryAll();
148
149
        $this->assertCount(0, Assert::getInaccessibleProperty($logger, 'messages'));
150
        $this->assertCount(1, Assert::getInaccessibleProperty($profiler, 'messages'));
151
152
        /* logging only */
153
        $db->setLogger($logger);
154
        $db->notProfiler();
155
        $logger->flush();
156
        $profiler->flush();
157
        $db->createCommand()->createTable('qlog3', ['id' => 'pk'])->execute();
158
159
        $this->assertCount(1, Assert::getInaccessibleProperty($logger, 'messages'));
160
        $this->assertCount(0, Assert::getInaccessibleProperty($profiler, 'messages'));
161
        $this->assertNotNull($db->getTableSchema('qlog3', true));
162
163
        $logger->flush();
164
        $profiler->flush();
165
        $db->createCommand('SELECT * FROM {{qlog3}}')->queryAll();
166
167
        $this->assertCount(1, Assert::getInaccessibleProperty($logger, 'messages'));
168
        $this->assertCount(0, Assert::getInaccessibleProperty($profiler, 'messages'));
169
170
        /* disabled */
171
        $db->setLogger(new NullLogger());
172
        $db->notProfiler();
173
        $logger->flush();
174
        $profiler->flush();
175
        $db->createCommand()->createTable('qlog4', ['id' => 'pk'])->execute();
176
177
        $this->assertNotNull($db->getTableSchema('qlog4', true));
178
        $this->assertCount(0, Assert::getInaccessibleProperty($logger, 'messages'));
179
        $this->assertCount(0, Assert::getInaccessibleProperty($profiler, 'messages'));
180
181
        $db->createCommand('SELECT * FROM {{qlog4}}')->queryAll();
182
183
        $this->assertCount(0, Assert::getInaccessibleProperty($logger, 'messages'));
184
        $this->assertCount(0, Assert::getInaccessibleProperty($profiler, 'messages'));
185
    }
186
187
    public function testNotProfiler(): void
188
    {
189
        $db = $this->getConnection();
190
191
        if ($db->getTableSchema('notProfiler1', true) !== null) {
192
            $db->createCommand()->dropTable('notProfiler1')->execute();
193
        }
194
195
        if ($db->getTableSchema('notProfiler2', true) !== null) {
196
            $db->createCommand()->dropTable('notProfiler2')->execute();
197
        }
198
199
        $profiler = $this->getProfiler();
200
        $db->notProfiler();
201
        $profiler->flush();
202
        $db->createCommand()->createTable('notProfiler1', ['id' => 'pk'])->execute();
203
204
        $this->assertCount(0, Assert::getInaccessibleProperty($profiler, 'messages'));
205
206
        $db->setProfiler($profiler);
207
        $db->createCommand()->createTable('notProfiler2', ['id' => 'pk'])->execute();
208
209
        $this->assertCount(1, Assert::getInaccessibleProperty($profiler, 'messages'));
210
    }
211
212
    public function testPartialRollbackTransactionsWithSavePoints(): void
213
    {
214
        $db = $this->getConnectionWithData();
215
216
        $db->open();
217
        $transaction = $db->beginTransaction();
218
219
        $this->assertSame(1, $transaction->getLevel());
220
221
        $db->createCommand()->insert('profile', ['description' => 'test transaction1'])->execute();
222
        $transaction->begin();
223
224
        $this->assertSame(2, $transaction->getLevel());
225
226
        $db->createCommand()->insert('profile', ['description' => 'test transaction2'])->execute();
227
        $transaction->rollBack();
228
229
        $this->assertSame(1, $transaction->getLevel());
230
        $this->assertTrue($transaction->isActive());
231
232
        $db->createCommand()->insert('profile', ['description' => 'test transaction3'])->execute();
233
        $transaction->commit();
234
235
        $this->assertSame(0, $transaction->getLevel());
236
        $this->assertFalse($transaction->isActive());
237
        $this->assertNull($db->getTransaction());
238
        $this->assertEquals(
239
            1,
240
            $db->createCommand(
241
                <<<SQL
242
                SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'test transaction1'
243
                SQL
244
            )->queryScalar(),
245
        );
246
        $this->assertEquals(
247
            0,
248
            $db->createCommand(
249
                <<<SQL
250
                SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'test transaction2'
251
                SQL
252
            )->queryScalar()
253
        );
254
        $this->assertEquals(
255
            1,
256
            $db->createCommand(
257
                <<<SQL
258
                SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'test transaction3'
259
                SQL
260
            )->queryScalar(),
261
        );
262
    }
263
264
    public function testRollbackTransactionsWithSavePoints(): void
265
    {
266
        $db = $this->getConnectionWithData();
267
268
        $db->open();
269
        $transaction = $db->beginTransaction();
270
271
        $this->assertSame(1, $transaction->getLevel());
272
273
        $db->createCommand()->insert('profile', ['description' => 'test transaction'])->execute();
274
        $transaction->begin();
275
276
        $this->assertSame(2, $transaction->getLevel());
277
278
        $db->createCommand()->insert('profile', ['description' => 'test transaction'])->execute();
279
        $transaction->rollBack();
280
281
        $this->assertSame(1, $transaction->getLevel());
282
        $this->assertTrue($transaction->isActive());
283
284
        $db->createCommand()->insert('profile', ['description' => 'test transaction'])->execute();
285
        $transaction->rollBack();
286
287
        $this->assertSame(0, $transaction->getLevel());
288
        $this->assertFalse($transaction->isActive());
289
        $this->assertNull($db->getTransaction());
290
        $this->assertEquals(
291
            0,
292
            $db->createCommand(
293
                <<<SQL
294
                SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'test transaction'
295
                SQL
296
            )->queryScalar(),
297
        );
298
    }
299
300
    public function testTransaction(): void
301
    {
302
        $db = $this->getConnectionWithData();
303
304
        $db->setLogger($this->getLogger());
305
306
        $this->assertNull($db->getTransaction());
307
308
        $transaction = $db->beginTransaction();
309
310
        $this->assertNotNull($db->getTransaction());
311
        $this->assertTrue($transaction->isActive());
312
313
        $db->createCommand()->insert('profile', ['description' => 'test transaction'])->execute();
314
        $transaction->rollBack();
315
316
        $this->assertFalse($transaction->isActive());
317
        $this->assertNull($db->getTransaction());
318
        $this->assertEquals(
319
            0,
320
            $db->createCommand(
321
                <<<SQL
322
                SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'test transaction'
323
                SQL
324
            )->queryScalar()
325
        );
326
327
        $transaction = $db->beginTransaction();
328
        $db->createCommand()->insert('profile', ['description' => 'test transaction'])->execute();
329
        $transaction->commit();
330
331
        $this->assertFalse($transaction->isActive());
332
        $this->assertNull($db->getTransaction());
333
        $this->assertEquals(
334
            1,
335
            $db->createCommand(
336
                <<<SQL
337
                SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'test transaction'
338
                SQL
339
            )->queryScalar(),
340
        );
341
    }
342
343
    public function testTransactionShortcutCorrect(): void
344
    {
345
        $db = $this->getConnectionWithData();
346
347
        $result = $db->transaction(static function () use ($db) {
348
            $db->createCommand()->insert('profile', ['description' => 'test transaction shortcut'])->execute();
349
            return true;
350
        });
351
352
        $this->assertTrue($result, 'transaction shortcut valid value should be returned from callback');
353
354
        $profilesCount = $db->createCommand(
355
            "SELECT COUNT(*) FROM {{profile}} WHERE [[description]] = 'test transaction shortcut'"
356
        )->queryScalar();
357
358
        $this->assertEquals(1, $profilesCount, 'profile should be inserted in transaction shortcut');
359
    }
360
361
    private function runExceptionTest(ConnectionInterface $db): void
362
    {
363
        $thrown = false;
364
        $command = $db->createCommand();
365
366
        try {
367
            $command->setSql(
368
                <<<SQL
369
                INSERT INTO qlog1(a) VALUES(1)
370
                SQL
371
            )->bindValues([':a' => 1])->execute();
372
        } catch (Exception $e) {
373
            $this->assertStringContainsString(
374
                <<<SQL
375
                INSERT INTO qlog1(a) VALUES(1)
376
                SQL,
377
                $e->getMessage(),
378
                'Exceptions message should contain raw SQL query: ' . $e,
379
            );
380
381
            $thrown = true;
382
        }
383
384
        $this->assertTrue($thrown, 'An exception should have been thrown by the command.');
385
386
        $thrown = false;
387
388
        $expected = match ($db->getName()) {
389
            'sqlite' => <<<SQL
390
            SELECT * FROM qlog1 WHERE id=:a ORDER BY nonexistingcolumn
391
            SQL,
392
            'sqlsrv' => <<<SQL
393
            SELECT * FROM qlog1 WHERE id=1 ORDER BY nonexistingcolumn
394
            SQL,
395
        };
396
397
        try {
398
            $command->setSql(
399
                <<<SQL
400
                SELECT * FROM qlog1 WHERE id=:a ORDER BY nonexistingcolumn
401
                SQL
402
            )->bindValues([':a' => 1])->queryAll();
403
        } catch (Exception $e) {
404
            $this->assertStringContainsString(
405
                $expected,
406
                $e->getMessage(),
407
                'Exceptions message should contain raw SQL query: ' . $e
408
            );
409
410
            $thrown = true;
411
        }
412
413
        $this->assertTrue($thrown, 'An exception should have been thrown by the command.');
414
    }
415
}
416