Passed
Push — master ( 372fe8...9b75cd )
by Jonathan
65:38
created

testExecuteCacheQueryStripsPlatformFromConnectionParamsBeforeGeneratingCacheKeys()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 46
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 27
dl 0
loc 46
rs 9.488
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Doctrine\Tests\DBAL;
4
5
use Doctrine\Common\Cache\Cache;
6
use Doctrine\Common\EventManager;
7
use Doctrine\DBAL\Cache\ArrayStatement;
8
use Doctrine\DBAL\Cache\QueryCacheProfile;
9
use Doctrine\DBAL\Configuration;
10
use Doctrine\DBAL\Connection;
11
use Doctrine\DBAL\ConnectionException;
12
use Doctrine\DBAL\DBALException;
13
use Doctrine\DBAL\Driver;
14
use Doctrine\DBAL\Driver\Connection as DriverConnection;
15
use Doctrine\DBAL\Driver\Statement;
16
use Doctrine\DBAL\DriverManager;
17
use Doctrine\DBAL\Events;
18
use Doctrine\DBAL\Exception\InvalidArgumentException;
19
use Doctrine\DBAL\FetchMode;
20
use Doctrine\DBAL\Logging\DebugStack;
21
use Doctrine\DBAL\Logging\EchoSQLLogger;
22
use Doctrine\DBAL\ParameterType;
23
use Doctrine\DBAL\Platforms\AbstractPlatform;
24
use Doctrine\Tests\DbalTestCase;
25
use Doctrine\Tests\Mocks\DriverStatementMock;
26
use Doctrine\Tests\Mocks\ServerInfoAwareConnectionMock;
27
use Doctrine\Tests\Mocks\VersionAwarePlatformDriverMock;
28
use Exception;
29
use PHPUnit\Framework\MockObject\MockObject;
30
use stdClass;
31
use function call_user_func_array;
32
33
/**
34
 * @requires extension pdo_mysql
35
 */
