* 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>
45 lines
No EOL
2.9 KiB
Markdown
45 lines
No EOL
2.9 KiB
Markdown
# 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. Причины:
|
||
|
||
1. **Изоляция** — тесты проверяют Python backend + ripgrep отдельно от TS
|
||
обёртки. TS tool — тонкий слой spawnSync, его логика (scoring, merge) уже
|
||
покрыта unit-тестами плагина.
|
||
2. **Простота env** — Python subprocess принимает `env` dict напрямую, можно
|
||
удалить `OPENAI_BASE_URL` (сценарий 1) или подменить `OPENAI_API_KEY` (сценарий
|
||
3) без манипуляций с process.env в TS.
|
||
3. **Скорость** — 4 теста прошли за 34с с реальным OpenRouter. TS tool добавил
|
||
бы накладные расходы на import/compile.
|
||
4. **Переиспользование паттерна** — `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`). |