1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace Doctrine\Tests\DBAL\Sharding; |
6
|
|
|
|
7
|
|
|
use Doctrine\DBAL\DriverManager; |
8
|
|
|
use Doctrine\DBAL\Sharding\PoolingShardConnection; |
9
|
|
|
use Doctrine\DBAL\Sharding\ShardChoser\MultiTenantShardChoser; |
10
|
|
|
use Doctrine\DBAL\Sharding\ShardingException; |
11
|
|
|
use InvalidArgumentException; |
12
|
|
|
use PHPUnit\Framework\TestCase; |
13
|
|
|
use stdClass; |
14
|
|
|
use function array_merge; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* @requires extension pdo_sqlite |
18
|
|
|
*/ |
19
|
|
|
class PoolingShardConnectionTest extends TestCase |
20
|
|
|
{ |
21
|
|
|
public function testConnect() : void |
22
|
|
|
{ |
23
|
|
|
$conn = $this->createConnection([ |
24
|
|
|
'driver' => 'pdo_sqlite', |
25
|
|
|
'global' => ['memory' => true], |
26
|
|
|
'shards' => [ |
27
|
|
|
['id' => 1, 'memory' => true], |
28
|
|
|
['id' => 2, 'memory' => true], |
29
|
|
|
], |
30
|
|
|
'shardChoser' => MultiTenantShardChoser::class, |
31
|
|
|
]); |
32
|
|
|
|
33
|
|
|
self::assertFalse($conn->isConnected(0)); |
34
|
|
|
$conn->connect(0); |
35
|
|
|
self::assertEquals(1, $conn->fetchColumn('SELECT 1')); |
36
|
|
|
self::assertTrue($conn->isConnected(0)); |
37
|
|
|
|
38
|
|
|
self::assertFalse($conn->isConnected(1)); |
39
|
|
|
$conn->connect(1); |
40
|
|
|
self::assertEquals(1, $conn->fetchColumn('SELECT 1')); |
41
|
|
|
self::assertTrue($conn->isConnected(1)); |
42
|
|
|
|
43
|
|
|
self::assertFalse($conn->isConnected(2)); |
44
|
|
|
$conn->connect(2); |
45
|
|
|
self::assertEquals(1, $conn->fetchColumn('SELECT 1')); |
46
|
|
|
self::assertTrue($conn->isConnected(2)); |
47
|
|
|
|
48
|
|
|
$conn->close(); |
49
|
|
|
self::assertFalse($conn->isConnected(0)); |
50
|
|
|
self::assertFalse($conn->isConnected(1)); |
51
|
|
|
self::assertFalse($conn->isConnected(2)); |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
public function testNoGlobalServerException() : void |
55
|
|
|
{ |
56
|
|
|
$this->expectException(InvalidArgumentException::class); |
57
|
|
|
$this->expectExceptionMessage('Connection Parameters require "global" and "shards" configurations.'); |
58
|
|
|
|
59
|
|
|
$this->createConnection([ |
60
|
|
|
'driver' => 'pdo_sqlite', |
61
|
|
|
'shards' => [ |
62
|
|
|
['id' => 1, 'memory' => true], |
63
|
|
|
['id' => 2, 'memory' => true], |
64
|
|
|
], |
65
|
|
|
'shardChoser' => MultiTenantShardChoser::class, |
66
|
|
|
]); |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
public function testNoShardsServersException() : void |
70
|
|
|
{ |
71
|
|
|
$this->expectException(InvalidArgumentException::class); |
72
|
|
|
$this->expectExceptionMessage('Connection Parameters require "global" and "shards" configurations.'); |
73
|
|
|
|
74
|
|
|
$this->createConnection([ |
75
|
|
|
'driver' => 'pdo_sqlite', |
76
|
|
|
'global' => ['memory' => true], |
77
|
|
|
'shardChoser' => MultiTenantShardChoser::class, |
78
|
|
|
]); |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
public function testNoShardsChoserException() : void |
82
|
|
|
{ |
83
|
|
|
$this->expectException(InvalidArgumentException::class); |
84
|
|
|
$this->expectExceptionMessage('Missing Shard Choser configuration "shardChoser".'); |
85
|
|
|
|
86
|
|
|
$this->createConnection([ |
87
|
|
|
'driver' => 'pdo_sqlite', |
88
|
|
|
'global' => ['memory' => true], |
89
|
|
|
'shards' => [ |
90
|
|
|
['id' => 1, 'memory' => true], |
91
|
|
|
['id' => 2, 'memory' => true], |
92
|
|
|
], |
93
|
|
|
]); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
public function testShardChoserWrongInstance() : void |
97
|
|
|
{ |
98
|
|
|
$this->expectException(InvalidArgumentException::class); |
99
|
|
|
$this->expectExceptionMessage('The "shardChoser" configuration is not a valid instance of Doctrine\DBAL\Sharding\ShardChoser\ShardChoser'); |
100
|
|
|
|
101
|
|
|
$this->createConnection([ |
102
|
|
|
'driver' => 'pdo_sqlite', |
103
|
|
|
'global' => ['memory' => true], |
104
|
|
|
'shards' => [ |
105
|
|
|
['id' => 1, 'memory' => true], |
106
|
|
|
['id' => 2, 'memory' => true], |
107
|
|
|
], |
108
|
|
|
'shardChoser' => new stdClass(), |
109
|
|
|
]); |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
public function testShardNonNumericId() : void |
113
|
|
|
{ |
114
|
|
|
$this->expectException('InvalidArgumentException'); |
115
|
|
|
$this->expectExceptionMessage('Shard Id has to be a non-negative number.'); |
116
|
|
|
|
117
|
|
|
$this->createConnection([ |
118
|
|
|
'driver' => 'pdo_sqlite', |
119
|
|
|
'global' => ['memory' => true], |
120
|
|
|
'shards' => [ |
121
|
|
|
['id' => 'foo', 'memory' => true], |
122
|
|
|
], |
123
|
|
|
'shardChoser' => MultiTenantShardChoser::class, |
124
|
|
|
]); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
public function testShardMissingId() : void |
128
|
|
|
{ |
129
|
|
|
$this->expectException(InvalidArgumentException::class); |
130
|
|
|
$this->expectExceptionMessage('Missing "id" for one configured shard. Please specify a unique shard-id.'); |
131
|
|
|
|
132
|
|
|
$this->createConnection([ |
133
|
|
|
'driver' => 'pdo_sqlite', |
134
|
|
|
'global' => ['memory' => true], |
135
|
|
|
'shards' => [ |
136
|
|
|
['memory' => true], |
137
|
|
|
], |
138
|
|
|
'shardChoser' => MultiTenantShardChoser::class, |
139
|
|
|
]); |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
public function testDuplicateShardId() : void |
143
|
|
|
{ |
144
|
|
|
$this->expectException(InvalidArgumentException::class); |
145
|
|
|
$this->expectExceptionMessage('Shard "1" is duplicated in the configuration.'); |
146
|
|
|
|
147
|
|
|
$this->createConnection([ |
148
|
|
|
'driver' => 'pdo_sqlite', |
149
|
|
|
'global' => ['memory' => true], |
150
|
|
|
'shards' => [ |
151
|
|
|
['id' => 1, 'memory' => true], |
152
|
|
|
['id' => 1, 'memory' => true], |
153
|
|
|
], |
154
|
|
|
'shardChoser' => MultiTenantShardChoser::class, |
155
|
|
|
]); |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
public function testSwitchShardWithOpenTransactionException() : void |
159
|
|
|
{ |
160
|
|
|
$conn = $this->createConnection([ |
161
|
|
|
'driver' => 'pdo_sqlite', |
162
|
|
|
'global' => ['memory' => true], |
163
|
|
|
'shards' => [ |
164
|
|
|
['id' => 1, 'memory' => true], |
165
|
|
|
], |
166
|
|
|
'shardChoser' => MultiTenantShardChoser::class, |
167
|
|
|
]); |
168
|
|
|
|
169
|
|
|
$conn->beginTransaction(); |
170
|
|
|
|
171
|
|
|
$this->expectException(ShardingException::class); |
172
|
|
|
$this->expectExceptionMessage('Cannot switch shard when transaction is active.'); |
173
|
|
|
$conn->connect(1); |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
public function testGetActiveShardId() : void |
177
|
|
|
{ |
178
|
|
|
$conn = $this->createConnection([ |
179
|
|
|
'driver' => 'pdo_sqlite', |
180
|
|
|
'global' => ['memory' => true], |
181
|
|
|
'shards' => [ |
182
|
|
|
['id' => 1, 'memory' => true], |
183
|
|
|
], |
184
|
|
|
'shardChoser' => MultiTenantShardChoser::class, |
185
|
|
|
]); |
186
|
|
|
|
187
|
|
|
self::assertNull($conn->getActiveShardId()); |
188
|
|
|
|
189
|
|
|
$conn->connect(0); |
190
|
|
|
self::assertEquals(0, $conn->getActiveShardId()); |
191
|
|
|
|
192
|
|
|
$conn->connect(1); |
193
|
|
|
self::assertEquals(1, $conn->getActiveShardId()); |
194
|
|
|
|
195
|
|
|
$conn->close(); |
196
|
|
|
self::assertNull($conn->getActiveShardId()); |
|
|
|
|
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
public function testGetParamsOverride() : void |
200
|
|
|
{ |
201
|
|
|
$conn = $this->createConnection([ |
202
|
|
|
'driver' => 'pdo_sqlite', |
203
|
|
|
'global' => ['memory' => true, 'host' => 'localhost'], |
204
|
|
|
'shards' => [ |
205
|
|
|
['id' => 1, 'memory' => true, 'host' => 'foo'], |
206
|
|
|
], |
207
|
|
|
'shardChoser' => MultiTenantShardChoser::class, |
208
|
|
|
]); |
209
|
|
|
|
210
|
|
|
self::assertEquals([ |
211
|
|
|
'wrapperClass' => PoolingShardConnection::class, |
212
|
|
|
'driver' => 'pdo_sqlite', |
213
|
|
|
'global' => ['memory' => true, 'host' => 'localhost'], |
214
|
|
|
'shards' => [ |
215
|
|
|
['id' => 1, 'memory' => true, 'host' => 'foo'], |
216
|
|
|
], |
217
|
|
|
'shardChoser' => new MultiTenantShardChoser(), |
218
|
|
|
'memory' => true, |
219
|
|
|
'host' => 'localhost', |
220
|
|
|
], $conn->getParams()); |
221
|
|
|
|
222
|
|
|
$conn->connect(1); |
223
|
|
|
self::assertEquals([ |
224
|
|
|
'wrapperClass' => PoolingShardConnection::class, |
225
|
|
|
'driver' => 'pdo_sqlite', |
226
|
|
|
'global' => ['memory' => true, 'host' => 'localhost'], |
227
|
|
|
'shards' => [ |
228
|
|
|
['id' => 1, 'memory' => true, 'host' => 'foo'], |
229
|
|
|
], |
230
|
|
|
'shardChoser' => new MultiTenantShardChoser(), |
231
|
|
|
'id' => 1, |
232
|
|
|
'memory' => true, |
233
|
|
|
'host' => 'foo', |
234
|
|
|
], $conn->getParams()); |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
/** |
238
|
|
|
* @param mixed[] $parameters |
239
|
|
|
*/ |
240
|
|
|
private function createConnection(array $parameters) : PoolingShardConnection |
241
|
|
|
{ |
242
|
|
|
return DriverManager::getConnection(array_merge( |
|
|
|
|
243
|
|
|
['wrapperClass' => PoolingShardConnection::class], |
244
|
|
|
$parameters |
245
|
|
|
)); |
246
|
|
|
} |
247
|
|
|
} |
248
|
|
|
|
This check looks for function or method calls that always return null and whose return value is used.
The method
getObject()
can return nothing but null, so it makes no sense to use the return value.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.