DriverManagerTest.php 12.9 KB
Newer Older
jwage's avatar
jwage committed
1 2
<?php

3
namespace Doctrine\DBAL\Tests;
jwage's avatar
jwage committed
4

5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\Connections\PrimaryReadReplicaConnection;
Luís Cobucci's avatar
Luís Cobucci committed
7
use Doctrine\DBAL\DBALException;
8
use Doctrine\DBAL\Driver;
9
use Doctrine\DBAL\Driver\PDO;
Sergei Morozov's avatar
Sergei Morozov committed
10 11
use Doctrine\DBAL\Driver\SQLSrv\Driver as SQLSrvDriver;
use Doctrine\DBAL\DriverManager;
12
use Doctrine\DBAL\Platforms\AbstractPlatform;
13
use PHPUnit\Framework\TestCase;
Sergei Morozov's avatar
Sergei Morozov committed
14
use stdClass;
15

16
use function get_class;
17 18
use function in_array;
use function is_array;
Luís Cobucci's avatar
Luís Cobucci committed
19

20
class DriverManagerTest extends TestCase
jwage's avatar
jwage committed
21
{
22
    public function testCheckParams(): void
jwage's avatar
jwage committed
23
    {
24 25
        $this->expectException(DBALException::class);

Sergei Morozov's avatar
Sergei Morozov committed
26
        DriverManager::getConnection([]);
jwage's avatar
jwage committed
27 28
    }

29
    public function testInvalidDriver(): void
jwage's avatar
jwage committed
30
    {
31 32
        $this->expectException(DBALException::class);

Sergei Morozov's avatar
Sergei Morozov committed
33
        DriverManager::getConnection(['driver' => 'invalid_driver']);
jwage's avatar
jwage committed
34
    }
35

36 37 38
    /**
     * @requires extension pdo_sqlite
     */
39
    public function testCustomPlatform(): void
40
    {
41 42
        $platform = $this->createMock(AbstractPlatform::class);
        $options  = [
43
            'url' => 'sqlite::memory:',
44
            'platform' => $platform,
Sergei Morozov's avatar
Sergei Morozov committed
45
        ];
46

Sergei Morozov's avatar
Sergei Morozov committed
47
        $conn = DriverManager::getConnection($options);
48
        self::assertSame($platform, $conn->getDatabasePlatform());
49
    }
50

51 52 53
    /**
     * @requires extension pdo_sqlite
     */
54
    public function testCustomWrapper(): void
55
    {
56 57
        $wrapper      = $this->createMock(Connection::class);
        $wrapperClass = get_class($wrapper);
58

Sergei Morozov's avatar
Sergei Morozov committed
59
        $options = [
60
            'url' => 'sqlite::memory:',
61
            'wrapperClass' => $wrapperClass,
Sergei Morozov's avatar
Sergei Morozov committed
62
        ];
63

Sergei Morozov's avatar
Sergei Morozov committed
64
        $conn = DriverManager::getConnection($options);
65
        self::assertInstanceOf($wrapperClass, $conn);
66 67
    }

68 69
    /**
     * @requires extension pdo_sqlite
70
     * @psalm-suppress InvalidArgument
71
     */
72
    public function testInvalidWrapperClass(): void
73
    {
Luís Cobucci's avatar
Luís Cobucci committed
74
        $this->expectException(DBALException::class);
75

Sergei Morozov's avatar
Sergei Morozov committed
76
        $options = [
77
            'url' => 'sqlite::memory:',
Sergei Morozov's avatar
Sergei Morozov committed
78 79
            'wrapperClass' => stdClass::class,
        ];
80

Sergei Morozov's avatar
Sergei Morozov committed
81
        DriverManager::getConnection($options);
82 83
    }

84
    public function testInvalidDriverClass(): void
85
    {
Luís Cobucci's avatar
Luís Cobucci committed
86
        $this->expectException(DBALException::class);
87

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

Sergei Morozov's avatar
Sergei Morozov committed
90
        DriverManager::getConnection($options);
91 92
    }

93
    public function testValidDriverClass(): void
94
    {
95
        $options = ['driverClass' => PDO\MySQL\Driver::class];
96

Sergei Morozov's avatar
Sergei Morozov committed
97
        $conn = DriverManager::getConnection($options);
98
        self::assertInstanceOf(PDO\MySQL\Driver::class, $conn->getDriver());
99
    }
100

101
    public function testDatabaseUrlPrimaryReplica(): void
102 103 104
    {
        $options = [
            'driver' => 'pdo_mysql',
105 106 107
            'primary' => ['url' => 'mysql://foo:bar@localhost:11211/baz'],
            'replica' => [
                'replica1' => ['url' => 'mysql://foo:bar@localhost:11211/baz_replica'],
108
            ],
109
            'wrapperClass' => PrimaryReadReplicaConnection::class,
110 111 112 113 114
        ];

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

        $params = $conn->getParams();
115
        self::assertInstanceOf(PDO\MySQL\Driver::class, $conn->getDriver());
116 117 118 119 120 121 122 123 124

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

        foreach ($expected as $key => $value) {
125 126
            self::assertEquals($value, $params['primary'][$key]);
            self::assertEquals($value, $params['replica']['replica1'][$key]);
127 128
        }

129 130
        self::assertEquals('baz', $params['primary']['dbname']);
        self::assertEquals('baz_replica', $params['replica']['replica1']['dbname']);
131 132
    }

133
    /**
134 135 136
     * @param mixed $url
     * @param mixed $expected
     *
137 138
     * @dataProvider databaseUrls
     */
139
    public function testDatabaseUrl($url, $expected): void
140
    {
Sergei Morozov's avatar
Sergei Morozov committed
141
        $options = is_array($url) ? $url : ['url' => $url];
142

143
        if ($expected === false) {
Luís Cobucci's avatar
Luís Cobucci committed
144
            $this->expectException(DBALException::class);
145
        }
146

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

149 150
        $params = $conn->getParams();
        foreach ($expected as $key => $value) {
151
            if (in_array($key, ['driver', 'driverClass'], true)) {
152
                self::assertInstanceOf($value, $conn->getDriver());
153
            } else {
154
                self::assertEquals($value, $params[$key]);
155 156 157
            }
        }
    }
158

159
    /**
Grégoire Paris's avatar
Grégoire Paris committed
160
     * @return array<string, list<mixed>>
161
     */
162
    public function databaseUrls(): iterable
163
    {
164 165 166
        $driver      = $this->createMock(Driver::class);
        $driverClass = get_class($driver);

Sergei Morozov's avatar
Sergei Morozov committed
167 168
        return [
            'simple URL' => [
169
                'mysql://foo:bar@localhost/baz',
Sergei Morozov's avatar
Sergei Morozov committed
170 171 172 173 174
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
175
                    'driver'   => PDO\MySQL\Driver::class,
Sergei Morozov's avatar
Sergei Morozov committed
176 177 178
                ],
            ],
            'simple URL with port' => [
179
                'mysql://foo:bar@localhost:11211/baz',
Sergei Morozov's avatar
Sergei Morozov committed
180 181 182 183 184 185
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'port'     => 11211,
                    'dbname'   => 'baz',
186
                    'driver'   => PDO\MySQL\Driver::class,
Sergei Morozov's avatar
Sergei Morozov committed
187 188 189
                ],
            ],
            'sqlite relative URL with host' => [
190
                'sqlite://localhost/foo/dbname.sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
191 192
                [
                    'path'   => 'foo/dbname.sqlite',
193
                    'driver' => PDO\SQLite\Driver::class,
Sergei Morozov's avatar
Sergei Morozov committed
194 195 196
                ],
            ],
            'sqlite absolute URL with host' => [
197
                'sqlite://localhost//tmp/dbname.sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
198 199
                [
                    'path'   => '/tmp/dbname.sqlite',
200
                    'driver' => PDO\SQLite\Driver::class,
Sergei Morozov's avatar
Sergei Morozov committed
201 202 203
                ],
            ],
            'sqlite relative URL without host' => [
204
                'sqlite:///foo/dbname.sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
205 206
                [
                    'path'   => 'foo/dbname.sqlite',
207
                    'driver' => PDO\SQLite\Driver::class,
Sergei Morozov's avatar
Sergei Morozov committed
208 209 210
                ],
            ],
            'sqlite absolute URL without host' => [
211
                'sqlite:////tmp/dbname.sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
212 213
                [
                    'path'   => '/tmp/dbname.sqlite',
214
                    'driver' => PDO\SQLite\Driver::class,
Sergei Morozov's avatar
Sergei Morozov committed
215 216 217
                ],
            ],
            'sqlite memory' => [
218
                'sqlite:///:memory:',
Sergei Morozov's avatar
Sergei Morozov committed
219 220
                [
                    'memory' => true,
221
                    'driver' => PDO\SQLite\Driver::class,
Sergei Morozov's avatar
Sergei Morozov committed
222 223 224
                ],
            ],
            'sqlite memory with host' => [
225
                'sqlite://localhost/:memory:',
Sergei Morozov's avatar
Sergei Morozov committed
226 227
                [
                    'memory' => true,
228
                    'driver' => PDO\SQLite\Driver::class,
Sergei Morozov's avatar
Sergei Morozov committed
229 230 231 232 233 234 235 236 237 238 239 240
                ],
            ],
            'params parsed from URL override individual params' => [
                [
                    'url'      => 'mysql://foo:bar@localhost/baz',
                    'password' => 'lulz',
                ],
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
241
                    'driver'   => PDO\MySQL\Driver::class,
Sergei Morozov's avatar
Sergei Morozov committed
242 243 244 245 246 247 248 249 250 251 252 253 254
                ],
            ],
            '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',
