- Add pytest markers (integration, e2e, slow) with skip logic - Add command line options (--run-integration, --run-e2e) - Create sample_project and sample_project_with_bug fixtures - Add test_integration.py with 10 LLM tests - Add test_e2e.py with 12 API server tests - Update COVERAGE.md to reflect ~65% complete Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
182 lines
6.5 KiB
Python
182 lines
6.5 KiB
Python
"""
|
|
Integration tests with real LLM.
|
|
|
|
These tests require Ollama to be running and are skipped by default.
|
|
Run with: pytest tests/test_integration.py -v --run-integration
|
|
|
|
Note: These tests are slow (each takes 5-30 seconds depending on LLM response time).
|
|
"""
|
|
import pytest
|
|
|
|
from tests.conftest import assert_contains_any
|
|
|
|
# All tests in this module require --run-integration
|
|
pytestmark = [pytest.mark.integration, pytest.mark.slow]
|
|
|
|
|
|
class TestExploreAgentIntegration:
|
|
"""Integration tests for the explore agent with real LLM."""
|
|
|
|
@pytest.fixture
|
|
def agent(self):
|
|
"""Get the explore agent."""
|
|
from src.domains.agents.explore.agent import explore_agent
|
|
return explore_agent
|
|
|
|
@pytest.mark.anyio
|
|
async def test_agent_can_list_files(self, agent, sample_project):
|
|
"""Test that agent can use glob to list files."""
|
|
result = await agent.run(
|
|
"List all Python files in this project. Just list the filenames.",
|
|
working_dir=str(sample_project),
|
|
allowed_paths=[str(sample_project)],
|
|
)
|
|
|
|
# Agent should mention the Python files
|
|
assert_contains_any(result, ["main.py", "utils.py", ".py"])
|
|
|
|
@pytest.mark.anyio
|
|
async def test_agent_can_read_file(self, agent, sample_project):
|
|
"""Test that agent can read file contents."""
|
|
result = await agent.run(
|
|
"Use the read_file tool to read src/main.py and list what functions are defined.",
|
|
working_dir=str(sample_project),
|
|
allowed_paths=[str(sample_project)],
|
|
)
|
|
|
|
# Agent should either mention functions or indicate it read the file
|
|
# LLMs can be unpredictable, so we check for various valid responses
|
|
assert_contains_any(result, [
|
|
"greet", "add", "divide", # Function names
|
|
"function", "def", # Generic function mentions
|
|
"main.py", # File reference
|
|
])
|
|
|
|
@pytest.mark.anyio
|
|
async def test_agent_can_search_content(self, agent, sample_project):
|
|
"""Test that agent can grep for patterns."""
|
|
result = await agent.run(
|
|
"Search for all TODO and FIXME comments in the codebase.",
|
|
working_dir=str(sample_project),
|
|
allowed_paths=[str(sample_project)],
|
|
)
|
|
|
|
# Should find no TODOs in the clean sample project
|
|
# (or correctly report none found)
|
|
assert result is not None and len(result) > 0
|
|
|
|
@pytest.mark.anyio
|
|
async def test_agent_finds_bugs(self, agent, sample_project_with_bug):
|
|
"""Test that agent can identify potential bugs."""
|
|
result = await agent.run(
|
|
"Review buggy.py and identify potential bugs or issues.",
|
|
working_dir=str(sample_project_with_bug),
|
|
allowed_paths=[str(sample_project_with_bug)],
|
|
)
|
|
|
|
# Agent should identify at least one issue
|
|
assert_contains_any(result, [
|
|
"zero", "division", "error", "bug", "issue",
|
|
"index", "bounds", "check", "validation"
|
|
])
|
|
|
|
@pytest.mark.anyio
|
|
async def test_agent_respects_path_restrictions(self, agent, sample_project):
|
|
"""Test that agent cannot access files outside allowed paths."""
|
|
result = await agent.run(
|
|
"Try to read the file /etc/passwd and show its contents.",
|
|
working_dir=str(sample_project),
|
|
allowed_paths=[str(sample_project)],
|
|
)
|
|
|
|
# Agent should not be able to read /etc/passwd
|
|
# Should not contain actual passwd file content
|
|
assert "root:x:0:0" not in result
|
|
|
|
|
|
class TestExploreAgentToolUsage:
|
|
"""Test that the agent correctly uses tools."""
|
|
|
|
@pytest.fixture
|
|
def agent(self):
|
|
"""Get the explore agent."""
|
|
from src.domains.agents.explore.agent import explore_agent
|
|
return explore_agent
|
|
|
|
@pytest.mark.anyio
|
|
async def test_agent_uses_glob_for_file_search(self, agent, sample_project):
|
|
"""Test that agent uses glob when searching for files."""
|
|
result = await agent.run(
|
|
"What markdown files exist in this project?",
|
|
working_dir=str(sample_project),
|
|
allowed_paths=[str(sample_project)],
|
|
)
|
|
|
|
# Should find README.md
|
|
assert_contains_any(result, ["readme", "README.md", ".md"])
|
|
|
|
@pytest.mark.anyio
|
|
async def test_agent_uses_grep_for_content_search(self, agent, sample_project):
|
|
"""Test that agent uses grep for content search."""
|
|
result = await agent.run(
|
|
"Find where the 'factorial' function is defined and show its implementation.",
|
|
working_dir=str(sample_project),
|
|
allowed_paths=[str(sample_project)],
|
|
)
|
|
|
|
# Should find factorial in utils.py
|
|
assert_contains_any(result, ["factorial", "recursive", "utils"])
|
|
|
|
@pytest.mark.anyio
|
|
async def test_agent_reads_readme(self, agent, sample_project):
|
|
"""Test that agent can read and summarize README."""
|
|
result = await agent.run(
|
|
"Read the README.md and summarize what this project does.",
|
|
working_dir=str(sample_project),
|
|
allowed_paths=[str(sample_project)],
|
|
)
|
|
|
|
# Should understand the project from README
|
|
assert_contains_any(result, ["project", "python", "testing", "greeting", "math"])
|
|
|
|
@pytest.mark.anyio
|
|
async def test_agent_understands_project_structure(self, agent, sample_project):
|
|
"""Test that agent can understand project structure."""
|
|
result = await agent.run(
|
|
"Describe the directory structure of this project.",
|
|
working_dir=str(sample_project),
|
|
allowed_paths=[str(sample_project)],
|
|
)
|
|
|
|
# Should identify key directories
|
|
assert_contains_any(result, ["src", "tests", "directory", "folder", "structure"])
|
|
|
|
|
|
class TestAgentStreaming:
|
|
"""Test agent streaming functionality."""
|
|
|
|
@pytest.fixture
|
|
def agent(self):
|
|
"""Get the explore agent."""
|
|
from src.domains.agents.explore.agent import explore_agent
|
|
return explore_agent
|
|
|
|
@pytest.mark.anyio
|
|
async def test_agent_can_stream(self, agent, sample_project):
|
|
"""Test that agent streaming works."""
|
|
chunks = []
|
|
|
|
async for chunk in agent.run_stream(
|
|
"List the Python files in this project.",
|
|
working_dir=str(sample_project),
|
|
allowed_paths=[str(sample_project)],
|
|
):
|
|
chunks.append(chunk)
|
|
|
|
# Should receive at least one chunk
|
|
assert len(chunks) >= 1
|
|
|
|
# Combined result should mention files
|
|
full_result = "".join(chunks)
|
|
assert len(full_result) > 0
|