Skip to content

Commit a040142

Browse files
committed
test: isolate streamable auth regression server lifecycle
1 parent 08ae6df commit a040142

File tree

1 file changed

+43
-6
lines changed

1 file changed

+43
-6
lines changed

tests/server/auth/middleware/test_auth_context_streamable_http.py

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
"""Regression tests for auth context in StreamableHTTP servers."""
22

3+
import multiprocessing
4+
import socket
35
import time
46
from collections.abc import Generator
57

68
import httpx
79
import pytest
10+
import uvicorn
811
from starlette.applications import Starlette
912
from starlette.middleware import Middleware
1013
from starlette.middleware.authentication import AuthenticationMiddleware
@@ -25,7 +28,7 @@
2528
TextContent,
2629
Tool,
2730
)
28-
from tests.test_helpers import run_uvicorn_in_thread
31+
from tests.test_helpers import wait_for_server
2932

3033

3134
class _EchoTokenVerifier:
@@ -55,15 +58,14 @@ def auth_flow(self, request: httpx.Request):
5558
yield request
5659

5760

58-
@pytest.fixture
59-
def stateful_auth_server() -> Generator[str, None, None]:
61+
def _create_stateful_auth_app() -> Starlette:
6062
server = Server(
6163
"auth-test-server",
6264
on_call_tool=_handle_whoami,
6365
on_list_tools=_handle_list_tools,
6466
)
6567
session_manager = StreamableHTTPSessionManager(app=server, stateless=False)
66-
app = Starlette(
68+
return Starlette(
6769
routes=[Mount("/mcp", app=session_manager.handle_request)],
6870
middleware=[
6971
Middleware(AuthenticationMiddleware, backend=BearerAuthBackend(_EchoTokenVerifier())),
@@ -72,8 +74,43 @@ def stateful_auth_server() -> Generator[str, None, None]:
7274
lifespan=lambda app: session_manager.run(),
7375
)
7476

75-
with run_uvicorn_in_thread(app, host="127.0.0.1", log_level="error") as base_url:
76-
yield f"{base_url}/mcp"
77+
78+
def run_stateful_auth_server(port: int) -> None: # pragma: no cover
79+
config = uvicorn.Config(
80+
app=_create_stateful_auth_app(),
81+
host="127.0.0.1",
82+
port=port,
83+
log_level="error",
84+
access_log=False,
85+
)
86+
uvicorn.Server(config).run()
87+
88+
89+
@pytest.fixture
90+
def stateful_auth_server_port() -> int:
91+
with socket.socket() as s:
92+
s.bind(("127.0.0.1", 0))
93+
return s.getsockname()[1]
94+
95+
96+
@pytest.fixture
97+
def stateful_auth_server(stateful_auth_server_port: int) -> Generator[str, None, None]:
98+
proc = multiprocessing.Process(
99+
target=run_stateful_auth_server,
100+
kwargs={"port": stateful_auth_server_port},
101+
daemon=True,
102+
)
103+
proc.start()
104+
wait_for_server(stateful_auth_server_port)
105+
106+
try:
107+
yield f"http://127.0.0.1:{stateful_auth_server_port}/mcp"
108+
finally:
109+
proc.terminate()
110+
proc.join(timeout=2)
111+
if proc.is_alive(): # pragma: no cover
112+
proc.kill()
113+
proc.join(timeout=1)
77114

78115

79116
@pytest.mark.anyio

0 commit comments

Comments
 (0)