annator-command-center / tests /integration /test_api_integration.py.bak5
techprotrade's picture
Deploy ATOM FastAPI command center runtime (part 8)
aef804e verified
Raw
History Blame Contribute Delete
15.1 kB
"""
API integration tests for FastAPI endpoints (INTG-01).
Tests cover:
- Agent endpoints (list, create, update, delete)
- Canvas endpoints (present, submit, close)
- Episode endpoints (create, retrieve, search)
- User endpoints (profile, settings)
- Request/response validation
- Error handling (401, 403, 404, 422)
"""
import pytest
from fastapi.testclient import TestClient
from sqlalchemy.orm import Session
from tests.factories.agent_factory import (
AgentFactory,
StudentAgentFactory,
InternAgentFactory,
SupervisedAgentFactory,
AutonomousAgentFactory
)
from tests.factories.user_factory import UserFactory, AdminUserFactory
from tests.factories.execution_factory import AgentExecutionFactory
from tests.factories.episode_factory import EpisodeFactory
from core.models import AgentRegistry, AgentStatus, Episode
class TestAgentEndpoints:
"""Integration tests for agent API endpoints."""
def test_list_agents_returns_empty_list(self, client: TestClient):
"""Test listing agents when none exist."""
response = client.get("/api/agents")
assert response.status_code == 200
data = response.json()
# Response might be wrapped in success response or be direct list
if isinstance(data, dict):
assert "agents" in data or "data" in data or data.get("success") is True
else:
assert isinstance(data, list)
def test_list_agents_filters_by_maturity(self, client: TestClient, db_session: Session):
"""Test listing agents can filter by maturity level."""
# Create agents at different maturity levels
student = StudentAgentFactory(name="Student Agent")
intern = InternAgentFactory(name="Intern Agent")
db_session.commit()
response = client.get("/api/agents")
assert response.status_code == 200
data = response.json()
# Verify agents are returned (exact structure depends on implementation)
def test_create_agent_requires_authentication(self, client_no_auth: TestClient):
"""Test creating agent requires valid JWT token."""
response = client_no_auth.post("/api/agents", json={
"name": "Test Agent",
"category": "testing"
})
# Should return 401 Unauthorized or be redirected
assert response.status_code in [401, 403, 422]
def test_create_agent_with_valid_token(self, client: TestClient, admin_token: str, db_session: Session):
"""Test creating agent with valid authentication."""
response = client.post(
"/api/agents",
json={
"name": "Test Agent",
"category": "testing",
"module_path": "test.module",
"class_name": "TestClass"
},
headers={"Authorization": f"Bearer {admin_token}"}
)
# Note: May not be implemented in current API
# Response should be either success or method not allowed
assert response.status_code in [200, 201, 404, 405, 422]
def test_get_agent_by_id(self, client: TestClient, db_session: Session):
"""Test retrieving a specific agent by ID."""
agent = AgentFactory(name="Retrieval Test Agent")
db_session.commit()
response = client.get(f"/api/agents/{agent.id}")
# May or may not be implemented
assert response.status_code in [200, 404, 405]
def test_update_agent_requires_auth(self, client: TestClient, db_session: Session):
"""Test updating agent requires authentication."""
agent = AgentFactory(name="Update Test Agent")
db_session.commit()
response = client_no_auth.put(f"/api/agents/{agent.id}", json={
"name": "Updated Agent"
})
assert response.status_code in [401, 403, 404, 405]
def test_delete_agent_requires_auth(self, client: TestClient, db_session: Session):
"""Test deleting agent requires authentication."""
agent = AgentFactory(name="Delete Test Agent")
db_session.commit()
response = client_no_auth.delete(f"/api/agents/{agent.id}")
assert response.status_code in [401, 403, 404, 405]
class TestCanvasEndpoints:
"""Integration tests for canvas API endpoints."""
def test_canvas_submit_requires_authentication(self, client_no_auth: TestClient):
"""Test canvas form submission requires authentication."""
response = client_no_auth.post("/api/canvas/submit", json={
"canvas_id": "test-canvas",
"form_data": {"field1": "value1"}
})
assert response.status_code == 401
def test_canvas_submit_with_valid_data(self, client: TestClient, auth_token: str):
"""Test canvas form submission with valid data."""
response = client.post(
"/api/canvas/submit",
json={
"canvas_id": "test-canvas",
"form_data": {"field1": "value1"}
},
headers={"Authorization": f"Bearer {auth_token}"}
)
# Should succeed or return appropriate error (governance, validation)
assert response.status_code in [200, 201, 400, 422]
def test_canvas_status_endpoint(self, client: TestClient, auth_token: str):
"""Test canvas status endpoint returns proper response."""
response = client.get(
"/api/canvas/status",
headers={"Authorization": f"Bearer {auth_token}"}
)
assert response.status_code == 200
data = response.json()
# Verify response structure
if isinstance(data, dict):
assert "status" in data or "data" in data or data.get("success") is True
def test_canvas_submit_with_agent_context(self, client: TestClient, auth_token: str, db_session: Session):
"""Test canvas submission with agent execution context."""
agent = AgentFactory(name="Canvas Agent")
db_session.commit()
response = client.post(
"/api/canvas/submit",
json={
"canvas_id": "test-canvas",
"form_data": {"field1": "value1"},
"agent_id": agent.id
},
headers={"Authorization": f"Bearer {auth_token}"}
)
assert response.status_code in [200, 201, 400, 403, 422]
def test_canvas_submit_invalid_data(self, client: TestClient, auth_token: str):
"""Test canvas submission with invalid data returns validation error."""
response = client.post(
"/api/canvas/submit",
json={
# Missing required fields
"form_data": {"field1": "value1"}
},
headers={"Authorization": f"Bearer {auth_token}"}
)
assert response.status_code == 422
class TestEpisodeEndpoints:
"""Integration tests for episode API endpoints."""
def test_list_episodes_requires_authentication(self, client_no_auth: TestClient):
"""Test listing episodes requires authentication."""
response = client_no_auth.get("/api/episodes")
# Episodes endpoint might not require auth for listing
assert response.status_code in [200, 401, 404]
def test_create_episode_requires_auth(self, client: TestClient, db_session: Session):
"""Test creating episode requires authentication."""
response = client_no_auth.post("/api/episodes/create", json={
"session_id": "test-session",
"agent_id": "test-agent"
})
assert response.status_code in [401, 422]
def test_create_episode_with_valid_data(self, client: TestClient, auth_token: str, db_session: Session):
"""Test creating episode with valid data."""
agent = AgentFactory(name="Episode Agent")
db_session.commit()
response = client.post(
"/api/episodes/create",
json={
"session_id": "test-session-123",
"agent_id": agent.id,
"title": "Test Episode"
},
headers={"Authorization": f"Bearer {auth_token}"}
)
# May succeed or fail depending on session data
assert response.status_code in [200, 201, 400, 404, 422]
def test_list_episodes_for_agent(self, client: TestClient, db_session: Session):
"""Test episode list respects agent filtering."""
agent = AgentFactory(name="Episode List Agent")
episode = EpisodeFactory(agent_id=agent.id, title="Test Episode")
db_session.commit()
response = client.get(f"/api/episodes/{agent.id}/list")
assert response.status_code == 200
data = response.json()
# Verify episodes are returned
def test_retrieve_temporal_episodes(self, client: TestClient, db_session: Session):
"""Test temporal retrieval of episodes."""
agent = AgentFactory(name="Temporal Agent")
db_session.commit()
response = client.post("/api/episodes/retrieve/temporal", json={
"agent_id": agent.id,
"time_range": "7d",
"limit": 10
})
assert response.status_code in [200, 404, 422]
def test_episode_feedback_submission(self, client: TestClient, auth_token: str, db_session: Session):
"""Test submitting feedback for an episode."""
agent = AgentFactory(name="Feedback Agent")
episode = EpisodeFactory(agent_id=agent.id)
db_session.commit()
response = client.post(
f"/api/episodes/{episode.id}/feedback/submit",
json={
"feedback_type": "thumbs_up",
"rating": 5,
"corrections": "Great work!"
},
headers={"Authorization": f"Bearer {auth_token}"}
)
assert response.status_code in [200, 201, 404]
def test_get_episode_stats(self, client: TestClient, db_session: Session):
"""Test retrieving episode statistics for an agent."""
agent = AgentFactory(name="Stats Agent")
db_session.commit()
response = client.get(f"/api/episodes/stats/{agent.id}")
assert response.status_code == 200
data = response.json()
# Verify stats structure
class TestUserEndpoints:
"""Integration tests for user API endpoints."""
def test_get_current_user_requires_auth(self, client_no_auth: TestClient):
"""Test getting current user requires authentication."""
response = client_no_auth.get("/api/users/me")
# May not be implemented or require auth
assert response.status_code in [401, 404, 405]
def test_get_current_user_with_token(self, client: TestClient, auth_token: str):
"""Test getting current user with valid token."""
response = client.get(
"/api/users/me",
headers={"Authorization": f"Bearer {auth_token}"}
)
# May or may not be implemented
assert response.status_code in [200, 404, 405]
def test_update_user_profile(self, client: TestClient, auth_token: str):
"""Test updating user profile."""
response = client.put(
"/api/users/me",
json={
"first_name": "Updated",
"last_name": "Name"
},
headers={"Authorization": f"Bearer {auth_token}"}
)
# May or may not be implemented
assert response.status_code in [200, 404, 405]
def test_list_users_requires_admin(self, client: TestClient, auth_token: str):
"""Test listing users requires admin privileges."""
response = client.get(
"/api/users",
headers={"Authorization": f"Bearer {auth_token}"}
)
# Regular user should not be able to list all users
assert response.status_code in [401, 403, 404, 405]
def test_list_users_with_admin_token(self, client: TestClient, admin_token: str):
"""Test listing users with admin token."""
response = client.get(
"/api/users",
headers={"Authorization": f"Bearer {admin_token}"}
)
# May or may not be implemented
assert response.status_code in [200, 404, 405]
class TestHealthEndpoints:
"""Integration tests for health check endpoints."""
def test_root_endpoint(self, client: TestClient):
"""Test root endpoint returns API info."""
response = client.get("/")
assert response.status_code == 200
data = response.json()
assert isinstance(data, dict)
# Verify basic structure
if "name" in data or "status" in data or "version" in data:
assert True
def test_health_check(self, client: TestClient):
"""Test health check endpoint."""
response = client.get("/health")
assert response.status_code == 200
data = response.json()
assert isinstance(data, dict)
# Should have status field
if "status" in data:
assert data["status"] in ["healthy", "ok", "running", "healthy_check_reload"]
class TestErrorHandling:
"""Integration tests for API error handling."""
def test_404_for_invalid_endpoint(self, client: TestClient):
"""Test 404 response for non-existent endpoint."""
response = client.get("/api/this-endpoint-does-not-exist")
assert response.status_code == 404
def test_422_for_invalid_json(self, client: TestClient):
"""Test 422 response for malformed JSON in POST body."""
response = client.post(
"/api/episodes/create",
data="invalid json{",
headers={"Content-Type": "application/json"}
)
assert response.status_code == 422
def test_405_for_method_not_allowed(self, client: TestClient):
"""Test 405 response for unsupported HTTP method."""
response = client.patch("/api/agents")
assert response.status_code in [405, 404]
def test_missing_required_fields(self, client: TestClient, auth_token: str):
"""Test validation error for missing required fields."""
response = client.post(
"/api/episodes/create",
json={
# Missing agent_id
"session_id": "test"
},
headers={"Authorization": f"Bearer {auth_token}"}
)
assert response.status_code in [400, 422]
def test_invalid_token_format(self, client_no_auth: TestClient):
"""Test authentication fails with invalid token format."""
response = client_no_auth.get(
"/api/canvas/status",
headers={"Authorization": "InvalidFormat token"}
)
assert response.status_code in [401, 403, 422]