255
                    'driver'   => PDO\MySQL\Driver::class,
Sergei Morozov's avatar
Sergei Morozov committed
256 257 258
                ],
            ],
            'query params from URL are used as extra params' => [
Grégoire Paris's avatar
Grégoire Paris committed
259
                'mysql://foo:bar@localhost/dbname?charset=UTF-8',
Sergei Morozov's avatar
Sergei Morozov committed
260 261 262
                ['charset' => 'UTF-8'],
            ],
            'simple URL with fallthrough scheme not defined in map' => [
263
                'sqlsrv://foo:bar@localhost/baz',
Sergei Morozov's avatar
Sergei Morozov committed
264 265 266 267 268 269 270 271 272
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
                    'driver'   => SQLSrvDriver::class,
                ],
            ],
            'simple URL with fallthrough scheme containing underscores fails' => [
Benjamin Morel's avatar
Benjamin Morel committed
273
                'pdo_mysql://foo:bar@localhost/baz',
274
                false,
Sergei Morozov's avatar
Sergei Morozov committed
275 276
            ],
            'simple URL with fallthrough scheme containing dashes works' => [
Benjamin Morel's avatar
Benjamin Morel committed
277
                'pdo-mysql://foo:bar@localhost/baz',
Sergei Morozov's avatar
Sergei Morozov committed
278 279 280 281 282
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
283
                    'driver'   => PDO\MySQL\Driver::class,
Sergei Morozov's avatar
Sergei Morozov committed
284 285 286
                ],
            ],
            'simple URL with percent encoding' => [
287
                'mysql://foo%3A:bar%2F@localhost/baz+baz%40',
Sergei Morozov's avatar
Sergei Morozov committed
288 289 290 291 292
                [
                    'user'     => 'foo:',
                    'password' => 'bar/',
                    'host'     => 'localhost',
                    'dbname'   => 'baz+baz@',
293
                    'driver'   => PDO\MySQL\Driver::class,
Sergei Morozov's avatar
Sergei Morozov committed
294 295 296
                ],
            ],
            'simple URL with percent sign in password' => [
297
                'mysql://foo:bar%25bar@localhost/baz',
Sergei Morozov's avatar
Sergei Morozov committed
298 299 300 301 302
                [
                    'user'     => 'foo',
                    'password' => 'bar%bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
303
                    'driver'   => PDO\MySQL\Driver::class,
Sergei Morozov's avatar
Sergei Morozov committed
304 305
                ],
            ],
