Skip to content

Commit 738576c

Browse files
committed
Prove the caller-supplied listen id end to end and undefer its requirement
1 parent 76c28fd commit 738576c

2 files changed

Lines changed: 29 additions & 6 deletions

File tree

tests/interaction/_requirements.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -486,12 +486,6 @@ def __post_init__(self) -> None:
486486
"id up front is the SDK surface that makes it satisfiable."
487487
),
488488
added_in="2026-07-28",
489-
deferred=(
490-
"No public API surface yet: the capability exists at the dispatcher seam "
491-
"(CallOptions['request_id'], unit-tested there), but ClientSession.send_request does not "
492-
"expose it. The public consumer arrives with the client-side listen driver (Client.listen), "
493-
"whose interaction tests will exercise it end to end."
494-
),
495489
),
496490
"protocol:notifications:no-response": Requirement(
497491
source=f"{SPEC_BASE_URL}/basic#notifications",

tests/interaction/lowlevel/test_subscriptions.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,32 @@ async def dropping_listen(
6060
proceed.set()
6161
with pytest.raises(SubscriptionLost): # pragma: no branch
6262
await anext(sub)
63+
64+
65+
@requirement("protocol:request-id:caller-supplied")
66+
async def test_the_subscription_id_is_the_listen_request_id_the_server_saw(connect: Connect) -> None:
67+
"""The handle's `subscription_id` is the listen request's own JSON-RPC id, known to the caller
68+
while the request is still in flight - the key the server stamps every frame with for demux.
69+
70+
The assertion runs inside the open stream: the ack has arrived but the listen request's
71+
response has not, so the id cannot have come from a response.
72+
"""
73+
bus = InMemorySubscriptionBus()
74+
stock = ListenHandler(bus)
75+
seen: list[types.RequestId] = []
76+
77+
async def recording_listen(
78+
ctx: ServerRequestContext[Any, Any], params: types.SubscriptionsListenRequestParams
79+
) -> types.SubscriptionsListenResult:
80+
assert ctx.request_id is not None
81+
seen.append(ctx.request_id)
82+
return await stock(ctx, params)
83+
84+
server = Server("subs", on_subscriptions_listen=recording_listen)
85+
async with connect(server) as client:
86+
with anyio.fail_after(10):
87+
async with client.listen(tools_list_changed=True) as sub: # pragma: no branch
88+
assert seen == [sub.subscription_id]
89+
stock.close()
90+
async for _event in sub:
91+
raise NotImplementedError # unreachable: nothing was published

0 commit comments

Comments
 (0)