Spaces:
Sleeping
Sleeping
| import os | |
| import json | |
| import logging | |
| from typing import Dict, Optional, Any | |
| from dataclasses import dataclass | |
| import requests | |
| import time | |
| # Set up logging | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format="%(asctime)s - %(levelname)s - %(message)s", | |
| handlers=[ | |
| logging.FileHandler("api_tests.log"), | |
| logging.StreamHandler(), | |
| ], | |
| ) | |
| logger = logging.getLogger(__name__) | |
| # Configuration | |
| class TestConfig: | |
| """Test configuration settings""" | |
| base_url: str | |
| timeout: int = 30 | |
| verify_ssl: bool = True | |
| debug: bool = True | |
| # Load config from environment or use defaults | |
| config = TestConfig( | |
| base_url=os.getenv("API_BASE_URL", "http://0.0.0.0:8000/v1") | |
| ) | |
| class APIClient: | |
| """API Client for testing""" | |
| def __init__(self, config: TestConfig): | |
| self.config = config | |
| self.session = requests.Session() | |
| def _url(self, path: str) -> str: | |
| """Construct full URL""" | |
| return f"{self.config.base_url}/{path.lstrip('/')}" | |
| def _log_request_details( | |
| self, method: str, url: str, headers: Dict, data: Any | |
| ): | |
| """Log request details for debugging""" | |
| logger.info("\nRequest Details:") | |
| logger.info(f"Method: {method}") | |
| logger.info(f"URL: {url}") | |
| logger.info(f"Headers: {json.dumps(headers, indent=2)}") | |
| logger.info( | |
| f"Data: {json.dumps(data, indent=2) if data else None}" | |
| ) | |
| def _log_response_details(self, response: requests.Response): | |
| """Log response details for debugging""" | |
| logger.info("\nResponse Details:") | |
| logger.info(f"Status Code: {response.status_code}") | |
| logger.info( | |
| f"Headers: {json.dumps(dict(response.headers), indent=2)}" | |
| ) | |
| try: | |
| logger.info( | |
| f"Body: {json.dumps(response.json(), indent=2)}" | |
| ) | |
| except Exception: | |
| logger.info(f"Body: {response.text}") | |
| def _request( | |
| self, | |
| method: str, | |
| path: str, | |
| headers: Optional[Dict] = None, | |
| **kwargs: Any, | |
| ) -> requests.Response: | |
| """Make HTTP request with config defaults""" | |
| url = self._url(path) | |
| headers = headers or {} | |
| if self.config.debug: | |
| self._log_request_details( | |
| method, url, headers, kwargs.get("json") | |
| ) | |
| try: | |
| response = self.session.request( | |
| method=method, | |
| url=url, | |
| headers=headers, | |
| timeout=self.config.timeout, | |
| verify=self.config.verify_ssl, | |
| **kwargs, | |
| ) | |
| if self.config.debug: | |
| self._log_response_details(response) | |
| if response.status_code >= 400: | |
| logger.error( | |
| f"Request failed with status {response.status_code}" | |
| ) | |
| logger.error(f"Response: {response.text}") | |
| response.raise_for_status() | |
| return response | |
| except requests.exceptions.RequestException as e: | |
| logger.error(f"Request failed: {str(e)}") | |
| if hasattr(e, "response") and e.response is not None: | |
| logger.error(f"Error response: {e.response.text}") | |
| raise | |
| class TestRunner: | |
| """Test runner with logging and reporting""" | |
| def __init__(self): | |
| self.client = APIClient(config) | |
| self.results = {"passed": 0, "failed": 0, "total_time": 0} | |
| self.api_key = None | |
| self.user_id = None | |
| self.agent_id = None | |
| def run_test(self, test_name: str, test_func: callable): | |
| """Run a single test with timing and logging""" | |
| logger.info(f"\nRunning test: {test_name}") | |
| start_time = time.time() | |
| try: | |
| test_func() | |
| self.results["passed"] += 1 | |
| logger.info(f"✅ {test_name} - PASSED") | |
| except Exception as e: | |
| self.results["failed"] += 1 | |
| logger.error(f"❌ {test_name} - FAILED: {str(e)}") | |
| logger.exception(e) | |
| end_time = time.time() | |
| duration = end_time - start_time | |
| self.results["total_time"] += duration | |
| logger.info(f"Test duration: {duration:.2f}s") | |
| def test_user_creation(self): | |
| """Test user creation""" | |
| response = self.client._request( | |
| "POST", "/users", json={"username": "test_user"} | |
| ) | |
| data = response.json() | |
| assert "user_id" in data, "No user_id in response" | |
| assert "api_key" in data, "No api_key in response" | |
| self.api_key = data["api_key"] | |
| self.user_id = data["user_id"] | |
| logger.info(f"Created user with ID: {self.user_id}") | |
| def test_create_api_key(self): | |
| """Test API key creation""" | |
| headers = {"api-key": self.api_key} | |
| response = self.client._request( | |
| "POST", | |
| f"/users/{self.user_id}/api-keys", | |
| headers=headers, | |
| json={"name": "test_key"}, | |
| ) | |
| data = response.json() | |
| assert "key" in data, "No key in response" | |
| logger.info("Successfully created new API key") | |
| def test_create_agent(self): | |
| """Test agent creation""" | |
| headers = {"api-key": self.api_key} | |
| agent_config = { | |
| "agent_name": "test_agent", | |
| "model_name": "gpt-4", | |
| "system_prompt": "You are a test agent", | |
| "description": "Test agent description", | |
| "temperature": 0.7, | |
| "max_loops": 1, | |
| } | |
| response = self.client._request( | |
| "POST", "/agent", headers=headers, json=agent_config | |
| ) | |
| data = response.json() | |
| assert "agent_id" in data, "No agent_id in response" | |
| self.agent_id = data["agent_id"] | |
| logger.info(f"Created agent with ID: {self.agent_id}") | |
| # Wait a bit for agent to be ready | |
| time.sleep(2) | |
| def test_list_agents(self): | |
| """Test agent listing""" | |
| headers = {"api-key": self.api_key} | |
| response = self.client._request( | |
| "GET", "/agents", headers=headers | |
| ) | |
| agents = response.json() | |
| assert isinstance(agents, list), "Response is not a list" | |
| assert len(agents) > 0, "No agents returned" | |
| logger.info(f"Successfully retrieved {len(agents)} agents") | |
| def test_agent_completion(self): | |
| """Test agent completion""" | |
| if not self.agent_id: | |
| logger.error("No agent_id available for completion test") | |
| raise ValueError("Agent ID not set") | |
| headers = {"api-key": self.api_key} | |
| completion_request = { | |
| "prompt": "Write 'Hello World!'", | |
| "agent_id": str( | |
| self.agent_id | |
| ), # Ensure UUID is converted to string | |
| "max_tokens": 100, | |
| "stream": False, | |
| "temperature_override": 0.7, | |
| } | |
| logger.info( | |
| f"Sending completion request for agent {self.agent_id}" | |
| ) | |
| response = self.client._request( | |
| "POST", | |
| "/agent/completions", | |
| headers=headers, | |
| json=completion_request, | |
| ) | |
| data = response.json() | |
| assert "response" in data, "No response in completion" | |
| logger.info(f"Completion response: {data.get('response')}") | |
| def run_all_tests(self): | |
| """Run all tests and generate report""" | |
| logger.info("\n" + "=" * 50) | |
| logger.info("Starting API test suite...") | |
| logger.info(f"Base URL: {config.base_url}") | |
| logger.info("=" * 50 + "\n") | |
| # Define test sequence | |
| tests = [ | |
| ("User Creation", self.test_user_creation), | |
| ("API Key Creation", self.test_create_api_key), | |
| ("Agent Creation", self.test_create_agent), | |
| ("List Agents", self.test_list_agents), | |
| ("Agent Completion", self.test_agent_completion), | |
| ] | |
| # Run tests | |
| for test_name, test_func in tests: | |
| self.run_test(test_name, test_func) | |
| # Generate report | |
| self.print_report() | |
| def print_report(self): | |
| """Print test results report""" | |
| total_tests = self.results["passed"] + self.results["failed"] | |
| success_rate = ( | |
| (self.results["passed"] / total_tests * 100) | |
| if total_tests > 0 | |
| else 0 | |
| ) | |
| report = f""" | |
| \n{'='*50} | |
| API TEST RESULTS | |
| {'='*50} | |
| Total Tests: {total_tests} | |
| Passed: {self.results['passed']} ✅ | |
| Failed: {self.results['failed']} ❌ | |
| Success Rate: {success_rate:.2f}% | |
| Total Time: {self.results['total_time']:.2f}s | |
| {'='*50} | |
| """ | |
| logger.info(report) | |
| if __name__ == "__main__": | |
| try: | |
| runner = TestRunner() | |
| runner.run_all_tests() | |
| except KeyboardInterrupt: | |
| logger.info("\nTest suite interrupted by user") | |
| except Exception as e: | |
| logger.error(f"Test suite failed: {str(e)}") | |
| logger.exception(e) | |