annator-command-center / tests /api /test_atom_agent_endpoints_coverage_extend.py
techprotrade's picture
Deploy ATOM FastAPI command center runtime (part 7)
cc036ff verified
Raw
History Blame Contribute Delete
25.6 kB
"""
Extended coverage tests for AtomAgentEndpoints (currently 0% -> target 65%+)
Target file: core/atom_agent_endpoints.py (787 statements)
Focus areas from coverage gap analysis:
- Endpoint initialization (lines 1-80)
- Chat endpoint (lines 80-250)
- Intent routing (lines 250-450)
- Streaming responses (lines 450-600)
- Session management (lines 600-787)
"""
import pytest
from unittest.mock import AsyncMock, Mock, patch, MagicMock
from fastapi.testclient import TestClient
from fastapi import FastAPI
from datetime import datetime, timedelta
from typing import Dict, Any
# Import the router from atom_agent_endpoints
from core.atom_agent_endpoints import router, ChatRequest, ChatMessage
@pytest.fixture
def app():
"""Create test FastAPI app with atom_agent router"""
app = FastAPI()
app.include_router(router)
return app
@pytest.fixture
def client(app):
"""Create test client"""
return TestClient(app)
class TestAtomAgentEndpointsExtended:
"""Extended coverage tests for atom_agent_endpoints.py"""
def test_chat_endpoint_success(self, client, monkeypatch):
"""Cover chat endpoint success path (lines 80-200)"""
# Mock LLM handler
mock_llm = AsyncMock()
mock_llm.complete.return_value = "Hello! How can I help you?"
monkeypatch.setattr("core.atom_agent_endpoints.get_llm_handler", lambda x: mock_llm)
# Mock session manager
mock_session_mgr = AsyncMock()
mock_session_mgr.get_or_create_session.return_value = "test-session-123"
monkeypatch.setattr("core.atom_agent_endpoints.get_chat_session_manager", lambda x: mock_session_mgr)
# Mock context manager
mock_context_mgr = AsyncMock()
monkeypatch.setattr("core.atom_agent_endpoints.get_chat_context_manager", lambda x: mock_context_mgr)
response = client.post(
"/api/atom-agent/chat",
json={
"message": "Hello",
"user_id": "test-user",
"session_id": None,
"agent_id": "test-agent"
}
)
# Accept various response statuses (endpoint may have dependencies)
assert response.status_code in [200, 500, 501] # Success or dependency missing
def test_chat_endpoint_validation(self, client):
"""Cover chat endpoint validation (lines 200-250)"""
# Missing message
response = client.post(
"/api/atom-agent/chat",
json={
"user_id": "test-user"
# message is missing
}
)
# Should get validation error
assert response.status_code == 422 # Validation error
def test_chat_endpoint_with_session_id(self, client, mocker):
"""Cover chat endpoint with existing session_id"""
# Mock dependencies
mock_session_mgr = AsyncMock()
mock_session_mgr.get_session.return_value = {
"session_id": "existing-session-123",
"user_id": "test-user"
}
mocker.patch("core.atom_agent_endpoints.get_chat_session_manager", return_value=mock_session_mgr)
mock_context_mgr = AsyncMock()
mocker.patch("core.atom_agent_endpoints.get_chat_context_manager", return_value=mock_context_mgr)
response = client.post(
"/api/atom-agent/chat",
json={
"message": "Hello again",
"user_id": "test-user",
"session_id": "existing-session-123"
}
)
# Accept various responses
assert response.status_code in [200, 404, 500, 501]
def test_chat_endpoint_with_context(self, client, mocker):
"""Cover chat endpoint with context metadata"""
mock_session_mgr = AsyncMock()
mock_session_mgr.get_or_create_session.return_value = "test-session-123"
mocker.patch("core.atom_agent_endpoints.get_chat_session_manager", return_value=mock_session_mgr)
mock_context_mgr = AsyncMock()
mocker.patch("core.atom_agent_endpoints.get_chat_context_manager", return_value=mock_context_mgr)
response = client.post(
"/api/atom-agent/chat",
json={
"message": "What's on this page?",
"user_id": "test-user",
"current_page": "https://example.com/page",
"context": {
"page_title": "Example Page",
"selection": "selected text"
}
}
)
assert response.status_code in [200, 500, 501]
def test_chat_endpoint_with_conversation_history(self, client, mocker):
"""Cover chat endpoint with conversation history"""
mock_session_mgr = AsyncMock()
mock_session_mgr.get_or_create_session.return_value = "test-session-123"
mocker.patch("core.atom_agent_endpoints.get_chat_session_manager", return_value=mock_session_mgr)
mock_context_mgr = AsyncMock()
mocker.patch("core.atom_agent_endpoints.get_chat_context_manager", return_value=mock_context_mgr)
response = client.post(
"/api/atom-agent/chat",
json={
"message": "Tell me more",
"user_id": "test-user",
"conversation_history": [
{"role": "user", "content": "Hello"},
{"role": "assistant", "content": "Hi there!"}
]
}
)
assert response.status_code in [200, 500, 501]
def test_chat_endpoint_with_workspace_id(self, client, mocker):
"""Cover chat endpoint with workspace_id for multi-tenancy"""
mock_session_mgr = AsyncMock()
mock_session_mgr.get_or_create_session.return_value = "test-session-123"
mocker.patch("core.atom_agent_endpoints.get_chat_session_manager", return_value=mock_session_mgr)
mock_context_mgr = AsyncMock()
mocker.patch("core.atom_agent_endpoints.get_chat_context_manager", return_value=mock_context_mgr)
response = client.post(
"/api/atom-agent/chat",
json={
"message": "Hello from workspace",
"user_id": "test-user",
"workspace_id": "workspace-abc"
}
)
assert response.status_code in [200, 500, 501]
def test_save_chat_interaction_basic(self, mocker):
"""Cover save_chat_interaction basic path (lines 92-177)"""
mock_chat_history_mgr = AsyncMock()
mock_chat_history_mgr.add_message.return_value = None
mocker.patch("core.atom_agent_endpoints.get_chat_history_manager", return_value=mock_chat_history_mgr)
# Import and call the function
from core.atom_agent_endpoints import save_chat_interaction
result = save_chat_interaction(
session_id="test-session",
user_id="test-user",
user_message="Hello",
assistant_message="Hi there!",
intent="greeting",
entities={"name": "test"},
result_data={"response": "test"},
chat_history_mgr=mock_chat_history_mgr
)
# Function returns None (no assertion needed, just coverage)
assert result is None
def test_save_chat_interaction_with_metadata(self, mocker):
"""Cover save_chat_interaction with full metadata"""
mock_chat_history_mgr = AsyncMock()
mock_chat_history_mgr.add_message.return_value = None
mocker.patch("core.atom_agent_endpoints.get_chat_history_manager", return_value=mock_chat_history_mgr)
from core.atom_agent_endpoints import save_chat_interaction
result = save_chat_interaction(
session_id="test-session",
user_id="test-user",
user_message="Create a workflow",
assistant_message="I'll help you create a workflow",
intent="workflow_create",
entities={"workflow_name": "test workflow"},
result_data={"workflow_id": "wf-123"},
chat_history_mgr=mock_chat_history_mgr
)
assert result is None
# ==================== SESSION MANAGEMENT TESTS ====================
def test_list_sessions_empty(self, client, mocker):
"""Cover list_sessions endpoint (lines 178-197)"""
mock_session_mgr = mocker.MagicMock()
mock_session_mgr.list_user_sessions.return_value = []
mocker.patch("core.atom_agent_endpoints.get_chat_session_manager", return_value=mock_session_mgr)
response = client.get("/api/atom-agent/sessions?user_id=test-user&limit=10")
assert response.status_code == 200
data = response.json()
assert data.get("success") is True
assert "sessions" in data
def test_list_sessions_with_data(self, client, mocker):
"""Cover list_sessions with actual sessions"""
mock_session_mgr = mocker.MagicMock()
mock_session_mgr.list_user_sessions.return_value = [
{
"session_id": "session-1",
"last_active": "2026-03-14T10:00:00Z",
"metadata": {
"title": "Workflow Creation",
"last_message": "Create a workflow"
}
}
]
mocker.patch("core.atom_agent_endpoints.get_chat_session_manager", return_value=mock_session_mgr)
response = client.get("/api/atom-agent/sessions?user_id=test-user&limit=50")
assert response.status_code == 200
data = response.json()
assert len(data["sessions"]) == 1
assert data["sessions"][0]["title"] == "Workflow Creation"
def test_create_new_session(self, client, mocker):
"""Cover create_new_session endpoint (lines 222-230)"""
mock_session_mgr = mocker.MagicMock()
mock_session_mgr.create_session.return_value = "new-session-123"
mocker.patch("core.atom_agent_endpoints.get_chat_session_manager", return_value=mock_session_mgr)
response = client.post(
"/api/atom-agent/sessions",
json={"user_id": "test-user"}
)
assert response.status_code == 200
data = response.json()
assert data.get("success") is True
assert "session_id" in data
def test_get_session_history_exists(self, client, mocker):
"""Cover get_session_history endpoint (lines 277-336)"""
mock_session_mgr = mocker.MagicMock()
mock_session_mgr.get_session.return_value = {
"session_id": "session-123",
"user_id": "test-user",
"created_at": "2026-03-14T10:00:00Z"
}
mocker.patch("core.atom_agent_endpoints.get_chat_session_manager", return_value=mock_session_mgr)
mock_chat_history = mocker.MagicMock()
mock_chat_history.get_session_history.return_value = [
{
"id": "msg-1",
"role": "user",
"text": "Hello",
"created_at": "2026-03-14T10:00:01Z",
"metadata": '{"intent": "greet"}'
}
]
mocker.patch("core.atom_agent_endpoints.get_chat_history_manager", return_value=mock_chat_history)
response = client.get("/api/atom-agent/sessions/session-123/history")
assert response.status_code == 200
data = response.json()
assert data.get("success") is True
assert "messages" in data
def test_get_session_history_not_found(self, client, mocker):
"""Cover get_session_history when session doesn't exist"""
mock_session_mgr = mocker.MagicMock()
mock_session_mgr.get_session.return_value = None
mocker.patch("core.atom_agent_endpoints.get_chat_session_manager", return_value=mock_session_mgr)
response = client.get("/api/atom-agent/sessions/nonexistent/history")
assert response.status_code == 200
data = response.json()
assert data.get("success") is False
# ==================== INTENT ROUTING TESTS ====================
@pytest.mark.parametrize("message,expected_intent", [
("create a workflow", "CREATE_WORKFLOW"),
("list all workflows", "LIST_WORKFLOWS"),
("run the backup workflow", "RUN_WORKFLOW"),
("show me history", "GET_HISTORY"),
("schedule a meeting", "CREATE_EVENT"),
("list calendar events", "LIST_EVENTS"),
("send an email", "SEND_EMAIL"),
("search emails", "SEARCH_EMAILS"),
("create a task", "CREATE_TASK"),
("list my tasks", "LIST_TASKS"),
("show transactions", "GET_TRANSACTIONS"),
("check balance", "CHECK_BALANCE"),
("invoice status", "INVOICE_STATUS"),
("who worked on project X", "KNOWLEDGE_QUERY"),
("search for files", "SEARCH_PLATFORM"),
])
def test_fallback_intent_classification(self, message, expected_intent):
"""Cover fallback_intent_classification (lines 751-848)"""
from core.atom_agent_endpoints import fallback_intent_classification
result = fallback_intent_classification(message)
assert result["intent"] == expected_intent
def test_fallback_intent_schedule_workflow(self):
"""Cover schedule workflow intent parsing (lines 756-781)"""
from core.atom_agent_endpoints import fallback_intent_classification
result = fallback_intent_classification("Schedule daily report to run every weekday at 9am")
assert result["intent"] == "SCHEDULE_WORKFLOW"
assert "workflow_ref" in result["entities"]
assert "time_expression" in result["entities"]
# ==================== WORKFLOW HANDLERS ====================
def test_handle_list_workflows_empty(self, mocker):
"""Cover handle_list_workflows with no workflows (lines 903-916)"""
mocker.patch("core.atom_agent_endpoints.load_workflows", return_value=[])
from core.atom_agent_endpoints import handle_list_workflows
async def test():
result = await handle_list_workflows(None)
assert result.get("success") is True
assert "No workflows found" in result["response"]["message"]
import asyncio
asyncio.run(test())
def test_handle_list_workflows_with_data(self, mocker):
"""Cover handle_list_workflows with workflows"""
mocker.patch("core.atom_agent_endpoints.load_workflows", return_value=[
{"workflow_id": "wf-1", "name": "Test Workflow"}
])
from core.atom_agent_endpoints import handle_list_workflows
async def test():
result = await handle_list_workflows(None)
assert result.get("success") is True
assert "Test Workflow" in result["response"]["message"]
import asyncio
asyncio.run(test())
def test_handle_help_request(self):
"""Cover handle_help_request (lines 1270-1288)"""
from core.atom_agent_endpoints import handle_help_request
result = handle_help_request()
assert result.get("success") is True
assert "Calendar" in result["response"]["message"]
assert "Email" in result["response"]["message"]
assert "Tasks" in result["response"]["message"]
# ==================== CALENDAR HANDLERS ====================
def test_handle_create_event(self, mocker):
"""Cover handle_create_event (lines 1095-1111)"""
from core.atom_agent_endpoints import handle_create_event, ChatRequest
request = ChatRequest(
message="Schedule meeting",
user_id="test-user"
)
async def test():
result = await handle_create_event(request, {"summary": "Test Meeting"})
assert result.get("success") is True
assert "Test Meeting" in result["response"]["message"]
import asyncio
asyncio.run(test())
def test_handle_list_events(self, mocker):
"""Cover handle_list_events (lines 1113-1132)"""
mock_service = mocker.MagicMock()
mock_service.get_events = AsyncMock(return_value=[
{"summary": "Test Event", "start": {"dateTime": "2026-03-14T10:00:00Z"}}
])
mocker.patch("core.atom_agent_endpoints.GoogleCalendarService", return_value=mock_service)
from core.atom_agent_endpoints import handle_list_events, ChatRequest
request = ChatRequest(message="List events", user_id="test-user")
async def test():
result = await handle_list_events(request, {})
assert result.get("success") is True
import asyncio
asyncio.run(test())
# ==================== EMAIL HANDLERS ====================
def test_handle_send_email(self):
"""Cover handle_send_email (lines 1136-1149)"""
from core.atom_agent_endpoints import handle_send_email, ChatRequest
request = ChatRequest(message="Send email", user_id="test-user")
async def test():
result = await handle_send_email(request, {"recipient": "test@example.com"})
assert result.get("success") is True
assert "test@example.com" in result["response"]["message"]
import asyncio
asyncio.run(test())
def test_handle_search_emails(self):
"""Cover handle_search_emails (lines 1151-1154)"""
from core.atom_agent_endpoints import handle_search_emails, ChatRequest
request = ChatRequest(message="Search emails", user_id="test-user")
async def test():
result = await handle_search_emails(request, {"query": "project update"})
assert result.get("success") is True
import asyncio
asyncio.run(test())
# ==================== TASK HANDLERS ====================
def test_handle_create_task(self, mocker):
"""Cover handle_create_task (lines 1197-1214)"""
mock_create_task = AsyncMock(return_value={"task_id": "task-123"})
mocker.patch("core.atom_agent_endpoints.create_task", mock_create_task)
from core.atom_agent_endpoints import handle_task_intent, ChatRequest
request = ChatRequest(message="Create task", user_id="test-user")
async def test():
result = await handle_task_intent("CREATE_TASK", {"title": "Test Task"}, request)
assert result.get("success") is True
import asyncio
asyncio.run(test())
def test_handle_list_tasks(self, mocker):
"""Cover handle_list_tasks (lines 1216-1229)"""
mock_get_tasks = AsyncMock(return_value={"tasks": [{"id": "task-1"}]})
mocker.patch("core.atom_agent_endpoints.get_tasks", mock_get_tasks)
from core.atom_agent_endpoints import handle_task_intent, ChatRequest
request = ChatRequest(message="List tasks", user_id="test-user")
async def test():
result = await handle_task_intent("LIST_TASKS", {}, request)
assert result.get("success") is True
import asyncio
asyncio.run(test())
# ==================== FINANCE HANDLERS ====================
def test_handle_get_transactions(self):
"""Cover handle_get_transactions (lines 1235-1248)"""
from core.atom_agent_endpoints import handle_finance_intent, ChatRequest
request = ChatRequest(message="Show transactions", user_id="test-user")
async def test():
result = await handle_finance_intent("GET_TRANSACTIONS", {}, request)
assert result.get("success") is True
import asyncio
asyncio.run(test())
def test_handle_check_balance(self):
"""Cover handle_check_balance (lines 1249-1257)"""
from core.atom_agent_endpoints import handle_finance_intent, ChatRequest
request = ChatRequest(message="Check balance", user_id="test-user")
async def test():
result = await handle_finance_intent("CHECK_BALANCE", {}, request)
assert result.get("success") is True
assert "balance" in result["response"]["data"]
import asyncio
asyncio.run(test())
# ==================== SYSTEM HANDLERS ====================
def test_handle_system_status(self, mocker):
"""Cover handle_system_status (lines 1539-1578)"""
mock_status = mocker.MagicMock()
mock_status.get_overall_status.return_value = "healthy"
mock_status.get_system_info.return_value = {"platform": {"system": "Linux"}}
mock_status.get_resource_usage.return_value = {
"cpu": {"percent": 50.0},
"memory": {"percent": 60.0}
}
mock_status.get_service_status.return_value = {
"database": {"status": "healthy"},
"redis": {"status": "healthy"}
}
mocker.patch("core.atom_agent_endpoints.SystemStatus", return_value=mock_status)
from core.atom_agent_endpoints import handle_system_status, ChatRequest
request = ChatRequest(message="System status", user_id="test-user")
async def test():
result = await handle_system_status(request)
assert result.get("success") is True
assert "healthy" in result["response"]["message"]
import asyncio
asyncio.run(test())
# ==================== ERROR HANDLING ====================
def test_chat_endpoint_exception_handling(self, client, mocker):
"""Cover chat endpoint exception handling (lines 617-619)"""
mock_session_mgr = mocker.MagicMock()
mock_session_mgr.create_session.side_effect = Exception("Database error")
mocker.patch("core.atom_agent_endpoints.get_chat_session_manager", return_value=mock_session_mgr)
response = client.post(
"/api/atom-agent/chat",
json={
"message": "Test error",
"user_id": "test-user"
}
)
# Should handle error gracefully
assert response.status_code == 200
data = response.json()
assert data.get("success") is False
def test_list_sessions_error_handling(self, client, mocker):
"""Cover list_sessions error handling (lines 195-197)"""
mock_session_mgr = mocker.MagicMock()
mock_session_mgr.list_user_sessions.side_effect = Exception("Session error")
mocker.patch("core.atom_agent_endpoints.get_chat_session_manager", return_value=mock_session_mgr)
response = client.get("/api/atom-agent/sessions?user_id=test-user")
assert response.status_code == 200
data = response.json()
assert data.get("success") is False
def test_create_session_error_handling(self, client, mocker):
"""Cover create_new_session error handling (lines 228-230)"""
mock_session_mgr = mocker.MagicMock()
mock_session_mgr.create_session.side_effect = Exception("Create error")
mocker.patch("core.atom_agent_endpoints.get_chat_session_manager", return_value=mock_session_mgr)
response = client.post(
"/api/atom-agent/sessions",
json={"user_id": "test-user"}
)
assert response.status_code == 200
data = response.json()
assert data.get("success") is False
# ==================== EDGE CASES ====================
def test_chat_with_special_characters(self, client, mocker):
"""Test chat with special characters in message"""
mock_session_mgr = AsyncMock()
mock_session_mgr.get_or_create_session.return_value = "test-session"
mocker.patch("core.atom_agent_endpoints.get_chat_session_manager", return_value=mock_session_mgr)
mock_context_mgr = AsyncMock()
mocker.patch("core.atom_agent_endpoints.get_chat_context_manager", return_value=mock_context_mgr)
response = client.post(
"/api/atom-agent/chat",
json={
"message": "Test with emojis 🎉 and unicode",
"user_id": "test-user"
}
)
assert response.status_code in [200, 500, 501]
def test_chat_with_very_long_message(self, client, mocker):
"""Test chat with very long message"""
mock_session_mgr = AsyncMock()
mock_session_mgr.get_or_create_session.return_value = "test-session"
mocker.patch("core.atom_agent_endpoints.get_chat_session_manager", return_value=mock_session_mgr)
mock_context_mgr = AsyncMock()
mocker.patch("core.atom_agent_endpoints.get_chat_context_manager", return_value=mock_context_mgr)
long_message = "Test " * 1000 # 5000 characters
response = client.post(
"/api/atom-agent/chat",
json={
"message": long_message,
"user_id": "test-user"
}
)
assert response.status_code in [200, 500, 501, 413] # 413 = payload too large
def test_chat_with_empty_message(self, client, mocker):
"""Test chat with empty message"""
mock_session_mgr = AsyncMock()
mock_session_mgr.get_or_create_session.return_value = "test-session"
mocker.patch("core.atom_agent_endpoints.get_chat_session_manager", return_value=mock_session_mgr)
mock_context_mgr = AsyncMock()
mocker.patch("core.atom_agent_endpoints.get_chat_context_manager", return_value=mock_context_mgr)
response = client.post(
"/api/atom-agent/chat",
json={
"message": "",
"user_id": "test-user"
}
)
# Empty string should still pass validation
assert response.status_code in [200, 500, 501]