36
class ConnectionTest extends DbalTestCase
37
{
38
    /** @var Connection */
39
    private $connection;
40
41
    /** @var string[] */
42
    protected $params = [
43
        'driver' => 'pdo_mysql',
44
        'host' => 'localhost',
45
        'user' => 'root',
46
        'password' => 'password',
47
        'port' => '1234',
48
    ];
49
50
    protected function setUp() : void
51
    {
52
        $this->connection = DriverManager::getConnection($this->params);
53
    }
54
55
    /**
56
     * @return Connection|MockObject
57
     */
58
    private function getExecuteUpdateMockConnection()
59
    {
60
        $driverMock = $this->createMock(Driver::class);
61
62
        $driverMock->expects($this->any())
63
            ->method('connect')
64
            ->will($this->returnValue(
65
                $this->createMock(DriverConnection::class)
66
            ));
67
68
        $platform = $this->getMockForAbstractClass(AbstractPlatform::class);
69
70
        return $this->getMockBuilder(Connection::class)
71
            ->setMethods(['executeUpdate'])
72
            ->setConstructorArgs([['platform' => $platform], $driverMock])
73
            ->getMock();
74
    }
75
76
    public function testIsConnected()
77
    {
78
        self::assertFalse($this->connection->isConnected());
79
    }
80
81
    public function testNoTransactionActiveByDefault()
82
    {
83
        self::assertFalse($this->connection->isTransactionActive());
84
    }
85
86
    public function testCommitWithNoActiveTransactionThrowsException()
87
    {
88
        $this->expectException(ConnectionException::class);
89
        $this->connection->commit();
90
    }
91
92
    public function testRollbackWithNoActiveTransactionThrowsException()
93
    {
94
        $this->expectException(ConnectionException::class);
95
        $this->connection->rollBack();
96
    }
97
98
    public function testSetRollbackOnlyNoActiveTransactionThrowsException()
99
    {
100
        $this->expectException(ConnectionException::class);
101
        $this->connection->setRollbackOnly();
102
    }
103
104
    public function testIsRollbackOnlyNoActiveTransactionThrowsException()
105
    {
106
        $this->expectException(ConnectionException::class);
107
        $this->connection->isRollbackOnly();
108
    }
109
110
    public function testGetConfiguration()
111
    {
112
        $config = $this->connection->getConfiguration();
113
114
        self::assertInstanceOf(Configuration::class, $config);
115
    }
116
117
    public function testGetHost()
118
    {
119
        self::assertEquals('localhost', $this->connection->getHost());
120
    }
121
122
    public function testGetPort()
123
    {
124
        self::assertEquals('1234', $this->connection->getPort());
125
    }
126
127
    public function testGetUsername()
128
    {
129
        self::assertEquals('root', $this->connection->getUsername());
130
    }
131
132
    public function testGetPassword()
133
    {
134
        self::assertEquals('password', $this->connection->getPassword());
135
    }
136
137
    public function testGetDriver()
138
    {
139
        self::assertInstanceOf(\Doctrine\DBAL\Driver\PDOMySql\Driver::class, $this->connection->getDriver());
140
    }
141
142
    public function testGetEventManager()
143
    {
144
        self::assertInstanceOf(EventManager::class, $this->connection->getEventManager());
145
    }
146
147
    public function testConnectDispatchEvent()
148
    {
149
        $listenerMock = $this->getMockBuilder('ConnectDispatchEventListener')
150
            ->setMethods(['postConnect'])
151
            ->getMock();
152
        $listenerMock->expects($this->once())->method('postConnect');
153
154
        $eventManager = new EventManager();
155
        $eventManager->addEventListener([Events::postConnect], $listenerMock);
156
157
        $driverMock = $this->createMock(Driver::class);
158
        $driverMock->expects($this->at(0))
159
                   ->method('connect');
160
161
        $conn = new Connection([], $driverMock, new Configuration(), $eventManager);
162
        $conn->connect();
163
    }
164
165
    public function testEventManagerPassedToPlatform()
166
    {
167
        $eventManager = new EventManager();
168
169
        /** @var AbstractPlatform|MockObject $driver */
170
        $platform = $this->createMock(AbstractPlatform::class);
171
        $platform->expects($this->once())
172
            ->method('setEventManager')
173
            ->with($eventManager);
174
175
        /** @var Driver|MockObject $driver */
176
        $driver = $this->createMock(Driver::class);
177
        $driver->expects($this->any())
178
            ->method('getDatabasePlatform')
179
            ->willReturn($platform);
180
181
        $connection = new Connection($this->params, $driver, null, $eventManager);
182
        $connection->getDatabasePlatform();
183
    }
184
185
    /**
186
     * @requires extension pdo_sqlite
187
     * @dataProvider getQueryMethods
188
     */
189
    public function testDriverExceptionIsWrapped($method)
190
    {
191
        $this->expectException(DBALException::class);
192
        $this->expectExceptionMessage("An exception occurred while executing 'MUUHAAAAHAAAA':\n\nSQLSTATE[HY000]: General error: 1 near \"MUUHAAAAHAAAA\"");
193
194
        $connection = DriverManager::getConnection([
195
            'driver' => 'pdo_sqlite',
196
            'memory' => true,
197
        ]);
198
199
        $connection->$method('MUUHAAAAHAAAA');
200
    }
201
202
    public function getQueryMethods()
203
    {
204
        return [
205
            ['exec'],
206
            ['query'],
207
            ['executeQuery'],
208
            ['executeUpdate'],
209
            ['prepare'],
210
        ];
211
    }
212
213
    /**
214
     * Pretty dumb test, however we want to check that the EchoSQLLogger correctly implements the interface.
215
     *
216
     * @group DBAL-11
217
     */
218
    public function testEchoSQLLogger()
219
    {
220
        $logger = new EchoSQLLogger();
221
        $this->connection->getConfiguration()->setSQLLogger($logger);
222
        self::assertSame($logger, $this->connection->getConfiguration()->getSQLLogger());
223
    }
224
225
    /**
226
     * Pretty dumb test, however we want to check that the DebugStack correctly implements the interface.
227
     *
228
     * @group DBAL-11
229
     */
230
    public function testDebugSQLStack()
231
    {
232
        $logger = new DebugStack();
233
        $this->connection->getConfiguration()->setSQLLogger($logger);
234
        self::assertSame($logger, $this->connection->getConfiguration()->getSQLLogger());
235
    }
236
237
    /**
238
     * @group DBAL-81
239
     */
240
    public function testIsAutoCommit()
241
    {
242
        self::assertTrue($this->connection->isAutoCommit());
243
    }
244
245
    /**
246
     * @group DBAL-81
247
     */
248
    public function testSetAutoCommit()
249
    {
250
        $this->connection->setAutoCommit(false);
251
        self::assertFalse($this->connection->isAutoCommit());
252
        $this->connection->setAutoCommit(0);
253
        self::assertFalse($this->connection->isAutoCommit());
254
    }
255
256
    /**
257
     * @group DBAL-81
258
     */
259
    public function testConnectStartsTransactionInNoAutoCommitMode()
260
    {
261
        $driverMock = $this->createMock(Driver::class);
262
        $driverMock->expects($this->any())
263
            ->method('connect')
264
            ->will($this->returnValue(
265
                $this->createMock(DriverConnection::class)
266
            ));
267
        $conn = new Connection([], $driverMock);
268
269
        $conn->setAutoCommit(false);
270
271
        self::assertFalse($conn->isTransactionActive());
272
273
        $conn->connect();
274
275
        self::assertTrue($conn->isTransactionActive());
276
    }
277
278
    /**
279
     * @group DBAL-81
280
     */
281
    public function testCommitStartsTransactionInNoAutoCommitMode()
282
    {
283
        $driverMock = $this->createMock(Driver::class);
284
        $driverMock->expects($this->any())
285
            ->method('connect')
286
            ->will($this->returnValue(
287
                $this->createMock(DriverConnection::class)
288
            ));
289
        $conn = new Connection([], $driverMock);
290
291
        $conn->setAutoCommit(false);
292
        $conn->connect();
293
        $conn->commit();
294
295
        self::assertTrue($conn->isTransactionActive());
296
    }
297
298
    /**
299
     * @group DBAL-81
300
     */
301
    public function testRollBackStartsTransactionInNoAutoCommitMode()
302
    {
303
        $driverMock = $this->createMock(Driver::class);
304
        $driverMock->expects($this->any())
305
            ->method('connect')
306
            ->will($this->returnValue(
307
                $this->createMock(DriverConnection::class)
308
            ));
309
        $conn = new Connection([], $driverMock);
310
311
        $conn->setAutoCommit(false);
312
        $conn->connect();
313
        $conn->rollBack();
314
315
        self::assertTrue($conn->isTransactionActive());
316
    }
317
318
    /**
319
     * @group DBAL-81
320
     */
321
    public function testSwitchingAutoCommitModeCommitsAllCurrentTransactions()
322
    {
323
        $driverMock = $this->createMock(Driver::class);
324
        $driverMock->expects($this->any())
325
            ->method('connect')
326
            ->will($this->returnValue(
327
                $this->createMock(DriverConnection::class)
328
            ));
329
        $conn = new Connection([], $driverMock);
330
331
        $conn->connect();
332
        $conn->beginTransaction();
333
        $conn->beginTransaction();
334
        $conn->setAutoCommit(false);
335
336
        self::assertSame(1, $conn->getTransactionNestingLevel());
337
338
        $conn->beginTransaction();
339
        $conn->beginTransaction();
340
        $conn->setAutoCommit(true);
341
342
        self::assertFalse($conn->isTransactionActive());
343
    }
344
345
    public function testEmptyInsert()
346
    {
347
        $conn = $this->getExecuteUpdateMockConnection();
348
349
        $conn->expects($this->once())
350
            ->method('executeUpdate')
351
            ->with('INSERT INTO footable () VALUES ()');
352
353
        $conn->insert('footable', []);
354
    }
355
356
    /**
357
     * @group DBAL-2511
358
     */
359
    public function testUpdateWithDifferentColumnsInDataAndIdentifiers()
360
    {
361
        $conn = $this->getExecuteUpdateMockConnection();
362
363
        $conn->expects($this->once())
364
            ->method('executeUpdate')
365
            ->with(
366
                'UPDATE TestTable SET text = ?, is_edited = ? WHERE id = ? AND name = ?',
367
                [
368
                    'some text',
369
                    true,
370
                    1,
371
                    'foo',
372
                ],
373
                [
374
                    'string',
375
                    'boolean',
376
                    'integer',
377
                    'string',
378
                ]
379
            );
380
381
        $conn->update(
382
            'TestTable',
383
            [
384
                'text' => 'some text',
385
                'is_edited' => true,
386
            ],
387
            [
388
                'id' => 1,
389
                'name' => 'foo',
390
            ],
391
            [
392
                'text' => 'string',
393
                'is_edited' => 'boolean',
394
                'id' => 'integer',
395
                'name' => 'string',
396
            ]
397
        );
398
    }
399
400
    /**
401
     * @group DBAL-2511
402
     */
403
    public function testUpdateWithSameColumnInDataAndIdentifiers()
404
    {
405
        $conn = $this->getExecuteUpdateMockConnection();
406
407
        $conn->expects($this->once())
408
            ->method('executeUpdate')
409
            ->with(
410
                'UPDATE TestTable SET text = ?, is_edited = ? WHERE id = ? AND is_edited = ?',
411
                [
412
                    'some text',
413
                    true,
414
                    1,
415
                    false,
416
                ],
417
                [
418
                    'string',
419
                    'boolean',
420
                    'integer',
421
                    'boolean',
422
                ]
423
            );
424
425
        $conn->update(
426
            'TestTable',
427
            [
428
                'text' => 'some text',
429
                'is_edited' => true,
430
            ],
431
            [
432
                'id' => 1,
433
                'is_edited' => false,
434
            ],
435
            [
436
                'text' => 'string',
437
                'is_edited' => 'boolean',
438
                'id' => 'integer',
439
            ]
440
        );
441
    }
442
443
    /**
444
     * @group DBAL-2688
445
     */
446
    public function testUpdateWithIsNull()
447
    {
448
        $conn = $this->getExecuteUpdateMockConnection();
449
450
        $conn->expects($this->once())
451
            ->method('executeUpdate')
452
            ->with(
453
                'UPDATE TestTable SET text = ?, is_edited = ? WHERE id IS NULL AND name = ?',
454
                [
455
                    'some text',
456
                    null,
457
                    'foo',
458
                ],
459
                [
460
                    'string',
461
                    'boolean',
462
                    'string',
463
                ]
464
            );
465
466
        $conn->update(
467
            'TestTable',
468
            [
469
                'text' => 'some text',
470
                'is_edited' => null,
471
            ],
472
            [
473
                'id' => null,
474
                'name' => 'foo',
475
            ],
476
            [
477
                'text' => 'string',
478
                'is_edited' => 'boolean',
479
                'id' => 'integer',
480
                'name' => 'string',
481
            ]
482
        );
483
    }
484
485
    /**
486
     * @group DBAL-2688
487
     */
488
    public function testDeleteWithIsNull()
489
    {
490
        $conn = $this->getExecuteUpdateMockConnection();
491
492
        $conn->expects($this->once())
493
            ->method('executeUpdate')
494
            ->with(
495
                'DELETE FROM TestTable WHERE id IS NULL AND name = ?',
496
                ['foo'],
497
                ['string']
498
            );
499
500
        $conn->delete(
501
            'TestTable',
502
            [
503
                'id' => null,
504
                'name' => 'foo',
505
            ],
506
            [
507
                'id' => 'integer',
508
                'name' => 'string',
509
            ]
510
        );
511
    }
512
513
    public function testFetchAssoc()
514
    {
515
        $statement = 'SELECT * FROM foo WHERE bar = ?';
516
        $params    = [666];
517
        $types     = [ParameterType::INTEGER];
518
        $result    = [];
519
520
        $driverMock = $this->createMock(Driver::class);
521
522
        $driverMock->expects($this->any())
523
            ->method('connect')
524
            ->will($this->returnValue(
525
                $this->createMock(DriverConnection::class)
526
            ));
527
528
        $driverStatementMock = $this->createMock(DriverStatementMock::class);
529
530
        $driverStatementMock->expects($this->once())
531
            ->method('fetch')
532
            ->with(FetchMode::ASSOCIATIVE)
533
            ->will($this->returnValue($result));
534
535
        /** @var Connection|MockObject $conn */
536
        $conn = $this->getMockBuilder(Connection::class)
537
            ->setMethods(['executeQuery'])
538
            ->setConstructorArgs([[], $driverMock])
539
            ->getMock();
540
541
        $conn->expects($this->once())
542
            ->method('executeQuery')
543
            ->with($statement, $params, $types)
544
            ->will($this->returnValue($driverStatementMock));
545
546
        self::assertSame($result, $conn->fetchAssoc($statement, $params, $types));
547
    }
548
549
    public function testFetchArray()
550
    {
551
        $statement = 'SELECT * FROM foo WHERE bar = ?';
552
        $params    = [666];
553
        $types     = [ParameterType::INTEGER];
554
        $result    = [];
555
556
        $driverMock = $this->createMock(Driver::class);
557
558
        $driverMock->expects($this->any())
559
            ->method('connect')
560
            ->will($this->returnValue(
561
                $this->createMock(DriverConnection::class)
562
            ));
563
564
        $driverStatementMock = $this->createMock(DriverStatementMock::class);
565
566
        $driverStatementMock->expects($this->once())
567
            ->method('fetch')
568
            ->with(FetchMode::NUMERIC)
569
            ->will($this->returnValue($result));
570
571
        /** @var Connection|MockObject $conn */
572
        $conn = $this->getMockBuilder(Connection::class)
573
            ->setMethods(['executeQuery'])
574
            ->setConstructorArgs([[], $driverMock])
575
            ->getMock();
576
577
        $conn->expects($this->once())
578
            ->method('executeQuery')
579
            ->with($statement, $params, $types)
580
            ->will($this->returnValue($driverStatementMock));
581
582
        self::assertSame($result, $conn->fetchArray($statement, $params, $types));
583
    }
584
585
    public function testFetchColumn()
586
    {
587
        $statement = 'SELECT * FROM foo WHERE bar = ?';
588
        $params    = [666];
589
        $types     = [ParameterType::INTEGER];
590
        $column    = 0;
591
        $result    = [];
592
593
        $driverMock = $this->createMock(Driver::class);
594
595
        $driverMock->expects($this->any())
596
            ->method('connect')
597
            ->will($this->returnValue(
598
                $this->createMock(DriverConnection::class)
599
            ));
600
601
        $driverStatementMock = $this->createMock(DriverStatementMock::class);
602
603
        $driverStatementMock->expects($this->once())
604
            ->method('fetchColumn')
605
            ->with($column)
606
            ->will($this->returnValue($result));
607
608
        /** @var Connection|MockObject $conn */
609
        $conn = $this->getMockBuilder(Connection::class)
610
            ->setMethods(['executeQuery'])
611
            ->setConstructorArgs([[], $driverMock])
612
            ->getMock();
613
614
        $conn->expects($this->once())
615
            ->method('executeQuery')
616
            ->with($statement, $params, $types)
617
            ->will($this->returnValue($driverStatementMock));
618
619
        self::assertSame($result, $conn->fetchColumn($statement, $params, $column, $types));
620
    }
621
622
    public function testFetchAll()
623
    {
624
        $statement = 'SELECT * FROM foo WHERE bar = ?';
625
        $params    = [666];
626
        $types     = [ParameterType::INTEGER];
627
        $result    = [];
628
629
        $driverMock = $this->createMock(Driver::class);
630
631
        $driverMock->expects($this->any())
632
            ->method('connect')
633
            ->will($this->returnValue(
634
                $this->createMock(DriverConnection::class)
635
            ));
636
637
        $driverStatementMock = $this->createMock(DriverStatementMock::class);
638
639
        $driverStatementMock->expects($this->once())
640
            ->method('fetchAll')
641
            ->will($this->returnValue($result));
642
643
        /** @var Connection|MockObject $conn */
644
        $conn = $this->getMockBuilder(Connection::class)
645
            ->setMethods(['executeQuery'])
646
            ->setConstructorArgs([[], $driverMock])
647
            ->getMock();
648
649
        $conn->expects($this->once())
650
            ->method('executeQuery')
651
            ->with($statement, $params, $types)
652
            ->will($this->returnValue($driverStatementMock));
653
654
        self::assertSame($result, $conn->fetchAll($statement, $params, $types));
655
    }
656
657
    public function testConnectionDoesNotMaintainTwoReferencesToExternalPDO()
658
    {
659
        $params['pdo'] = new stdClass();
0 ignored issues
show
Comprehensibility Best Practice introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.
Loading history...
660
661
        $driverMock = $this->createMock(Driver::class);
662
663
        $conn = new Connection($params, $driverMock);
664
665
        self::assertArrayNotHasKey('pdo', $conn->getParams(), 'Connection is maintaining additional reference to the PDO connection');
666
    }
667
668
    public function testPassingExternalPDOMeansConnectionIsConnected()
669
    {
670
        $params['pdo'] = new stdClass();
0 ignored issues
show
Comprehensibility Best Practice introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.
Loading history...
671
672
        $driverMock = $this->createMock(Driver::class);
673
674
        $conn = new Connection($params, $driverMock);
675
676
        self::assertTrue($conn->isConnected(), 'Connection is not connected after passing external PDO');
677
    }
678
679
    public function testCallingDeleteWithNoDeletionCriteriaResultsInInvalidArgumentException()
680
    {
681
        /** @var Driver $driver */
682
        $driver  = $this->createMock(Driver::class);
683
        $pdoMock = $this->createMock(\Doctrine\DBAL\Driver\Connection::class);
684
685
        // should never execute queries with invalid arguments
686
        $pdoMock->expects($this->never())->method('exec');
687
        $pdoMock->expects($this->never())->method('prepare');
688
689
        $conn = new Connection(['pdo' => $pdoMock], $driver);
690
691
        $this->expectException(InvalidArgumentException::class);
692
        $conn->delete('kittens', []);
693
    }
694
695
    public function dataCallConnectOnce()
696
    {
697
        return [
698
            ['delete', ['tbl', ['id' => 12345]]],
699
            ['insert', ['tbl', ['data' => 'foo']]],
700
            ['update', ['tbl', ['data' => 'bar'], ['id' => 12345]]],
701
            ['prepare', ['select * from dual']],
702
            ['executeUpdate', ['insert into tbl (id) values (?)'], [123]],
703
        ];
704
    }
705
706
    /**
707
     * @dataProvider dataCallConnectOnce
708
     */
709
    public function testCallConnectOnce($method, $params)
710
    {
711
        $driverMock   = $this->createMock(Driver::class);
712
        $pdoMock      = $this->createMock(Connection::class);
713
        $platformMock = $this->createMock(AbstractPlatform::class);
714
        $stmtMock     = $this->createMock(Statement::class);
715
716
        $pdoMock->expects($this->any())
717
            ->method('prepare')
718
            ->will($this->returnValue($stmtMock));
719
720
        $conn = $this->getMockBuilder(Connection::class)
721
            ->setConstructorArgs([['pdo' => $pdoMock, 'platform' => $platformMock], $driverMock])
722
            ->setMethods(['connect'])
723
            ->getMock();
724
725
        $conn->expects($this->once())->method('connect');
726
727
        call_user_func_array([$conn, $method], $params);
728
    }
729
730
    /**
731
     * @group DBAL-1127
732
     */
733
    public function testPlatformDetectionIsTriggerOnlyOnceOnRetrievingPlatform()
734
    {
735
        /** @var VersionAwarePlatformDriverMock|MockObject $driverMock */
736
        $driverMock = $this->createMock(VersionAwarePlatformDriverMock::class);
737
738
        /** @var ServerInfoAwareConnectionMock|MockObject $driverConnectionMock */
739
        $driverConnectionMock = $this->createMock(ServerInfoAwareConnectionMock::class);
740
741
        /** @var AbstractPlatform|MockObject $platformMock */
742
        $platformMock = $this->getMockForAbstractClass(AbstractPlatform::class);
743
744
        $connection = new Connection([], $driverMock);
745
746
        $driverMock->expects($this->once())
747
            ->method('connect')
748
            ->will($this->returnValue($driverConnectionMock));
749
750
        $driverConnectionMock->expects($this->once())
751
            ->method('requiresQueryForServerVersion')
752
            ->will($this->returnValue(false));
753
754
        $driverConnectionMock->expects($this->once())
755
            ->method('getServerVersion')
756
            ->will($this->returnValue('6.6.6'));
757
758
        $driverMock->expects($this->once())
759
            ->method('createDatabasePlatformForVersion')
760
            ->with('6.6.6')
761
            ->will($this->returnValue($platformMock));
762
763
        self::assertSame($platformMock, $connection->getDatabasePlatform());
764
    }
765
766
    public function testConnectionParamsArePassedToTheQueryCacheProfileInExecuteCacheQuery()
767
    {
768
        $resultCacheDriverMock = $this->createMock(Cache::class);
769
770
        $resultCacheDriverMock
771
            ->expects($this->atLeastOnce())
772
            ->method('fetch')
773
            ->with('cacheKey')
774
            ->will($this->returnValue(['realKey' => []]));
775
776
        $query  = 'SELECT * FROM foo WHERE bar = ?';
777
        $params = [666];
778
        $types  = [ParameterType::INTEGER];
779
780
        /** @var QueryCacheProfile|MockObject $queryCacheProfileMock */
781
        $queryCacheProfileMock = $this->createMock(QueryCacheProfile::class);
782
783
        $queryCacheProfileMock
784
            ->expects($this->any())
785
            ->method('getResultCacheDriver')
786
            ->will($this->returnValue($resultCacheDriverMock));
787
788
        // This is our main expectation
789
        $queryCacheProfileMock
790
            ->expects($this->once())
791
            ->method('generateCacheKeys')
792
            ->with($query, $params, $types, $this->params)
793
            ->will($this->returnValue(['cacheKey', 'realKey']));
794
795
        /** @var Driver $driver */
796
        $driver = $this->createMock(Driver::class);
797
798
        self::assertInstanceOf(
799
            ArrayStatement::class,
800
            (new Connection($this->params, $driver))->executeCacheQuery($query, $params, $types, $queryCacheProfileMock)
801
        );
802
    }
803
804
    /**
805
     * @group #2821
806
     */
807
    public function testShouldNotPassPlatformInParamsToTheQueryCacheProfileInExecuteCacheQuery() : void
808
    {
809
        $resultCacheDriverMock = $this->createMock(Cache::class);
810
811
        $resultCacheDriverMock
812
            ->expects($this->atLeastOnce())
813
            ->method('fetch')
814
            ->with('cacheKey')
815
            ->will($this->returnValue(['realKey' => []]));
816
817
        /** @var QueryCacheProfile|MockObject $queryCacheProfileMock */
818
        $queryCacheProfileMock = $this->createMock(QueryCacheProfile::class);
819
820
        $queryCacheProfileMock
821
            ->expects($this->any())
822
            ->method('getResultCacheDriver')
823
            ->will($this->returnValue($resultCacheDriverMock));
824
825
        $query = 'SELECT 1';
826
827
        $connectionParams = $this->params;
828
829
        $queryCacheProfileMock
830
            ->expects($this->once())
831
            ->method('generateCacheKeys')
832
            ->with($query, [], [], $connectionParams)
833
            ->will($this->returnValue(['cacheKey', 'realKey']));
834
835
        $connectionParams['platform'] = $this->createMock(AbstractPlatform::class);
836
837
        /** @var Driver $driver */
838
        $driver = $this->createMock(Driver::class);
839
840
        (new Connection($connectionParams, $driver))->executeCacheQuery($query, [], [], $queryCacheProfileMock);
841
    }
842
843
    /**
844
     * @group #2821
845
     */
846
    public function testThrowsExceptionWhenInValidPlatformSpecified() : void
847
    {
848
        $connectionParams             = $this->params;
849
        $connectionParams['platform'] = new stdClass();
850
851
        /** @var Driver $driver */
852
        $driver = $this->createMock(Driver::class);
853
854
        $this->expectException(DBALException::class);
855
856
        new Connection($connectionParams, $driver);
857
    }
858
859
    /**
860
     * @group DBAL-990
861
     */
862
    public function testRethrowsOriginalExceptionOnDeterminingPlatformWhenConnectingToNonExistentDatabase()
863
    {
864
        /** @var VersionAwarePlatformDriverMock|MockObject $driverMock */
865
        $driverMock = $this->createMock(VersionAwarePlatformDriverMock::class);
866
867
        $connection        = new Connection(['dbname' => 'foo'], $driverMock);
868
        $originalException = new Exception('Original exception');
869
        $fallbackException = new Exception('Fallback exception');
870
871
        $driverMock->expects($this->at(0))
872
            ->method('connect')
873
            ->willThrowException($originalException);
874
875
        $driverMock->expects($this->at(1))
876
            ->method('connect')
877
            ->willThrowException($fallbackException);
878
879
        $this->expectExceptionMessage($originalException->getMessage());
880
881
        $connection->getDatabasePlatform();
882
    }
883
884
    /**
885
     * @group #3194
886
     */
887
    public function testExecuteCacheQueryStripsPlatformFromConnectionParamsBeforeGeneratingCacheKeys() : void
888
    {
889
        /** @var Driver|MockObject $driver */
890
        $driver = $this->createMock(Driver::class);
891
892
        /** @var AbstractPlatform|MockObject $platform */
893
        $platform = $this->createMock(AbstractPlatform::class);
894
895
        /** @var QueryCacheProfile|MockObject $queryCacheProfile */
896
        $queryCacheProfile = $this->createMock(QueryCacheProfile::class);
897
898
        /** @var Cache|MockObject $resultCacheDriver */
899
        $resultCacheDriver = $this->createMock(Cache::class);
900
901
        $queryCacheProfile
902
            ->expects($this->any())
903
            ->method('getResultCacheDriver')
904
            ->will($this->returnValue($resultCacheDriver));
905
906
        $resultCacheDriver
907
            ->expects($this->atLeastOnce())
908
            ->method('fetch')
909
            ->with('cacheKey')
910
            ->will($this->returnValue(['realKey' => []]));
911
912
        $query = 'SELECT 1';
913
914
        $params = [
915
            'dbname' => 'foo',
916
            'platform' => $platform,
917
        ];
918
919
        $paramsWithoutPlatform = $params;
920
        unset($paramsWithoutPlatform['platform']);
921
922
        $queryCacheProfile
923
            ->expects($this->once())
924
            ->method('generateCacheKeys')
925
            ->with($query, [], [], $paramsWithoutPlatform)
926
            ->will($this->returnValue(['cacheKey', 'realKey']));
927
928
        $connection = new Connection($params, $driver);
929
930
        self::assertSame($params, $connection->getParams());
931
932
        $connection->executeCacheQuery($query, [], [], $queryCacheProfile);
933
    }
934
}
935