2020use function fclose ;
2121use function fopen ;
2222use function MongoDB \is_last_pipeline_operator_write ;
23+ use function MongoDB \with_transaction ;
2324use function stream_get_contents ;
2425use function strtolower ;
2526
@@ -127,6 +128,29 @@ public static function fromCommandMonitoring(stdClass $operation)
127128 return $ o ;
128129 }
129130
131+ /**
132+ * This method is exclusively used to prepare nested operations for the
133+ * withTransaction session operation
134+ *
135+ * @return Operation
136+ */
137+ private static function fromConvenientTransactions (stdClass $ operation )
138+ {
139+ $ o = new self ($ operation );
140+
141+ if (isset ($ operation ->error )) {
142+ $ o ->errorExpectation = ErrorExpectation::fromTransactions ($ operation );
143+ }
144+
145+ $ o ->resultExpectation = ResultExpectation::fromTransactions ($ operation , $ o ->getResultAssertionType ());
146+
147+ if (isset ($ operation ->collectionOptions )) {
148+ $ o ->collectionOptions = (array ) $ operation ->collectionOptions ;
149+ }
150+
151+ return $ o ;
152+ }
153+
130154 public static function fromCrud (stdClass $ operation )
131155 {
132156 $ o = new self ($ operation );
@@ -177,16 +201,17 @@ public static function fromTransactions(stdClass $operation)
177201 /**
178202 * Execute the operation and assert its outcome.
179203 *
180- * @param FunctionalTestCase $test Test instance
181- * @param Context $context Execution context
204+ * @param FunctionalTestCase $test Test instance
205+ * @param Context $context Execution context
206+ * @param bool $bubbleExceptions If true, any exception that was caught is rethrown
182207 */
183- public function assert (FunctionalTestCase $ test , Context $ context )
208+ public function assert (FunctionalTestCase $ test , Context $ context, $ bubbleExceptions = false )
184209 {
185210 $ result = null ;
186211 $ exception = null ;
187212
188213 try {
189- $ result = $ this ->execute ($ context );
214+ $ result = $ this ->execute ($ test , $ context );
190215
191216 /* Eagerly iterate the results of a cursor. This both allows an
192217 * exception to be thrown sooner and ensures that any expected
@@ -211,6 +236,10 @@ public function assert(FunctionalTestCase $test, Context $context)
211236 if (isset ($ this ->resultExpectation )) {
212237 $ this ->resultExpectation ->assert ($ test , $ result );
213238 }
239+
240+ if ($ exception && $ bubbleExceptions ) {
241+ throw $ exception ;
242+ }
214243 }
215244
216245 /**
@@ -220,7 +249,7 @@ public function assert(FunctionalTestCase $test, Context $context)
220249 * @return mixed
221250 * @throws LogicException if the operation is unsupported
222251 */
223- private function execute (Context $ context )
252+ private function execute (FunctionalTestCase $ test , Context $ context )
224253 {
225254 switch ($ this ->object ) {
226255 case self ::OBJECT_CLIENT :
@@ -248,9 +277,9 @@ private function execute(Context $context)
248277
249278 return $ this ->executeForDatabase ($ database , $ context );
250279 case self ::OBJECT_SESSION0 :
251- return $ this ->executeForSession ($ context ->session0 , $ context );
280+ return $ this ->executeForSession ($ context ->session0 , $ test , $ context );
252281 case self ::OBJECT_SESSION1 :
253- return $ this ->executeForSession ($ context ->session1 , $ context );
282+ return $ this ->executeForSession ($ context ->session1 , $ test , $ context );
254283 default :
255284 throw new LogicException ('Unsupported object: ' . $ this ->object );
256285 }
@@ -479,12 +508,13 @@ private function executeForGridFSBucket(Bucket $bucket, Context $context)
479508 /**
480509 * Executes the session operation and return its result.
481510 *
482- * @param Session $session
483- * @param Context $context Execution context
511+ * @param Session $session
512+ * @param FunctionalTestCase $test
513+ * @param Context $context Execution context
484514 * @return mixed
485515 * @throws LogicException if the session operation is unsupported
486516 */
487- private function executeForSession (Session $ session , Context $ context )
517+ private function executeForSession (Session $ session , FunctionalTestCase $ test , Context $ context )
488518 {
489519 switch ($ this ->name ) {
490520 case 'abortTransaction ' :
@@ -495,6 +525,21 @@ private function executeForSession(Session $session, Context $context)
495525 $ options = isset ($ this ->arguments ['options ' ]) ? (array ) $ this ->arguments ['options ' ] : [];
496526
497527 return $ session ->startTransaction ($ context ->prepareOptions ($ options ));
528+ case 'withTransaction ' :
529+ /** @var self[] $callbackOperations */
530+ $ callbackOperations = array_map (function ($ operation ) {
531+ return self ::fromConvenientTransactions ($ operation );
532+ }, $ this ->arguments ['callback ' ]->operations );
533+
534+ $ callback = function () use ($ callbackOperations , $ test , $ context ) {
535+ foreach ($ callbackOperations as $ operation ) {
536+ $ operation ->assert ($ test , $ context , true );
537+ }
538+ };
539+
540+ $ options = isset ($ this ->arguments ['options ' ]) ? (array ) $ this ->arguments ['options ' ] : [];
541+
542+ return with_transaction ($ session , $ callback , $ context ->prepareOptions ($ options ));
498543 default :
499544 throw new LogicException ('Unsupported session operation: ' . $ this ->name );
500545 }
0 commit comments