Skip to content

Commit bfd113e

Browse files
authored
Merge branch 'main' into stainless/release
2 parents 2afe161 + 98659ce commit bfd113e

1 file changed

Lines changed: 53 additions & 1 deletion

File tree

tests/test_browser_routing.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
from __future__ import annotations
22

33
import os
4-
from typing import Any, cast
4+
import asyncio
5+
from typing import Any, AsyncIterator, cast
6+
from typing_extensions import override
57

68
import httpx
79
import respx
@@ -119,6 +121,56 @@ def test_telemetry_stream_routes_directly_to_vm(monkeypatch: pytest.MonkeyPatch)
119121
assert request.headers.get("Authorization") is None
120122

121123

124+
@pytest.mark.asyncio
125+
async def test_async_telemetry_stream_cancellation_survives_direct_routing(
126+
monkeypatch: pytest.MonkeyPatch,
127+
) -> None:
128+
monkeypatch.setenv("KERNEL_BROWSER_ROUTING_SUBRESOURCES", "telemetry/stream")
129+
read_started = asyncio.Event()
130+
read_stopped = asyncio.Event()
131+
132+
class BlockingSSEStream(httpx.AsyncByteStream):
133+
@override
134+
async def __aiter__(self) -> AsyncIterator[bytes]:
135+
read_started.set()
136+
try:
137+
await asyncio.Event().wait()
138+
finally:
139+
read_stopped.set()
140+
yield b""
141+
142+
@override
143+
async def aclose(self) -> None:
144+
read_stopped.set()
145+
146+
async def handle_request(request: httpx.Request) -> httpx.Response:
147+
assert request.url.path == "/browser/kernel/telemetry/stream"
148+
return httpx.Response(
149+
200,
150+
headers={"content-type": "text/event-stream"},
151+
stream=BlockingSSEStream(),
152+
)
153+
154+
http_client = httpx.AsyncClient(transport=httpx.MockTransport(handle_request))
155+
async with AsyncKernel(
156+
base_url=base_url,
157+
api_key=api_key,
158+
http_client=http_client,
159+
_strict_response_validation=True,
160+
) as client:
161+
route = browser_route_from_browser(_fake_browser())
162+
assert route is not None
163+
client.browser_route_cache.set(route)
164+
stream = await client.browsers.telemetry.stream("sess-1")
165+
consumer = asyncio.create_task(stream.__anext__())
166+
await asyncio.wait_for(read_started.wait(), timeout=1)
167+
168+
consumer.cancel()
169+
with pytest.raises(asyncio.CancelledError):
170+
await asyncio.wait_for(consumer, timeout=1)
171+
await asyncio.wait_for(read_stopped.wait(), timeout=1)
172+
173+
122174
@respx.mock
123175
def test_browser_request_params_cannot_override_target_url_or_jwt() -> None:
124176
route = respx.get("http://browser-session.test/browser/kernel/curl/raw").mock(

0 commit comments

Comments
 (0)