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