Files
enduro-trails/docs/work-items/ET-015/04-test-plan.yaml
claude-bot 68076fca1a
Some checks failed
CI / lint (push) Failing after 4s
CI / test (push) Failing after 5s
CI / build (push) Has been skipped
analyst(ET): auto-commit from analyst run_id=56
2026-06-02 19:03:41 +00:00

254 lines
13 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
work_item_id: ET-015
title: "Multi-repo support для оркестратора"
target_repo: orchestrator
notes: >
Тесты пишутся и запускаются в репо `orchestrator` (pytest).
Поскольку фича чисто бэкендовая (нет UI-изменений в enduro-trails),
UI test cases НЕ создаются.
unit:
- id: UT-01
name: get_next_work_item_id — per-prefix numbering
file: tests/test_db_multi_repo.py::test_next_id_per_prefix
given: "tasks table has ET-001..ET-015 (repo=enduro-trails) and no ORCH-* rows"
when: "вызывается get_next_work_item_id для проекта с prefix='ET'"
expect: "возвращает 'ET-016'"
and_when: "вызывается get_next_work_item_id для проекта с prefix='ORCH'"
expect_2: "возвращает 'ORCH-001'"
covers_ac: [AC-4]
- id: UT-02
name: get_next_work_item_id — нумерация ORCH идёт независимо от ET
file: tests/test_db_multi_repo.py::test_orch_numbering_independent
given: "в tasks есть ET-001..ET-015 и ORCH-001..ORCH-003"
when: "запрашивается следующий ID для ORCH"
expect: "ORCH-004 (не ORCH-016)"
covers_ac: [AC-4]
- id: UT-03
name: ProjectRegistry — load from config
file: tests/test_project_registry.py::test_load_two_projects
given: "конфиг с двумя проектами"
when: "registry загружается на старте"
expect: "len(registry.projects) == 2; lookup по plane_project_id возвращает правильный key"
covers_ac: [AC-1, AC-2]
- id: UT-04
name: ProjectRegistry — invalid config
file: tests/test_project_registry.py::test_invalid_config_logged
given: "конфиг с проектом без plane_project_id"
when: "registry загружается"
expect: "запись пропускается с WARNING, остальные грузятся"
covers_ac: [AC-1]
- id: UT-05
name: ProjectRegistry — lookup by plane_project_id
file: tests/test_project_registry.py::test_lookup_by_plane_project_id
given: "registry с тремя проектами"
when: "lookup по plane_project_id='unknown-uuid'"
expect: "возвращает None"
covers_ac: [AC-12]
- id: UT-06
name: ProjectRegistry — lookup by repo name
file: tests/test_project_registry.py::test_lookup_by_repo
given: "registry с проектом repo='orchestrator'"
when: "lookup('orchestrator')"
expect: "возвращает конфиг проекта"
covers_ac: [AC-3]
- id: UT-07
name: plane_sync — workspace/project определяется по work_item_id
file: tests/test_plane_sync_multi.py::test_workspace_per_project
given: "tasks содержит ORCH-001 (repo=orchestrator); registry имеет настройки orchestrator"
when: "вызывается update_issue_state('ORCH-001', 'in_progress')"
expect: "httpx.patch вызывается с URL содержащим workspace проекта orchestrator и state-id из его plane_states"
covers_ac: [AC-5, AC-6]
- id: UT-08
name: verify_plane_signature — per-project secret
file: tests/test_webhooks_multi.py::test_hmac_per_project
given: "проект orchestrator имеет secret S2"
when: "вебхук подписан S1"
expect: "verify возвращает False"
and_when: "вебхук подписан S2"
expect_2: "verify возвращает True"
covers_ac: [AC-14]
- id: UT-09
name: get_repo_path_or_fail — отсутствие main-clone
file: tests/test_launcher_multi.py::test_missing_main_clone
given: "проект foo в реестре, /repos/foo не существует"
when: "launcher.launch('analyst', 'foo', ...)"
expect: "raises FileNotFoundError И логируется ERROR с текстом 'Main repo not found'"
covers_ac: [AC-13]
- id: UT-10
name: has_deploy_stage=false — skip deployer
file: tests/test_launcher_multi.py::test_skip_deploy_stage
given: "проект orchestrator с has_deploy_stage=false; задача в testing с PASS test report"
when: "_try_advance_stage вызывается"
expect: "task.stage становится done; deployer.launch НЕ вызывается"
covers_ac: [AC-15]
- id: UT-11
name: STAGE_TO_STATE — стейт берётся из конфига проекта
file: tests/test_plane_sync_multi.py::test_stage_to_state_per_project
given: "два проекта с разными UUID для in_progress"
when: "оба переходят в стадию development"
expect: "patch с разными UUID — каждый со своим"
covers_ac: [AC-5]
- id: UT-12
name: handle_work_item_created — branch создаётся в нужном репо
file: tests/test_webhooks_multi.py::test_branch_in_correct_repo
given: "вебхук с project_id orchestrator"
when: "обрабатывается work_item.created"
expect: "POST /api/v1/repos/admin/orchestrator/branches; НЕ /enduro-trails/branches"
covers_ac: [AC-2]
integration:
- id: IT-01
name: End-to-end создание задачи в проекте enduro-trails
file: tests/integration/test_e2e_enduro.py::test_create_et_task
given: "оркестратор запущен, registry с обоими проектами; mock Plane + mock Gitea"
when: "POST /webhook/plane с work_item.created для enduro-trails"
expect:
- "Plane mock получил PATCH issue.state = in_progress"
- "Gitea mock получил POST /branches"
- "tasks содержит запись (repo=enduro-trails, work_item_id=ET-NNN, stage=analysis)"
- "Был вызван launcher.launch('analyst', 'enduro-trails', ...)"
covers_ac: [AC-2, AC-9]
- id: IT-02
name: End-to-end создание задачи в проекте orchestrator
file: tests/integration/test_e2e_orch.py::test_create_orch_task
given: "то же, что IT-01"
when: "POST /webhook/plane с work_item.created для orchestrator (другой project_id)"
expect:
- "Gitea mock получил POST /repos/admin/orchestrator/branches"
- "tasks содержит (repo=orchestrator, work_item_id=ORCH-001)"
- "launcher.launch('analyst', 'orchestrator', ...) — НЕ enduro-trails"
covers_ac: [AC-2, AC-4]
- id: IT-03
name: Параллельные задачи в разных репо не пересекаются
file: tests/integration/test_concurrent_repos.py::test_two_repos
given: "две задачи: ET-099 в enduro-trails и ORCH-099 в orchestrator"
when: "обе на стадии analysis с активными worktree"
expect:
- "/repos/_wt/enduro-trails/feature_ET-099-... существует"
- "/repos/_wt/orchestrator/feature_ORCH-099-... существует"
- "артефакты ET записаны в enduro-trails worktree, ORCH — в orchestrator worktree"
covers_ac: [AC-7]
- id: IT-04
name: Gitea push для одного репо не задевает задачи в другом
file: tests/integration/test_gitea_routing.py::test_push_isolation
given: "активны ET-099 и ORCH-099"
when: "приходит push на ветку ORCH-099 в репо orchestrator"
expect:
- "tasks.stage для ORCH-099 обновляется при наличии валидных файлов"
- "tasks.stage для ET-099 НЕ меняется"
covers_ac: [AC-3]
- id: IT-05
name: Plane comment :approved: для orchestrator advance'ит правильную задачу
file: tests/integration/test_plane_comment_routing.py::test_approved_routing
given: "ET-099 stage=analysis, ORCH-099 stage=analysis"
when: "comment.created с :approved: на issue ORCH-099"
expect:
- "tasks для ORCH-099 advance в architecture"
- "tasks для ET-099 не меняется"
covers_ac: [AC-6]
- id: IT-06
name: Неизвестный project_id игнорируется без 500
file: tests/integration/test_unknown_project.py::test_unknown_returns_202
given: "registry с одним проектом enduro-trails"
when: "приходит вебхук с project_id='unknown'"
expect:
- "HTTP 202"
- "WARNING в логах с текстом 'Unknown project_id'"
- "tasks без новых записей"
covers_ac: [AC-12]
- id: IT-07
name: Отсутствие main-clone — Telegram + 202
file: tests/integration/test_missing_clone.py::test_no_main_clone
given: "registry с проектом foo, /repos/foo отсутствует; Telegram mock"
when: "приходит work_item.created для foo"
expect:
- "HTTP 202"
- "ERROR в логах 'Main repo not found: /repos/foo'"
- "Telegram mock получил одно сообщение"
covers_ac: [AC-13]
e2e:
- id: E2E-01
name: Smoke: подключение нового проекта на тестовом стенде
type: manual
where: "test stand (mva154)"
steps:
- "Подготовить /repos/orchestrator на хосте (git clone, если ещё нет)"
- "Создать в Plane проект 'Orchestrator-smoke', получить state UUID'ы"
- "Добавить запись в конфиг проектов оркестратора (см. ADR)"
- "Перезапустить контейнер оркестратора: docker compose restart"
- "Проверить логи: 'Loaded 2 projects: enduro-trails, orchestrator-smoke'"
- "Зарегистрировать webhook Plane (target orchestrator) для Orchestrator-smoke"
- "Создать тестовый work item 'Smoke ORCH-1' в Plane"
- "Дождаться появления ветки в gitea-репо orchestrator (~30s)"
- "Проверить tasks в БД оркестратора: repo=orchestrator, work_item_id=ORCH-001"
- "Удалить тестовую запись Plane и проверить, что enduro-trails не пострадал"
expect: "Все шаги без ошибок, регрессий на enduro-trails нет"
covers_ac: [AC-2, AC-4, AC-7, AC-9, AC-17]
- id: E2E-02
name: Smoke: создание следующей задачи в enduro-trails после релиза
type: manual
where: "test stand"
steps:
- "После раскатки фичи создать в Plane-проекте enduro-trails новый WI"
- "Дождаться появления ветки feature/ET-016-..."
- "Проверить artifact'ы в docs/work-items/ET-016/"
expect: "ID=ET-016 (следующий после ET-015), всё как раньше"
covers_ac: [AC-9, AC-4]
regression:
- id: REG-01
name: Активные задачи продолжают работу после рестарта
type: manual
where: "test stand"
steps:
- "Перед раскаткой запомнить snapshot tasks (id, stage, repo, branch)"
- "Раскатать фичу"
- "Перезапустить orchestrator container"
- "Проверить tasks snapshot после рестарта"
expect: "Записи идентичны (stage не сбился, repo/branch не изменились)"
covers_ac: [AC-10]
- id: REG-02
name: Test report check_tests_local продолжает работать
given: "enduro-trails branch с зелёными тестами"
when: "agent developer завершается"
expect: "QG check_tests_local вызывает make test в worktree и проходит"
covers_ac: [AC-9]
coverage:
required_min_percent: 75
applies_to:
- src/config.py
- src/db.py
- src/plane_sync.py
- src/webhooks/plane.py
- src/webhooks/gitea.py
- src/agents/launcher.py
new_modules_expected:
- src/project_registry.py # имя ориентировочное, точное название — на усмотрение архитектора
notes_for_tester:
- "В существующих тестах могут быть моки на settings.default_repo — их нужно расширить под новый registry"
- "find_issue_id в plane_sync.py делает DB lookup — учесть это при моках"
- "Telegram-нотификации логировать через send_telegram моки, чтобы избежать реальных запросов"
- "Не нужно тестировать сами Plane/Gitea API — только что оркестратор формирует правильные запросы"