Skip to content

Commit 9b80c04

Browse files
committed
test: convert context_aware_server to in-process threads for coverage
- Replace multiprocessing.Process with threading.Thread for context_aware_server fixture (same pattern as PR #2341) - Remove 5 pragma: no cover markers from context-aware server code - Remove dead run_server() function and unused imports - Remaining 5 pragmas are on genuinely unreachable defensive code
1 parent d9b8d94 commit 9b80c04

File tree

1 file changed

+11
-54
lines changed

1 file changed

+11
-54
lines changed

tests/shared/test_streamable_http.py

Lines changed: 11 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@
66
from __future__ import annotations as _annotations
77

88
import json
9-
import multiprocessing
109
import socket
1110
import threading
1211
import time
13-
import traceback
1412
from collections.abc import AsyncIterator, Generator
1513
from contextlib import asynccontextmanager
1614
from dataclasses import dataclass, field
@@ -430,43 +428,6 @@ def create_app(
430428
return app
431429

432430

433-
def run_server(
434-
port: int,
435-
is_json_response_enabled: bool = False,
436-
event_store: EventStore | None = None,
437-
retry_interval: int | None = None,
438-
) -> None: # pragma: no cover
439-
"""Run the test server in a subprocess (used only by context_aware_server).
440-
441-
Args:
442-
port: Port to listen on.
443-
is_json_response_enabled: If True, use JSON responses instead of SSE streams.
444-
event_store: Optional event store for testing resumability.
445-
retry_interval: Retry interval in milliseconds for SSE polling.
446-
"""
447-
448-
app = create_app(is_json_response_enabled, event_store, retry_interval)
449-
# Configure server
450-
config = uvicorn.Config(
451-
app=app,
452-
host="127.0.0.1",
453-
port=port,
454-
log_level="info",
455-
limit_concurrency=10,
456-
timeout_keep_alive=5,
457-
access_log=False,
458-
)
459-
460-
# Start the server
461-
server = uvicorn.Server(config=config)
462-
463-
# This is important to catch exceptions and prevent test hangs
464-
try:
465-
server.run()
466-
except Exception:
467-
traceback.print_exc()
468-
469-
470431
def _start_server_thread(
471432
port: int,
472433
is_json_response_enabled: bool = False,
@@ -1477,7 +1438,7 @@ async def sampling_callback(
14771438

14781439

14791440
# Context-aware server implementation for testing request context propagation
1480-
async def _handle_context_list_tools( # pragma: no cover
1441+
async def _handle_context_list_tools(
14811442
ctx: ServerRequestContext, params: PaginatedRequestParams | None
14821443
) -> ListToolsResult:
14831444
return ListToolsResult(
@@ -1502,9 +1463,7 @@ async def _handle_context_list_tools( # pragma: no cover
15021463
)
15031464

15041465

1505-
async def _handle_context_call_tool( # pragma: no cover
1506-
ctx: ServerRequestContext, params: CallToolRequestParams
1507-
) -> CallToolResult:
1466+
async def _handle_context_call_tool(ctx: ServerRequestContext, params: CallToolRequestParams) -> CallToolResult:
15081467
name = params.name
15091468
args = params.arguments or {}
15101469

@@ -1532,8 +1491,8 @@ async def _handle_context_call_tool( # pragma: no cover
15321491

15331492

15341493
# Server runner for context-aware testing
1535-
def run_context_aware_server(port: int): # pragma: no cover
1536-
"""Run the context-aware test server."""
1494+
def _create_context_aware_app(port: int) -> tuple[uvicorn.Server, Starlette]:
1495+
"""Create the context-aware test server app and uvicorn.Server."""
15371496
server = Server(
15381497
"ContextAwareServer",
15391498
on_list_tools=_handle_context_list_tools,
@@ -1562,24 +1521,22 @@ def run_context_aware_server(port: int): # pragma: no cover
15621521
log_level="error",
15631522
)
15641523
)
1565-
server_instance.run()
1524+
return server_instance, app
15661525

15671526

15681527
@pytest.fixture
15691528
def context_aware_server(basic_server_port: int) -> Generator[None, None, None]:
1570-
"""Start the context-aware server in a separate process."""
1571-
proc = multiprocessing.Process(target=run_context_aware_server, args=(basic_server_port,), daemon=True)
1572-
proc.start()
1529+
"""Start the context-aware server on a background thread (in-process for coverage)."""
1530+
server_instance, _ = _create_context_aware_app(basic_server_port)
1531+
thread = threading.Thread(target=server_instance.run, daemon=True)
1532+
thread.start()
15731533

1574-
# Wait for server to be running
15751534
wait_for_server(basic_server_port)
15761535

15771536
yield
15781537

1579-
proc.kill()
1580-
proc.join(timeout=2)
1581-
if proc.is_alive(): # pragma: no cover
1582-
print("Context-aware server process failed to terminate")
1538+
server_instance.should_exit = True
1539+
thread.join(timeout=5)
15831540

15841541

15851542
@pytest.mark.anyio

0 commit comments

Comments
 (0)