8.7 KiB
DEV TASK — изолировать 3 теста от живого Plane API (сделать CI зелёным)
Проект: orchestrator | Сервер: slin@82.22.50.71 (pw motoZ@yaz2010, ConnectTimeout=15, StrictHostKeyChecking=no) | Репо (хост): /home/slin/repos/orchestrator | Контейнер: orchestrator (порт 8500)
Ветка: fix/isolate-webhook-tests-from-plane из свежего origin/main (git fetch origin main && git checkout -B fix/isolate-webhook-tests-from-plane origin/main).
Контекст / зачем
В PR #26 мы впервые включили Gitea CI для orchestrator. CI прогнал тесты в чистом окружении (БЕЗ сети к Plane) и 3 теста упали — они дёргают живой Plane API и в CI получают Connection refused. Это дефект изоляции тестов (pre-existing), а не баг кода. Локально на хосте они «проходят» только потому что там живой Plane под боком. Нужно замокать сетевые вызовы Plane в этих 3 тестах → CI станет зелёным → гейт качества для self-hosting orchestrator заработает честно.
ВАЖНО: чинить ТОЛЬКО тесты (tests/test_webhooks.py). НЕ трогать src/, логику, поведение. Задача — добавить недостающие @patch, тесты по сути не переписывать.
Точная причина каждого падения (проверено на проде)
Тест 1 — test_plane_webhook_creates_task (tests/test_webhooks.py:59)
- Путь
work_item.created→handle_work_item_created→ внутри вызываетсяfetch_issue_sequence_id(plane_id, plane_project_id)(src/webhooks/plane.py:448-449) — сетевой вызов к Plane. В CIConnection refused→ исключение прерывает цепочку ДОINSERT INTO tasks→assert task is not Noneпадает. - Код задуман с fallback: если
fetch_issue_sequence_idвернётNone→ берётсяget_next_work_item_id(DB-инкремент). Но реальный сетевой сбой бросает exception, а не None. - Фикс теста: добавить
@patchнаsrc.webhooks.plane.fetch_issue_sequence_id→return_value = None(штатный fallback на DB-инкремент, поведение кода НЕ меняется, просто без сети). Также замокатьsrc.webhooks.plane.add_comment(вызывается на :534 после создания, тоже сетевой) —new_callable=MagicMock. - Образец: тест уже мокает
_create_gitea_branchи_create_initial_docs(AsyncMock) — добавить ещё два @patch к этим.
Тест 2 — test_gitea_push_with_adr_advances_stage (tests/test_webhooks.py:206)
- Путь gitea push →
handle_push→ после advance вызываетсяplane_notify_stage(work_item_id, ...)(src/webhooks/gitea.py:129) — сетевой вызов к Plane →Connection refused→ исключение валит доmock_launcher.launch.assert_called_once()(launch вызывается 0 раз / падает раньше). - Фикс теста: добавить
@patch("src.webhooks.gitea.plane_notify_stage")(MagicMock).
Тест 3 — test_gitea_ci_failure_on_development_notifies_qg_failure (tests/test_webhooks.py:278)
- Тот же класс проблемы: путь gitea status=failure на development. Проверь точно, какой сетевой вызов Plane срабатывает на этом пути (вероятно
plane_notify_stageилиadd_commentв gitea.py при notify_qg_failure-ветке ~:217-223). Замокать ровно тот, что лезет в сеть. - Фикс теста: добавить недостающий
@patchна сетевой Plane-вызов в этом пути (src.webhooks.gitea.plane_notify_stageи/или соответствующий). НЕ трогать assert'ы проmock_notify/check_ci_green/stage.
Рабочие образцы моков (уже в этом файле, копировать стиль)
tests/test_webhooks.py:151-154—@patch("src.webhooks.plane.httpx.get")(как мокают сеть в plane).tests/test_webhooks.py:241-246—@patch("src.webhooks.gitea.check_ci_green")+@patch("src.webhooks.gitea.launcher")(как мокают gitea-путь). Тестtest_gitea_ci_success_advances_to_reviewрядом — успешный близнец, посмотри, что он мокает, и сделай по аналогии.- Импорты уже есть:
from unittest.mock import patch, MagicMock, AsyncMock(строка 5).
Принцип (не нарушать)
- Мокать НАДО место вызова (
src.webhooks.plane.X/src.webhooks.gitea.X), а не источник вplane_sync, т.к. некоторые импорты локальные внутри функций — мок источника не перехватит. Смотри как сделано в conftest.py для send_telegram (там описано почему патчат именно место связывания). - Если функция импортируется ЛОКАЛЬНО внутри тела (
from ..plane_sync import add_commentвнутри функции) — патчить надоsrc.plane_sync.add_comment(источник), т.к. локальный импорт резолвится в рантайме из источника. Определи для каждого вызова: модульный импорт вверху файла → патчить место (src.webhooks.X.name); локальный импорт внутри функции → патчить источник (src.plane_sync.name). Это критично, проверь по факту, не угадывай.
Проверка (выполнить и приложить пруф)
- Прогнать ровно эти 3 теста как в CI (чистое окружение, read-only, без .env):
— должно быть 3 passed.
docker run --rm -v /home/slin/repos/orchestrator:/code:ro -w /code -e PYTHONPATH=/code \ --entrypoint python3 $(docker inspect orchestrator --format '{{.Config.Image}}') \ -m pytest tests/test_webhooks.py::test_plane_webhook_creates_task \ tests/test_webhooks.py::test_gitea_push_with_adr_advances_stage \ tests/test_webhooks.py::test_gitea_ci_failure_on_development_notifies_qg_failure -q - Прогнать ВЕСЬ test_webhooks.py тем же способом — убедиться, что ничего не сломал (не появилось новых fail сверх известных 9 HMAC/401, которые из-за .env и в read-only без .env ведут себя стабильно — зафиксируй число).
- После push ветки: убедиться, что Gitea Actions прогнал workflow и job test → success (
/api/v1/repos/admin/orchestrator/actions/tasks, токенdocker exec orchestrator printenv ORCH_GITEA_TOKEN). git log origin/main..origin/fix/isolate-webhook-tests-from-planeпоказывает коммит ДО отчёта.
Ограничения / правила
- ⚠️ PR в Gitea, push в main ЗАПРЕЩЁН (pre-receive hook). НЕ мержить самому — мержит ревьюер (Стрим). Только ветка + PR.
- Менять ТОЛЬКО
tests/test_webhooks.py. НЕ трогать src/, off-limits тесты (9 HMAC/401), conftest.py, workflow-файл. - Conventional Commits, один коммит:
test: isolate webhook tests from live Plane API (fix CI). - ⚠️ НЕ регистрировать новых раннеров, НЕ запускать ничего через nohup. Раннер orchestrator уже есть (
mva154-runner-orch). Если CI не подхватывает — СТОП, отчёт, НЕ плоди процессы. - Если факт ТЗ разошёлся с реальностью — СТОП, отчёт с вопросом.
Результат
- PR с правкой только
tests/test_webhooks.py, 3 целевых теста зелёные в чистом окружении, workflow прогнан и job test = success, отчёт с пруфом. Сохрани отчёт вtasks/orchestrator/reports/dev-2026-06-04-fix-plane-mocks.md.