import unittest from pathlib import Path from semantic_index.app import create_app from semantic_index.config import Settings from semantic_index.models import SearchResult class FakeSearchService: def search(self, query): return [ SearchResult( id="redmine:issue:1:chunk:0", score=0.8, text="Snippet text", payload={ "source": "redmine", "project_identifier": "customer-service", "doc_type": "issue", "issue_id": 1, "redmine_url": "http://redmine/issues/1", "source_record_id": "issue:1", }, ) ] def get_document(self, document_id): return {"id": document_id, "text": "Full text", "payload": {}} class FakeStore: def list_projects(self, source=None, limit=1000): return [{"project_identifier": "customer-service", "document_count": 10}] class FakeRefreshService: def __init__(self): self.calls = [] def refresh_redmine_project_limits(self, project_limits, dry_run=False, force_rebuild=False, overlap_minutes=15): self.calls.append((project_limits, dry_run, force_rebuild, overlap_minutes)) return {"source": "redmine", "projects": len(project_limits), "dry_run": dry_run} def fake_services(): refresh = FakeRefreshService() return { "settings": Settings( openai_api_key="", qdrant_url="http://qdrant", qdrant_api_key=None, qdrant_collection="semantic", redmine_url="http://redmine", redmine_api_key="", redmine_project_identifier=None, sample_limit=50, bind_host="127.0.0.1", bind_port=8787, service_api_key=None, refresh_state_path=Path(".cache/semantic_index/refresh_state.json"), ), "search": FakeSearchService(), "store": FakeStore(), "refresh": refresh, } class SemanticIndexAppTest(unittest.TestCase): def test_health_does_not_build_live_services(self): def broken_builder(): raise AssertionError("health should not build live clients") app = create_app(service_builder=broken_builder) routes = {route.path: route.endpoint for route in app.routes} self.assertEqual({"status": "ok"}, routes["/health"]()) def test_search_endpoint_returns_normalized_agent_response(self): app = create_app(service_builder=fake_services) routes = {route.path: route.endpoint for route in app.routes} response = routes["/search"]({"query": "printer", "project_identifier": "customer-service", "limit": 3}) self.assertEqual("printer", response["query"]) self.assertEqual("customer-service", response["filters"]["project_identifier"]) self.assertEqual("customer-service", response["results"][0]["citation"]["project_identifier"]) def test_projects_endpoint_lists_indexed_projects(self): app = create_app(service_builder=fake_services) routes = {route.path: route.endpoint for route in app.routes} response = routes["/projects"]() self.assertEqual("customer-service", response["projects"][0]["project_identifier"]) def test_refresh_endpoint_passes_project_limits_and_cost_flags(self): services = fake_services() app = create_app(service_builder=lambda: services) routes = {route.path: route.endpoint for route in app.routes} response = routes["/sources/redmine/refresh"]( { "project_limits": {"customer-service": 5}, "dry_run": True, "force_rebuild": False, "overlap_minutes": 30, } ) self.assertTrue(response["dry_run"]) self.assertEqual(({"customer-service": 5}, True, False, 30), services["refresh"].calls[0]) if __name__ == "__main__": unittest.main()