Get baseline 100% clean coverage (#1553)
This commit is contained in:
parent
da4fce2195
commit
89e9c43acf
6 changed files with 1032 additions and 1084 deletions
|
|
@ -13,7 +13,7 @@ def mcp_server() -> Server:
|
|||
server = Server(name="test_server")
|
||||
|
||||
@server.list_resources()
|
||||
async def handle_list_resources():
|
||||
async def handle_list_resources(): # pragma: no cover
|
||||
return [
|
||||
Resource(
|
||||
uri=AnyUrl("memory://test"),
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ async def test_bidirectional_progress_notifications():
|
|||
async for message in server_session.incoming_messages:
|
||||
try:
|
||||
await server._handle_message(message, server_session, {})
|
||||
except Exception as e:
|
||||
except Exception as e: # pragma: no cover
|
||||
raise e
|
||||
|
||||
# Track progress updates
|
||||
|
|
@ -91,10 +91,10 @@ async def test_bidirectional_progress_notifications():
|
|||
if arguments and "_meta" in arguments:
|
||||
progressToken = arguments["_meta"]["progressToken"]
|
||||
|
||||
if not progressToken:
|
||||
if not progressToken: # pragma: no cover
|
||||
raise ValueError("Empty progress token received")
|
||||
|
||||
if progressToken != client_progress_token:
|
||||
if progressToken != client_progress_token: # pragma: no cover
|
||||
raise ValueError("Server sending back incorrect progressToken")
|
||||
|
||||
# Send progress notifications
|
||||
|
|
@ -119,22 +119,22 @@ async def test_bidirectional_progress_notifications():
|
|||
message="Server progress 100%",
|
||||
)
|
||||
|
||||
else:
|
||||
else: # pragma: no cover
|
||||
raise ValueError("Progress token not sent.")
|
||||
|
||||
return [types.TextContent(type="text", text="Tool executed successfully")]
|
||||
|
||||
raise ValueError(f"Unknown tool: {name}")
|
||||
raise ValueError(f"Unknown tool: {name}") # pragma: no cover
|
||||
|
||||
# Client message handler to store progress notifications
|
||||
async def handle_client_message(
|
||||
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
|
||||
) -> None:
|
||||
if isinstance(message, Exception):
|
||||
if isinstance(message, Exception): # pragma: no cover
|
||||
raise message
|
||||
|
||||
if isinstance(message, types.ServerNotification):
|
||||
if isinstance(message.root, types.ProgressNotification):
|
||||
if isinstance(message, types.ServerNotification): # pragma: no branch
|
||||
if isinstance(message.root, types.ProgressNotification): # pragma: no branch
|
||||
params = message.root.params
|
||||
client_progress_updates.append(
|
||||
{
|
||||
|
|
@ -248,14 +248,14 @@ async def test_progress_context_manager():
|
|||
async for message in server_session.incoming_messages:
|
||||
try:
|
||||
await server._handle_message(message, server_session, {})
|
||||
except Exception as e:
|
||||
except Exception as e: # pragma: no cover
|
||||
raise e
|
||||
|
||||
# Client message handler
|
||||
async def handle_client_message(
|
||||
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
|
||||
) -> None:
|
||||
if isinstance(message, Exception):
|
||||
if isinstance(message, Exception): # pragma: no cover
|
||||
raise message
|
||||
|
||||
# run client session
|
||||
|
|
@ -335,7 +335,9 @@ async def test_progress_callback_exception_logging():
|
|||
logged_errors.append(msg % args if args else msg)
|
||||
|
||||
# Create a progress callback that raises an exception
|
||||
async def failing_progress_callback(progress: float, total: float | None, message: str | None) -> None:
|
||||
async def failing_progress_callback(
|
||||
progress: float, total: float | None, message: str | None
|
||||
) -> None: # pragma: no cover
|
||||
raise ValueError("Progress callback failed!")
|
||||
|
||||
# Create a server with a tool that sends progress notifications
|
||||
|
|
@ -352,7 +354,7 @@ async def test_progress_callback_exception_logging():
|
|||
message="Halfway done",
|
||||
)
|
||||
return [types.TextContent(type="text", text="progress_result")]
|
||||
raise ValueError(f"Unknown tool: {name}")
|
||||
raise ValueError(f"Unknown tool: {name}") # pragma: no cover
|
||||
|
||||
@server.list_tools()
|
||||
async def handle_list_tools() -> list[types.Tool]:
|
||||
|
|
|
|||
|
|
@ -66,8 +66,8 @@ async def test_request_cancellation():
|
|||
request_id = server.request_context.request_id
|
||||
ev_tool_called.set()
|
||||
await anyio.sleep(10) # Long enough to ensure we can cancel
|
||||
return []
|
||||
raise ValueError(f"Unknown tool: {name}")
|
||||
return [] # pragma: no cover
|
||||
raise ValueError(f"Unknown tool: {name}") # pragma: no cover
|
||||
|
||||
# Register the tool so it shows up in list_tools
|
||||
@server.list_tools()
|
||||
|
|
@ -93,7 +93,7 @@ async def test_request_cancellation():
|
|||
),
|
||||
types.CallToolResult,
|
||||
)
|
||||
pytest.fail("Request should have been cancelled")
|
||||
pytest.fail("Request should have been cancelled") # pragma: no cover
|
||||
except McpError as e:
|
||||
# Expected - request was cancelled
|
||||
assert "Request cancelled" in str(e)
|
||||
|
|
@ -141,7 +141,7 @@ async def test_connection_closed():
|
|||
try:
|
||||
# any request will do
|
||||
await client_session.initialize()
|
||||
pytest.fail("Request should have errored")
|
||||
pytest.fail("Request should have errored") # pragma: no cover
|
||||
except McpError as e:
|
||||
# Expected - request errored
|
||||
assert "Connection closed" in str(e)
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ def server_url(server_port: int) -> str:
|
|||
|
||||
|
||||
# Test server implementation
|
||||
class ServerTest(Server):
|
||||
class ServerTest(Server): # pragma: no cover
|
||||
def __init__(self):
|
||||
super().__init__(SERVER_NAME)
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ class ServerTest(Server):
|
|||
|
||||
|
||||
# Test fixtures
|
||||
def make_server_app() -> Starlette:
|
||||
def make_server_app() -> Starlette: # pragma: no cover
|
||||
"""Create test Starlette app with SSE transport"""
|
||||
# Configure security with allowed hosts/origins for testing
|
||||
security_settings = TransportSecuritySettings(
|
||||
|
|
@ -105,7 +105,7 @@ def make_server_app() -> Starlette:
|
|||
return app
|
||||
|
||||
|
||||
def run_server(server_port: int) -> None:
|
||||
def run_server(server_port: int) -> None: # pragma: no cover
|
||||
app = make_server_app()
|
||||
server = uvicorn.Server(config=uvicorn.Config(app=app, host="127.0.0.1", port=server_port, log_level="error"))
|
||||
print(f"starting server on {server_port}")
|
||||
|
|
@ -133,7 +133,7 @@ def server(server_port: int) -> Generator[None, None, None]:
|
|||
# Signal the server to stop
|
||||
proc.kill()
|
||||
proc.join(timeout=2)
|
||||
if proc.is_alive():
|
||||
if proc.is_alive(): # pragma: no cover
|
||||
print("server process failed to terminate")
|
||||
|
||||
|
||||
|
|
@ -156,7 +156,7 @@ async def test_raw_sse_connection(http_client: httpx.AsyncClient) -> None:
|
|||
assert response.headers["content-type"] == "text/event-stream; charset=utf-8"
|
||||
|
||||
line_number = 0
|
||||
async for line in response.aiter_lines():
|
||||
async for line in response.aiter_lines(): # pragma: no branch
|
||||
if line_number == 0:
|
||||
assert line == "event: endpoint"
|
||||
elif line_number == 1:
|
||||
|
|
@ -214,7 +214,7 @@ async def test_sse_client_exception_handling(
|
|||
|
||||
@pytest.mark.anyio
|
||||
@pytest.mark.skip("this test highlights a possible bug in SSE read timeout exception handling")
|
||||
async def test_sse_client_timeout(
|
||||
async def test_sse_client_timeout( # pragma: no cover
|
||||
initialized_sse_client_session: ClientSession,
|
||||
) -> None:
|
||||
session = initialized_sse_client_session
|
||||
|
|
@ -232,7 +232,7 @@ async def test_sse_client_timeout(
|
|||
pytest.fail("the client should have timed out and returned an error already")
|
||||
|
||||
|
||||
def run_mounted_server(server_port: int) -> None:
|
||||
def run_mounted_server(server_port: int) -> None: # pragma: no cover
|
||||
app = make_server_app()
|
||||
main_app = Starlette(routes=[Mount("/mounted_app", app=app)])
|
||||
server = uvicorn.Server(config=uvicorn.Config(app=main_app, host="127.0.0.1", port=server_port, log_level="error"))
|
||||
|
|
@ -261,7 +261,7 @@ def mounted_server(server_port: int) -> Generator[None, None, None]:
|
|||
# Signal the server to stop
|
||||
proc.kill()
|
||||
proc.join(timeout=2)
|
||||
if proc.is_alive():
|
||||
if proc.is_alive(): # pragma: no cover
|
||||
print("server process failed to terminate")
|
||||
|
||||
|
||||
|
|
@ -280,7 +280,7 @@ async def test_sse_client_basic_connection_mounted_app(mounted_server: None, ser
|
|||
|
||||
|
||||
# Test server with request context that returns headers in the response
|
||||
class RequestContextServer(Server[object, Request]):
|
||||
class RequestContextServer(Server[object, Request]): # pragma: no cover
|
||||
def __init__(self):
|
||||
super().__init__("request_context_server")
|
||||
|
||||
|
|
@ -322,7 +322,7 @@ class RequestContextServer(Server[object, Request]):
|
|||
]
|
||||
|
||||
|
||||
def run_context_server(server_port: int) -> None:
|
||||
def run_context_server(server_port: int) -> None: # pragma: no cover
|
||||
"""Run a server that captures request context"""
|
||||
# Configure security with allowed hosts/origins for testing
|
||||
security_settings = TransportSecuritySettings(
|
||||
|
|
@ -364,7 +364,7 @@ def context_server(server_port: int) -> Generator[None, None, None]:
|
|||
print("killing context server")
|
||||
proc.kill()
|
||||
proc.join(timeout=2)
|
||||
if proc.is_alive():
|
||||
if proc.is_alive(): # pragma: no cover
|
||||
print("context server process failed to terminate")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ INIT_REQUEST = {
|
|||
|
||||
|
||||
# Helper functions
|
||||
def extract_protocol_version_from_sse(response: requests.Response) -> str:
|
||||
def extract_protocol_version_from_sse(response: requests.Response) -> str: # pragma: no cover
|
||||
"""Extract the negotiated protocol version from an SSE initialization response."""
|
||||
assert response.headers.get("Content-Type") == "text/event-stream"
|
||||
for line in response.text.splitlines():
|
||||
|
|
@ -78,14 +78,14 @@ class SimpleEventStore(EventStore):
|
|||
self._events: list[tuple[StreamId, EventId, types.JSONRPCMessage]] = []
|
||||
self._event_id_counter = 0
|
||||
|
||||
async def store_event(self, stream_id: StreamId, message: types.JSONRPCMessage) -> EventId:
|
||||
async def store_event(self, stream_id: StreamId, message: types.JSONRPCMessage) -> EventId: # pragma: no cover
|
||||
"""Store an event and return its ID."""
|
||||
self._event_id_counter += 1
|
||||
event_id = str(self._event_id_counter)
|
||||
self._events.append((stream_id, event_id, message))
|
||||
return event_id
|
||||
|
||||
async def replay_events_after(
|
||||
async def replay_events_after( # pragma: no cover
|
||||
self,
|
||||
last_event_id: EventId,
|
||||
send_callback: EventCallback,
|
||||
|
|
@ -114,7 +114,7 @@ class SimpleEventStore(EventStore):
|
|||
|
||||
|
||||
# Test server implementation that follows MCP protocol
|
||||
class ServerTest(Server):
|
||||
class ServerTest(Server): # pragma: no cover
|
||||
def __init__(self):
|
||||
super().__init__(SERVER_NAME)
|
||||
self._lock = None # Will be initialized in async context
|
||||
|
|
@ -254,7 +254,9 @@ class ServerTest(Server):
|
|||
return [TextContent(type="text", text=f"Called {name}")]
|
||||
|
||||
|
||||
def create_app(is_json_response_enabled: bool = False, event_store: EventStore | None = None) -> Starlette:
|
||||
def create_app(
|
||||
is_json_response_enabled: bool = False, event_store: EventStore | None = None
|
||||
) -> Starlette: # pragma: no cover
|
||||
"""Create a Starlette application for testing using the session manager.
|
||||
|
||||
Args:
|
||||
|
|
@ -287,7 +289,9 @@ def create_app(is_json_response_enabled: bool = False, event_store: EventStore |
|
|||
return app
|
||||
|
||||
|
||||
def run_server(port: int, is_json_response_enabled: bool = False, event_store: EventStore | None = None) -> None:
|
||||
def run_server(
|
||||
port: int, is_json_response_enabled: bool = False, event_store: EventStore | None = None
|
||||
) -> None: # pragma: no cover
|
||||
"""Run the test server.
|
||||
|
||||
Args:
|
||||
|
|
@ -726,8 +730,8 @@ def test_get_sse_stream(basic_server: None, basic_server_url: str):
|
|||
# Extract negotiated protocol version from SSE response
|
||||
init_data = None
|
||||
assert init_response.headers.get("Content-Type") == "text/event-stream"
|
||||
for line in init_response.text.splitlines():
|
||||
if line.startswith("data: "):
|
||||
for line in init_response.text.splitlines(): # pragma: no branch
|
||||
if line.startswith("data: "): # pragma: no cover
|
||||
init_data = json.loads(line[6:])
|
||||
break
|
||||
assert init_data is not None
|
||||
|
|
@ -786,8 +790,8 @@ def test_get_validation(basic_server: None, basic_server_url: str):
|
|||
# Extract negotiated protocol version from SSE response
|
||||
init_data = None
|
||||
assert init_response.headers.get("Content-Type") == "text/event-stream"
|
||||
for line in init_response.text.splitlines():
|
||||
if line.startswith("data: "):
|
||||
for line in init_response.text.splitlines(): # pragma: no branch
|
||||
if line.startswith("data: "): # pragma: no cover
|
||||
init_data = json.loads(line[6:])
|
||||
break
|
||||
assert init_data is not None
|
||||
|
|
@ -820,7 +824,7 @@ def test_get_validation(basic_server: None, basic_server_url: str):
|
|||
|
||||
# Client-specific fixtures
|
||||
@pytest.fixture
|
||||
async def http_client(basic_server: None, basic_server_url: str):
|
||||
async def http_client(basic_server: None, basic_server_url: str): # pragma: no cover
|
||||
"""Create test client matching the SSE test pattern."""
|
||||
async with httpx.AsyncClient(base_url=basic_server_url) as client:
|
||||
yield client
|
||||
|
|
@ -959,10 +963,10 @@ async def test_streamablehttp_client_get_stream(basic_server: None, basic_server
|
|||
notifications_received: list[types.ServerNotification] = []
|
||||
|
||||
# Define message handler to capture notifications
|
||||
async def message_handler(
|
||||
async def message_handler( # pragma: no branch
|
||||
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
|
||||
) -> None:
|
||||
if isinstance(message, types.ServerNotification):
|
||||
if isinstance(message, types.ServerNotification): # pragma: no branch
|
||||
notifications_received.append(message)
|
||||
|
||||
async with streamablehttp_client(f"{basic_server_url}/mcp") as (
|
||||
|
|
@ -984,7 +988,7 @@ async def test_streamablehttp_client_get_stream(basic_server: None, basic_server
|
|||
# Verify the notification is a ResourceUpdatedNotification
|
||||
resource_update_found = False
|
||||
for notif in notifications_received:
|
||||
if isinstance(notif.root, types.ResourceUpdatedNotification):
|
||||
if isinstance(notif.root, types.ResourceUpdatedNotification): # pragma: no branch
|
||||
assert str(notif.root.params.uri) == "http://test_resource/"
|
||||
resource_update_found = True
|
||||
|
||||
|
|
@ -1014,8 +1018,8 @@ async def test_streamablehttp_client_session_termination(basic_server: None, bas
|
|||
tools = await session.list_tools()
|
||||
assert len(tools.tools) == 6
|
||||
|
||||
headers: dict[str, str] = {}
|
||||
if captured_session_id:
|
||||
headers: dict[str, str] = {} # pragma: no cover
|
||||
if captured_session_id: # pragma: no cover
|
||||
headers[MCP_SESSION_ID_HEADER] = captured_session_id
|
||||
|
||||
async with streamablehttp_client(f"{basic_server_url}/mcp", headers=headers) as (
|
||||
|
|
@ -1025,7 +1029,7 @@ async def test_streamablehttp_client_session_termination(basic_server: None, bas
|
|||
):
|
||||
async with ClientSession(read_stream, write_stream) as session:
|
||||
# Attempt to make a request after termination
|
||||
with pytest.raises(
|
||||
with pytest.raises( # pragma: no branch
|
||||
McpError,
|
||||
match="Session terminated",
|
||||
):
|
||||
|
|
@ -1080,8 +1084,8 @@ async def test_streamablehttp_client_session_termination_204(
|
|||
tools = await session.list_tools()
|
||||
assert len(tools.tools) == 6
|
||||
|
||||
headers: dict[str, str] = {}
|
||||
if captured_session_id:
|
||||
headers: dict[str, str] = {} # pragma: no cover
|
||||
if captured_session_id: # pragma: no cover
|
||||
headers[MCP_SESSION_ID_HEADER] = captured_session_id
|
||||
|
||||
async with streamablehttp_client(f"{basic_server_url}/mcp", headers=headers) as (
|
||||
|
|
@ -1091,7 +1095,7 @@ async def test_streamablehttp_client_session_termination_204(
|
|||
):
|
||||
async with ClientSession(read_stream, write_stream) as session:
|
||||
# Attempt to make a request after termination
|
||||
with pytest.raises(
|
||||
with pytest.raises( # pragma: no branch
|
||||
McpError,
|
||||
match="Session terminated",
|
||||
):
|
||||
|
|
@ -1110,13 +1114,13 @@ async def test_streamablehttp_client_resumption(event_server: tuple[SimpleEventS
|
|||
captured_protocol_version = None
|
||||
first_notification_received = False
|
||||
|
||||
async def message_handler(
|
||||
async def message_handler( # pragma: no branch
|
||||
message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception,
|
||||
) -> None:
|
||||
if isinstance(message, types.ServerNotification):
|
||||
if isinstance(message, types.ServerNotification): # pragma: no branch
|
||||
captured_notifications.append(message)
|
||||
# Look for our first notification
|
||||
if isinstance(message.root, types.LoggingMessageNotification):
|
||||
if isinstance(message.root, types.LoggingMessageNotification): # pragma: no branch
|
||||
if message.root.params.data == "First notification before lock":
|
||||
nonlocal first_notification_received
|
||||
first_notification_received = True
|
||||
|
|
@ -1169,18 +1173,18 @@ async def test_streamablehttp_client_resumption(event_server: tuple[SimpleEventS
|
|||
tg.cancel_scope.cancel()
|
||||
|
||||
# Verify we received exactly one notification
|
||||
assert len(captured_notifications) == 1
|
||||
assert isinstance(captured_notifications[0].root, types.LoggingMessageNotification)
|
||||
assert captured_notifications[0].root.params.data == "First notification before lock"
|
||||
assert len(captured_notifications) == 1 # pragma: no cover
|
||||
assert isinstance(captured_notifications[0].root, types.LoggingMessageNotification) # pragma: no cover
|
||||
assert captured_notifications[0].root.params.data == "First notification before lock" # pragma: no cover
|
||||
|
||||
# Clear notifications for the second phase
|
||||
captured_notifications = []
|
||||
captured_notifications = [] # pragma: no cover
|
||||
|
||||
# Now resume the session with the same mcp-session-id and protocol version
|
||||
headers: dict[str, Any] = {}
|
||||
if captured_session_id:
|
||||
headers: dict[str, Any] = {} # pragma: no cover
|
||||
if captured_session_id: # pragma: no cover
|
||||
headers[MCP_SESSION_ID_HEADER] = captured_session_id
|
||||
if captured_protocol_version:
|
||||
if captured_protocol_version: # pragma: no cover
|
||||
headers[MCP_PROTOCOL_VERSION_HEADER] = captured_protocol_version
|
||||
async with streamablehttp_client(f"{server_url}/mcp", headers=headers) as (
|
||||
read_stream,
|
||||
|
|
@ -1278,7 +1282,7 @@ async def test_streamablehttp_server_sampling(basic_server: None, basic_server_u
|
|||
|
||||
|
||||
# Context-aware server implementation for testing request context propagation
|
||||
class ContextAwareServerTest(Server):
|
||||
class ContextAwareServerTest(Server): # pragma: no cover
|
||||
def __init__(self):
|
||||
super().__init__("ContextAwareServer")
|
||||
|
||||
|
|
@ -1338,7 +1342,7 @@ class ContextAwareServerTest(Server):
|
|||
|
||||
|
||||
# Server runner for context-aware testing
|
||||
def run_context_aware_server(port: int):
|
||||
def run_context_aware_server(port: int): # pragma: no cover
|
||||
"""Run the context-aware test server."""
|
||||
server = ContextAwareServerTest()
|
||||
|
||||
|
|
@ -1380,7 +1384,7 @@ def context_aware_server(basic_server_port: int) -> Generator[None, None, None]:
|
|||
|
||||
proc.kill()
|
||||
proc.join(timeout=2)
|
||||
if proc.is_alive():
|
||||
if proc.is_alive(): # pragma: no cover
|
||||
print("Context-aware server process failed to terminate")
|
||||
|
||||
|
||||
|
|
@ -1443,8 +1447,8 @@ async def test_streamablehttp_request_context_isolation(context_aware_server: No
|
|||
contexts.append(context_data)
|
||||
|
||||
# Verify each request had its own context
|
||||
assert len(contexts) == 3
|
||||
for i, ctx in enumerate(contexts):
|
||||
assert len(contexts) == 3 # pragma: no cover
|
||||
for i, ctx in enumerate(contexts): # pragma: no cover
|
||||
assert ctx["request_id"] == f"request-{i}"
|
||||
assert ctx["headers"].get("x-request-id") == f"request-{i}"
|
||||
assert ctx["headers"].get("x-custom-value") == f"value-{i}"
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ def server_url(server_port: int) -> str:
|
|||
|
||||
|
||||
# Test server implementation
|
||||
class ServerTest(Server):
|
||||
class ServerTest(Server): # pragma: no cover
|
||||
def __init__(self):
|
||||
super().__init__(SERVER_NAME)
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ class ServerTest(Server):
|
|||
|
||||
|
||||
# Test fixtures
|
||||
def make_server_app() -> Starlette:
|
||||
def make_server_app() -> Starlette: # pragma: no cover
|
||||
"""Create test Starlette app with WebSocket transport"""
|
||||
server = ServerTest()
|
||||
|
||||
|
|
@ -92,7 +92,7 @@ def make_server_app() -> Starlette:
|
|||
return app
|
||||
|
||||
|
||||
def run_server(server_port: int) -> None:
|
||||
def run_server(server_port: int) -> None: # pragma: no cover
|
||||
app = make_server_app()
|
||||
server = uvicorn.Server(config=uvicorn.Config(app=app, host="127.0.0.1", port=server_port, log_level="error"))
|
||||
print(f"starting server on {server_port}")
|
||||
|
|
@ -104,7 +104,7 @@ def run_server(server_port: int) -> None:
|
|||
time.sleep(0.5)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@pytest.fixture() # pragma: no cover
|
||||
def server(server_port: int) -> Generator[None, None, None]:
|
||||
proc = multiprocessing.Process(target=run_server, kwargs={"server_port": server_port}, daemon=True)
|
||||
print("starting process")
|
||||
|
|
@ -120,7 +120,7 @@ def server(server_port: int) -> Generator[None, None, None]:
|
|||
# Signal the server to stop
|
||||
proc.kill()
|
||||
proc.join(timeout=2)
|
||||
if proc.is_alive():
|
||||
if proc.is_alive(): # pragma: no cover
|
||||
print("server process failed to terminate")
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue