test_error_handling.py•5.34 kB
#!/usr/bin/env python3
# Tests for generic API error handling in the cBioPortal MCP Server
import pytest
from unittest.mock import patch
import httpx
@pytest.mark.parametrize(
"method_name_to_test, method_args, method_kwargs, exception_to_raise, expected_error_prefix",
[
(
"get_study_details",
("non_existent_study",), # args tuple
{}, # kwargs dict
httpx.HTTPStatusError(
message="404 Client Error: Not Found for url: /api/studies/non_existent_study",
request=httpx.Request("GET", "/api/studies/non_existent_study"),
response=httpx.Response(
404, request=httpx.Request("GET", "/api/studies/non_existent_study")
),
),
"Failed to get study details for non_existent_study",
),
(
"get_cancer_studies",
(), # args tuple
{"page_number": 0, "page_size": 10}, # kwargs dict
httpx.RequestError(
message="Timeout occurred while requesting /api/studies",
request=httpx.Request("GET", "/api/studies"),
),
"Failed to get cancer studies",
),
(
"get_molecular_profiles",
("study_123",), # args: study_id
{"page_number": 0, "page_size": 10}, # kwargs
httpx.HTTPStatusError(
message="500 Server Error: Internal Server Error for url: /api/studies/study_123/molecular-profiles",
request=httpx.Request(
"GET", "/api/studies/study_123/molecular-profiles"
),
response=httpx.Response(
500,
request=httpx.Request(
"GET", "/api/studies/study_123/molecular-profiles"
),
),
),
"Failed to get molecular profiles for study_123",
),
(
"get_genes",
(["TP53"],), # args: gene_ids as a list
{"gene_id_type": "HUGO_SYMBOL", "projection": "SUMMARY"}, # kwargs
httpx.RequestError(
message="Network error while fetching gene TP53",
request=httpx.Request("GET", "/api/genes/fetch"),
),
"Failed to get gene information",
),
(
"get_clinical_data",
("study_forbidden",), # args: study_id
{}, # kwargs: no attribute_ids, fetch all
httpx.HTTPStatusError(
message="403 Client Error: Forbidden for url: /api/studies/study_forbidden/clinical-data",
request=httpx.Request(
"GET", "/api/studies/study_forbidden/clinical-data"
),
response=httpx.Response(
403,
request=httpx.Request(
"GET", "/api/studies/study_forbidden/clinical-data"
),
),
),
"Failed to get clinical data for study study_forbidden",
),
(
"get_clinical_data",
("study_network_error",), # args: study_id
{"attribute_ids": ["ATTR1", "ATTR2"]}, # kwargs: specific attributes
httpx.RequestError(
message="Network error while fetching clinical data for study_network_error",
request=httpx.Request(
"POST", "/api/studies/study_network_error/clinical-data/fetch"
),
),
"Failed to get clinical data for study study_network_error",
),
],
)
@patch("cbioportal_mcp.api_client.APIClient.make_api_request")
@pytest.mark.asyncio
async def test_generic_api_error_handling(
mock_make_api_request,
cbioportal_server_instance, # This fixture is defined in conftest.py
method_name_to_test,
method_args,
method_kwargs,
exception_to_raise,
expected_error_prefix,
):
"""Test generic error handling for API calls that raise httpx exceptions."""
server = cbioportal_server_instance
mock_make_api_request.side_effect = exception_to_raise
method_to_call = getattr(server, method_name_to_test)
actual_args = []
if (
method_name_to_test == "get_genes"
and len(method_args) == 1
and isinstance(method_args[0], tuple)
):
actual_args = list(method_args[0])
else:
actual_args = list(method_args)
result = await method_to_call(*actual_args, **method_kwargs)
assert "error" in result, (
f"Result should contain an error key for {method_name_to_test}"
)
assert expected_error_prefix in result["error"], (
f"Error message for {method_name_to_test} did not contain expected prefix '{expected_error_prefix}'. Got: {result['error']}"
)
assert (
str(
exception_to_raise.args[0]
if exception_to_raise.args
else str(exception_to_raise)
)
in result["error"]
), (
f"Error message for {method_name_to_test} did not contain the original exception message. Got: {result['error']}"
)
assert mock_make_api_request.called, (
f"_make_api_request was not called for {method_name_to_test}"
)