2020from temporalio .common import WorkflowIDConflictPolicy
2121from temporalio .testing import WorkflowEnvironment
2222from temporalio .worker import Worker
23+ from tests .helpers import assert_eventually
2324from tests .helpers .nexus import make_nexus_endpoint_name
2425
2526
@@ -40,25 +41,41 @@ class TestContext:
4041class HandlerWorkflow :
4142 def __init__ (self ):
4243 self .caller_op_future_resolved = asyncio .Event ()
44+ self .cancel_requested = False
45+ self .release_cancellation = asyncio .Event ()
4346
4447 @workflow .run
4548 async def run (self ) -> None :
4649 try :
4750 await asyncio .Future ()
4851 except asyncio .CancelledError :
52+ self .cancel_requested = True
4953 if test_context .cancellation_type in [
5054 workflow .NexusOperationCancellationType .TRY_CANCEL ,
5155 workflow .NexusOperationCancellationType .WAIT_REQUESTED ,
5256 ]:
5357 # We want to prove that the caller op future can be resolved before the operation
5458 # (i.e. its backing workflow) is cancelled.
5559 await self .caller_op_future_resolved .wait ()
60+ elif (
61+ test_context .cancellation_type
62+ == workflow .NexusOperationCancellationType .WAIT_COMPLETED
63+ ):
64+ await self .release_cancellation .wait ()
5665 raise
5766
5867 @workflow .signal
5968 def set_caller_op_future_resolved (self ) -> None :
6069 self .caller_op_future_resolved .set ()
6170
71+ @workflow .signal
72+ def set_release_cancellation (self ) -> None :
73+ self .release_cancellation .set ()
74+
75+ @workflow .query
76+ def has_cancel_requested (self ) -> bool :
77+ return self .cancel_requested
78+
6279
6380@nexusrpc .service
6481class Service :
@@ -151,6 +168,10 @@ async def get_operation_token(self) -> str:
151168 async def wait_caller_op_future_resolved (self ) -> None :
152169 await self .caller_op_future_resolved
153170
171+ @workflow .query
172+ def has_caller_op_future_resolved (self ) -> bool :
173+ return self .caller_op_future_resolved .done ()
174+
154175 @workflow .run
155176 async def run (self , input : Input ) -> CancellationResult :
156177 op_handle = await (
@@ -408,6 +429,17 @@ async def check_behavior_for_wait_cancellation_completed(
408429 Check that a cancellation request is sent and the caller workflow nexus operation future is
409430 unblocked after the operation is canceled.
410431 """
432+
433+ async def assert_handler_cancel_requested () -> None :
434+ assert await handler_wf .query (HandlerWorkflow .has_cancel_requested )
435+
436+ await assert_eventually (assert_handler_cancel_requested )
437+
438+ handler_status = (await handler_wf .describe ()).status
439+ assert handler_status == WorkflowExecutionStatus .RUNNING
440+ assert not await caller_wf .query (CallerWorkflow .has_caller_op_future_resolved )
441+
442+ await handler_wf .signal (HandlerWorkflow .set_release_cancellation )
411443 try :
412444 await handler_wf .result ()
413445 except WorkflowFailureError as err :
@@ -418,8 +450,13 @@ async def check_behavior_for_wait_cancellation_completed(
418450 handler_status = (await handler_wf .describe ()).status
419451 assert handler_status == WorkflowExecutionStatus .CANCELED
420452
453+ async def assert_caller_op_future_resolved () -> None :
454+ assert await caller_wf .query (CallerWorkflow .has_caller_op_future_resolved )
455+
456+ await assert_eventually (assert_caller_op_future_resolved )
457+
421458 await caller_wf .signal (CallerWorkflow .release )
422- result = await caller_wf .result ()
459+ await caller_wf .result ()
423460
424461 await assert_event_subsequence (
425462 caller_wf ,
@@ -430,14 +467,6 @@ async def check_behavior_for_wait_cancellation_completed(
430467 EventType .EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED ,
431468 ],
432469 )
433- handler_wf_canceled_event = await get_event_time (
434- handler_wf ,
435- EventType .EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED ,
436- )
437- assert handler_wf_canceled_event <= result .caller_op_future_resolved , (
438- "expected caller op future resolved after handler workflow canceled, but got "
439- f"{ result .caller_op_future_resolved } before { handler_wf_canceled_event } "
440- )
441470
442471
443472async def has_event (wf_handle : WorkflowHandle , event_type : EventType .ValueType ):
0 commit comments