@@ -405,4 +405,120 @@ GIVEN( "a Session with a registered challenge handler" )
405405 }
406406}}
407407
408+ // ------------------------------------------------------------------------------
409+ SCENARIO ( " RPC Cancellation" , " [WAMP]" )
410+ {
411+ GIVEN ( " a caller and a callee" )
412+ {
413+ AsioService iosvc;
414+ RpcFixture f (iosvc, tcp (iosvc));
415+
416+ WHEN ( " cancelling an RPC in kill mode before it returns" )
417+ {
418+ boost::asio::spawn (iosvc, [&](boost::asio::yield_context yield)
419+ {
420+ RequestId callRequestId = 0 ;
421+ RequestId invocationRequestId = 0 ;
422+ RequestId interruptionRequestId = 0 ;
423+ bool responseReceived = false ;
424+ AsyncResult<Result> response;
425+
426+ f.join (yield);
427+
428+ f.callee ->enroll (
429+ Procedure (" rpc" ),
430+ [&invocationRequestId](Invocation inv) -> Outcome
431+ {
432+ invocationRequestId = inv.requestId ();
433+ return Outcome::deferred ();
434+ },
435+ [&interruptionRequestId](Interruption intr) -> Outcome
436+ {
437+ interruptionRequestId = intr.requestId ();
438+ return Error (" wamp.error.canceled" );
439+ },
440+ yield);
441+
442+ callRequestId = f.caller ->call (Rpc (" rpc" ),
443+ [&response, &responseReceived](AsyncResult<Result> callResponse)
444+ {
445+ responseReceived = true ;
446+ response = std::move (callResponse);
447+ });
448+
449+ REQUIRE ( callRequestId != 0 );
450+
451+ while (invocationRequestId == 0 )
452+ f.caller ->suspend (yield);
453+
454+ REQUIRE ( invocationRequestId != 0 );
455+
456+ f.caller ->cancel (Cancellation (callRequestId, CancelMode::kill));
457+
458+ while (!responseReceived)
459+ f.caller ->suspend (yield);
460+
461+ CHECK ( interruptionRequestId == invocationRequestId );
462+ CHECK ( response.errorCode () == SessionErrc::cancelled );
463+
464+ f.disconnect ();
465+ });
466+ iosvc.run ();
467+ }
468+
469+ WHEN ( " cancelling an RPC after it returns" )
470+ {
471+ boost::asio::spawn (iosvc, [&](boost::asio::yield_context yield)
472+ {
473+ RequestId callRequestId = 0 ;
474+ RequestId invocationRequestId = 0 ;
475+ RequestId interruptionRequestId = 0 ;
476+ bool responseReceived = false ;
477+ AsyncResult<Result> response;
478+
479+ f.join (yield);
480+
481+ f.callee ->enroll (
482+ Procedure (" rpc" ),
483+ [&invocationRequestId](Invocation inv) -> Outcome
484+ {
485+ invocationRequestId = inv.requestId ();
486+ return Result{Variant{" completed" }};
487+ },
488+ [&interruptionRequestId](Interruption intr) -> Outcome
489+ {
490+ interruptionRequestId = intr.requestId ();
491+ return Error (" wamp.error.canceled" );
492+ },
493+ yield);
494+
495+ callRequestId = f.caller ->call (Rpc (" rpc" ),
496+ [&response, &responseReceived](AsyncResult<Result> callResponse)
497+ {
498+ responseReceived = true ;
499+ response = std::move (callResponse);
500+ });
501+
502+ while (!responseReceived)
503+ f.caller ->suspend (yield);
504+
505+ REQUIRE ( response.get ().args () == Array{Variant{" completed" }} );
506+
507+ f.caller ->cancel (Cancellation (callRequestId, CancelMode::kill));
508+
509+ /* Router should not treat late CANCEL as a protocol error, and
510+ should allow clients to continue calling RPCs. */
511+ f.caller ->call (Rpc (" rpc" ), yield);
512+
513+ /* Router should discard INTERRUPT messages for non-pending RPCs. */
514+ CHECK ( interruptionRequestId == 0 );
515+
516+ f.disconnect ();
517+ });
518+ iosvc.run ();
519+ }
520+
521+ // TODO: Test other cancel modes once they're supported by Crossbar
522+ }}
523+
408524#endif // #if CPPWAMP_TESTING_WAMP
0 commit comments