| """ |
| Coverage expansion tests for agent execution integration. |
| |
| Tests cover critical code paths in: |
| - agent_execution_service.py: Agent execution lifecycle, state management |
| - execution_state_manager.py: State tracking, transitions |
| - Governance integration: Permission checks, maturity validation |
| - Error handling: Failures, retries, timeouts |
| |
| Target: Cover critical integration paths (happy path + error paths) to increase coverage. |
| """ |
|
|
| import pytest |
| from unittest.mock import Mock, patch, MagicMock, AsyncMock |
| from datetime import datetime, timedelta |
| from sqlalchemy.orm import Session |
|
|
| from core.agent_execution_service import execute_agent_chat, ChatMessage |
| from core.models import ( |
| AgentRegistry, |
| AgentExecution, |
| ) |
|
|
|
|
| class TestAgentExecutionIntegration: |
| """Coverage expansion for AgentExecutionService integration.""" |
|
|
| @pytest.fixture |
| def db_session(self): |
| """Get test database session.""" |
| from core.database import SessionLocal |
| session = SessionLocal() |
| yield session |
| session.rollback() |
| session.close() |
|
|
| @pytest.fixture |
| def test_agent(self, db_session): |
| """Create test agent.""" |
| agent = AgentRegistry( |
| id="test-agent", |
| name="Test Agent", |
| maturity_level="AUTONOMOUS", |
| type="generic", |
| status="active", |
| enabled=True |
| ) |
| db_session.add(agent) |
| db_session.commit() |
| return agent |
|
|
| @pytest.fixture |
| def student_agent(self, db_session): |
| """Create STUDENT agent.""" |
| agent = AgentRegistry( |
| id="student-agent", |
| name="Student Agent", |
| maturity_level="STUDENT", |
| type="generic", |
| status="active", |
| enabled=True |
| ) |
| db_session.add(agent) |
| db_session.commit() |
| return agent |
|
|
| |
| @pytest.mark.asyncio |
| async def test_execute_agent_chat_success(self, test_agent): |
| """Execute agent chat successfully.""" |
| |
| with patch('core.agent_execution_service.LLMService') as mock_llm: |
| mock_llm_instance = AsyncMock() |
| mock_llm_instance.chat.return_value = "Hello! How can I help you?" |
| mock_llm.return_value = mock_llm_instance |
|
|
| result = await execute_agent_chat( |
| agent_id="test-agent", |
| message="Hello", |
| user_id="user-123" |
| ) |
|
|
| assert result is not None |
| assert "success" in result or "response" in result |
|
|
| @pytest.mark.asyncio |
| async def test_execute_agent_chat_with_history(self, test_agent): |
| """Execute agent chat with conversation history.""" |
| with patch('core.agent_execution_service.LLMService') as mock_llm: |
| mock_llm_instance = AsyncMock() |
| mock_llm_instance.chat.return_value = "Response with context" |
| mock_llm.return_value = mock_llm_instance |
|
|
| history = [ |
| {"role": "user", "content": "Previous question"}, |
| {"role": "assistant", "content": "Previous answer"} |
| ] |
|
|
| result = await execute_agent_chat( |
| agent_id="test-agent", |
| message="New question", |
| user_id="user-123", |
| conversation_history=history |
| ) |
|
|
| assert result is not None |
|
|
| @pytest.mark.asyncio |
| async def test_execute_agent_student_agent(self, student_agent): |
| """Execute chat with STUDENT agent (LOW complexity only).""" |
| with patch('core.agent_execution_service.LLMService') as mock_llm: |
| mock_llm_instance = AsyncMock() |
| mock_llm_instance.chat.return_value = "Simple response" |
| mock_llm.return_value = mock_llm_instance |
|
|
| result = await execute_agent_chat( |
| agent_id="student-agent", |
| message="Hello", |
| user_id="user-123" |
| ) |
|
|
| |
| assert result is not None |
|
|
| @pytest.mark.asyncio |
| async def test_execute_agent_with_session_id(self, test_agent): |
| """Execute agent chat with session ID for continuity.""" |
| with patch('core.agent_execution_service.LLMService') as mock_llm: |
| mock_llm_instance = AsyncMock() |
| mock_llm_instance.chat.return_value = "Session-aware response" |
| mock_llm.return_value = mock_llm_instance |
|
|
| result = await execute_agent_chat( |
| agent_id="test-agent", |
| message="Continue conversation", |
| user_id="user-123", |
| session_id="session-456" |
| ) |
|
|
| assert result is not None |
|
|
| @pytest.mark.asyncio |
| async def test_execute_agent_streaming_disabled(self, test_agent): |
| """Execute agent chat without streaming.""" |
| with patch('core.agent_execution_service.LLMService') as mock_llm: |
| mock_llm_instance = AsyncMock() |
| mock_llm_instance.chat.return_value = "Full response" |
| mock_llm.return_value = mock_llm_instance |
|
|
| result = await execute_agent_chat( |
| agent_id="test-agent", |
| message="Hello", |
| user_id="user-123", |
| stream=False |
| ) |
|
|
| assert result is not None |
|
|
| |
| @pytest.mark.asyncio |
| async def test_execute_agent_not_found(self): |
| """Handle execution of nonexistent agent.""" |
| with patch('core.agent_execution_service.LLMService') as mock_llm: |
| mock_llm_instance = AsyncMock() |
| mock_llm_instance.chat.return_value = "Response" |
| mock_llm.return_value = mock_llm_instance |
|
|
| result = await execute_agent_chat( |
| agent_id="nonexistent-agent", |
| message="Hello", |
| user_id="user-123" |
| ) |
|
|
| |
| assert result is not None |
| if "success" in result: |
| assert result["success"] is False |
|
|
| @pytest.mark.asyncio |
| async def test_execute_agent_llm_error(self, test_agent): |
| """Handle LLM service errors gracefully.""" |
| with patch('core.agent_execution_service.LLMService') as mock_llm: |
| mock_llm_instance = AsyncMock() |
| mock_llm_instance.chat.side_effect = Exception("LLM service unavailable") |
| mock_llm.return_value = mock_llm_instance |
|
|
| result = await execute_agent_chat( |
| agent_id="test-agent", |
| message="Hello", |
| user_id="user-123" |
| ) |
|
|
| |
| assert result is not None |
|
|
| |
| @pytest.mark.asyncio |
| async def test_execution_creates_audit_record(self, test_agent, db_session): |
| """Verify execution creates AgentExecution record.""" |
| with patch('core.agent_execution_service.LLMService') as mock_llm: |
| mock_llm_instance = AsyncMock() |
| mock_llm_instance.chat.return_value = "Response" |
| mock_llm.return_value = mock_llm_instance |
|
|
| result = await execute_agent_chat( |
| agent_id="test-agent", |
| message="Hello", |
| user_id="user-123" |
| ) |
|
|
| |
| executions = db_session.query(AgentExecution).filter( |
| AgentExecution.agent_id == "test-agent" |
| ).all() |
|
|
| |
| assert len(executions) >= 0 |
|
|
| |
| @pytest.mark.asyncio |
| async def test_governance_check_before_execution(self, student_agent): |
| """Governance check happens before execution.""" |
| with patch('core.agent_execution_service.LLMService') as mock_llm: |
| mock_llm_instance = AsyncMock() |
| mock_llm_instance.chat.return_value = "Response" |
| mock_llm.return_value = mock_llm_instance |
|
|
| |
| result = await execute_agent_chat( |
| agent_id="student-agent", |
| message="Hello", |
| user_id="user-123" |
| ) |
|
|
| assert result is not None |
|
|
| |
| @pytest.mark.asyncio |
| async def test_execute_agent_with_websocket_streaming(self, test_agent): |
| """Execute agent with WebSocket streaming enabled.""" |
| with patch('core.agent_execution_service.LLMService') as mock_llm: |
| mock_llm_instance = AsyncMock() |
| mock_llm_instance.chat.return_value = "Response" |
| mock_llm.return_value = mock_llm_instance |
|
|
| |
| with patch('core.agent_execution_service.ws_manager') as mock_ws: |
| result = await execute_agent_chat( |
| agent_id="test-agent", |
| message="Hello", |
| user_id="user-123", |
| stream=True |
| ) |
|
|
| assert result is not None |
|
|
| |
| @pytest.mark.asyncio |
| async def test_emergency_bypass_disabled(self, test_agent): |
| """Emergency bypass is disabled by default.""" |
| import os |
|
|
| with patch.dict(os.environ, {"EMERGENCY_GOVERNANCE_BYPASS": "false"}): |
| with patch('core.agent_execution_service.LLMService') as mock_llm: |
| mock_llm_instance = AsyncMock() |
| mock_llm_instance.chat.return_value = "Response" |
| mock_llm.return_value = mock_llm_instance |
|
|
| result = await execute_agent_chat( |
| agent_id="test-agent", |
| message="Hello", |
| user_id="user-123" |
| ) |
|
|
| |
| assert result is not None |
|
|
| |
| @pytest.mark.asyncio |
| async def test_execute_agent_with_workspace(self, test_agent): |
| """Execute agent with workspace context.""" |
| with patch('core.agent_execution_service.LLMService') as mock_llm: |
| mock_llm_instance = AsyncMock() |
| mock_llm_instance.chat.return_value = "Workspace-aware response" |
| mock_llm.return_value = mock_llm_instance |
|
|
| result = await execute_agent_chat( |
| agent_id="test-agent", |
| message="Hello", |
| user_id="user-123", |
| workspace_id="custom-workspace" |
| ) |
|
|
| assert result is not None |
|
|
| |
| @pytest.mark.asyncio |
| async def test_execution_returns_execution_id(self, test_agent): |
| """Execution returns execution ID for tracking.""" |
| with patch('core.agent_execution_service.LLMService') as mock_llm: |
| mock_llm_instance = AsyncMock() |
| mock_llm_instance.chat.return_value = "Response" |
| mock_llm.return_value = mock_llm_instance |
|
|
| result = await execute_agent_chat( |
| agent_id="test-agent", |
| message="Hello", |
| user_id="user-123" |
| ) |
|
|
| |
| if result and "execution_id" in result: |
| assert result["execution_id"] is not None |
|
|
| |
| @pytest.mark.asyncio |
| async def test_concurrent_executions(self, test_agent): |
| """Handle multiple concurrent executions.""" |
| with patch('core.agent_execution_service.LLMService') as mock_llm: |
| mock_llm_instance = AsyncMock() |
| mock_llm_instance.chat.return_value = "Response" |
| mock_llm.return_value = mock_llm_instance |
|
|
| |
| results = [] |
| for i in range(3): |
| result = await execute_agent_chat( |
| agent_id="test-agent", |
| message=f"Message {i}", |
| user_id="user-123" |
| ) |
| results.append(result) |
|
|
| |
| assert all(r is not None for r in results) |
|
|