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 <noreply@anthropic.com>
This commit is contained in:
Julio Quinteros Pro
2026-02-18 14:08:48 -03:00
co-authored by Claude Sonnet 4.6
parent 81827be215
commit 2e0a8b3cf8
3 changed files with 16 additions and 4 deletions
@@ -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
@@ -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:
@@ -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 = [