Skip to content

Commit f7cf6ba

Browse files
committed
test: preserve post-call release order in teardown failures
Regression for the pending replay-compatible #306 dependency update; not published until the verified replacement base is integrated. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 974213a5-9101-41b4-9bde-aa86a72f25e1
1 parent 85e5eed commit f7cf6ba

1 file changed

Lines changed: 37 additions & 0 deletions

File tree

‎tests/durabletask/test_orchestration_dispatch_recovery.py‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,43 @@ def orchestrator(ctx: task.OrchestrationContext, _: Any) -> Generator[task.Task[
134134
assert result.encoded_custom_status is None
135135

136136

137+
def test_teardown_failure_preserves_post_call_lock_release_order():
138+
entity_a = EntityInstanceId("Counter", "a")
139+
entity_b = EntityInstanceId("Counter", "b")
140+
141+
def orchestrator(ctx: task.OrchestrationContext, _: Any) -> Generator[task.Task[Any], Any, None]:
142+
call_finished = False
143+
try:
144+
with (yield ctx.lock_entities([entity_a, entity_b])):
145+
yield ctx.call_entity(entity_a, "get")
146+
call_finished = True
147+
yield ctx.wait_for_external_event("ready")
148+
finally:
149+
if call_finished:
150+
raise TeardownExit("cleanup after successful entity call")
151+
152+
executor = _executor(orchestrator)
153+
request = _request()
154+
initial = executor.execute(INSTANCE_ID, [], request.newEvents)
155+
lock_id = initial.actions[0].sendEntityMessage.entityLockRequested.criticalSectionId
156+
lock_events = [
157+
helpers.new_event_sent_event(1, str(entity_a), json.dumps({"id": lock_id})),
158+
helpers.new_event_raised_event(lock_id, None),
159+
]
160+
calling = executor.execute(INSTANCE_ID, request.newEvents, lock_events)
161+
call_id = calling.actions[0].sendEntityMessage.entityOperationCalled.requestId
162+
history = list(request.newEvents) + lock_events + [
163+
helpers.new_event_sent_event(2, str(entity_a), json.dumps({"id": call_id})),
164+
]
165+
result = executor.execute(INSTANCE_ID, history, [
166+
helpers.new_event_raised_event(call_id, json.dumps({"result": "42"})),
167+
])
168+
169+
assert [action.sendEntityMessage.entityUnlockSent.targetInstanceId.value
170+
for action in result.actions[:-1]] == [str(entity_b), str(entity_a)]
171+
assert result.actions[-1].completeOrchestration.orchestrationStatus == pb.ORCHESTRATION_STATUS_FAILED
172+
173+
137174
def test_cleanup_does_not_replace_pending_control_flow_error(monkeypatch: pytest.MonkeyPatch):
138175
primary = asyncio.CancelledError("original cancellation")
139176

0 commit comments

Comments
 (0)