Skip to main content
Glama
test_api_client.py13.6 kB
"""Unit tests for KYC API client.""" import pytest from unittest.mock import AsyncMock, MagicMock, patch import httpx from src.clients.kyc_api_client import ( KYCAPIClient, APIError, ValidationError, ServiceUnavailableError, ) class TestKYCAPIClient: """Test suite for KYC API client.""" def test_initialization(self): """Test client initialization.""" client = KYCAPIClient( base_url="https://api.test.com", api_key="test_key", jwt_token="test_token", timeout=30, max_connections=100 ) assert client.base_url == "https://api.test.com" assert client.api_key == "test_key" assert client.jwt_token == "test_token" assert client.timeout == 30 @pytest.mark.asyncio async def test_post_success(self, mock_api_client): """Test successful POST request.""" mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = {"data": {"result": "success"}} mock_response.raise_for_status = MagicMock() mock_api_client.client.post = AsyncMock(return_value=mock_response) result = await mock_api_client.post( endpoint="/test", data={"param": "value"} ) assert result == {"data": {"result": "success"}} mock_api_client.client.post.assert_called_once() @pytest.mark.asyncio async def test_post_with_custom_headers(self, mock_api_client): """Test POST request with custom headers.""" mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = {"data": {}} mock_response.raise_for_status = MagicMock() mock_api_client.client.post = AsyncMock(return_value=mock_response) custom_headers = {"X-Custom": "value"} await mock_api_client.post( endpoint="/test", data={}, headers=custom_headers ) call_args = mock_api_client.client.post.call_args assert call_args[1]["headers"] == custom_headers @pytest.mark.asyncio async def test_post_validation_error_422(self, mock_api_client): """Test handling of 422 validation error.""" mock_response = MagicMock() mock_response.status_code = 422 mock_response.json.return_value = { "message": "Validation failed", "errors": [{"field": "pan", "message": "Invalid format"}] } request = MagicMock() request.url = "https://api.test.com/test" request.method = "POST" mock_response.request = request error = httpx.HTTPStatusError( message="422", request=request, response=mock_response ) mock_response.raise_for_status = MagicMock(side_effect=error) mock_api_client.client.post = AsyncMock(return_value=mock_response) with pytest.raises(ValidationError): await mock_api_client.post(endpoint="/test", data={}) @pytest.mark.asyncio async def test_post_service_unavailable_503(self, mock_api_client): """Test handling of 503 service unavailable error.""" mock_response = MagicMock() mock_response.status_code = 503 mock_response.json.return_value = {"message": "Service unavailable"} request = MagicMock() request.url = "https://api.test.com/test" request.method = "POST" mock_response.request = request error = httpx.HTTPStatusError( message="503", request=request, response=mock_response ) mock_response.raise_for_status = MagicMock(side_effect=error) mock_api_client.client.post = AsyncMock(return_value=mock_response) with pytest.raises(ServiceUnavailableError, match="temporarily unavailable"): await mock_api_client.post(endpoint="/test", data={}) @pytest.mark.asyncio async def test_post_server_error_500(self, mock_api_client): """Test handling of 500 server error.""" mock_response = MagicMock() mock_response.status_code = 500 mock_response.json.return_value = {"message": "Internal server error"} request = MagicMock() request.url = "https://api.test.com/test" request.method = "POST" mock_response.request = request error = httpx.HTTPStatusError( message="500", request=request, response=mock_response ) mock_response.raise_for_status = MagicMock(side_effect=error) mock_api_client.client.post = AsyncMock(return_value=mock_response) with pytest.raises(ServiceUnavailableError, match="Server error"): await mock_api_client.post(endpoint="/test", data={}) @pytest.mark.asyncio async def test_post_unauthorized_401(self, mock_api_client): """Test handling of 401 unauthorized error.""" mock_response = MagicMock() mock_response.status_code = 401 mock_response.json.return_value = {"message": "Unauthorized"} request = MagicMock() request.url = "https://api.test.com/test" request.method = "POST" mock_response.request = request error = httpx.HTTPStatusError( message="401", request=request, response=mock_response ) mock_response.raise_for_status = MagicMock(side_effect=error) mock_api_client.client.post = AsyncMock(return_value=mock_response) with pytest.raises(APIError, match="401"): await mock_api_client.post(endpoint="/test", data={}) @pytest.mark.asyncio async def test_post_request_error(self, mock_api_client): """Test handling of request errors (network issues).""" mock_api_client.client.post = AsyncMock( side_effect=httpx.RequestError("Connection failed") ) with pytest.raises(APIError, match="Request failed"): await mock_api_client.post(endpoint="/test", data={}) @pytest.mark.asyncio async def test_get_success(self, mock_api_client): """Test successful GET request.""" mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = {"data": {"result": "success"}} mock_response.raise_for_status = MagicMock() mock_api_client.client.get = AsyncMock(return_value=mock_response) result = await mock_api_client.get( endpoint="/test", params={"id": "123"} ) assert result == {"data": {"result": "success"}} mock_api_client.client.get.assert_called_once() @pytest.mark.asyncio async def test_get_with_params(self, mock_api_client): """Test GET request with query parameters.""" mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = {"data": {}} mock_response.raise_for_status = MagicMock() mock_api_client.client.get = AsyncMock(return_value=mock_response) params = {"id": "123", "type": "test"} await mock_api_client.get(endpoint="/test", params=params) call_args = mock_api_client.client.get.call_args assert call_args[1]["params"] == params @pytest.mark.asyncio async def test_get_error_handling(self, mock_api_client): """Test GET request error handling.""" mock_response = MagicMock() mock_response.status_code = 404 mock_response.json.return_value = {"message": "Not found"} request = MagicMock() request.url = "https://api.test.com/test" request.method = "GET" mock_response.request = request error = httpx.HTTPStatusError( message="404", request=request, response=mock_response ) mock_response.raise_for_status = MagicMock(side_effect=error) mock_api_client.client.get = AsyncMock(return_value=mock_response) with pytest.raises(APIError): await mock_api_client.get(endpoint="/test") @pytest.mark.asyncio async def test_close(self, mock_api_client): """Test closing the client.""" mock_api_client.client.aclose = AsyncMock() await mock_api_client.close() mock_api_client.client.aclose.assert_called_once() def test_map_error_422(self, mock_api_client): """Test error mapping for 422 status.""" mock_response = MagicMock() mock_response.status_code = 422 mock_response.json.return_value = {"message": "Validation error"} request = MagicMock() mock_response.request = request error = httpx.HTTPStatusError( message="422", request=request, response=mock_response ) mapped = mock_api_client._map_error(error) assert isinstance(mapped, ValidationError) def test_map_error_503(self, mock_api_client): """Test error mapping for 503 status.""" mock_response = MagicMock() mock_response.status_code = 503 mock_response.json.return_value = {"message": "Service unavailable"} request = MagicMock() mock_response.request = request error = httpx.HTTPStatusError( message="503", request=request, response=mock_response ) mapped = mock_api_client._map_error(error) assert isinstance(mapped, ServiceUnavailableError) def test_map_error_500_range(self, mock_api_client): """Test error mapping for 500+ status codes.""" for status_code in [500, 501, 502, 504]: mock_response = MagicMock() mock_response.status_code = status_code mock_response.json.return_value = {"message": "Server error"} request = MagicMock() mock_response.request = request error = httpx.HTTPStatusError( message=str(status_code), request=request, response=mock_response ) mapped = mock_api_client._map_error(error) assert isinstance(mapped, ServiceUnavailableError) def test_map_error_generic(self, mock_api_client): """Test error mapping for generic errors.""" mock_response = MagicMock() mock_response.status_code = 400 mock_response.json.return_value = {"message": "Bad request"} request = MagicMock() mock_response.request = request error = httpx.HTTPStatusError( message="400", request=request, response=mock_response ) mapped = mock_api_client._map_error(error) assert isinstance(mapped, APIError) assert "400" in str(mapped) def test_map_error_invalid_json_response(self, mock_api_client): """Test error mapping when response JSON is invalid.""" mock_response = MagicMock() mock_response.status_code = 400 mock_response.json.side_effect = Exception("Invalid JSON") request = MagicMock() mock_response.request = request error = httpx.HTTPStatusError( message="400", request=request, response=mock_response ) # Should handle JSON parsing error gracefully mapped = mock_api_client._map_error(error) assert isinstance(mapped, APIError) @pytest.mark.asyncio async def test_retry_on_failure(self): """Test that requests are retried on failure.""" client = KYCAPIClient( base_url="https://api.test.com", api_key="test_key", jwt_token="test_token" ) # Mock to fail twice then succeed call_count = 0 async def mock_post(*args, **kwargs): nonlocal call_count call_count += 1 if call_count < 3: raise httpx.RequestError("Temporary failure") mock_response = MagicMock() mock_response.status_code = 200 mock_response.json.return_value = {"data": "success"} mock_response.raise_for_status = MagicMock() return mock_response client.client.post = mock_post result = await client.post(endpoint="/test", data={}) assert result == {"data": "success"} assert call_count == 3 # Failed twice, succeeded on third attempt @pytest.mark.asyncio async def test_retry_exhaustion(self): """Test that retries are exhausted after max attempts.""" client = KYCAPIClient( base_url="https://api.test.com", api_key="test_key", jwt_token="test_token" ) # Mock to always fail client.client.post = AsyncMock( side_effect=httpx.RequestError("Persistent failure") ) with pytest.raises(APIError): await client.post(endpoint="/test", data={})

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/CTD-Techs/CTD-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server