PoolingShardConnectionTest.php 10.5 KB
Newer Older
1 2 3 4 5
<?php

namespace Doctrine\Tests\DBAL\Sharding;

use Doctrine\DBAL\DriverManager;
Sergei Morozov's avatar
Sergei Morozov committed
6
use Doctrine\DBAL\Sharding\PoolingShardConnection;
7
use Doctrine\DBAL\Sharding\ShardChoser\MultiTenantShardChoser;
Sergei Morozov's avatar
Sergei Morozov committed
8
use Doctrine\DBAL\Sharding\ShardingException;
Sergei Morozov's avatar
Sergei Morozov committed
9
use PHPUnit\Framework\TestCase;
Sergei Morozov's avatar
Sergei Morozov committed
10
use stdClass;
11

12 13 14
/**
 * @requires extension pdo_sqlite
 */
Sergei Morozov's avatar
Sergei Morozov committed
15
class PoolingShardConnectionTest extends TestCase
16
{
17
    public function testConnect() : void
18
    {
Sergei Morozov's avatar
Sergei Morozov committed
19
        $conn = DriverManager::getConnection([
Sergei Morozov's avatar
Sergei Morozov committed
20
            'wrapperClass' => PoolingShardConnection::class,
21
            'driver' => 'pdo_sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
22 23 24 25 26
            'global' => ['memory' => true],
            'shards' => [
                ['id' => 1, 'memory' => true],
                ['id' => 2, 'memory' => true],
            ],
Sergei Morozov's avatar
Sergei Morozov committed
27
            'shardChoser' => MultiTenantShardChoser::class,
Sergei Morozov's avatar
Sergei Morozov committed
28
        ]);
29

30
        self::assertFalse($conn->isConnected(0));
31
        $conn->connect(0);
32 33
        self::assertEquals(1, $conn->fetchColumn('SELECT 1'));
        self::assertTrue($conn->isConnected(0));
34

35
        self::assertFalse($conn->isConnected(1));
36
        $conn->connect(1);
37 38
        self::assertEquals(1, $conn->fetchColumn('SELECT 1'));
        self::assertTrue($conn->isConnected(1));
39

40
        self::assertFalse($conn->isConnected(2));
41
        $conn->connect(2);
42 43
        self::assertEquals(1, $conn->fetchColumn('SELECT 1'));
        self::assertTrue($conn->isConnected(2));
44 45

        $conn->close();
46 47 48
        self::assertFalse($conn->isConnected(0));
        self::assertFalse($conn->isConnected(1));
        self::assertFalse($conn->isConnected(2));
49 50
    }

51
    public function testNoGlobalServerException() : void
52
    {
53 54
        $this->expectException('InvalidArgumentException');
        $this->expectExceptionMessage("Connection Parameters require 'global' and 'shards' configurations.");
55

Sergei Morozov's avatar
Sergei Morozov committed
56
        DriverManager::getConnection([
Sergei Morozov's avatar
Sergei Morozov committed
57
            'wrapperClass' => PoolingShardConnection::class,
58
            'driver' => 'pdo_sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
59 60 61 62
            'shards' => [
                ['id' => 1, 'memory' => true],
                ['id' => 2, 'memory' => true],
            ],
Sergei Morozov's avatar
Sergei Morozov committed
63
            'shardChoser' => MultiTenantShardChoser::class,
Sergei Morozov's avatar
Sergei Morozov committed
64
        ]);
65 66
    }

67
    public function testNoShardsServersException() : void
68
    {
69 70
        $this->expectException('InvalidArgumentException');
        $this->expectExceptionMessage("Connection Parameters require 'global' and 'shards' configurations.");
71

Sergei Morozov's avatar
Sergei Morozov committed
72
        DriverManager::getConnection([
Sergei Morozov's avatar
Sergei Morozov committed
73
            'wrapperClass' => PoolingShardConnection::class,
74
            'driver' => 'pdo_sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
75
            'global' => ['memory' => true],
Sergei Morozov's avatar
Sergei Morozov committed
76
            'shardChoser' => MultiTenantShardChoser::class,
Sergei Morozov's avatar
Sergei Morozov committed
77
        ]);
78 79
    }

80
    public function testNoShardsChoserException() : void
81
    {
82 83
        $this->expectException('InvalidArgumentException');
        $this->expectExceptionMessage("Missing Shard Choser configuration 'shardChoser'");
84

Sergei Morozov's avatar
Sergei Morozov committed
85
        DriverManager::getConnection([
Sergei Morozov's avatar
Sergei Morozov committed
86
            'wrapperClass' => PoolingShardConnection::class,
87
            'driver' => 'pdo_sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
88 89 90 91 92 93
            'global' => ['memory' => true],
            'shards' => [
                ['id' => 1, 'memory' => true],
                ['id' => 2, 'memory' => true],
            ],
        ]);
94 95
    }

96
    public function testShardChoserWrongInstance() : void
97
    {
98 99
        $this->expectException('InvalidArgumentException');
        $this->expectExceptionMessage("The 'shardChoser' configuration is not a valid instance of Doctrine\DBAL\Sharding\ShardChoser\ShardChoser");
100

Sergei Morozov's avatar
Sergei Morozov committed
101
        DriverManager::getConnection([
Sergei Morozov's avatar
Sergei Morozov committed
102
            'wrapperClass' => PoolingShardConnection::class,
103
            'driver' => 'pdo_sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
104 105 106 107 108
            'global' => ['memory' => true],
            'shards' => [
                ['id' => 1, 'memory' => true],
                ['id' => 2, 'memory' => true],
            ],
Sergei Morozov's avatar
Sergei Morozov committed
109
            'shardChoser' => new stdClass(),
Sergei Morozov's avatar
Sergei Morozov committed
110
        ]);
111 112
    }

113
    public function testShardNonNumericId() : void
114
    {
115 116
        $this->expectException('InvalidArgumentException');
        $this->expectExceptionMessage('Shard Id has to be a non-negative number.');
117

Sergei Morozov's avatar
Sergei Morozov committed
118
        DriverManager::getConnection([
Sergei Morozov's avatar
Sergei Morozov committed
119
            'wrapperClass' => PoolingShardConnection::class,
120
            'driver' => 'pdo_sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
121 122 123 124
            'global' => ['memory' => true],
            'shards' => [
                ['id' => 'foo', 'memory' => true],
            ],
Sergei Morozov's avatar
Sergei Morozov committed
125
            'shardChoser' => MultiTenantShardChoser::class,
Sergei Morozov's avatar
Sergei Morozov committed
126
        ]);
127 128
    }

129
    public function testShardMissingId() : void
130
    {
131 132
        $this->expectException('InvalidArgumentException');
        $this->expectExceptionMessage("Missing 'id' for one configured shard. Please specify a unique shard-id.");
133

Sergei Morozov's avatar
Sergei Morozov committed
134
        DriverManager::getConnection([
Sergei Morozov's avatar
Sergei Morozov committed
135
            'wrapperClass' => PoolingShardConnection::class,
136
            'driver' => 'pdo_sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
137 138 139 140
            'global' => ['memory' => true],
            'shards' => [
                ['memory' => true],
            ],
Sergei Morozov's avatar
Sergei Morozov committed
141
            'shardChoser' => MultiTenantShardChoser::class,
Sergei Morozov's avatar
Sergei Morozov committed
142
        ]);
143 144
    }

145
    public function testDuplicateShardId() : void
146
    {
147 148
        $this->expectException('InvalidArgumentException');
        $this->expectExceptionMessage('Shard 1 is duplicated in the configuration.');
149

Sergei Morozov's avatar
Sergei Morozov committed
150
        DriverManager::getConnection([
Sergei Morozov's avatar
Sergei Morozov committed
151
            'wrapperClass' => PoolingShardConnection::class,
152
            'driver' => 'pdo_sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
153 154 155 156 157
            'global' => ['memory' => true],
            'shards' => [
                ['id' => 1, 'memory' => true],
                ['id' => 1, 'memory' => true],
            ],
Sergei Morozov's avatar
Sergei Morozov committed
158
            'shardChoser' => MultiTenantShardChoser::class,
Sergei Morozov's avatar
Sergei Morozov committed
159
        ]);
160 161
    }

162
    public function testSwitchShardWithOpenTransactionException() : void
163
    {
Sergei Morozov's avatar
Sergei Morozov committed
164
        $conn = DriverManager::getConnection([
Sergei Morozov's avatar
Sergei Morozov committed
165
            'wrapperClass' => PoolingShardConnection::class,
166
            'driver' => 'pdo_sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
167 168 169 170
            'global' => ['memory' => true],
            'shards' => [
                ['id' => 1, 'memory' => true],
            ],
Sergei Morozov's avatar
Sergei Morozov committed
171
            'shardChoser' => MultiTenantShardChoser::class,
Sergei Morozov's avatar
Sergei Morozov committed
172
        ]);
173 174 175

        $conn->beginTransaction();

Sergei Morozov's avatar
Sergei Morozov committed
176
        $this->expectException(ShardingException::class);
177
        $this->expectExceptionMessage('Cannot switch shard when transaction is active.');
178 179 180
        $conn->connect(1);
    }

181
    public function testGetActiveShardId() : void
182
    {
Sergei Morozov's avatar
Sergei Morozov committed
183
        $conn = DriverManager::getConnection([
Sergei Morozov's avatar
Sergei Morozov committed
184
            'wrapperClass' => PoolingShardConnection::class,
185
            'driver' => 'pdo_sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
186 187 188 189
            'global' => ['memory' => true],
            'shards' => [
                ['id' => 1, 'memory' => true],
            ],
Sergei Morozov's avatar
Sergei Morozov committed
190
            'shardChoser' => MultiTenantShardChoser::class,
Sergei Morozov's avatar
Sergei Morozov committed
191
        ]);
192

193
        self::assertNull($conn->getActiveShardId());
194 195

        $conn->connect(0);
196
        self::assertEquals(0, $conn->getActiveShardId());
197 198

        $conn->connect(1);
199
        self::assertEquals(1, $conn->getActiveShardId());
200 201

        $conn->close();
202
        self::assertNull($conn->getActiveShardId());
203 204
    }

205
    public function testGetParamsOverride() : void
206
    {
Sergei Morozov's avatar
Sergei Morozov committed
207
        $conn = DriverManager::getConnection([
Sergei Morozov's avatar
Sergei Morozov committed
208
            'wrapperClass' => PoolingShardConnection::class,
209
            'driver' => 'pdo_sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
210 211 212 213
            'global' => ['memory' => true, 'host' => 'localhost'],
            'shards' => [
                ['id' => 1, 'memory' => true, 'host' => 'foo'],
            ],
Sergei Morozov's avatar
Sergei Morozov committed
214
            'shardChoser' => MultiTenantShardChoser::class,
Sergei Morozov's avatar
Sergei Morozov committed
215
        ]);
216

Sergei Morozov's avatar
Sergei Morozov committed
217
        self::assertEquals([
Sergei Morozov's avatar
Sergei Morozov committed
218
            'wrapperClass' => PoolingShardConnection::class,
219
            'driver' => 'pdo_sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
220 221 222 223
            'global' => ['memory' => true, 'host' => 'localhost'],
            'shards' => [
                ['id' => 1, 'memory' => true, 'host' => 'foo'],
            ],
224
            'shardChoser' => new MultiTenantShardChoser(),
225 226
            'memory' => true,
            'host' => 'localhost',
Sergei Morozov's avatar
Sergei Morozov committed
227
        ], $conn->getParams());
228 229

        $conn->connect(1);
Sergei Morozov's avatar
Sergei Morozov committed
230
        self::assertEquals([
Sergei Morozov's avatar
Sergei Morozov committed
231
            'wrapperClass' => PoolingShardConnection::class,
232
            'driver' => 'pdo_sqlite',
Sergei Morozov's avatar
Sergei Morozov committed
233 234 235 236
            'global' => ['memory' => true, 'host' => 'localhost'],
            'shards' => [
                ['id' => 1, 'memory' => true, 'host' => 'foo'],
            ],
237 238 239
            'shardChoser' => new MultiTenantShardChoser(),
            'id' => 1,
            'memory' => true,
240
            'host' => 'foo',
Sergei Morozov's avatar
Sergei Morozov committed
241
        ], $conn->getParams());
242 243
    }

244
    public function testGetHostOverride() : void
245
    {
Sergei Morozov's avatar
Sergei Morozov committed
246
        $conn = DriverManager::getConnection([
Sergei Morozov's avatar
Sergei Morozov committed
247
            'wrapperClass' => PoolingShardConnection::class,
248 249
            'driver' => 'pdo_sqlite',
            'host' => 'localhost',
Sergei Morozov's avatar
Sergei Morozov committed
250 251 252 253
            'global' => ['memory' => true],
            'shards' => [
                ['id' => 1, 'memory' => true, 'host' => 'foo'],
            ],
Sergei Morozov's avatar
Sergei Morozov committed
254
            'shardChoser' => MultiTenantShardChoser::class,
Sergei Morozov's avatar
Sergei Morozov committed
255
        ]);
256

257
        self::assertEquals('localhost', $conn->getHost());
258 259

        $conn->connect(1);
260
        self::assertEquals('foo', $conn->getHost());
261 262
    }

263
    public function testGetPortOverride() : void
264
    {
Sergei Morozov's avatar
Sergei Morozov committed
265
        $conn = DriverManager::getConnection([
Sergei Morozov's avatar
Sergei Morozov committed
266
            'wrapperClass' => PoolingShardConnection::class,
267 268
            'driver' => 'pdo_sqlite',
            'port' => 3306,
Sergei Morozov's avatar
Sergei Morozov committed
269 270 271 272
            'global' => ['memory' => true],
            'shards' => [
                ['id' => 1, 'memory' => true, 'port' => 3307],
            ],
Sergei Morozov's avatar
Sergei Morozov committed
273
            'shardChoser' => MultiTenantShardChoser::class,
Sergei Morozov's avatar
Sergei Morozov committed
274
        ]);
275

276
        self::assertEquals(3306, $conn->getPort());
277 278

        $conn->connect(1);
279
        self::assertEquals(3307, $conn->getPort());
280 281
    }

282
    public function testGetUsernameOverride() : void
283
    {
Sergei Morozov's avatar
Sergei Morozov committed
284
        $conn = DriverManager::getConnection([
Sergei Morozov's avatar
Sergei Morozov committed
285
            'wrapperClass' => PoolingShardConnection::class,
286 287
            'driver' => 'pdo_sqlite',
            'user' => 'foo',
Sergei Morozov's avatar
Sergei Morozov committed
288 289 290 291
            'global' => ['memory' => true],
            'shards' => [
                ['id' => 1, 'memory' => true, 'user' => 'bar'],
            ],
Sergei Morozov's avatar
Sergei Morozov committed
292
            'shardChoser' => MultiTenantShardChoser::class,
Sergei Morozov's avatar
Sergei Morozov committed
293
        ]);
294

295
        self::assertEquals('foo', $conn->getUsername());
296 297

        $conn->connect(1);
298
        self::assertEquals('bar', $conn->getUsername());
299 300
    }

301
    public function testGetPasswordOverride() : void
302
    {
Sergei Morozov's avatar
Sergei Morozov committed
303
        $conn = DriverManager::getConnection([
Sergei Morozov's avatar
Sergei Morozov committed
304
            'wrapperClass' => PoolingShardConnection::class,
305 306
            'driver' => 'pdo_sqlite',
            'password' => 'foo',
Sergei Morozov's avatar
Sergei Morozov committed
307 308 309 310
            'global' => ['memory' => true],
            'shards' => [
                ['id' => 1, 'memory' => true, 'password' => 'bar'],
            ],
Sergei Morozov's avatar
Sergei Morozov committed
311
            'shardChoser' => MultiTenantShardChoser::class,
Sergei Morozov's avatar
Sergei Morozov committed
312
        ]);
313

314
        self::assertEquals('foo', $conn->getPassword());
315 316

        $conn->connect(1);
317
        self::assertEquals('bar', $conn->getPassword());
318 319
    }
}