You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
swarms/api/agent_api_test.py

486 lines
14 KiB

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__)
from typing import Dict, Optional, Tuple
from uuid import UUID
BASE_URL = "http://0.0.0.0:8000/v1"
# Configuration
@dataclass
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()
<<<<<<< HEAD
=======
def create_test_user(session: TestSession) -> Tuple[bool, str]:
"""Create a test user and store credentials in session."""
logger.info("Creating test user")
try:
response = requests.post(
f"{BASE_URL}/users",
json={"username": f"test_user_{int(time.time())}"},
)
if response.status_code == 200:
data = response.json()
session.user_id = data["user_id"]
session.api_key = data["api_key"]
logger.success(f"Created user with ID: {session.user_id}")
return True, "Success"
else:
logger.error(f"Failed to create user: {response.text}")
return False, response.text
except Exception as e:
logger.exception("Exception during user creation")
return False, str(e)
def create_additional_api_key(
session: TestSession,
) -> Tuple[bool, str]:
"""Test creating an additional API key."""
logger.info("Creating additional API key")
try:
response = requests.post(
f"{BASE_URL}/users/{session.user_id}/api-keys",
headers=session.headers,
json={"name": "Test Key"},
)
if response.status_code == 200:
logger.success("Created additional API key")
return True, response.json()["key"]
else:
logger.error(f"Failed to create API key: {response.text}")
return False, response.text
except Exception as e:
logger.exception("Exception during API key creation")
return False, str(e)
def test_create_agent(
session: TestSession,
) -> Tuple[bool, Optional[UUID]]:
"""Test creating a new agent."""
logger.info("Testing agent creation")
payload = {
"agent_name": f"Test Agent {int(time.time())}",
"system_prompt": "You are a helpful assistant",
"model_name": "gpt-4",
"description": "Test agent",
"tags": ["test", "automated"],
}
try:
response = requests.post(
f"{BASE_URL}/agent", headers=session.headers, json=payload
)
if response.status_code == 200:
agent_id = response.json()["agent_id"]
session.test_agents.append(agent_id)
logger.success(f"Created agent with ID: {agent_id}")
return True, agent_id
else:
logger.error(f"Failed to create agent: {response.text}")
return False, None
except Exception:
logger.exception("Exception during agent creation")
return False, None
def test_list_user_agents(session: TestSession) -> bool:
"""Test listing user's agents."""
logger.info("Testing user agent listing")
try:
response = requests.get(
f"{BASE_URL}/users/me/agents", headers=session.headers
)
if response.status_code == 200:
agents = response.json()
logger.success(f"Found {len(agents)} user agents")
return True
else:
logger.error(
f"Failed to list user agents: {response.text}"
)
return False
except Exception:
logger.exception("Exception during agent listing")
return False
def test_agent_operations(
session: TestSession, agent_id: UUID
) -> bool:
"""Test various operations on an agent."""
logger.info(f"Testing operations for agent {agent_id}")
# Test update
try:
update_response = requests.patch(
f"{BASE_URL}/agent/{agent_id}",
headers=session.headers,
json={
"description": "Updated description",
"tags": ["test", "updated"],
},
)
if update_response.status_code != 200:
logger.error(
f"Failed to update agent: {update_response.text}"
)
return False
# Test metrics
metrics_response = requests.get(
f"{BASE_URL}/agent/{agent_id}/metrics",
headers=session.headers,
)
if metrics_response.status_code != 200:
logger.error(
f"Failed to get agent metrics: {metrics_response.text}"
)
return False
logger.success("Successfully performed agent operations")
return True
except Exception:
logger.exception("Exception during agent operations")
return False
def test_completion(session: TestSession, agent_id: UUID) -> bool:
"""Test running a completion."""
logger.info("Testing completion")
payload = {
"prompt": "What is the weather like today?",
"agent_id": agent_id,
"max_tokens": 100,
}
try:
response = requests.post(
f"{BASE_URL}/agent/completions",
headers=session.headers,
json=payload,
)
if response.status_code == 200:
completion_data = response.json()
print(completion_data)
logger.success(
f"Got completion, used {completion_data['token_usage']['total_tokens']} tokens"
)
return True
else:
logger.error(f"Failed to get completion: {response.text}")
return False
except Exception:
logger.exception("Exception during completion")
return False
def cleanup_test_resources(session: TestSession):
"""Clean up all test resources."""
logger.info("Cleaning up test resources")
# Delete test agents
for agent_id in session.test_agents:
>>>>>>> 68728698 ([AGENT][LiteLLM FIX] [API FIX])
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__":
<<<<<<< HEAD
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)
=======
success = run_test_workflow()
print(success)
>>>>>>> 68728698 ([AGENT][LiteLLM FIX] [API FIX])