DriverManagerTest.php 17.6 KB
Newer Older
jwage's avatar
jwage committed
1 2 3 4
<?php

namespace Doctrine\Tests\DBAL;

5
use Doctrine\DBAL\Connections\MasterSlaveConnection;
Luís Cobucci's avatar
Luís Cobucci committed
6
use Doctrine\DBAL\DBALException;
Sergei Morozov's avatar
Sergei Morozov committed
7
use Doctrine\DBAL\Driver\DrizzlePDOMySql\Driver as DrizzlePDOMySqlDriver;
8
use Doctrine\DBAL\Driver\PDOMySql\Driver as PDOMySQLDriver;
Sergei Morozov's avatar
Sergei Morozov committed
9 10 11
use Doctrine\DBAL\Driver\PDOSqlite\Driver as PDOSqliteDriver;
use Doctrine\DBAL\Driver\SQLSrv\Driver as SQLSrvDriver;
use Doctrine\DBAL\DriverManager;
12 13
use Doctrine\DBAL\Sharding\PoolingShardConnection;
use Doctrine\DBAL\Sharding\ShardChoser\MultiTenantShardChoser;
Sergei Morozov's avatar
Sergei Morozov committed
14 15 16 17
use Doctrine\Tests\DBAL\Mocks\MockPlatform;
use Doctrine\Tests\DbalTestCase;
use Doctrine\Tests\Mocks\ConnectionMock;
use Doctrine\Tests\Mocks\DriverMock;
Sergei Morozov's avatar
Sergei Morozov committed
18
use PDO;
Sergei Morozov's avatar
Sergei Morozov committed
19
use stdClass;
20 21 22
use function extension_loaded;
use function in_array;
use function is_array;
Luís Cobucci's avatar
Luís Cobucci committed
23

