From 2e0a8b3cf892ee4fb179fc502f0e43f597b36e2c Mon Sep 17 00:00:00 2001 From: Julio Quinteros Pro Date: Wed, 18 Feb 2026 14:08:48 -0300 Subject: [PATCH] fix(tests): resolve MCP test isolation failures in parallel execution Three test isolation issues fixed: 1. test_mcp_debug.py: Replace deprecated asyncio.get_event_loop().run_until_complete() with asyncio.run() in TestWrapSendWithDebugHeaders. In Python 3.10+, get_event_loop() raises RuntimeError when no event loop is set in the current thread, causing test_injects_headers and test_body_messages_unchanged to fail in isolation. 2. test_mcp_server_manager.py: After _reload_mcp_manager_module() creates a new global_mcp_server_manager instance, server.py still holds a stale reference to the old instance. Tests in test_mcp_server.py that populate the new manager's registry and then call server.py functions (e.g. _get_tools_from_mcp_servers) get empty results because server.py reads from the old manager. Fix: update server.py's module-level reference after each reload. 3. test_litellm_pre_call_utils.py: test_add_litellm_metadata_from_request_headers sets litellm.callbacks without restoring it afterward. Add cleanup to restore original callbacks after the test to prevent state leaking to subsequent tests. Co-Authored-By: Claude Sonnet 4.6 --- .../proxy/_experimental/mcp_server/test_mcp_debug.py | 4 ++-- .../mcp_server/test_mcp_server_manager.py | 11 ++++++++++- .../test_litellm/proxy/test_litellm_pre_call_utils.py | 5 ++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_debug.py b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_debug.py index 0fb299a57c..de2037793c 100644 --- a/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_debug.py +++ b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_debug.py @@ -230,7 +230,7 @@ class TestWrapSendWithDebugHeaders: ) message = {"type": "http.response.start", "status": 200, "headers": []} - asyncio.get_event_loop().run_until_complete(wrapped(message)) + asyncio.run(wrapped(message)) assert len(captured) == 1 headers = dict(captured[0]["headers"]) @@ -247,6 +247,6 @@ class TestWrapSendWithDebugHeaders: ) body_msg = {"type": "http.response.body", "body": b"hello"} - asyncio.get_event_loop().run_until_complete(wrapped(body_msg)) + asyncio.run(wrapped(body_msg)) assert captured[0] == body_msg diff --git a/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_server_manager.py b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_server_manager.py index 1a50cacd30..464e523832 100644 --- a/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_server_manager.py +++ b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_server_manager.py @@ -39,7 +39,16 @@ def _reload_mcp_manager_module(): "litellm.proxy._experimental.mcp_server.mcp_server_manager" ] importlib.reload(utils_module) - return importlib.reload(manager_module) + reloaded = importlib.reload(manager_module) + # After reload, server.py still holds a stale reference to the old + # global_mcp_server_manager. Update it so tests that exercise server.py + # functions (e.g. _get_tools_from_mcp_servers) use the fresh instance. + server_module = sys.modules.get( + "litellm.proxy._experimental.mcp_server.server" + ) + if server_module is not None and hasattr(server_module, "global_mcp_server_manager"): + server_module.global_mcp_server_manager = reloaded.global_mcp_server_manager + return reloaded class TestMCPServerManager: diff --git a/tests/test_litellm/proxy/test_litellm_pre_call_utils.py b/tests/test_litellm/proxy/test_litellm_pre_call_utils.py index 452db3902c..3bf783c09d 100644 --- a/tests/test_litellm/proxy/test_litellm_pre_call_utils.py +++ b/tests/test_litellm/proxy/test_litellm_pre_call_utils.py @@ -1014,6 +1014,7 @@ async def test_add_litellm_metadata_from_request_headers(): # Set up test logger litellm._turn_on_debug() test_logger = TestCustomLogger() + original_callbacks = litellm.callbacks litellm.callbacks = [test_logger] # Prepare test data (ensure no streaming, add mock_response and api_key to route to litellm.acompletion) @@ -1098,7 +1099,9 @@ async def test_add_litellm_metadata_from_request_headers(): SPEND_LOGS_METADATA = standard_logging_obj["metadata"]["spend_logs_metadata"] assert SPEND_LOGS_METADATA == dict(json.loads(headers["x-litellm-spend-logs-metadata"])), "spend_logs_metadata should be the same as the headers" - + litellm.callbacks = original_callbacks + + def test_get_internal_user_header_from_mapping_returns_expected_header(): mappings = [