Skip to content

Commit 7faf4a4

Browse files
authored
[https://nvbugs/6337229][fix] Stabilize scaffolding MCP worker test server startup and cleanup (NVIDIA#15958)
Signed-off-by: kleinc <kleinc@nvidia.com> Signed-off-by: KleinBlueC <102355066+KleinBlueC@users.noreply.github.com>
1 parent 0d97e9c commit 7faf4a4

3 files changed

Lines changed: 33 additions & 26 deletions

File tree

tests/unittest/scaffolding/test_bench.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import asyncio
22
import math
3-
from typing import List
3+
from typing import Iterator, List
44

55
import numpy as np
6+
import pytest
67

78
from tensorrt_llm.executor.request import GenerationRequest
89
from tensorrt_llm.executor.result import GenerationResult
@@ -19,6 +20,17 @@
1920
OUTPUT_STR = "Yes."
2021

2122

23+
@pytest.fixture(autouse=True)
24+
def _restore_native_generation_controller() -> Iterator[None]:
25+
original_init = NativeGenerationController.__init__
26+
original_process = NativeGenerationController.process
27+
28+
yield
29+
30+
NativeGenerationController.__init__ = original_init
31+
NativeGenerationController.process = original_process
32+
33+
2234
class DummyWorker(Worker):
2335

2436
async def dummy_generation_handler(self, task: GenerationTask):

tests/unittest/scaffolding/test_mcp_worker.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2-
# SPDX-License-Identifier: Apache-2.0
3-
41
import asyncio
52
import json
63
import multiprocessing
@@ -15,7 +12,7 @@
1512
from mcp.server.sse import SseServerTransport
1613
from starlette.applications import Starlette
1714
from starlette.requests import Request
18-
from starlette.responses import StreamingResponse
15+
from starlette.responses import JSONResponse, StreamingResponse
1916
from starlette.routing import Mount, Route
2017

2118
from tensorrt_llm.scaffolding.controller import ChatWithMCPController, NativeGenerationController
@@ -67,9 +64,13 @@ async def handle_sse(request: Request) -> StreamingResponse:
6764
# Return an empty streaming response after SSE connection closes
6865
return StreamingResponse(iter([]), media_type="text/event-stream")
6966

67+
async def handle_health(_request: Request) -> JSONResponse:
68+
return JSONResponse({"status": "ok"})
69+
7070
return Starlette(
7171
debug=debug,
7272
routes=[
73+
Route("/health", endpoint=handle_health),
7374
Route("/sse", endpoint=handle_sse),
7475
Mount("/messages/", app=sse.handle_post_message),
7576
],
@@ -103,9 +104,13 @@ def __init__(self, host: str = "0.0.0.0", port: int = 8080, env: Optional[dict]
103104
)
104105
self.proc.start()
105106

106-
# Wait for server to be ready
107-
# self._wait_for_server(url=self.sse_url,
108-
# timeout=self.MAX_SERVER_START_WAIT_S)
107+
try:
108+
self._wait_for_server(
109+
url=f"{self.url_root}/health", timeout=self.MAX_SERVER_START_WAIT_S
110+
)
111+
except RuntimeError:
112+
self.terminate()
113+
raise
109114

110115
def __enter__(self):
111116
return self
@@ -166,9 +171,9 @@ def get_sse_url(self) -> str:
166171

167172

168173
@pytest.fixture(scope="module")
169-
def mcp_server():
174+
def mcp_server(unused_tcp_port_factory):
170175
# Create and start MCP server (similar to RemoteOpenAIServer usage)
171-
remote_server = RemoteMCPServer(host="0.0.0.0", port=8080)
176+
remote_server = RemoteMCPServer(host="127.0.0.1", port=unused_tcp_port_factory())
172177

173178
# Yield server instance for test use
174179
yield remote_server
@@ -220,7 +225,6 @@ async def dummy_handler(self, task: ChatTask):
220225
# ============================================================
221226

222227

223-
@pytest.mark.skip(reason="https://nvbugs/6337229")
224228
@pytest.mark.asyncio
225229
async def test_mcp_worker_add_numbers(mcp_server):
226230
# 1. Initialize MCPWorker with mcp_server's SSE URL
@@ -254,10 +258,9 @@ async def test_mcp_worker_add_numbers(mcp_server):
254258

255259
finally:
256260
# 6. Clean up worker resources
257-
worker.shutdown()
261+
await worker.async_shutdown()
258262

259263

260-
@pytest.mark.skip(reason="https://nvbugs/6337229")
261264
@pytest.mark.asyncio
262265
async def test_mcp_worker_echo_message(mcp_server):
263266
# Initialize MCPWorker
@@ -284,10 +287,9 @@ async def test_mcp_worker_echo_message(mcp_server):
284287
print(f"✓ Test passed: echo_message returned '{task.result_str}'")
285288

286289
finally:
287-
worker.shutdown()
290+
await worker.async_shutdown()
288291

289292

290-
@pytest.mark.skip(reason="https://nvbugs/6337229")
291293
@pytest.mark.asyncio
292294
async def test_mcp_worker_multiple_calls(mcp_server):
293295
import json
@@ -337,10 +339,9 @@ async def test_mcp_worker_multiple_calls(mcp_server):
337339
print(f" - Call 3: echo_message returned '{task3.result_str}'")
338340

339341
finally:
340-
worker.shutdown()
342+
await worker.async_shutdown()
341343

342344

343-
@pytest.mark.skip(reason="https://nvbugs/6337229")
344345
@pytest.mark.asyncio
345346
async def test_multiple_calls_to_same_tool(mcp_server):
346347
sse_url = mcp_server.get_sse_url()
@@ -368,10 +369,9 @@ async def test_multiple_calls_to_same_tool(mcp_server):
368369
print(f" - Call 1: add_numbers(10, 20) = {result1}")
369370
print(f" - Call 2: add_numbers(100, 200) = {result2}")
370371

371-
worker.shutdown()
372+
await worker.async_shutdown()
372373

373374

374-
@pytest.mark.skip(reason="https://nvbugs/6337229")
375375
@pytest.mark.asyncio
376376
async def test_scaffolding_with_chat_mcp_controller(mcp_server):
377377
# Initialize workers
@@ -441,7 +441,7 @@ async def test_scaffolding_with_chat_mcp_controller(mcp_server):
441441

442442
finally:
443443
# Clean up
444-
await mcp_worker.shutdown()
444+
await mcp_worker.async_shutdown()
445445
scaffolding_llm.shutdown(shutdown_workers=False) # Don't shutdown workers again
446446

447447

tests/unittest/scaffolding/test_worker.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@
1818
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
1919
from llmapi.test_llm import get_model_path
2020

21-
_SCAFFOLDING_MCP_NVBUG = pytest.mark.skip(reason="https://nvbugs/6337229")
22-
_TRTOAI_PROCESSPOOL_NVBUG = pytest.mark.skip(reason="https://nvbugs/6341072")
23-
2421

2522
@pytest.fixture(scope="module")
2623
def deepseek_distill_7b_path() -> Path:
@@ -37,7 +34,7 @@ def default_prompt():
3734
@pytest.fixture(scope="module")
3835
def model_name():
3936
#return "DeepSeek-R1/DeepSeek-R1-Distill-Qwen-7B"
40-
return "gpt-oss-20b"
37+
return "gpt_oss/gpt-oss-20b"
4138

4239

4340
@pytest.fixture(scope="module", params=['pytorch'])
@@ -68,7 +65,6 @@ def create_trtoai_worker(model_name, async_client):
6865
)
6966

7067

71-
@_TRTOAI_PROCESSPOOL_NVBUG
7268
@pytest.mark.asyncio(loop_scope="module")
7369
def test_trtoai_worker_generation(default_prompt, model_name, server):
7470
worker = create_trtoai_worker(model_name, server.get_async_client())
@@ -82,7 +78,6 @@ def test_trtoai_worker_generation(default_prompt, model_name, server):
8278
raise e
8379

8480

85-
@_SCAFFOLDING_MCP_NVBUG
8681
@pytest.mark.asyncio(loop_scope="module")
8782
def test_trtoai_worker_chat(default_prompt, model_name, server):
8883
worker = create_trtoai_worker(model_name, server.get_async_client())

0 commit comments

Comments
 (0)