Sergei Morozov's avatar
Sergei Morozov committed
24
class DriverManagerTest extends DbalTestCase
jwage's avatar
jwage committed
25 26
{
    /**
27
     * @requires extension pdo_sqlite
28
     * @expectedException \Doctrine\DBAL\DBALException
jwage's avatar
jwage committed
29 30 31
     */
    public function testInvalidPdoInstance()
    {
Sergei Morozov's avatar
Sergei Morozov committed
32
        DriverManager::getConnection(['pdo' => 'test']);
jwage's avatar
jwage committed
33 34
    }

35 36 37
    /**
     * @requires extension pdo_sqlite
     */
jwage's avatar
jwage committed
38 39
    public function testValidPdoInstance()
    {
Sergei Morozov's avatar
Sergei Morozov committed
40
        $conn = DriverManager::getConnection([
Sergei Morozov's avatar
Sergei Morozov committed
41
            'pdo' => new PDO('sqlite::memory:'),
Sergei Morozov's avatar
Sergei Morozov committed
42 43
        ]);

44
        self::assertEquals('sqlite', $conn->getDatabasePlatform()->getName());
jwage's avatar
jwage committed
45 46
    }

47 48
    /**
     * @group DBAL-32
49
     * @requires extension pdo_sqlite
50 51 52
     */
    public function testPdoInstanceSetErrorMode()
    {
Sergei Morozov's avatar
Sergei Morozov committed
53 54
        $pdo = new PDO('sqlite::memory:');
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
Sergei Morozov's avatar
Sergei Morozov committed
55
        $options = ['pdo' => $pdo];
56

Sergei Morozov's avatar
Sergei Morozov committed
57
        DriverManager::getConnection($options);
Sergei Morozov's avatar
Sergei Morozov committed
58
        self::assertEquals(PDO::ERRMODE_EXCEPTION, $pdo->getAttribute(PDO::ATTR_ERRMODE));
59 60
    }

jwage's avatar
jwage committed
61
    /**
62
     * @expectedException \Doctrine\DBAL\DBALException
jwage's avatar
jwage committed
63 64 65
     */
    public function testCheckParams()
    {
Sergei Morozov's avatar
Sergei Morozov committed
66
        DriverManager::getConnection([]);
jwage's avatar
jwage committed
67 68 69
    }

    /**
70
     * @expectedException \Doctrine\DBAL\DBALException
jwage's avatar
jwage committed
71 72 73
     */
    public function testInvalidDriver()
    {
Sergei Morozov's avatar
Sergei Morozov committed
74
        DriverManager::getConnection(['driver' => 'invalid_driver']);
jwage's avatar
jwage committed
75
    }
76

77 78 79
    /**
     * @requires extension pdo_sqlite
     */
80 81
    public function testCustomPlatform()
    {
Sergei Morozov's avatar
Sergei Morozov committed
82 83
        $mockPlatform = new MockPlatform();
        $options      = [
Sergei Morozov's avatar
Sergei Morozov committed
84
            'pdo'      => new PDO('sqlite::memory:'),
Sergei Morozov's avatar
Sergei Morozov committed
85 86
            'platform' => $mockPlatform,
        ];
87

Sergei Morozov's avatar
Sergei Morozov committed
88
        $conn = DriverManager::getConnection($options);
89
        self::assertSame($mockPlatform, $conn->getDatabasePlatform());
90
    }
91

92 93 94
    /**
     * @requires extension pdo_sqlite
     */
95 96
    public function testCustomWrapper()
    {
Sergei Morozov's avatar
Sergei Morozov committed
97
        $wrapperClass = ConnectionMock::class;
98

Sergei Morozov's avatar
Sergei Morozov committed
99
        $options = [
Sergei Morozov's avatar
Sergei Morozov committed
100
            'pdo' => new PDO('sqlite::memory:'),
101
            'wrapperClass' => $wrapperClass,
Sergei Morozov's avatar
Sergei Morozov committed
102
        ];
103

Sergei Morozov's avatar
Sergei Morozov committed
104
        $conn = DriverManager::getConnection($options);
105
        self::assertInstanceOf($wrapperClass, $conn);
106 107
    }

108 109 110
    /**
     * @requires extension pdo_sqlite
     */
111 112
    public function testInvalidWrapperClass()
    {
Luís Cobucci's avatar
Luís Cobucci committed
113
        $this->expectException(DBALException::class);
114

Sergei Morozov's avatar
Sergei Morozov committed
115
        $options = [
Sergei Morozov's avatar
Sergei Morozov committed
116
            'pdo' => new PDO('sqlite::memory:'),
Sergei Morozov's avatar
Sergei Morozov committed
117 118
            'wrapperClass' => stdClass::class,
        ];
119

Sergei Morozov's avatar
Sergei Morozov committed
120
        DriverManager::getConnection($options);
121 122 123 124
    }

    public function testInvalidDriverClass()
    {
Luís Cobucci's avatar
Luís Cobucci committed
125
        $this->expectException(DBALException::class);
126

Sergei Morozov's avatar
Sergei Morozov committed
127
        $options = ['driverClass' => stdClass::class];
128

Sergei Morozov's avatar
Sergei Morozov committed
129
        DriverManager::getConnection($options);
130 131 132 133
    }

    public function testValidDriverClass()
    {
Sergei Morozov's avatar
Sergei Morozov committed
134
        $options = ['driverClass' => PDOMySQLDriver::class];
135

Sergei Morozov's avatar
Sergei Morozov committed
136 137
        $conn = DriverManager::getConnection($options);
        self::assertInstanceOf(PDOMySQLDriver::class, $conn->getDriver());
138
    }
139

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
    public function testDatabaseUrlMasterSlave()
    {
        $options = [
            'driver' => 'pdo_mysql',
            'master' => ['url' => 'mysql://foo:bar@localhost:11211/baz'],
            'slaves' => [
                'slave1' => ['url' => 'mysql://foo:bar@localhost:11211/baz_slave'],
            ],
            'wrapperClass' => MasterSlaveConnection::class,
        ];

        $conn = DriverManager::getConnection($options);

        $params = $conn->getParams();
        self::assertInstanceOf(PDOMySQLDriver::class, $conn->getDriver());

        $expected = [
            'user'     => 'foo',
            'password' => 'bar',
            'host'     => 'localhost',
            'port'     => 11211,
        ];

        foreach ($expected as $key => $value) {
            self::assertEquals($value, $params['master'][$key]);
            self::assertEquals($value, $params['slaves']['slave1'][$key]);
        }

        self::assertEquals('baz', $params['master']['dbname']);
        self::assertEquals('baz_slave', $params['slaves']['slave1']['dbname']);
    }

    public function testDatabaseUrlShard()
    {
        $options = [
            'driver' => 'pdo_mysql',
            'shardChoser' => MultiTenantShardChoser::class,
            'global' => ['url' => 'mysql://foo:bar@localhost:11211/baz'],
            'shards' => [
                [
                    'id' => 1,
                    'url' => 'mysql://foo:bar@localhost:11211/baz_slave',
                ],
            ],
            'wrapperClass' => PoolingShardConnection::class,
        ];

        $conn = DriverManager::getConnection($options);

        $params = $conn->getParams();
        self::assertInstanceOf(PDOMySQLDriver::class, $conn->getDriver());

        $expected = [
            'user'     => 'foo',
            'password' => 'bar',
            'host'     => 'localhost',
            'port'     => 11211,
        ];

        foreach ($expected as $key => $value) {
            self::assertEquals($value, $params['global'][$key]);
            self::assertEquals($value, $params['shards'][0][$key]);
        }

        self::assertEquals('baz', $params['global']['dbname']);
        self::assertEquals('baz_slave', $params['shards'][0]['dbname']);
    }

208 209 210 211 212
    /**
     * @dataProvider databaseUrls
     */
    public function testDatabaseUrl($url, $expected)
    {
Sergei Morozov's avatar
Sergei Morozov committed
213
        $options = is_array($url) ? $url : ['url' => $url];
214

215
        if (isset($options['pdo'])) {
Sergei Morozov's avatar
Sergei Morozov committed
216
            if (! extension_loaded('pdo')) {
217 218 219
                $this->markTestSkipped('PDO is not installed');
            }

Sergei Morozov's avatar
Sergei Morozov committed
220
            $options['pdo'] = $this->createMock(PDO::class);
221 222
        }

Sergei Morozov's avatar
Sergei Morozov committed
223
        $options = is_array($url) ? $url : ['url' => $url];
224

225
        if ($expected === false) {
Luís Cobucci's avatar
Luís Cobucci committed
226
            $this->expectException(DBALException::class);
227
        }
228

Sergei Morozov's avatar
Sergei Morozov committed
229
        $conn = DriverManager::getConnection($options);
230

231 232
        $params = $conn->getParams();
        foreach ($expected as $key => $value) {
Sergei Morozov's avatar
Sergei Morozov committed
233
            if (in_array($key, ['pdo', 'driver', 'driverClass'], true)) {
234
                self::assertInstanceOf($value, $conn->getDriver());
235
            } else {
236
                self::assertEquals($value, $params[$key]);
237 238 239
            }
        }
    }
240

241 242
    public function databaseUrls()
    {
Sergei Morozov's avatar
Sergei Morozov committed
243 244
        return [
            'simple URL' => [
245
                'mysql://foo:bar@localhost/baz',
Sergei Morozov's avatar
Sergei Morozov committed
246 247 248 249 250 251 252 253 254
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
                    'driver'   => PDOMySQLDriver::class,
                ],
            ],
            'simple URL with port' => [
255
                'mysql://foo:bar@localhost:11211/baz',
Sergei Morozov's avatar
Sergei Morozov committed
256 257 258 259 260 261 262 263 264 265
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'port'     => 11211,
                    'dbname'   => 'baz',
                    'driver'   => PDOMySQLDriver::class,
                ],
            ],
            'sqlite relative URL with host' => [
266
                'sqlite://localhost/foo/dbname.sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
267 268 269 270 271 272
                [
                    'path'   => 'foo/dbname.sqlite',
                    'driver' => PDOSqliteDriver::class,
                ],
            ],
            'sqlite absolute URL with host' => [
273
                'sqlite://localhost//tmp/dbname.sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
274 275 276 277 278 279
                [
                    'path'   => '/tmp/dbname.sqlite',
                    'driver' => PDOSqliteDriver::class,
                ],
            ],
            'sqlite relative URL without host' => [
280
                'sqlite:///foo/dbname.sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
281 282 283 284 285 286
                [
                    'path'   => 'foo/dbname.sqlite',
                    'driver' => PDOSqliteDriver::class,
                ],
            ],
            'sqlite absolute URL without host' => [
287
                'sqlite:////tmp/dbname.sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
288 289 290 291 292 293
                [
                    'path'   => '/tmp/dbname.sqlite',
                    'driver' => PDOSqliteDriver::class,
                ],
            ],
            'sqlite memory' => [
294
                'sqlite:///:memory:',
Sergei Morozov's avatar
Sergei Morozov committed
295 296 297 298 299 300
                [
                    'memory' => true,
                    'driver' => PDOSqliteDriver::class,
                ],
            ],
            'sqlite memory with host' => [
301
                'sqlite://localhost/:memory:',
Sergei Morozov's avatar
Sergei Morozov committed
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
                [
                    'memory' => true,
                    'driver' => PDOSqliteDriver::class,
                ],
            ],
            'params parsed from URL override individual params' => [
                [
                    'url'      => 'mysql://foo:bar@localhost/baz',
                    'password' => 'lulz',
                ],
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
                    'driver'   => PDOMySQLDriver::class,
                ],
            ],
            'params not parsed from URL but individual params are preserved' => [
                [
                    'url'  => 'mysql://foo:bar@localhost/baz',
                    'port' => 1234,
                ],
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'port'     => 1234,
                    'dbname'   => 'baz',
                    'driver'   => PDOMySQLDriver::class,
                ],
            ],
            'query params from URL are used as extra params' => [
335
                'url' => 'mysql://foo:bar@localhost/dbname?charset=UTF-8',
Sergei Morozov's avatar
Sergei Morozov committed
336 337 338
                ['charset' => 'UTF-8'],
            ],
            'simple URL with fallthrough scheme not defined in map' => [
339
                'sqlsrv://foo:bar@localhost/baz',
Sergei Morozov's avatar
Sergei Morozov committed
340 341 342 343 344 345 346 347 348
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
                    'driver'   => SQLSrvDriver::class,
                ],
            ],
            'simple URL with fallthrough scheme containing underscores fails' => [
349 350
                'drizzle_pdo_mysql://foo:bar@localhost/baz',
                false,
Sergei Morozov's avatar
Sergei Morozov committed
351 352
            ],
            'simple URL with fallthrough scheme containing dashes works' => [
353
                'drizzle-pdo-mysql://foo:bar@localhost/baz',
Sergei Morozov's avatar
Sergei Morozov committed
354 355 356 357 358 359 360 361 362
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
                    'driver'   => DrizzlePDOMySqlDriver::class,
                ],
            ],
            'simple URL with percent encoding' => [
363
                'mysql://foo%3A:bar%2F@localhost/baz+baz%40',
Sergei Morozov's avatar
Sergei Morozov committed
364 365 366 367 368 369 370 371 372
                [
                    'user'     => 'foo:',
                    'password' => 'bar/',
                    'host'     => 'localhost',
                    'dbname'   => 'baz+baz@',
                    'driver'   => PDOMySQLDriver::class,
                ],
            ],
            'simple URL with percent sign in password' => [
373
                'mysql://foo:bar%25bar@localhost/baz',
Sergei Morozov's avatar
Sergei Morozov committed
374 375 376 377 378 379 380 381
                [
                    'user'     => 'foo',
                    'password' => 'bar%bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
                    'driver'   => PDOMySQLDriver::class,
                ],
            ],
