myrmidon / python /tests /mcp_server /utils /test_error_handling.py
tek Atrust
chore(deploy): build monolithic server for Hugging Face
d5ef46f
Raw
History Blame Contribute Delete
6.46 kB
"""Unit tests for MCPErrorFormatter utility."""
import json
from unittest.mock import MagicMock
import httpx
from src.mcp_server.utils.error_handling import MCPErrorFormatter
def test_format_error_basic():
"""Test basic error formatting."""
result = MCPErrorFormatter.format_error(
error_type="validation_error",
message="Invalid input",
)
result_data = json.loads(result)
assert result_data["success"] is False
assert result_data["error"]["type"] == "validation_error"
assert result_data["error"]["message"] == "Invalid input"
assert "details" not in result_data["error"]
assert "suggestion" not in result_data["error"]
def test_format_error_with_all_fields():
"""Test error formatting with all optional fields."""
result = MCPErrorFormatter.format_error(
error_type="connection_timeout",
message="Connection timed out",
details={"url": "http://api.example.com", "timeout": 30},
suggestion="Check network connectivity",
http_status=504,
)
result_data = json.loads(result)
assert result_data["success"] is False
assert result_data["error"]["type"] == "connection_timeout"
assert result_data["error"]["message"] == "Connection timed out"
assert result_data["error"]["details"]["url"] == "http://api.example.com"
assert result_data["error"]["suggestion"] == "Check network connectivity"
assert result_data["error"]["http_status"] == 504
def test_from_http_error_with_json_body():
"""Test formatting from HTTP response with JSON error body."""
mock_response = MagicMock(spec=httpx.Response)
mock_response.status_code = 400
mock_response.json.return_value = {
"detail": {"error": "Field is required"},
"message": "Validation failed",
}
result = MCPErrorFormatter.from_http_error(mock_response, "create item")
result_data = json.loads(result)
assert result_data["success"] is False
# When JSON body has error details, it returns api_error, not http_error
assert result_data["error"]["type"] == "api_error"
assert "Field is required" in result_data["error"]["message"]
assert result_data["error"]["http_status"] == 400
def test_from_http_error_with_text_body():
"""Test formatting from HTTP response with text error body."""
mock_response = MagicMock(spec=httpx.Response)
mock_response.status_code = 404
mock_response.json.side_effect = json.JSONDecodeError("msg", "doc", 0)
mock_response.text = "Resource not found"
result = MCPErrorFormatter.from_http_error(mock_response, "get item")
result_data = json.loads(result)
assert result_data["success"] is False
assert result_data["error"]["type"] == "http_error"
# The message format is "Failed to {operation}: HTTP {status_code}"
assert "Failed to get item: HTTP 404" == result_data["error"]["message"]
assert result_data["error"]["http_status"] == 404
def test_from_exception_timeout():
"""Test formatting from timeout exception."""
# httpx.TimeoutException is a subclass of httpx.RequestError
exception = httpx.TimeoutException("Request timed out after 30s")
result = MCPErrorFormatter.from_exception(exception, "fetch data", {"url": "http://api.example.com"})
result_data = json.loads(result)
assert result_data["success"] is False
# TimeoutException is categorized as request_error since it's a RequestError subclass
assert result_data["error"]["type"] == "request_error"
assert "Request timed out" in result_data["error"]["message"]
assert result_data["error"]["details"]["context"]["url"] == "http://api.example.com"
assert "network connectivity" in result_data["error"]["suggestion"].lower()
def test_from_exception_connection():
"""Test formatting from connection exception."""
exception = httpx.ConnectError("Failed to connect to host")
result = MCPErrorFormatter.from_exception(exception, "connect to API")
result_data = json.loads(result)
assert result_data["success"] is False
assert result_data["error"]["type"] == "connection_error"
assert "Failed to connect" in result_data["error"]["message"]
# The actual suggestion is "Ensure the Archon server is running on the correct port"
assert "archon server" in result_data["error"]["suggestion"].lower()
def test_from_exception_request_error():
"""Test formatting from generic request error."""
exception = httpx.RequestError("Network error")
result = MCPErrorFormatter.from_exception(exception, "make request")
result_data = json.loads(result)
assert result_data["success"] is False
assert result_data["error"]["type"] == "request_error"
assert "Network error" in result_data["error"]["message"]
assert "network connectivity" in result_data["error"]["suggestion"].lower()
def test_from_exception_generic():
"""Test formatting from generic exception."""
exception = ValueError("Invalid value")
result = MCPErrorFormatter.from_exception(exception, "process data")
result_data = json.loads(result)
assert result_data["success"] is False
# ValueError is specifically categorized as validation_error
assert result_data["error"]["type"] == "validation_error"
assert "process data" in result_data["error"]["message"]
assert "Invalid value" in result_data["error"]["details"]["exception_message"]
def test_from_exception_connect_timeout():
"""Test formatting from connect timeout exception."""
exception = httpx.ConnectTimeout("Connection timed out")
result = MCPErrorFormatter.from_exception(exception, "connect to API")
result_data = json.loads(result)
assert result_data["success"] is False
assert result_data["error"]["type"] == "connection_timeout"
assert "Connection timed out" in result_data["error"]["message"]
assert "server is running" in result_data["error"]["suggestion"].lower()
def test_from_exception_read_timeout():
"""Test formatting from read timeout exception."""
exception = httpx.ReadTimeout("Read timed out")
result = MCPErrorFormatter.from_exception(exception, "read data")
result_data = json.loads(result)
assert result_data["success"] is False
assert result_data["error"]["type"] == "read_timeout"
assert "Read timed out" in result_data["error"]["message"]
assert "taking longer than expected" in result_data["error"]["suggestion"].lower()