* test(memory): E2E coverage for 4 scenarios * docs(handoff): set PR number * style(memory): ruff format e2e test * docs(project-map): add test_memory_tools_e2e.py after PR#102 --------- Co-authored-by: opencode-agent <agent@opencode.local>
2.9 KiB
ADR-044: E2E test structure for hybrid memory (subprocess-based)
Статус
Accepted (2026-07-26)
Контекст
Гибридная память (keyword ripgrep + semantic Python OpenRouter) после рефактора
(PR #100 lazy-init, PR #101 5 TS tools) нуждалась в E2E гарантии стабильности.
Существующие unit-тесты (test_search.py, test_index.py, test_embedder.py)
мокают embed_texts — не проверяют реальный keyword path (ripgrep subprocess) и
не проверяют fallback при реальном падении OpenRouter.
Нужно было решить: как структурировать E2E тесты — через TS tools (spawnSync TS
plugin) или напрямую через Python src.memory + ripgrep subprocess.
Решение
Тесты вызывают Python src.memory (search/index) и ripgrep напрямую через
subprocess.run из Python тестов, НЕ через TS tools. Причины:
- Изоляция — тесты проверяют Python backend + ripgrep отдельно от TS обёртки. TS tool — тонкий слой spawnSync, его логика (scoring, merge) уже покрыта unit-тестами плагина.
- Простота env — Python subprocess принимает
envdict напрямую, можно удалитьOPENAI_BASE_URL(сценарий 1) или подменитьOPENAI_API_KEY(сценарий 3) без манипуляций с process.env в TS. - Скорость — 4 теста прошли за 34с с реальным OpenRouter. TS tool добавил бы накладные расходы на import/compile.
- Переиспользование паттерна —
test_embedder_live.pyуже использует@pytest.mark.skipif(not RUN_LIVE)— тот же маркер на module level.
Каждый сценарий создаёт tmp memoryDir через tmp_path fixture, пишет .md с
уникальным термином zzuniqtestterm42, вызывает _reindex (poll reindex.log)
и _semantic_search/_rg_search, сравнивает результаты.
Альтернативы
- TS tool через subprocess (
npx opencode-tool memory-search) — отклонено: сложно передать кастомный env, медленнее, тестирует TS обёртку а не backend. - pytest + import src.memory in-process — отклонено:
embed_textsчитаетos.environпри вызове (lazy после PR #100), но monkeypatch на module-level ломает параллельные тесты. Subprocess даёт полную изоляцию env per-test. - Mock OpenRouter через httpx mock — отклонено: цель E2E = реальный API,
мок = unit-тест (уже есть
test_embedder.py).