Skip to content

Commit 194ba47

Browse files
committed
Implement GridFS, transactions, and collate events by client
1 parent 7953d0f commit 194ba47

File tree

8 files changed

+440
-106
lines changed

8 files changed

+440
-106
lines changed

tests/UnifiedSpecTests/Constraint/Matches.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,9 @@ private function assertMatchesOperator(BSONDocument $operator, $actual, string $
268268
if ($name === '$$matchesHexBytes') {
269269
assertInternalType('string', $operator['$$matchesHexBytes'], '$$matchesHexBytes requires string');
270270
assertRegExp('/^([0-9a-fA-F]{2})*$/', $operator['$$matchesHexBytes'], '$$matchesHexBytes requires pairs of hex chars');
271-
assertThat($actual, new IsStream());
271+
assertInternalType('string', $actual);
272272

273-
if (stream_get_contents($actual, -1, 0) !== hex2bin($operator['$$matchesHexBytes'])) {
273+
if ($actual !== hex2bin($operator['$$matchesHexBytes'])) {
274274
self::failAt(sprintf('%s does not match expected hex bytes: %s', $this->exporter()->shortenedExport($actual), $operator['$$matchesHexBytes']), $keyPath);
275275
}
276276

@@ -310,7 +310,7 @@ private function assertMatchesOperator(BSONDocument $operator, $actual, string $
310310
return;
311311
}
312312

313-
throw new LogicException('unsupported operator: ' . $operator);
313+
throw new LogicException('unsupported operator: ' . $name);
314314
}
315315

316316
/** @see ConstraintTrait */

tests/UnifiedSpecTests/Constraint/MatchesTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ public function testOperatorType()
7676
public function testOperatorMatchesEntity()
7777
{
7878
$entityMap = new EntityMap();
79-
$entityMap['integer'] = 1;
80-
$entityMap['object'] = ['y' => 1];
79+
$entityMap->set('integer', 1);
80+
$entityMap->set('object', ['y' => 1]);
8181

8282
$c = new Matches(['x' => ['$$matchesEntity' => 'integer']], $entityMap);
8383
$this->assertResult(true, $c, ['x' => 1], 'value matches integer entity (embedded)');
@@ -138,7 +138,7 @@ public function testOperatorSessionLsid()
138138
$session = $this->manager->startSession();
139139

140140
$entityMap = new EntityMap();
141-
$entityMap['session'] = $session;
141+
$entityMap->set('session', $session);
142142

143143
$lsidWithWrongId = ['id' => new Binary('0123456789ABCDEF', Binary::TYPE_UUID)];
144144
$lsidWithExtraField = (array) $session->getLogicalSessionId() + ['y' => 1];
@@ -255,7 +255,7 @@ public function testOperatorSyntaxValidation($expectedMessage, Matches $constrai
255255
public function operatorErrorMessageProvider()
256256
{
257257
$entityMap = new EntityMap();
258-
$entityMap['notSession'] = 1;
258+
$entityMap->set('notSession', 1);
259259

260260
return [
261261
'$$exists type' => [

tests/UnifiedSpecTests/Context.php

Lines changed: 136 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use LogicException;
66
use MongoDB\Client;
7-
use MongoDB\Collection;
87
use MongoDB\Database;
98
use MongoDB\Driver\Manager;
109
use MongoDB\Driver\ReadPreference;
@@ -17,13 +16,18 @@
1716
use function assertInternalType;
1817
use function assertNotEmpty;
1918
use function assertNotFalse;
19+
use function assertRegExp;
2020
use function assertStringStartsWith;
2121
use function count;
2222
use function current;
2323
use function explode;
24+
use function fopen;
25+
use function fwrite;
26+
use function hex2bin;
2427
use function implode;
2528
use function key;
2629
use function parse_url;
30+
use function rewind;
2731
use function strlen;
2832
use function strpos;
2933
use function substr_replace;
@@ -77,15 +81,27 @@ public function createEntities(array $entities)
7781

7882
switch ($type) {
7983
case 'client':
80-
$this->entityMap[$id] = $this->createClient($def);
84+
$this->createClient($id, $def);
8185
break;
8286

8387
case 'database':
84-
$this->entityMap[$id] = $this->createDatabase($def);
88+
$this->createDatabase($id, $def);
8589
break;
8690

8791
case 'collection':
88-
$this->entityMap[$id] = $this->createCollection($def);
92+
$this->createCollection($id, $def);
93+
break;
94+
95+
case 'session':
96+
$this->createSession($id, $def);
97+
break;
98+
99+
case 'bucket':
100+
$this->createBucket($id, $def);
101+
break;
102+
103+
case 'stream':
104+
$this->createStream($id, $def);
89105
break;
90106

91107
default:
@@ -104,6 +120,16 @@ public function getInternalClient() : Client
104120
return $this->internalClient;
105121
}
106122

123+
public function isActiveClient(string $clientId) : bool
124+
{
125+
return $this->activeClient === $clientId;
126+
}
127+
128+
public function setActiveClient(string $clientId = null)
129+
{
130+
$this->activeClient = $clientId;
131+
}
132+
107133
public function assertExpectedEventsForClients(array $expectedEventsForClients)
108134
{
109135
assertNotEmpty($expectedEventsForClients);
@@ -144,7 +170,7 @@ public function getEventObserverForClient(string $id) : EventObserver
144170
return $this->eventObserversByClient[$id];
145171
}
146172

147-
private function createClient(stdClass $o) : Client
173+
private function createClient(string $id, stdClass $o)
148174
{
149175
Util::assertHasOnlyKeys($o, ['id', 'uriOptions', 'useMultipleMongoses', 'observeEvents', 'ignoreCommandMonitoringEvents']);
150176

@@ -178,23 +204,23 @@ private function createClient(stdClass $o) : Client
178204
assertInternalType('array', $observeEvents);
179205
assertInternalType('array', $ignoreCommandMonitoringEvents);
180206

181-
$this->eventObserversByClient[$o->id] = new EventObserver($observeEvents, $ignoreCommandMonitoringEvents, $o->id, $this->entityMap);
207+
$this->eventObserversByClient[$id] = new EventObserver($observeEvents, $ignoreCommandMonitoringEvents, $id, $this);
182208
}
183209

184-
return new Client($uri, $uriOptions);
210+
$this->entityMap->set($id, new Client($uri, $uriOptions));
185211
}
186212

187-
private function createCollection(stdClass $o) : Collection
213+
private function createCollection(string $id, stdClass $o)
188214
{
189215
Util::assertHasOnlyKeys($o, ['id', 'database', 'collectionName', 'collectionOptions']);
190216

191217
$collectionName = $o->collectionName ?? null;
192-
$database = $o->database ?? null;
218+
$databaseId = $o->database ?? null;
193219

194220
assertInternalType('string', $collectionName);
195-
assertInternalType('string', $database);
221+
assertInternalType('string', $databaseId);
196222

197-
$database = $this->entityMap[$database];
223+
$database = $this->entityMap[$databaseId];
198224
assertInstanceOf(Database::class, $database);
199225

200226
$options = [];
@@ -204,20 +230,20 @@ private function createCollection(stdClass $o) : Collection
204230
$options = self::prepareCollectionOrDatabaseOptions((array) $o->collectionOptions);
205231
}
206232

207-
return $database->selectCollection($o->collectionName, $options);
233+
$this->entityMap->set($id, $database->selectCollection($o->collectionName, $options), $databaseId);
208234
}
209235

210-
private function createDatabase(stdClass $o) : Database
236+
private function createDatabase(string $id, stdClass $o)
211237
{
212238
Util::assertHasOnlyKeys($o, ['id', 'client', 'databaseName', 'databaseOptions']);
213239

214240
$databaseName = $o->databaseName ?? null;
215-
$client = $o->client ?? null;
241+
$clientId = $o->client ?? null;
216242

217243
assertInternalType('string', $databaseName);
218-
assertInternalType('string', $client);
244+
assertInternalType('string', $clientId);
219245

220-
$client = $this->entityMap[$client];
246+
$client = $this->entityMap[$clientId];
221247
assertInstanceOf(Client::class, $client);
222248

223249
$options = [];
@@ -227,31 +253,115 @@ private function createDatabase(stdClass $o) : Database
227253
$options = self::prepareCollectionOrDatabaseOptions((array) $o->databaseOptions);
228254
}
229255

230-
return $client->selectDatabase($databaseName, $options);
256+
$this->entityMap->set($id, $client->selectDatabase($databaseName, $options), $clientId);
257+
}
258+
259+
private function createSession(string $id, stdClass $o)
260+
{
261+
Util::assertHasOnlyKeys($o, ['id', 'client', 'sessionOptions']);
262+
263+
$clientId = $o->client ?? null;
264+
assertInternalType('string', $clientId);
265+
$client = $this->entityMap[$clientId];
266+
assertInstanceOf(Client::class, $client);
267+
268+
$options = [];
269+
270+
if (isset($o->sessionOptions)) {
271+
assertInternalType('object', $o->sessionOptions);
272+
$options = self::prepareSessionOptions((array) $o->sessionOptions);
273+
}
274+
275+
$this->entityMap->set($id, $client->startSession($options), $clientId);
276+
}
277+
278+
private function createBucket(string $id, stdClass $o)
279+
{
280+
Util::assertHasOnlyKeys($o, ['id', 'database', 'bucketOptions']);
281+
282+
$databaseId = $o->database ?? null;
283+
assertInternalType('string', $databaseId);
284+
$database = $this->entityMap[$databaseId];
285+
assertInstanceOf(Database::class, $database);
286+
287+
$options = [];
288+
289+
if (isset($o->bucketOptions)) {
290+
assertInternalType('object', $o->bucketOptions);
291+
$options = self::prepareBucketOptions((array) $o->bucketOptions);
292+
}
293+
294+
$this->entityMap->set($id, $database->selectGridFSBucket($options), $databaseId);
295+
}
296+
297+
private function createStream(string $id, stdClass $o)
298+
{
299+
Util::assertHasOnlyKeys($o, ['id', 'hexBytes']);
300+
301+
$hexBytes = $o->hexBytes ?? null;
302+
assertInternalType('string', $hexBytes);
303+
assertRegExp('/^([0-9a-fA-F]{2})*$/', $hexBytes);
304+
305+
$stream = fopen('php://temp', 'w+b');
306+
fwrite($stream, hex2bin($hexBytes));
307+
rewind($stream);
308+
309+
$this->entityMap->set($id, $stream);
231310
}
232311

233312
private static function prepareCollectionOrDatabaseOptions(array $options) : array
234313
{
235314
Util::assertHasOnlyKeys($options, ['readConcern', 'readPreference', 'writeConcern']);
236315

237-
if (array_key_exists('readConcern', $options)) {
238-
assertInternalType('object', $options['readConcern']);
239-
$options['readConcern'] = Util::createReadConcern($options['readConcern']);
316+
return Util::prepareCommonOptions($options);
317+
}
318+
319+
private static function prepareBucketOptions(array $options) : array
320+
{
321+
Util::assertHasOnlyKeys($options, ['bucketName', 'chunkSizeBytes', 'disableMD5', 'readConcern', 'readPreference', 'writeConcern']);
322+
323+
if (array_key_exists('bucketName', $options)) {
324+
assertInternalType('string', $options['bucketName']);
240325
}
241326

242-
if (array_key_exists('readPreference', $options)) {
243-
assertInternalType('object', $options['readPreference']);
244-
$options['readPreference'] = Util::createReadPreference($options['readPreference']);
327+
if (array_key_exists('chunkSizeBytes', $options)) {
328+
assertInternalType('int', $options['chunkSizeBytes']);
245329
}
246330

247-
if (array_key_exists('writeConcern', $options)) {
248-
assertInternalType('object', $options['writeConcern']);
249-
$options['writeConcern'] = Util::createWriteConcern($options['writeConcern']);
331+
if (array_key_exists('disableMD5', $options)) {
332+
assertInternalType('bool', $options['disableMD5']);
333+
}
334+
335+
return Util::prepareCommonOptions($options);
336+
}
337+
338+
private static function prepareSessionOptions(array $options) : array
339+
{
340+
Util::assertHasOnlyKeys($options, ['causalConsistency', 'defaultTransactionOptions']);
341+
342+
if (array_key_exists('causalConsistency', $options)) {
343+
assertInternalType('bool', $options['causalConsistency']);
344+
}
345+
346+
if (array_key_exists('defaultTransactionOptions', $options)) {
347+
assertInternalType('object', $options['defaultTransactionOptions']);
348+
$options['defaultTransactionOptions'] = self::prepareDefaultTransactionOptions((array) $options['defaultTransactionOptions']);
250349
}
251350

252351
return $options;
253352
}
254353

354+
private static function prepareDefaultTransactionOptions(array $options) : array
355+
{
356+
Util::assertHasOnlyKeys($options, ['maxCommitTimeMS', 'readConcern', 'readPreference', 'writeConcern']);
357+
358+
if (array_key_exists('maxCommitTimeMS', $options)) {
359+
assertInternalType('int', $options['maxCommitTimeMS']);
360+
}
361+
362+
return Util::prepareCommonOptions($options);
363+
}
364+
255365
/**
256366
* Removes mongos hosts beyond the first if the URI refers to a sharded
257367
* cluster. Otherwise, the URI is returned as-is.

0 commit comments

Comments
 (0)