306 307

            // DBAL-1234
Sergei Morozov's avatar
Sergei Morozov committed
308 309
            'URL without scheme and without any driver information' => [
                ['url' => '//foo:bar@localhost/baz'],
310
                false,
Sergei Morozov's avatar
Sergei Morozov committed
311 312 313 314 315 316 317 318 319 320 321
            ],
            'URL without scheme but default driver' => [
                [
                    'url'    => '//foo:bar@localhost/baz',
                    'driver' => 'pdo_mysql',
                ],
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
322
                    'driver'   => PDO\MySQL\Driver::class,
Sergei Morozov's avatar
Sergei Morozov committed
323 324 325 326 327
                ],
            ],
            'URL without scheme but custom driver' => [
                [
                    'url'         => '//foo:bar@localhost/baz',
328
                    'driverClass' => $driverClass,
Sergei Morozov's avatar
Sergei Morozov committed
329 330 331 332 333 334
                ],
                [
                    'user'        => 'foo',
                    'password'    => 'bar',
                    'host'        => 'localhost',
                    'dbname'      => 'baz',
335
                    'driverClass' => $driverClass,
Sergei Morozov's avatar
Sergei Morozov committed
336 337 338 339 340 341
                ],
            ],
            'URL without scheme but driver and custom driver' => [
                [
                    'url'         => '//foo:bar@localhost/baz',
                    'driver'      => 'pdo_mysql',
342
                    'driverClass' => $driverClass,
Sergei Morozov's avatar
Sergei Morozov committed
343 344 345 346 347 348
                ],
                [
                    'user'        => 'foo',
                    'password'    => 'bar',
                    'host'        => 'localhost',
                    'dbname'      => 'baz',
349
                    'driverClass' => $driverClass,
Sergei Morozov's avatar
Sergei Morozov committed
350 351 352 353 354 355 356 357 358 359 360 361
                ],
            ],
            'URL with default driver' => [
                [
                    'url'    => 'mysql://foo:bar@localhost/baz',
                    'driver' => 'sqlite',
                ],
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
362
                    'driver'   => PDO\MySQL\Driver::class,
Sergei Morozov's avatar
Sergei Morozov committed
363 364 365 366 367
                ],
            ],
            'URL with default custom driver' => [
                [
                    'url'         => 'mysql://foo:bar@localhost/baz',
368
                    'driverClass' => $driverClass,
Sergei Morozov's avatar
Sergei Morozov committed
369 370 371 372 373 374
                ],
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
375
                    'driver'   => PDO\MySQL\Driver::class,
Sergei Morozov's avatar
Sergei Morozov committed
376 377 378 379 380 381
                ],
            ],
            'URL with default driver and default custom driver' => [
                [
                    'url'         => 'mysql://foo:bar@localhost/baz',
                    'driver'      => 'sqlite',
382
                    'driverClass' => $driverClass,
Sergei Morozov's avatar
Sergei Morozov committed
383 384 385 386 387 388
                ],
                [
                    'user'     => 'foo',
                    'password' => 'bar',
                    'host'     => 'localhost',
                    'dbname'   => 'baz',
389
                    'driver'   => PDO\MySQL\Driver::class,
Sergei Morozov's avatar
Sergei Morozov committed
390 391 392
                ],
            ],
        ];
393
    }
394
}