forked from cardosofelipe/fast-next-template
Improved code readability and uniformity by standardizing line breaks, indentation, and inline conditions across safety-related services, models, and tests, including content filters, validation rules, and emergency controls.
270 lines
8.7 KiB
Python
270 lines
8.7 KiB
Python
"""
|
|
Tests for MCP Exception Classes
|
|
"""
|
|
|
|
import pytest
|
|
|
|
from app.services.mcp.exceptions import (
|
|
MCPCircuitOpenError,
|
|
MCPConnectionError,
|
|
MCPError,
|
|
MCPServerNotFoundError,
|
|
MCPTimeoutError,
|
|
MCPToolError,
|
|
MCPToolNotFoundError,
|
|
MCPValidationError,
|
|
)
|
|
|
|
|
|
class TestMCPError:
|
|
"""Tests for base MCPError class."""
|
|
|
|
def test_basic_error(self):
|
|
"""Test basic error creation."""
|
|
error = MCPError("Test error")
|
|
assert error.message == "Test error"
|
|
assert error.server_name is None
|
|
assert error.details == {}
|
|
assert str(error) == "Test error"
|
|
|
|
def test_error_with_server_name(self):
|
|
"""Test error with server name."""
|
|
error = MCPError("Test error", server_name="test-server")
|
|
assert error.server_name == "test-server"
|
|
assert "server=test-server" in str(error)
|
|
|
|
def test_error_with_details(self):
|
|
"""Test error with additional details."""
|
|
error = MCPError(
|
|
"Test error",
|
|
server_name="test-server",
|
|
details={"key": "value"},
|
|
)
|
|
assert error.details == {"key": "value"}
|
|
assert "details={'key': 'value'}" in str(error)
|
|
|
|
|
|
class TestMCPConnectionError:
|
|
"""Tests for MCPConnectionError class."""
|
|
|
|
def test_basic_connection_error(self):
|
|
"""Test basic connection error."""
|
|
error = MCPConnectionError("Connection failed")
|
|
assert error.message == "Connection failed"
|
|
assert error.url is None
|
|
assert error.cause is None
|
|
|
|
def test_connection_error_with_url(self):
|
|
"""Test connection error with URL."""
|
|
error = MCPConnectionError(
|
|
"Connection failed",
|
|
server_name="test-server",
|
|
url="http://localhost:8000",
|
|
)
|
|
assert error.url == "http://localhost:8000"
|
|
assert "url=http://localhost:8000" in str(error)
|
|
|
|
def test_connection_error_with_cause(self):
|
|
"""Test connection error with cause."""
|
|
cause = ConnectionError("Network error")
|
|
error = MCPConnectionError(
|
|
"Connection failed",
|
|
cause=cause,
|
|
)
|
|
assert error.cause is cause
|
|
assert "ConnectionError" in str(error)
|
|
|
|
|
|
class TestMCPTimeoutError:
|
|
"""Tests for MCPTimeoutError class."""
|
|
|
|
def test_basic_timeout_error(self):
|
|
"""Test basic timeout error."""
|
|
error = MCPTimeoutError("Request timed out")
|
|
assert error.message == "Request timed out"
|
|
assert error.timeout_seconds is None
|
|
assert error.operation is None
|
|
|
|
def test_timeout_error_with_details(self):
|
|
"""Test timeout error with details."""
|
|
error = MCPTimeoutError(
|
|
"Request timed out",
|
|
server_name="test-server",
|
|
timeout_seconds=30.0,
|
|
operation="POST /mcp",
|
|
)
|
|
assert error.timeout_seconds == 30.0
|
|
assert error.operation == "POST /mcp"
|
|
assert "timeout=30.0s" in str(error)
|
|
assert "operation=POST /mcp" in str(error)
|
|
|
|
|
|
class TestMCPToolError:
|
|
"""Tests for MCPToolError class."""
|
|
|
|
def test_basic_tool_error(self):
|
|
"""Test basic tool error."""
|
|
error = MCPToolError("Tool execution failed")
|
|
assert error.message == "Tool execution failed"
|
|
assert error.tool_name is None
|
|
assert error.tool_args is None
|
|
assert error.error_code is None
|
|
|
|
def test_tool_error_with_details(self):
|
|
"""Test tool error with all details."""
|
|
error = MCPToolError(
|
|
"Tool execution failed",
|
|
server_name="llm-gateway",
|
|
tool_name="chat",
|
|
tool_args={"prompt": "Hello"},
|
|
error_code="INVALID_ARGS",
|
|
)
|
|
assert error.tool_name == "chat"
|
|
assert error.tool_args == {"prompt": "Hello"}
|
|
assert error.error_code == "INVALID_ARGS"
|
|
assert "tool=chat" in str(error)
|
|
assert "error_code=INVALID_ARGS" in str(error)
|
|
|
|
|
|
class TestMCPServerNotFoundError:
|
|
"""Tests for MCPServerNotFoundError class."""
|
|
|
|
def test_server_not_found(self):
|
|
"""Test server not found error."""
|
|
error = MCPServerNotFoundError("unknown-server")
|
|
assert error.server_name == "unknown-server"
|
|
assert "MCP server not found: unknown-server" in error.message
|
|
assert error.available_servers == []
|
|
|
|
def test_server_not_found_with_available(self):
|
|
"""Test server not found with available servers listed."""
|
|
error = MCPServerNotFoundError(
|
|
"unknown-server",
|
|
available_servers=["server-1", "server-2"],
|
|
)
|
|
assert error.available_servers == ["server-1", "server-2"]
|
|
assert "available=['server-1', 'server-2']" in str(error)
|
|
|
|
|
|
class TestMCPToolNotFoundError:
|
|
"""Tests for MCPToolNotFoundError class."""
|
|
|
|
def test_tool_not_found(self):
|
|
"""Test tool not found error."""
|
|
error = MCPToolNotFoundError("unknown-tool")
|
|
assert error.tool_name == "unknown-tool"
|
|
assert "Tool not found: unknown-tool" in error.message
|
|
assert error.available_tools == []
|
|
|
|
def test_tool_not_found_with_available(self):
|
|
"""Test tool not found with available tools listed."""
|
|
error = MCPToolNotFoundError(
|
|
"unknown-tool",
|
|
available_tools=[
|
|
"tool-1",
|
|
"tool-2",
|
|
"tool-3",
|
|
"tool-4",
|
|
"tool-5",
|
|
"tool-6",
|
|
],
|
|
)
|
|
assert len(error.available_tools) == 6
|
|
# Should show first 5 tools with ellipsis
|
|
assert (
|
|
"available_tools=['tool-1', 'tool-2', 'tool-3', 'tool-4', 'tool-5']..."
|
|
in str(error)
|
|
)
|
|
|
|
|
|
class TestMCPCircuitOpenError:
|
|
"""Tests for MCPCircuitOpenError class."""
|
|
|
|
def test_circuit_open_error(self):
|
|
"""Test circuit open error."""
|
|
error = MCPCircuitOpenError("test-server")
|
|
assert error.server_name == "test-server"
|
|
assert "Circuit breaker open for server: test-server" in error.message
|
|
assert error.failure_count is None
|
|
assert error.reset_timeout is None
|
|
|
|
def test_circuit_open_error_with_details(self):
|
|
"""Test circuit open error with details."""
|
|
error = MCPCircuitOpenError(
|
|
"test-server",
|
|
failure_count=5,
|
|
reset_timeout=30.0,
|
|
)
|
|
assert error.failure_count == 5
|
|
assert error.reset_timeout == 30.0
|
|
assert "failures=5" in str(error)
|
|
assert "reset_in=30.0s" in str(error)
|
|
|
|
|
|
class TestMCPValidationError:
|
|
"""Tests for MCPValidationError class."""
|
|
|
|
def test_validation_error(self):
|
|
"""Test validation error."""
|
|
error = MCPValidationError("Validation failed")
|
|
assert error.message == "Validation failed"
|
|
assert error.tool_name is None
|
|
assert error.field_errors == {}
|
|
|
|
def test_validation_error_with_details(self):
|
|
"""Test validation error with field errors."""
|
|
error = MCPValidationError(
|
|
"Validation failed",
|
|
tool_name="create_issue",
|
|
field_errors={
|
|
"title": "Title is required",
|
|
"priority": "Invalid priority value",
|
|
},
|
|
)
|
|
assert error.tool_name == "create_issue"
|
|
assert error.field_errors == {
|
|
"title": "Title is required",
|
|
"priority": "Invalid priority value",
|
|
}
|
|
assert "tool=create_issue" in str(error)
|
|
assert "fields=['title', 'priority']" in str(error)
|
|
|
|
|
|
class TestExceptionInheritance:
|
|
"""Tests for exception inheritance chain."""
|
|
|
|
def test_all_errors_inherit_from_mcp_error(self):
|
|
"""Test that all custom exceptions inherit from MCPError."""
|
|
assert issubclass(MCPConnectionError, MCPError)
|
|
assert issubclass(MCPTimeoutError, MCPError)
|
|
assert issubclass(MCPToolError, MCPError)
|
|
assert issubclass(MCPServerNotFoundError, MCPError)
|
|
assert issubclass(MCPToolNotFoundError, MCPError)
|
|
assert issubclass(MCPCircuitOpenError, MCPError)
|
|
assert issubclass(MCPValidationError, MCPError)
|
|
|
|
def test_all_errors_inherit_from_exception(self):
|
|
"""Test that base MCPError inherits from Exception."""
|
|
assert issubclass(MCPError, Exception)
|
|
|
|
def test_catch_all_with_mcp_error(self):
|
|
"""Test that all errors can be caught with MCPError."""
|
|
|
|
def raise_connection_error():
|
|
raise MCPConnectionError("Connection failed")
|
|
|
|
def raise_timeout_error():
|
|
raise MCPTimeoutError("Timeout")
|
|
|
|
def raise_tool_error():
|
|
raise MCPToolError("Tool failed")
|
|
|
|
with pytest.raises(MCPError):
|
|
raise_connection_error()
|
|
|
|
with pytest.raises(MCPError):
|
|
raise_timeout_error()
|
|
|
|
with pytest.raises(MCPError):
|
|
raise_tool_error()
|