ConnectionTest.php 25.7 KB
Newer Older
jwage's avatar
jwage committed
1 2
<?php

Michael Moravec's avatar
Michael Moravec committed
3 4
declare(strict_types=1);

5
namespace Doctrine\DBAL\Tests;
jwage's avatar
jwage committed
6

7
use Doctrine\Common\Cache\Cache;
8
use Doctrine\Common\EventManager;
Luís Cobucci's avatar
Luís Cobucci committed
9
use Doctrine\DBAL\Cache\ArrayStatement;
10
use Doctrine\DBAL\Cache\QueryCacheProfile;
11
use Doctrine\DBAL\Configuration;
jeroendedauw's avatar
jeroendedauw committed
12
use Doctrine\DBAL\Connection;
Luís Cobucci's avatar
Luís Cobucci committed
13
use Doctrine\DBAL\ConnectionException;
14
use Doctrine\DBAL\DBALException;
15
use Doctrine\DBAL\Driver;
16
use Doctrine\DBAL\Driver\Connection as DriverConnection;
17
use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
Sergei Morozov's avatar
Sergei Morozov committed
18 19
use Doctrine\DBAL\Driver\Statement;
use Doctrine\DBAL\DriverManager;
20
use Doctrine\DBAL\Events;
Luís Cobucci's avatar
Luís Cobucci committed
21
use Doctrine\DBAL\Exception\InvalidArgumentException;
22
use Doctrine\DBAL\FetchMode;
Sergei Morozov's avatar
Sergei Morozov committed
23
use Doctrine\DBAL\Logging\DebugStack;
24
use Doctrine\DBAL\ParameterType;
25
use Doctrine\DBAL\Platforms\AbstractPlatform;
26
use Doctrine\DBAL\VersionAwarePlatformDriver;
Sergei Morozov's avatar
Sergei Morozov committed
27
use Exception;
28
use PHPUnit\Framework\MockObject\MockObject;
29
use PHPUnit\Framework\TestCase;
Sergei Morozov's avatar
Sergei Morozov committed
30
use stdClass;
31

32 33 34
/**
 * @requires extension pdo_mysql
 */
