1212"""
1313
1414import gc
15- import socket
1615import sys
1716from collections .abc import Iterator
1817from contextlib import contextmanager
2625from mcp .client .websocket import websocket_client
2726
2827
29- def _unused_tcp_port () -> int :
30- """Return a port with no listener. Binding then closing leaves the port unbound."""
31- with socket .socket () as s :
32- s .bind (("127.0.0.1" , 0 ))
33- return s .getsockname ()[1 ]
34-
35-
3628@contextmanager
3729def _assert_no_memory_stream_leak () -> Iterator [None ]:
3830 """Fail if any anyio MemoryObject stream emits ResourceWarning during the block.
@@ -63,19 +55,17 @@ def hook(args: Any) -> None: # pragma: no cover
6355
6456
6557@pytest .mark .anyio
66- async def test_sse_client_closes_all_streams_on_connection_error () -> None :
58+ async def test_sse_client_closes_all_streams_on_connection_error (free_tcp_port : int ) -> None :
6759 """sse_client must close all 4 stream ends when the connection fails.
6860
6961 Before the fix, only read_stream_writer and write_stream were closed in
7062 the finally block. read_stream and write_stream_reader were leaked.
7163 """
72- port = _unused_tcp_port ()
73-
7464 with _assert_no_memory_stream_leak ():
7565 # sse_client enters a task group BEFORE connecting, so anyio wraps the
7666 # ConnectError from aconnect_sse in an ExceptionGroup.
7767 with pytest .raises (Exception ) as exc_info : # noqa: B017
78- async with sse_client (f"http://127.0.0.1:{ port } /sse" ):
68+ async with sse_client (f"http://127.0.0.1:{ free_tcp_port } /sse" ):
7969 pytest .fail ("should not reach here" ) # pragma: no cover
8070
8171 assert exc_info .group_contains (httpx .ConnectError )
@@ -98,15 +88,13 @@ async def test_streamable_http_client_closes_all_streams_on_exit() -> None:
9888
9989
10090@pytest .mark .anyio
101- async def test_websocket_client_closes_all_streams_on_connection_error () -> None :
91+ async def test_websocket_client_closes_all_streams_on_connection_error (free_tcp_port : int ) -> None :
10292 """websocket_client must close all 4 stream ends when ws_connect fails.
10393
10494 Before the fix, there was no try/finally at all — if ws_connect raised,
10595 all 4 streams were leaked.
10696 """
107- port = _unused_tcp_port ()
108-
10997 with _assert_no_memory_stream_leak ():
11098 with pytest .raises (OSError ):
111- async with websocket_client (f"ws://127.0.0.1:{ port } /ws" ):
99+ async with websocket_client (f"ws://127.0.0.1:{ free_tcp_port } /ws" ):
112100 pytest .fail ("should not reach here" ) # pragma: no cover
0 commit comments