#!/usr/bin/env python # -*- coding: utf-8 -*- """ API Caller Test Module Unit tests for ddms_compliance_suite.api_caller.caller module, validates API request and response handling. """ import os import sys import unittest import json from unittest import mock from pathlib import Path # Add project root to Python path sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from ddms_compliance_suite.api_caller.caller import APICaller, APIRequest, APIResponse class MockResponse: """Mock class for requests response""" def __init__(self, json_data, status_code, headers=None, content=None, elapsed_seconds=0.1): self.json_data = json_data self.status_code = status_code self.headers = headers or {"Content-Type": "application/json"} self.content = content or json.dumps(json_data).encode('utf-8') self.elapsed = mock.Mock() self.elapsed.total_seconds.return_value = elapsed_seconds def json(self): return self.json_data def raise_for_status(self): if self.status_code >= 400: from requests.exceptions import HTTPError raise HTTPError(f"HTTP Error: {self.status_code}") class TestAPICaller(unittest.TestCase): """API Caller Test Class""" def setUp(self): """Setup before tests""" self.api_caller = APICaller( default_timeout=30, # Match the default timeout in the actual implementation default_headers={"X-Test": "test-value"} ) @mock.patch('requests.request') def test_successful_get_request(self, mock_request): """Test successful GET request""" # Set mock return value mock_response = MockResponse( json_data={"message": "success", "data": {"id": 1, "name": "Test Project"}}, status_code=200 ) mock_request.return_value = mock_response # Create request object request = APIRequest( method="GET", url="https://api.example.com/test", params={"id": 1} ) # Execute request response = self.api_caller.call_api(request) # Validate self.assertEqual(response.status_code, 200) self.assertEqual(response.json_content["message"], "success") self.assertEqual(response.json_content["data"]["name"], "Test Project") # Validate mock call with proper timeout mock_request.assert_called_once_with( method="GET", url="https://api.example.com/test", headers={"X-Test": "test-value"}, params={"id": 1}, json=None, data=None, timeout=30 # Default timeout from the implementation ) @mock.patch('requests.request') def test_successful_post_request(self, mock_request): """Test successful POST request""" # Set mock return value mock_response = MockResponse( json_data={"message": "created", "id": 123}, status_code=201 ) mock_request.return_value = mock_response # Create request object request = APIRequest( method="POST", url="https://api.example.com/create", json_data={"name": "New Test Project", "description": "Test Description"}, headers={"Content-Type": "application/json"} ) # Execute request response = self.api_caller.call_api(request) # Validate self.assertEqual(response.status_code, 201) self.assertEqual(response.json_content["message"], "created") self.assertEqual(response.json_content["id"], 123) # Validate mock call with proper timeout mock_request.assert_called_once_with( method="POST", url="https://api.example.com/create", headers={"X-Test": "test-value", "Content-Type": "application/json"}, params=None, json={"name": "New Test Project", "description": "Test Description"}, data=None, timeout=30 # Default timeout from the implementation ) @mock.patch('requests.request') def test_error_request(self, mock_request): """Test request failure case""" # Set mock to raise exception from requests.exceptions import HTTPError mock_response = mock.Mock() mock_response.status_code = 404 mock_response.headers = {"Content-Type": "application/json"} mock_response.content = b"Not Found" # Create a proper HTTPError with response attached http_error = HTTPError("404 Client Error") http_error.response = mock_response mock_request.side_effect = http_error # Create request object request = APIRequest( method="GET", url="https://api.example.com/nonexistent" ) # Execute request response = self.api_caller.call_api(request) # Validate self.assertEqual(response.status_code, 404) self.assertIsNone(response.json_content) @mock.patch('requests.request') def test_non_json_response(self, mock_request): """Test non-JSON response""" # Create a real mock for requests.request content = b"Non-JSON content" mock_response = mock.Mock() mock_response.status_code = 200 mock_response.headers = {"Content-Type": "text/plain"} mock_response.content = content mock_response.elapsed.total_seconds.return_value = 0.1 # Setup the JSON decode error when json() is called from requests.exceptions import JSONDecodeError mock_response.json.side_effect = JSONDecodeError("Invalid JSON", "", 0) # Set the mock response for the request mock_request.return_value = mock_response # Create request object request = APIRequest( method="GET", url="https://api.example.com/text" ) # Execute request response = self.api_caller.call_api(request) # Validate self.assertEqual(response.status_code, 200) self.assertEqual(response.content, b"Non-JSON content") self.assertIsNone(response.json_content) @mock.patch('requests.request') def test_custom_timeout(self, mock_request): """Test custom timeout setting""" # Set mock return value mock_response = MockResponse( json_data={"message": "success"}, status_code=200 ) mock_request.return_value = mock_response # Create request object with custom timeout request = APIRequest( method="GET", url="https://api.example.com/slow", timeout=10 ) # Execute request response = self.api_caller.call_api(request) # Validate self.assertEqual(response.status_code, 200) # Validate mock call used custom timeout mock_request.assert_called_once_with( method="GET", url="https://api.example.com/slow", headers={"X-Test": "test-value"}, params=None, json=None, data=None, timeout=10 # Custom timeout specified in the request ) if __name__ == "__main__": unittest.main()