382 383

            // DBAL-1234
Sergei Morozov's avatar
Sergei Morozov committed
384 385
            'URL without scheme and without any driver information' => [
                ['url' => '//foo:bar@localhost/baz'],
386
                false,
Sergei Morozov's avatar
Sergei Morozov committed
387 388 389 390 391 392
            ],
            'URL without scheme but default PDO driver' => [
                [
                    'url' => '//foo:bar@localhost/baz',
                    'pdo' => true,
                ],
393
                false,
Sergei Morozov's avatar
Sergei Morozov committed
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 429 430 431 432 433 434 435 436 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 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
            ],
            'URL without scheme but default driver' => [
                [
                    'url'    => '//foo:bar@localhost/baz',
                    'driver' => 'pdo_mysql',
                ],
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
                    'driver'   => PDOMySQLDriver::class,
                ],
            ],
            'URL without scheme but custom driver' => [
                [
                    'url'         => '//foo:bar@localhost/baz',
                    'driverClass' => DriverMock::class,
                ],
                [
                    'user'        => 'foo',
                    'password'    => 'bar',
                    'host'        => 'localhost',
                    'dbname'      => 'baz',
                    'driverClass' => DriverMock::class,
                ],
            ],
            'URL without scheme but default PDO driver and default driver' => [
                [
                    'url'    => '//foo:bar@localhost/baz',
                    'pdo'    => true,
                    'driver' => 'pdo_mysql',
                ],
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
                    'driver'   => PDOMySQLDriver::class,
                ],
            ],
            'URL without scheme but driver and custom driver' => [
                [
                    'url'         => '//foo:bar@localhost/baz',
                    'driver'      => 'pdo_mysql',
                    'driverClass' => DriverMock::class,
                ],
                [
                    'user'        => 'foo',
                    'password'    => 'bar',
                    'host'        => 'localhost',
                    'dbname'      => 'baz',
                    'driverClass' => DriverMock::class,
                ],
            ],
            'URL with default PDO driver' => [
                [
                    'url' => 'mysql://foo:bar@localhost/baz',
                    'pdo' => true,
                ],
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
                    'driver'   => PDOMySQLDriver::class,
                ],
            ],
            'URL with default driver' => [
                [
                    'url'    => 'mysql://foo:bar@localhost/baz',
                    'driver' => 'sqlite',
                ],
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
                    'driver'   => PDOMySQLDriver::class,
                ],
            ],
            'URL with default custom driver' => [
                [
                    'url'         => 'mysql://foo:bar@localhost/baz',
                    'driverClass' => DriverMock::class,
                ],
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
                    'driver'   => PDOMySQLDriver::class,
                ],
            ],
            'URL with default PDO driver and default driver' => [
                [
                    'url'    => 'mysql://foo:bar@localhost/baz',
                    'pdo'    => true,
                    'driver' => 'sqlite',
                ],
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
                    'driver'   => PDOMySQLDriver::class,
                ],
            ],
            'URL with default driver and default custom driver' => [
                [
                    'url'         => 'mysql://foo:bar@localhost/baz',
                    'driver'      => 'sqlite',
                    'driverClass' => DriverMock::class,
                ],
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
                    'driver'   => PDOMySQLDriver::class,
                ],
            ],
            'URL with default PDO driver and default driver and default custom driver' => [
                [
                    'url'         => 'mysql://foo:bar@localhost/baz',
                    'pdo'         => true,
                    'driver'      => 'sqlite',
                    'driverClass' => DriverMock::class,
                ],
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
                    'driver'   => PDOMySQLDriver::class,
                ],
            ],
        ];
532
    }
533
}