Skip to content

Commit 7b2804e

Browse files
committed
test(sse): add coverage for ASGIStreamingSSEResponse guard and fallback paths
1 parent bf88ddb commit 7b2804e

File tree

1 file changed

+72
-0
lines changed

1 file changed

+72
-0
lines changed

tests/unit/test_response/test_sse.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,3 +288,75 @@ async def mock_receive() -> HTTPDisconnectEvent:
288288
body = b"".join(received).decode()
289289
assert "hello" in body
290290
assert "world" in body
291+
292+
293+
async def test_sse_send_raises_without_ping_interval() -> None:
294+
"""_send requires a lock (and therefore ping_interval); RuntimeError if missing."""
295+
296+
async def empty() -> AsyncIterator[str]:
297+
return
298+
yield
299+
300+
response = ASGIStreamingSSEResponse(
301+
iterator=empty(),
302+
media_type="text/event-stream",
303+
status_code=200,
304+
)
305+
306+
async def mock_send(message: Message) -> None:
307+
pass
308+
309+
with pytest.raises(RuntimeError, match="_send called without a send lock"):
310+
await response._send(mock_send, b"data")
311+
312+
313+
async def test_sse_ping_raises_without_ping_interval() -> None:
314+
"""_ping requires ping_interval; RuntimeError if called without one."""
315+
316+
async def empty() -> AsyncIterator[str]:
317+
return
318+
yield
319+
320+
response = ASGIStreamingSSEResponse(
321+
iterator=empty(),
322+
media_type="text/event-stream",
323+
status_code=200,
324+
)
325+
326+
async def mock_send(message: Message) -> None:
327+
pass
328+
329+
with pytest.raises(RuntimeError, match="_ping called without a ping interval"):
330+
await response._ping(mock_send, anyio.Event())
331+
332+
333+
async def test_sse_send_body_delegates_to_parent_without_ping() -> None:
334+
"""Without ping_interval, send_body falls through to the parent (no lock, no task group)."""
335+
336+
async def gen() -> AsyncIterator[str]:
337+
yield "chunk1"
338+
yield "chunk2"
339+
340+
response = ASGIStreamingSSEResponse(
341+
iterator=gen(),
342+
media_type="text/event-stream",
343+
status_code=200,
344+
)
345+
346+
received: list[bytes] = []
347+
348+
async def mock_send(message: Message) -> None:
349+
if message.get("type") == "http.response.body":
350+
body = message.get("body", b"")
351+
received.append(body if isinstance(body, bytes) else b"")
352+
353+
async def mock_receive() -> HTTPDisconnectEvent:
354+
await anyio.sleep(10)
355+
return {"type": "http.disconnect"}
356+
357+
await response.send_body(mock_send, mock_receive)
358+
359+
body = b"".join(received).decode()
360+
assert "chunk1" in body
361+
assert "chunk2" in body
362+
assert ": ping" not in body

0 commit comments

Comments
 (0)