asyncio_mode = auto)mocker fixtureTestClient for FastAPI routestests/
├── conftest.py # Shared fixtures (settings override, event_loop policy)
├── conftest_factory.py # Factories: FakeLLMBackend, FakeTool, make_profile, FakePool
├── unit/ # No external deps (mocked DB / LLM)
│ ├── core/
│ │ ├── test_events.py # 17 tests — wire serialization for all 15 event types
│ │ ├── test_context_builder.py # 9 tests — system prompt caching, persona, iteration budget
│ │ ├── test_compressor.py # 14 tests — partition, format, compress_context
│ │ ├── test_registry.py # 10 tests — Tool/Profile/Backend registries
│ │ └── test_planning.py
│ ├── memory/
│ │ ├── test_store.py # 18 tests — upsert, search, delete, summary, session state
│ │ └── test_extractor.py # 11 tests — JSON fact extraction, summary regeneration
│ ├── tools/
│ │ └── test_filesystem.py
│ ├── profiles/
│ │ └── test_base.py # 9 tests — Pydantic coercion, defaults, extra fields
│ └── config/
│ └── test_settings.py
├── integration/ # FastAPI TestClient + mocked or real DB
│ ├── test_api_routes.py
│ ├── test_websocket.py
│ └── test_memory_store.py
└── e2e/
└── test_chat_flow.py # Critical path: message → tool call → response
FakeLLMBackend cycles through a list of pre-defined responses and optionally emits ToolCallRequest objects. This lets us test the agent loop and planning without real Ollama.
from tests.conftest_factory import FakeLLMBackend
backend = FakeLLMBackend(
responses=["Hello", "DIRECT"],
tool_calls=[None, None],
thinking=["Hmm", None],
)
resp = await backend.complete([]) # → LLMResponse(content="Hello")
Unit tests mock asyncpg.Pool via an in-memory FakePool/FakeConnection. Integration tests may use a real Postgres instance via TEST_DATABASE_URL.
from tests.conftest_factory import FakeConnection, FakeRecord, make_store_with_pool conn = FakeConnection() conn.enqueue(42) # fetchval result conn.enqueue([FakeRecord(id="1", key="name", value="Eugene")]) # fetch result store = make_store_with_pool(conn)
| Phase | Module | Tests | Status |
|---|---|---|---|
| 1 | navi.core.events |
17 | ✅ Done |
| 1 | navi.core.compressor |
14 | ✅ Done |
| 1 | navi.core.registry |
10 | ✅ Done |
| 1 | navi.core.context_builder |
9 | ✅ Done |
| 1 | navi.profiles.base |
9 | ✅ Done |
| 2 | navi.memory.store |
18 | ✅ Done |
| 2 | navi.memory.extractor |
11 | ✅ Done |
| 3 | navi.api.routes |
— | ⏳ Pending |
| 3 | navi.api.websocket |
— | ⏳ Pending |
| 4 | navi.core.agent |
— | ⏳ Pending |
| 4 | navi.core.planning |
— | ⏳ Pending |
| 5 | navi.tools.filesystem |
— | ⏳ Pending |
| 5 | navi.tools.code_exec |
— | ⏳ Pending |
| 5 | navi.tools.terminal |
— | ⏳ Pending |
# All tests pytest # Unit only pytest tests/unit # With verbose pytest -v tests/unit/core # Single file pytest -v tests/unit/core/test_events.py # Single test pytest -v tests/unit/core/test_events.py::TestToolStarted::test_to_wire # Integration (requires TEST_DATABASE_URL) TEST_DATABASE_URL=postgresql://... pytest tests/integration
tests/unit/ or tests/integration/ directory.async def for async tests — pytest-asyncio handles the rest.tests.conftest_factory for fakes.navi.config.settings are reset automatically by the autouse fixture in conftest.py.FakeLLMBackend, DB → FakePool, filesystem → tmp_path.tests/integration/.datetime.now.