| |
| """ |
| Integration Tests for Stack 2.9 Agent + CLI |
| Agent and CLI integration tests. |
| """ |
|
|
| import pytest |
| import sys |
| from pathlib import Path |
| from unittest.mock import MagicMock, patch |
|
|
| |
| sys.path.insert(0, str(Path(__file__).parent.parent / "stack_cli")) |
|
|
| from stack_cli.agent import ( |
| StackAgent, |
| create_agent, |
| AgentResponse, |
| ToolCall, |
| QueryIntent |
| ) |
| from stack_cli.cli import StackCLI, ChatMode, CommandMode |
| from stack_cli.context import ContextManager, create_context_manager |
| from stack_cli.tools import TOOLS, get_tool |
|
|
|
|
| class TestAgentCLIIntegration: |
| """Test agent and CLI integration.""" |
|
|
| def test_agent_in_cli(self): |
| """Test agent is used in CLI.""" |
| with patch('stack_cli.cli.create_agent') as mock_create: |
| mock_agent = MagicMock() |
| mock_create.return_value = mock_agent |
| |
| cli = StackCLI() |
| |
| assert cli.agent is not None |
|
|
| def test_chat_mode_uses_agent(self): |
| """Test chat mode uses agent.""" |
| with patch('stack_cli.cli.create_agent') as mock_create: |
| mock_agent = MagicMock() |
| mock_response = AgentResponse(content="test", tool_calls=[]) |
| mock_agent.process.return_value = mock_response |
| mock_create.return_value = mock_agent |
| |
| chat = ChatMode(mock_agent) |
| |
| |
| with patch('stack_cli.agent.StackAgent.process', return_value=mock_response): |
| chat.default("test query") |
| |
| |
| assert len(chat.history) >= 0 |
|
|
| def test_command_mode_uses_agent(self): |
| """Test command mode uses agent.""" |
| with patch('stack_cli.cli.create_agent') as mock_create: |
| mock_agent = MagicMock() |
| mock_response = AgentResponse(content="result", tool_calls=[]) |
| mock_agent.process.return_value = mock_response |
| mock_create.return_value = mock_agent |
| |
| cmd = CommandMode(mock_agent) |
| |
| |
| result = cmd.execute("test query") |
| |
| |
|
|
|
|
| class TestAgentContextIntegration: |
| """Test agent and context integration.""" |
|
|
| def test_agent_uses_context_manager(self): |
| """Test agent uses context manager.""" |
| with patch('stack_cli.context.create_context_manager'): |
| agent = create_agent() |
| |
| assert agent.context_manager is not None |
|
|
| def test_agent_records_tool_usage(self): |
| """Test agent records tool usage.""" |
| with patch('stack_cli.context.create_context_manager'): |
| with patch('stack_cli.tools.get_tool') as mock_get_tool: |
| mock_tool = MagicMock(return_value={"success": True}) |
| mock_get_tool.return_value = mock_tool |
| |
| agent = StackAgent() |
| response = agent.process("read test.py") |
| |
| |
| assert agent.context_manager is not None |
|
|
| def test_agent_gets_context(self): |
| """Test agent can get context.""" |
| with patch('stack_cli.context.create_context_manager'): |
| agent = StackAgent() |
| |
| context = agent.get_context() |
| |
| assert context is not None |
| assert isinstance(context, str) |
|
|
|
|
| class TestAgentToolsIntegration: |
| """Test agent and tools integration.""" |
|
|
| def test_agent_gets_schemas(self): |
| """Test agent can get tool schemas.""" |
| with patch('stack_cli.context.create_context_manager'): |
| agent = StackAgent() |
| |
| schemas = agent.get_schemas() |
| |
| assert isinstance(schemas, list) |
| if schemas: |
| assert "name" in schemas[0] |
|
|
| def test_agent_process_with_forced_tools(self): |
| """Test agent can process with forced tools.""" |
| with patch('stack_cli.context.create_context_manager'): |
| with patch('stack_cli.tools.get_tool') as mock_get_tool: |
| mock_tool = MagicMock(return_value={"success": True}) |
| mock_get_tool.return_value = mock_tool |
| |
| agent = StackAgent() |
| response = agent.process_with_tools("test", ["read", "write"]) |
| |
| assert response is not None |
| assert isinstance(response, AgentResponse) |
|
|
|
|
| class TestFullWorkflow: |
| """Test complete agent-CLI workflows.""" |
|
|
| def test_read_file_workflow(self): |
| """Test read file workflow.""" |
| with patch('stack_cli.context.create_context_manager'): |
| with patch('stack_cli.tools.get_tool') as mock_get_tool: |
| mock_tool = MagicMock(return_value={ |
| "success": True, |
| "content": "file content here", |
| "total_lines": 10 |
| }) |
| mock_get_tool.return_value = mock_tool |
| |
| agent = StackAgent() |
| response = agent.process("read test.py") |
| |
| assert response.content is not None |
|
|
| def test_write_file_workflow(self): |
| """Test write file workflow.""" |
| with patch('stack_cli.context.create_context_manager'): |
| with patch('stack_cli.tools.get_tool') as mock_get_tool: |
| mock_tool = MagicMock(return_value={"success": True}) |
| mock_get_tool.return_value = mock_tool |
| |
| agent = StackAgent() |
| response = agent.process("write output.txt with test content") |
| |
| assert response is not None |
|
|
| def test_git_workflow(self): |
| """Test git operations workflow.""" |
| with patch('stack_cli.context.create_context_manager'): |
| with patch('stack_cli.tools.get_tool') as mock_get_tool: |
| mock_tool = MagicMock(return_value={"success": True, "files": ["test.py"]}) |
| mock_get_tool.return_value = mock_tool |
| |
| agent = StackAgent() |
| response = agent.process("git status") |
| |
| assert response is not None |
|
|
|
|
| class TestMultiToolIntegration: |
| """Test multiple tools working together.""" |
|
|
| def test_read_then_process(self): |
| """Test reading then processing.""" |
| with patch('stack_cli.context.create_context_manager'): |
| with patch('stack_cli.tools.get_tool') as mock_get_tool: |
| call_count = [0] |
| |
| def mock_tool(**kwargs): |
| call_count[0] += 1 |
| if call_count[0] == 1: |
| return {"success": True, "content": "data"} |
| return {"success": True} |
| |
| mock_get_tool.return_value = mock_tool |
| |
| agent = StackAgent() |
| response = agent.process("read data.txt and process it") |
| |
| assert response is not None |
|
|
| def test_multiple_git_operations(self): |
| """Test multiple git operations.""" |
| with patch('stack_cli.context.create_context_manager'): |
| with patch('stack_cli.tools.get_tool') as mock_get_tool: |
| mock_tool = MagicMock(return_value={"success": True}) |
| mock_get_tool.return_value = mock_tool |
| |
| agent = StackAgent() |
| response = agent.process("check git status and commit") |
| |
| assert response is not None |
|
|
|
|
| class TestErrorIntegration: |
| """Test error handling in integration.""" |
|
|
| def test_tool_failure_handling(self): |
| """Test handling of tool failures.""" |
| with patch('stack_cli.context.create_context_manager'): |
| with patch('stack_cli.tools.get_tool') as mock_get_tool: |
| mock_tool = MagicMock(return_value={"success": False, "error": "Not found"}) |
| mock_get_tool.return_value = mock_tool |
| |
| agent = StackAgent() |
| response = agent.process("read missing.py") |
| |
| |
| assert response is not None |
|
|
| def test_context_error_recovery(self): |
| """Test recovery from context errors.""" |
| with patch('stack_cli.context.create_context_manager') as mock_cm: |
| mock_cm.side_effect = RuntimeError("Context error") |
| |
| |
| try: |
| agent = create_agent() |
| except: |
| pass |
|
|
|
|
| if __name__ == "__main__": |
| pytest.main([__file__, "-v"]) |
|
|