Skip to content

Commit f953617

Browse files
committed
Add tests for shutdown coverage gaps
Cover the three lines that were missing from code coverage: - streamable_http.py L777: terminate() closing active SSE stream writers - streamable_http_manager.py L139-140: exception handling when transport.terminate() fails during manager shutdown Github-Issue:#2150
1 parent cca5d27 commit f953617

File tree

1 file changed

+48
-0
lines changed

1 file changed

+48
-0
lines changed

tests/server/test_streamable_http_manager.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,3 +413,51 @@ def test_session_idle_timeout_rejects_non_positive():
413413
def test_session_idle_timeout_rejects_stateless():
414414
with pytest.raises(RuntimeError, match="not supported in stateless"):
415415
StreamableHTTPSessionManager(app=Server("test"), session_idle_timeout=30, stateless=True)
416+
417+
418+
@pytest.mark.anyio
419+
async def test_terminate_closes_sse_stream_writers():
420+
"""Test that terminate() closes all active SSE stream writers."""
421+
transport = StreamableHTTPServerTransport(mcp_session_id="test-sse-close")
422+
423+
# Create memory object streams to simulate active SSE writers
424+
send1, recv1 = anyio.create_memory_object_stream[dict[str, str]]()
425+
send2, recv2 = anyio.create_memory_object_stream[dict[str, str]]()
426+
427+
# Inject fake SSE writers into the transport
428+
transport._sse_stream_writers["req-1"] = send1
429+
transport._sse_stream_writers["req-2"] = send2
430+
431+
await transport.terminate()
432+
433+
# Writers should be closed (sending raises ClosedResourceError)
434+
with pytest.raises(anyio.ClosedResourceError):
435+
await send1.send({"data": "test"})
436+
with pytest.raises(anyio.ClosedResourceError):
437+
await send2.send({"data": "test"})
438+
439+
# Dict should be cleared
440+
assert len(transport._sse_stream_writers) == 0
441+
442+
# Clean up receive streams
443+
recv1.close()
444+
recv2.close()
445+
446+
447+
@pytest.mark.anyio
448+
async def test_manager_shutdown_handles_terminate_exception(caplog: pytest.LogCaptureFixture):
449+
"""Test that manager shutdown continues even if transport.terminate() raises."""
450+
app = Server("test-shutdown-error")
451+
manager = StreamableHTTPSessionManager(app=app)
452+
453+
with caplog.at_level(logging.DEBUG):
454+
async with manager.run():
455+
# Inject a mock transport that raises on terminate
456+
mock_transport = AsyncMock(spec=StreamableHTTPServerTransport)
457+
mock_transport.terminate = AsyncMock(side_effect=RuntimeError("terminate failed"))
458+
mock_transport.idle_scope = None
459+
manager._server_instances["bad-session"] = mock_transport
460+
461+
# Manager should have shut down cleanly despite the exception
462+
assert len(manager._server_instances) == 0
463+
assert "Error terminating transport during shutdown" in caplog.text

0 commit comments

Comments
 (0)