Files
local-api-docs-search/tests/test_integration.py
7000pctAUTO 57e204fe44
Some checks failed
CI / test (push) Failing after 3m46s
CI / build (push) Has been skipped
Add test files
2026-02-03 01:25:57 +00:00

215 lines
6.9 KiB
Python

"""Integration tests for the complete workflow."""
import pytest
from pathlib import Path
from unittest.mock import Mock, patch
from src.cli.commands import cli
from src.search.searcher import Searcher
from src.models.document import Document, SourceType, SearchResult
class TestIntegration:
"""Integration tests for the complete workflow."""
@pytest.fixture
def runner(self):
"""Create a CLI runner."""
from click.testing import CliRunner
return CliRunner()
def test_index_then_search_workflow(self, runner, tmp_path):
"""Test complete workflow: index then search."""
openapi_file = tmp_path / "api.yaml"
openapi_file.write_text("""
openapi: "3.0.0"
info:
title: Test API
version: "1.0.0"
paths:
/users:
get:
summary: Get users
operationId: getUsers
responses:
'200':
description: OK
""")
readme_file = tmp_path / "README.md"
readme_file.write_text("""
# Test API
This is a test API.
## Endpoints
- GET /users - List users
""")
with patch("src.cli.commands.Searcher") as MockSearcher:
mock_searcher = Mock()
mock_searcher.index.return_value = 2
mock_doc = Document(
id="test",
content="test content",
source_type=SourceType.OPENAPI,
title="Test",
)
mock_result = SearchResult(document=mock_doc, score=0.9)
mock_searcher.hybrid_search.return_value = [mock_result]
MockSearcher.return_value = mock_searcher
index_result = runner.invoke(cli, ["index", str(tmp_path)])
assert index_result.exit_code == 0
search_result = runner.invoke(cli, ["search", "users"])
assert search_result.exit_code == 0
def test_search_with_no_index(self, runner):
"""Test search behavior when index is empty."""
with patch("src.cli.commands.Searcher") as MockSearcher:
mock_searcher = Mock()
mock_searcher.hybrid_search.return_value = []
MockSearcher.return_value = mock_searcher
result = runner.invoke(cli, ["search", "test query"])
assert result.exit_code == 0
mock_searcher.hybrid_search.assert_called_once()
def test_multiple_index_types(self, runner, tmp_path):
"""Test indexing multiple document types."""
(tmp_path / "api.yaml").write_text("""
openapi: "3.0.0"
info:
title: API
version: "1.0.0"
paths: {}
""")
(tmp_path / "README.md").write_text("# Test\n")
(tmp_path / "code.py").write_text('"""Test."""\ndef foo(): pass\n')
with patch("src.cli.commands.Searcher") as MockSearcher:
mock_searcher = Mock()
mock_searcher.index.return_value = 3
MockSearcher.return_value = mock_searcher
result = runner.invoke(cli, ["index", str(tmp_path), "--type", "all"])
assert result.exit_code == 0
mock_searcher.index.assert_called_once()
def test_list_with_stats(self, runner):
"""Test list command shows correct stats."""
from src.models.document import IndexStats
with patch("src.cli.commands.Searcher") as MockSearcher:
mock_searcher = Mock()
mock_searcher.get_stats.return_value = IndexStats(
total_documents=25,
openapi_count=10,
readme_count=8,
code_count=7,
)
MockSearcher.return_value = mock_searcher
result = runner.invoke(cli, ["list"])
assert result.exit_code == 0
assert "25" in result.output or "total" in result.output.lower()
def test_clear_index(self, runner):
"""Test clearing the index."""
with patch("src.cli.commands.Searcher") as MockSearcher:
mock_searcher = Mock()
mock_searcher._vector_store.count.return_value = 10
mock_searcher.clear_index.return_value = True
MockSearcher.return_value = mock_searcher
result = runner.invoke(cli, ["clear", "--force"])
assert result.exit_code == 0
def test_config_management(self, runner, tmp_path):
"""Test configuration show and reset."""
with patch("src.cli.commands.get_config") as mock_get_config:
mock_config = Mock()
mock_config.to_dict.return_value = {
"index_path": "./docs",
"model_name": "test-model",
"embedding_device": "cpu",
}
mock_get_config.return_value = mock_config
show_result = runner.invoke(cli, ["config", "--show"])
assert show_result.exit_code == 0
mock_get_config.return_value = mock_config
reset_result = runner.invoke(cli, ["config", "--reset"])
assert reset_result.exit_code == 0
mock_config.reset.assert_called_once()
class TestEdgeCases:
"""Edge case tests."""
@pytest.fixture
def runner(self):
"""Create a CLI runner."""
from click.testing import CliRunner
return CliRunner()
def test_search_empty_query(self, runner):
"""Test search with empty query."""
with patch("src.cli.commands.Searcher") as MockSearcher:
mock_searcher = Mock()
mock_searcher.hybrid_search.return_value = []
MockSearcher.return_value = mock_searcher
result = runner.invoke(cli, ["search", ""])
assert result.exit_code == 0
def test_search_very_long_query(self, runner):
"""Test search with very long query."""
with patch("src.cli.commands.Searcher") as MockSearcher:
mock_searcher = Mock()
mock_searcher.hybrid_search.return_value = []
MockSearcher.return_value = mock_searcher
long_query = "test " * 1000
result = runner.invoke(cli, ["search", long_query])
assert result.exit_code == 0
def test_index_empty_directory(self, runner, tmp_path):
"""Test indexing an empty directory."""
with patch("src.cli.commands.Searcher") as MockSearcher:
mock_searcher = Mock()
mock_searcher.index.return_value = 0
MockSearcher.return_value = mock_searcher
result = runner.invoke(cli, ["index", str(tmp_path)])
assert result.exit_code == 0
def test_list_json_output(self, runner):
"""Test list with JSON output."""
from src.models.document import IndexStats
with patch("src.cli.commands.Searcher") as MockSearcher:
mock_searcher = Mock()
mock_searcher.get_stats.return_value = IndexStats(
total_documents=5,
openapi_count=2,
readme_count=2,
code_count=1,
)
MockSearcher.return_value = mock_searcher
result = runner.invoke(cli, ["list", "--json"])
assert result.exit_code == 0