Skip to content

Commit 2ee59b7

Browse files
committed
test: restructure resumption test so 3.11 traces every line
The previous attempt cancelled only the child task, but ClientSession and streamable_http_client both cancel internal task groups in __aexit__, so the comma-form unwind still tripped 3.11's tracer dead-zone. Hoist the phase-1 assertions and header setup inside the block before cancelling, and split fail_after into two phases so no sync statements sit between the cancel-on-exit unwind and the next await.
1 parent 5e129bf commit 2ee59b7

1 file changed

Lines changed: 10 additions & 17 deletions

File tree

tests/interaction/transports/test_hosting_resume.py

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -340,34 +340,27 @@ async def collect(params: LoggingMessageNotificationParams) -> None:
340340

341341
async with mounted_app(mcp, event_store=store, retry_interval=0) as (http, manager):
342342
with anyio.fail_after(5): # pragma: no branch
343-
async with (
343+
async with ( # pragma: no branch
344344
streamable_http_client(f"{BASE_URL}/mcp", http_client=http, terminate_on_close=False) as (r1, w1),
345345
ClientSession(r1, w1, logging_callback=collect) as first,
346346
anyio.create_task_group() as tg,
347347
):
348348
await first.initialize()
349-
# The call is abandoned via its own scope so the task group exits cleanly: cancelling
350-
# the whole group propagates Cancelled through this frame, which 3.11's tracer mishandles.
351-
call_scope = anyio.CancelScope()
352-
353-
async def issue_call() -> None:
354-
with call_scope:
355-
await first.send_request(call, CallToolResult, metadata=capture)
356-
357-
tg.start_soon(issue_call)
349+
tg.start_soon(first.send_request, call, CallToolResult, None, capture)
358350
await first_seen.wait()
359351
await token_seen.wait()
360-
call_scope.cancel()
361-
assert captured == snapshot(["3", "4"])
362-
assert received == snapshot(["first"])
363-
# The session id is only observable via the manager (the client transport does not expose it).
364-
(session_id,) = manager._server_instances
352+
assert captured == snapshot(["3", "4"])
353+
assert received == snapshot(["first"])
354+
# The session id is only observable via the manager (the client transport does not expose it).
355+
(session_id,) = manager._server_instances
356+
http.headers["mcp-session-id"] = session_id
357+
http.headers["mcp-protocol-version"] = LATEST_PROTOCOL_VERSION
358+
tg.cancel_scope.cancel()
365359

360+
with anyio.fail_after(5): # pragma: no branch
366361
release.set()
367362
# init priming + init response + call priming + "first" + "second" + result = 6 stored events.
368363
await store.wait_until_stored(6)
369-
http.headers["mcp-session-id"] = session_id
370-
http.headers["mcp-protocol-version"] = LATEST_PROTOCOL_VERSION
371364
async with ( # pragma: no branch
372365
streamable_http_client(f"{BASE_URL}/mcp", http_client=http) as (r2, w2),
373366
ClientSession(r2, w2, logging_callback=collect) as second,

0 commit comments

Comments
 (0)