@@ -181,12 +181,14 @@ private function doTestCase(stdClass $test, string $schemaVersion, ?array $runOn
181
181
$ this ->checkRunOnRequirements ($ test ->runOnRequirements );
182
182
}
183
183
184
- if (isset ($ initialData )) {
185
- $ this ->prepareInitialData ($ initialData );
186
- }
184
+ assertIsArray ($ test ->operations );
187
185
188
186
$ context = $ this ->createContext ();
189
187
188
+ if (isset ($ initialData )) {
189
+ $ this ->prepareInitialData ($ initialData , $ context , $ this ->isAdvanceClusterTimeNeeded ($ test ->operations ));
190
+ }
191
+
190
192
/* If an EntityMap observer has been configured, assign the Context's
191
193
* EntityMap to a class property so it can later be accessed from run(),
192
194
* irrespective of whether this test succeeds or fails. */
@@ -198,7 +200,6 @@ private function doTestCase(stdClass $test, string $schemaVersion, ?array $runOn
198
200
$ context ->createEntities ($ createEntities );
199
201
}
200
202
201
- assertIsArray ($ test ->operations );
202
203
$ this ->preventStaleDbVersionError ($ test ->operations , $ context );
203
204
204
205
$ context ->startEventObservers ();
@@ -421,17 +422,48 @@ private function assertOutcome(array $outcome): void
421
422
}
422
423
}
423
424
424
- private function prepareInitialData (array $ initialData ): void
425
+ private function prepareInitialData (array $ initialData, Context $ context , bool $ isAdvanceClusterTimeNeeded ): void
425
426
{
426
427
assertNotEmpty ($ initialData );
427
428
assertContainsOnly ('object ' , $ initialData );
428
429
430
+ /* In order to avoid MigrationConflict errors on sharded clusters, use the cluster time obtained from creating
431
+ * collections to advance session entities. This is necessary because initialData uses an internal MongoClient,
432
+ * which will not share/gossip its cluster time via the test entities. */
433
+ if ($ isAdvanceClusterTimeNeeded ) {
434
+ $ session = $ this ->internalClient ->startSession ();
435
+ }
436
+
429
437
foreach ($ initialData as $ data ) {
430
438
$ collectionData = new CollectionData ($ data );
431
- $ collectionData ->prepareInitialData ($ this ->internalClient );
439
+ $ collectionData ->prepareInitialData ($ this ->internalClient , $ session ?? null );
440
+ }
441
+
442
+ if (isset ($ session )) {
443
+ $ context ->setAdvanceClusterTime ($ session ->getClusterTime ());
432
444
}
433
445
}
434
446
447
+ /**
448
+ * Work around potential MigrationConflict errors on sharded clusters.
449
+ */
450
+ private function isAdvanceClusterTimeNeeded (array $ operations ): bool
451
+ {
452
+ if (! in_array ($ this ->getPrimaryServer ()->getType (), [Server::TYPE_MONGOS , Server::TYPE_LOAD_BALANCER ], true )) {
453
+ return false ;
454
+ }
455
+
456
+ foreach ($ operations as $ operation ) {
457
+ switch ($ operation ->name ) {
458
+ case 'startTransaction ' :
459
+ case 'withTransaction ' :
460
+ return true ;
461
+ }
462
+ }
463
+
464
+ return false ;
465
+ }
466
+
435
467
/**
436
468
* Work around potential error executing distinct on sharded clusters.
437
469
*
0 commit comments