chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import builtins
|
||||
import sys
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from agents import Agent
|
||||
from agents.exceptions import UserError
|
||||
from agents.mcp.server import MCPServerStreamableHttp, _MCPServerWithClientSession
|
||||
from agents.run_context import RunContextWrapper
|
||||
|
||||
# Handle Python version compatibility for ExceptionGroups
|
||||
if sys.version_info < (3, 11):
|
||||
from exceptiongroup import BaseExceptionGroup
|
||||
else:
|
||||
BaseExceptionGroup = builtins.BaseExceptionGroup
|
||||
|
||||
|
||||
class CrashingClientSessionServer(_MCPServerWithClientSession):
|
||||
def __init__(self):
|
||||
super().__init__(cache_tools_list=False, client_session_timeout_seconds=5)
|
||||
self.cleanup_called = False
|
||||
|
||||
def create_streams(self):
|
||||
raise ValueError("Crash!")
|
||||
|
||||
async def cleanup(self):
|
||||
self.cleanup_called = True
|
||||
await super().cleanup()
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return "crashing_client_session_server"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_server_errors_cause_error_and_cleanup_called():
|
||||
server = CrashingClientSessionServer()
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
await server.connect()
|
||||
|
||||
assert server.cleanup_called
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_not_calling_connect_causes_error():
|
||||
server = CrashingClientSessionServer()
|
||||
|
||||
run_context = RunContextWrapper(context=None)
|
||||
agent = Agent(name="test_agent", instructions="Test agent")
|
||||
|
||||
with pytest.raises(UserError):
|
||||
await server.list_tools(run_context, agent)
|
||||
|
||||
with pytest.raises(UserError):
|
||||
await server.call_tool("foo", {})
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_call_tool_nested_exception_group_mapping():
|
||||
"""
|
||||
Regression test ensuring that nested ExceptionGroups containing HTTP errors
|
||||
are recursively extracted and mapped to a UserError in call_tool().
|
||||
"""
|
||||
# 1. Initialize the server with mock streamable parameters
|
||||
server = MCPServerStreamableHttp(params={"url": "http://fake-mcp-server"})
|
||||
|
||||
# 2. Simulate an active connection by mocking the session object
|
||||
server.session = MagicMock()
|
||||
|
||||
# 3. Construct a nested ExceptionGroup hierarchy containing a connection error
|
||||
http_error = httpx.ConnectError("Network unreachable")
|
||||
inner_group = BaseExceptionGroup("inner_failures", [http_error])
|
||||
outer_group = BaseExceptionGroup("outer_failures", [inner_group])
|
||||
|
||||
# 4 & 5. Mock the internal retry handler to raise the nested group, and assert UserError
|
||||
with patch.object(server, "_call_tool_with_isolated_retry", side_effect=outer_group):
|
||||
with pytest.raises(UserError) as exc_info:
|
||||
await server.call_tool(tool_name="test_tool", arguments={})
|
||||
|
||||
# 6. Verify that the user-facing message is mapped correctly based on the root cause
|
||||
assert "Connection lost" in str(exc_info.value)
|
||||
assert exc_info.value.__cause__ is http_error
|
||||
Reference in New Issue
Block a user