35
class ConnectionTest extends TestCase
jwage's avatar
jwage committed
36
{
Sergei Morozov's avatar
Sergei Morozov committed
37
    /** @var Connection */
Sergei Morozov's avatar
Sergei Morozov committed
38
    private $connection;
39

40
    /** @var array<string, mixed> */
Sergei Morozov's avatar
Sergei Morozov committed
41
    protected $params = [
42 43 44 45
        'driver' => 'pdo_mysql',
        'host' => 'localhost',
        'user' => 'root',
        'password' => 'password',
46
        'port' => 1234,
Sergei Morozov's avatar
Sergei Morozov committed
47
    ];
48

49
    protected function setUp() : void
jwage's avatar
jwage committed
50
    {
Sergei Morozov's avatar
Sergei Morozov committed
51
        $this->connection = DriverManager::getConnection($this->params);
jwage's avatar
jwage committed
52 53
    }

54 55 56 57
    /**
     * @return Connection|MockObject
     */
    private function getExecuteUpdateMockConnection()
58
    {
Sergei Morozov's avatar
Sergei Morozov committed
59
        $driverMock = $this->createMock(Driver::class);
60

61
        $driverMock->expects(self::any())
62
            ->method('connect')
63
            ->will(self::returnValue(
64 65
                $this->createMock(DriverConnection::class)
            ));
66

67 68
        $platform = $this->getMockForAbstractClass(AbstractPlatform::class);

Sergei Morozov's avatar
Sergei Morozov committed
69
        return $this->getMockBuilder(Connection::class)
70
            ->onlyMethods(['executeUpdate'])
71
            ->setConstructorArgs([['platform' => $platform], $driverMock])
72 73 74
            ->getMock();
    }

75
    public function testIsConnected() : void
76
    {
Sergei Morozov's avatar
Sergei Morozov committed
77
        self::assertFalse($this->connection->isConnected());
78 79
    }

80
    public function testNoTransactionActiveByDefault() : void
81
    {
Sergei Morozov's avatar
Sergei Morozov committed
82
        self::assertFalse($this->connection->isTransactionActive());
83 84
    }

85
    public function testCommitWithNoActiveTransactionThrowsException() : void
86
    {
Luís Cobucci's avatar
Luís Cobucci committed
87
        $this->expectException(ConnectionException::class);
Sergei Morozov's avatar
Sergei Morozov committed
88
        $this->connection->commit();
89 90
    }

91
    public function testRollbackWithNoActiveTransactionThrowsException() : void
92
    {
Luís Cobucci's avatar
Luís Cobucci committed
93
        $this->expectException(ConnectionException::class);
Sergei Morozov's avatar
Sergei Morozov committed
94
        $this->connection->rollBack();
95 96
    }

97
    public function testSetRollbackOnlyNoActiveTransactionThrowsException() : void
98
    {
Luís Cobucci's avatar
Luís Cobucci committed
99
        $this->expectException(ConnectionException::class);
Sergei Morozov's avatar
Sergei Morozov committed
100
        $this->connection->setRollbackOnly();
101 102
    }

103
    public function testIsRollbackOnlyNoActiveTransactionThrowsException() : void
104
    {
Luís Cobucci's avatar
Luís Cobucci committed
105
        $this->expectException(ConnectionException::class);
Sergei Morozov's avatar
Sergei Morozov committed
106
        $this->connection->isRollbackOnly();
107 108
    }

109
    public function testGetDriver() : void
jwage's avatar
jwage committed
110
    {
Sergei Morozov's avatar
Sergei Morozov committed
111
        self::assertInstanceOf(\Doctrine\DBAL\Driver\PDOMySql\Driver::class, $this->connection->getDriver());
jwage's avatar
jwage committed
112 113
    }

114
    public function testConnectDispatchEvent() : void
115
    {
116 117
        $listenerMock = $this->getMockBuilder($this->getMockClass('ConnectDispatchEventListener'))
            ->addMethods(['postConnect'])
118
            ->getMock();
119
        $listenerMock->expects(self::once())->method('postConnect');
120 121

        $eventManager = new EventManager();
Sergei Morozov's avatar
Sergei Morozov committed
122
        $eventManager->addEventListener([Events::postConnect], $listenerMock);
123

Sergei Morozov's avatar
Sergei Morozov committed
124
        $driverMock = $this->createMock(Driver::class);
125
        $driverMock->expects(self::at(0))
126 127
                   ->method('connect');

128
        $conn = new Connection([], $driverMock, new Configuration(), $eventManager);
129
        $conn->connect();
jwage's avatar
jwage committed
130
    }
131

132
    public function testEventManagerPassedToPlatform() : void
133
    {
134 135
        $eventManager = new EventManager();

136
        /** @var AbstractPlatform|MockObject $platform */
137
        $platform = $this->createMock(AbstractPlatform::class);
138
        $platform->expects(self::once())
139 140 141 142 143
            ->method('setEventManager')
            ->with($eventManager);

        /** @var Driver|MockObject $driver */
        $driver = $this->createMock(Driver::class);
144
        $driver->expects(self::any())
145 146 147 148 149
            ->method('getDatabasePlatform')
            ->willReturn($platform);

        $connection = new Connection($this->params, $driver, null, $eventManager);
        $connection->getDatabasePlatform();
150 151
    }

152
    /**
153
     * @requires extension pdo_sqlite
154 155
     * @dataProvider getQueryMethods
     */
156
    public function testDriverExceptionIsWrapped(callable $callback) : void
157
    {
Luís Cobucci's avatar
Luís Cobucci committed
158
        $this->expectException(DBALException::class);
159
        $this->expectExceptionMessage("An exception occurred while executing \"MUUHAAAAHAAAA\":\n\nSQLSTATE[HY000]: General error: 1 near \"MUUHAAAAHAAAA\"");
160

Sergei Morozov's avatar
Sergei Morozov committed
161
        $connection = DriverManager::getConnection([
162 163
            'driver' => 'pdo_sqlite',
            'memory' => true,
Sergei Morozov's avatar
Sergei Morozov committed
164
        ]);
165

166
        $callback($connection, 'MUUHAAAAHAAAA');
167 168
    }

169
    /**
170
     * @return iterable<string, array<int, callable>>
171 172
     */
    public static function getQueryMethods() : iterable
173
    {
174 175 176 177
        yield 'exec' => [
            static function (Connection $connection, string $statement) : void {
                $connection->exec($statement);
            },
Sergei Morozov's avatar
Sergei Morozov committed
178
        ];
179

180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
        yield 'query' => [
            static function (Connection $connection, string $statement) : void {
                $connection->query($statement);
            },
        ];

        yield 'executeQuery' => [
            static function (Connection $connection, string $statement) : void {
                $connection->executeQuery($statement);
            },
        ];

        yield 'executeUpdate' => [
            static function (Connection $connection, string $statement) : void {
                $connection->executeUpdate($statement);
            },
        ];

        yield 'prepare' => [
            static function (Connection $connection, string $statement) : void {
                $connection->prepare($statement);
            },
Sergei Morozov's avatar
Sergei Morozov committed
202
        ];
203 204 205 206 207 208 209
    }

    /**
     * Pretty dumb test, however we want to check that the DebugStack correctly implements the interface.
     *
     * @group DBAL-11
     */
210
    public function testDebugSQLStack() : void
211
    {
Sergei Morozov's avatar
Sergei Morozov committed
212
        $logger = new DebugStack();
Sergei Morozov's avatar
Sergei Morozov committed
213 214
        $this->connection->getConfiguration()->setSQLLogger($logger);
        self::assertSame($logger, $this->connection->getConfiguration()->getSQLLogger());
215
    }
216 217 218 219

    /**
     * @group DBAL-81
     */
220
    public function testIsAutoCommit() : void
221
    {
Sergei Morozov's avatar
Sergei Morozov committed
222
        self::assertTrue($this->connection->isAutoCommit());
223 224 225 226 227
    }

    /**
     * @group DBAL-81
     */
228
    public function testSetAutoCommit() : void
229
    {
Sergei Morozov's avatar
Sergei Morozov committed
230 231
        $this->connection->setAutoCommit(false);
        self::assertFalse($this->connection->isAutoCommit());
232 233 234 235 236
    }

    /**
     * @group DBAL-81
     */
237
    public function testConnectStartsTransactionInNoAutoCommitMode() : void
238
    {
Sergei Morozov's avatar
Sergei Morozov committed
239
        $driverMock = $this->createMock(Driver::class);
240
        $driverMock->expects(self::any())
241
            ->method('connect')
242
            ->will(self::returnValue(
243 244
                $this->createMock(DriverConnection::class)
            ));
245
        $conn = new Connection([], $driverMock);
246 247 248

        $conn->setAutoCommit(false);

249
        self::assertFalse($conn->isTransactionActive());
250 251 252

        $conn->connect();

253
        self::assertTrue($conn->isTransactionActive());
254 255 256 257 258
    }

    /**
     * @group DBAL-81
     */
259
    public function testCommitStartsTransactionInNoAutoCommitMode() : void
260
    {
Sergei Morozov's avatar
Sergei Morozov committed
261
        $driverMock = $this->createMock(Driver::class);
262
        $driverMock->expects(self::any())
263
            ->method('connect')
264
            ->will(self::returnValue(
265 266
                $this->createMock(DriverConnection::class)
            ));
267
        $conn = new Connection([], $driverMock);
268 269 270 271 272

        $conn->setAutoCommit(false);
        $conn->connect();
        $conn->commit();

273
        self::assertTrue($conn->isTransactionActive());
274 275
    }

276 277 278 279 280 281 282 283
    /**
     * @return bool[][]
     */
    public function resultProvider() : array
    {
        return [[true], [false]];
    }

284 285 286
    /**
     * @group DBAL-81
     */
287
    public function testRollBackStartsTransactionInNoAutoCommitMode() : void
288
    {
Sergei Morozov's avatar
Sergei Morozov committed
289
        $driverMock = $this->createMock(Driver::class);
290
        $driverMock->expects(self::any())
291
            ->method('connect')
292
            ->will(self::returnValue(
293 294
                $this->createMock(DriverConnection::class)
            ));
295
        $conn = new Connection([], $driverMock);
296 297 298 299 300

        $conn->setAutoCommit(false);
        $conn->connect();
        $conn->rollBack();

301
        self::assertTrue($conn->isTransactionActive());
302 303 304 305 306
    }

    /**
     * @group DBAL-81
     */
307
    public function testSwitchingAutoCommitModeCommitsAllCurrentTransactions() : void
308
    {
Sergei Morozov's avatar
Sergei Morozov committed
309
        $driverMock = $this->createMock(Driver::class);
310
        $driverMock->expects(self::any())
311
            ->method('connect')
312
            ->will(self::returnValue(
313 314
                $this->createMock(DriverConnection::class)
            ));
315
        $conn = new Connection([], $driverMock);
316 317 318 319 320 321

        $conn->connect();
        $conn->beginTransaction();
        $conn->beginTransaction();
        $conn->setAutoCommit(false);

322
        self::assertSame(1, $conn->getTransactionNestingLevel());
323 324 325 326 327

        $conn->beginTransaction();
        $conn->beginTransaction();
        $conn->setAutoCommit(true);

328
        self::assertFalse($conn->isTransactionActive());
329
    }
330

331
    public function testEmptyInsert() : void
332
    {
333
        $conn = $this->getExecuteUpdateMockConnection();
334

335
        $conn->expects(self::once())
336 337 338
            ->method('executeUpdate')
            ->with('INSERT INTO footable () VALUES ()');

Sergei Morozov's avatar
Sergei Morozov committed
339
        $conn->insert('footable', []);
340
    }
341

342 343 344
    /**
     * @group DBAL-2511
     */
345
    public function testUpdateWithDifferentColumnsInDataAndIdentifiers() : void
346
    {
347
        $conn = $this->getExecuteUpdateMockConnection();
348

349
        $conn->expects(self::once())
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
            ->method('executeUpdate')
            ->with(
                'UPDATE TestTable SET text = ?, is_edited = ? WHERE id = ? AND name = ?',
                [
                    'some text',
                    true,
                    1,
                    'foo',
                ],
                [
                    'string',
                    'boolean',
                    'integer',
                    'string',
                ]
            );

        $conn->update(
            'TestTable',
            [
                'text' => 'some text',
                'is_edited' => true,
            ],
            [
                'id' => 1,
                'name' => 'foo',
            ],
            [
                'text' => 'string',
                'is_edited' => 'boolean',
                'id' => 'integer',
                'name' => 'string',
            ]
        );
    }

    /**
     * @group DBAL-2511
     */
389
    public function testUpdateWithSameColumnInDataAndIdentifiers() : void
390
    {
391
        $conn = $this->getExecuteUpdateMockConnection();
392

393
        $conn->expects(self::once())
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
            ->method('executeUpdate')
            ->with(
                'UPDATE TestTable SET text = ?, is_edited = ? WHERE id = ? AND is_edited = ?',
                [
                    'some text',
                    true,
                    1,
                    false,
                ],
                [
                    'string',
                    'boolean',
                    'integer',
                    'boolean',
                ]
            );

        $conn->update(
            'TestTable',
            [
                'text' => 'some text',
                'is_edited' => true,
            ],
            [
                'id' => 1,
                'is_edited' => false,
            ],
            [
                'text' => 'string',
                'is_edited' => 'boolean',
                'id' => 'integer',
            ]
        );
    }

429 430 431
    /**
     * @group DBAL-2688
     */
432
    public function testUpdateWithIsNull() : void
433
    {
434
        $conn = $this->getExecuteUpdateMockConnection();
435

436
        $conn->expects(self::once())
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
            ->method('executeUpdate')
            ->with(
                'UPDATE TestTable SET text = ?, is_edited = ? WHERE id IS NULL AND name = ?',
                [
                    'some text',
                    null,
                    'foo',
                ],
                [
                    'string',
                    'boolean',
                    'string',
                ]
            );

        $conn->update(
            'TestTable',
            [
                'text' => 'some text',
                'is_edited' => null,
            ],
            [
                'id' => null,
                'name' => 'foo',
            ],
            [
                'text' => 'string',
                'is_edited' => 'boolean',
                'id' => 'integer',
                'name' => 'string',
            ]
        );
    }

    /**
     * @group DBAL-2688
     */
474
    public function testDeleteWithIsNull() : void
475
    {
476
        $conn = $this->getExecuteUpdateMockConnection();
477

478
        $conn->expects(self::once())
479 480 481
            ->method('executeUpdate')
            ->with(
                'DELETE FROM TestTable WHERE id IS NULL AND name = ?',
Sergei Morozov's avatar
Sergei Morozov committed
482 483
                ['foo'],
                ['string']
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
            );

        $conn->delete(
            'TestTable',
            [
                'id' => null,
                'name' => 'foo',
            ],
            [
                'id' => 'integer',
                'name' => 'string',
            ]
        );
    }

499
    public function testFetchAssoc() : void
500 501
    {
        $statement = 'SELECT * FROM foo WHERE bar = ?';
Sergei Morozov's avatar
Sergei Morozov committed
502 503 504
        $params    = [666];
        $types     = [ParameterType::INTEGER];
        $result    = [];
505

Sergei Morozov's avatar
Sergei Morozov committed
506
        $driverMock = $this->createMock(Driver::class);
507

508
        $driverMock->expects(self::any())
509
            ->method('connect')
510
            ->will(self::returnValue(
511 512
                $this->createMock(DriverConnection::class)
            ));
513

514
        $driverStatementMock = $this->createMock(Statement::class);
515

516
        $driverStatementMock->expects(self::once())
517
            ->method('fetch')
518
            ->with(FetchMode::ASSOCIATIVE)
519
            ->will(self::returnValue($result));
520

521
        /** @var Connection|MockObject $conn */
Sergei Morozov's avatar
Sergei Morozov committed
522
        $conn = $this->getMockBuilder(Connection::class)
523
            ->onlyMethods(['executeQuery'])
524
            ->setConstructorArgs([[], $driverMock])
525 526
            ->getMock();

527
        $conn->expects(self::once())
528 529
            ->method('executeQuery')
            ->with($statement, $params, $types)
530
            ->will(self::returnValue($driverStatementMock));
531

532
        self::assertSame($result, $conn->fetchAssoc($statement, $params, $types));
533 534
    }

535
    public function testFetchArray() : void
536 537
    {
        $statement = 'SELECT * FROM foo WHERE bar = ?';
Sergei Morozov's avatar
Sergei Morozov committed
538 539 540
        $params    = [666];
        $types     = [ParameterType::INTEGER];
        $result    = [];
541

Sergei Morozov's avatar
Sergei Morozov committed
542
        $driverMock = $this->createMock(Driver::class);
543

544
        $driverMock->expects(self::any())
545
            ->method('connect')
546
            ->will(self::returnValue(
547 548
                $this->createMock(DriverConnection::class)
            ));
549

550
        $driverStatementMock = $this->createMock(Statement::class);
551

552
        $driverStatementMock->expects(self::once())
553
            ->method('fetch')
554
            ->with(FetchMode::NUMERIC)
555
            ->will(self::returnValue($result));
556

557
        /** @var Connection|MockObject $conn */
Sergei Morozov's avatar
Sergei Morozov committed
558
        $conn = $this->getMockBuilder(Connection::class)
559
            ->onlyMethods(['executeQuery'])
560
            ->setConstructorArgs([[], $driverMock])
561 562
            ->getMock();

563
        $conn->expects(self::once())
564 565
            ->method('executeQuery')
            ->with($statement, $params, $types)
566
            ->will(self::returnValue($driverStatementMock));
567

568
        self::assertSame($result, $conn->fetchArray($statement, $params, $types));
569 570
    }

571
    public function testFetchColumn() : void
572 573
    {
        $statement = 'SELECT * FROM foo WHERE bar = ?';
Sergei Morozov's avatar
Sergei Morozov committed
574 575 576
        $params    = [666];
        $types     = [ParameterType::INTEGER];
        $result    = [];
577

Sergei Morozov's avatar
Sergei Morozov committed
578
        $driverMock = $this->createMock(Driver::class);
579

580
        $driverMock->expects(self::any())
581
            ->method('connect')
582
            ->will(self::returnValue(
583 584
                $this->createMock(DriverConnection::class)
            ));
585

586
        $driverStatementMock = $this->createMock(Statement::class);
587

588
        $driverStatementMock->expects(self::once())
589
            ->method('fetchColumn')
590
            ->will(self::returnValue($result));
591

592
        /** @var Connection|MockObject $conn */
Sergei Morozov's avatar
Sergei Morozov committed
593
        $conn = $this->getMockBuilder(Connection::class)
594
            ->onlyMethods(['executeQuery'])
595
            ->setConstructorArgs([[], $driverMock])
596 597
            ->getMock();

598
        $conn->expects(self::once())
599 600
            ->method('executeQuery')
            ->with($statement, $params, $types)
601
            ->will(self::returnValue($driverStatementMock));
602

603
        self::assertSame($result, $conn->fetchColumn($statement, $params, $types));
604
    }
malukenho's avatar
malukenho committed
605

606
    public function testFetchAll() : void
607 608
    {
        $statement = 'SELECT * FROM foo WHERE bar = ?';
Sergei Morozov's avatar
Sergei Morozov committed
609 610 611
        $params    = [666];
        $types     = [ParameterType::INTEGER];
        $result    = [];
612

Sergei Morozov's avatar
Sergei Morozov committed
613
        $driverMock = $this->createMock(Driver::class);
614

615
        $driverMock->expects(self::any())
616
            ->method('connect')
617
            ->will(self::returnValue(
618 619
                $this->createMock(DriverConnection::class)
            ));
620

621
        $driverStatementMock = $this->createMock(Statement::class);
622

623
        $driverStatementMock->expects(self::once())
624
            ->method('fetchAll')
625
            ->will(self::returnValue($result));
626

627
        /** @var Connection|MockObject $conn */
Sergei Morozov's avatar
Sergei Morozov committed
628
        $conn = $this->getMockBuilder(Connection::class)
629
            ->onlyMethods(['executeQuery'])
630
            ->setConstructorArgs([[], $driverMock])
631 632
            ->getMock();

633
        $conn->expects(self::once())
634 635
            ->method('executeQuery')
            ->with($statement, $params, $types)
636
            ->will(self::returnValue($driverStatementMock));
637

638
        self::assertSame($result, $conn->fetchAll($statement, $params, $types));
639
    }
640

641
    public function testCallingDeleteWithNoDeletionCriteriaResultsInInvalidArgumentException() : void
642
    {
Sergei Morozov's avatar
Sergei Morozov committed
643
        /** @var Driver $driver */
644 645
        $driver = $this->createMock(Driver::class);
        $conn   = new Connection([], $driver);
646

Luís Cobucci's avatar
Luís Cobucci committed
647
        $this->expectException(InvalidArgumentException::class);
Sergei Morozov's avatar
Sergei Morozov committed
648
        $conn->delete('kittens', []);
649
    }
650

651
    public function testCallConnectOnce() : void
652
    {
653 654
        /** @var Driver|MockObject $driver */
        $driver = $this->createMock(Driver::class);
655
        $driver->expects(self::once())
656
            ->method('connect');
657

658
        $platform = $this->createMock(AbstractPlatform::class);
659

660 661 662
        $conn = new Connection(['platform' => $platform], $driver);
        $conn->connect();
        $conn->connect();
663
    }
664 665 666 667

    /**
     * @group DBAL-1127
     */
668
    public function testPlatformDetectionIsTriggerOnlyOnceOnRetrievingPlatform() : void
669
    {
670 671
        /** @var VersionAwarePlatformDriver|MockObject $driverMock */
        $driverMock = $this->createMock(VersionAwarePlatformDriver::class);
672

673
        /** @var DriverConnection|ServerInfoAwareConnection|MockObject $driverConnectionMock */
674
        $driverConnectionMock = $this->createMock(ServerInfoAwareConnection::class);
675

676
        /** @var AbstractPlatform|MockObject $platformMock */
Sergei Morozov's avatar
Sergei Morozov committed
677
        $platformMock = $this->getMockForAbstractClass(AbstractPlatform::class);
678

Sergei Morozov's avatar
Sergei Morozov committed
679
        $connection = new Connection([], $driverMock);
680

681
        $driverMock->expects(self::once())
682
            ->method('connect')
683
            ->will(self::returnValue($driverConnectionMock));
684

685
        $driverConnectionMock->expects(self::once())
686
            ->method('getServerVersion')
687
            ->will(self::returnValue('6.6.6'));
688

689
        $driverMock->expects(self::once())
690 691
            ->method('createDatabasePlatformForVersion')
            ->with('6.6.6')
692
            ->will(self::returnValue($platformMock));
693

694
        self::assertSame($platformMock, $connection->getDatabasePlatform());
695
    }
696

697
    public function testConnectionParamsArePassedToTheQueryCacheProfileInExecuteCacheQuery() : void
698
    {
699
        $resultCacheDriverMock = $this->createMock(Cache::class);
700

701
        $resultCacheDriverMock
702
            ->expects(self::atLeastOnce())
703
            ->method('fetch')
Antonio Vilar's avatar
Antonio Vilar committed
704
            ->with('cacheKey')
705
            ->will(self::returnValue(['realKey' => []]));
706

707 708
        $query  = 'SELECT * FROM foo WHERE bar = ?';
        $params = [666];
709
        $types  = [ParameterType::INTEGER];
710

711
        /** @var QueryCacheProfile|MockObject $queryCacheProfileMock */
712
        $queryCacheProfileMock = $this->createMock(QueryCacheProfile::class);
713

714
        $queryCacheProfileMock
715
            ->expects(self::any())
716
            ->method('getResultCacheDriver')
717
            ->will(self::returnValue($resultCacheDriverMock));
718 719

        // This is our main expectation
720
        $queryCacheProfileMock
721
            ->expects(self::once())
722 723
            ->method('generateCacheKeys')
            ->with($query, $params, $types, $this->params)
724
            ->will(self::returnValue(['cacheKey', 'realKey']));
725

Sergei Morozov's avatar
Sergei Morozov committed
726
        /** @var Driver $driver */
727 728
        $driver = $this->createMock(Driver::class);

729
        self::assertInstanceOf(
730 731
            ArrayStatement::class,
            (new Connection($this->params, $driver))->executeCacheQuery($query, $params, $types, $queryCacheProfileMock)
732 733 734
        );
    }

735
    /**
736
     * @group #2821
737
     */
Sergei Morozov's avatar
Sergei Morozov committed
738
    public function testShouldNotPassPlatformInParamsToTheQueryCacheProfileInExecuteCacheQuery() : void
739 740 741 742
    {
        $resultCacheDriverMock = $this->createMock(Cache::class);

        $resultCacheDriverMock
743
            ->expects(self::atLeastOnce())
744 745
            ->method('fetch')
            ->with('cacheKey')
746
            ->will(self::returnValue(['realKey' => []]));
747

748
        /** @var QueryCacheProfile|MockObject $queryCacheProfileMock */
749 750 751
        $queryCacheProfileMock = $this->createMock(QueryCacheProfile::class);

        $queryCacheProfileMock
752
            ->expects(self::any())
753
            ->method('getResultCacheDriver')
754
            ->will(self::returnValue($resultCacheDriverMock));
755

Sergei Morozov's avatar
Sergei Morozov committed
756
        $query = 'SELECT 1';
757

758
        $connectionParams = $this->params;
759 760

        $queryCacheProfileMock
761
            ->expects(self::once())
762
            ->method('generateCacheKeys')
763
            ->with($query, [], [], $connectionParams)
764
            ->will(self::returnValue(['cacheKey', 'realKey']));
765

766 767
        $connectionParams['platform'] = $this->createMock(AbstractPlatform::class);

Sergei Morozov's avatar
Sergei Morozov committed
768
        /** @var Driver $driver */
769 770
        $driver = $this->createMock(Driver::class);

771
        (new Connection($connectionParams, $driver))->executeCacheQuery($query, [], [], $queryCacheProfileMock);
772
    }
773

774
    /**
775
     * @group #2821
776
     */
Sergei Morozov's avatar
Sergei Morozov committed
777
    public function testThrowsExceptionWhenInValidPlatformSpecified() : void
778
    {
Sergei Morozov's avatar
Sergei Morozov committed
779 780
        $connectionParams             = $this->params;
        $connectionParams['platform'] = new stdClass();
781

Sergei Morozov's avatar
Sergei Morozov committed
782
        /** @var Driver $driver */
783
        $driver = $this->createMock(Driver::class);
784 785

        $this->expectException(DBALException::class);
786 787 788 789

        new Connection($connectionParams, $driver);
    }

790 791 792
    /**
     * @group DBAL-990
     */
793
    public function testRethrowsOriginalExceptionOnDeterminingPlatformWhenConnectingToNonExistentDatabase() : void
794
    {
795 796
        /** @var VersionAwarePlatformDriver|MockObject $driverMock */
        $driverMock = $this->createMock(VersionAwarePlatformDriver::class);
797

Sergei Morozov's avatar
Sergei Morozov committed
798 799 800
        $connection        = new Connection(['dbname' => 'foo'], $driverMock);
        $originalException = new Exception('Original exception');
        $fallbackException = new Exception('Fallback exception');
801

802
        $driverMock->expects(self::at(0))
803 804 805
            ->method('connect')
            ->willThrowException($originalException);

806
        $driverMock->expects(self::at(1))
807 808 809 810 811 812 813
            ->method('connect')
            ->willThrowException($fallbackException);

        $this->expectExceptionMessage($originalException->getMessage());

        $connection->getDatabasePlatform();
    }
814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832

    /**
     * @group #3194
     */
    public function testExecuteCacheQueryStripsPlatformFromConnectionParamsBeforeGeneratingCacheKeys() : void
    {
        /** @var Driver|MockObject $driver */
        $driver = $this->createMock(Driver::class);

        /** @var AbstractPlatform|MockObject $platform */
        $platform = $this->createMock(AbstractPlatform::class);

        /** @var QueryCacheProfile|MockObject $queryCacheProfile */
        $queryCacheProfile = $this->createMock(QueryCacheProfile::class);

        /** @var Cache|MockObject $resultCacheDriver */
        $resultCacheDriver = $this->createMock(Cache::class);

        $queryCacheProfile
833
            ->expects(self::any())
834
            ->method('getResultCacheDriver')
835
            ->will(self::returnValue($resultCacheDriver));
836 837

        $resultCacheDriver
838
            ->expects(self::atLeastOnce())
839 840
            ->method('fetch')
            ->with('cacheKey')
841
            ->will(self::returnValue(['realKey' => []]));
842 843 844 845 846 847 848 849 850 851 852 853

        $query = 'SELECT 1';

        $params = [
            'dbname' => 'foo',
            'platform' => $platform,
        ];

        $paramsWithoutPlatform = $params;
        unset($paramsWithoutPlatform['platform']);

        $queryCacheProfile
854
            ->expects(self::once())
855 856
            ->method('generateCacheKeys')
            ->with($query, [], [], $paramsWithoutPlatform)
857
            ->will(self::returnValue(['cacheKey', 'realKey']));
858 859 860 861 862 863 864

        $connection = new Connection($params, $driver);

        self::assertSame($params, $connection->getParams());

        $connection->executeCacheQuery($query, [], [], $queryCacheProfile);
    }
865
}