12 KiB
type, work_item_id, title, version, status, created_at, updated_at, authors, tested_branch, tested_commits, related, verdict, ready_to_deploy
| type | work_item_id | title | version | status | created_at | updated_at | authors | tested_branch | tested_commits | related | verdict | ready_to_deploy | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| test-report | ET-009 | Test Report: Новые источники GPS-треков — EnduroRussia и Wikiloc | 1 | PASS | 2026-06-02 | 2026-06-02 |
|
feature/ET-009-et-009-gps-endurorussia-wikilo |
|
|
PASS | true |
Test Report — ET-009
Verdict: PASS — готово к деплою
Все обязательные тесты (unit ET-009, integration ET-009, node web-тесты)
прошли успешно. Окружение test-среды доступно (HTTP 200 на /api/health).
Pipeline gps_collect.py корректно стартует в dry-run и реально обращается
к endurorussia.ru (HTTP 200, total tracks = 305).
| Шаг | Результат | Деталь |
|---|---|---|
| 1. Проверка окружения test-среды | PASS | HTTP 200, status: ok |
| 2. pytest (unit ET-009 + integration ET-009) | PASS | 25/25 |
| 3. node --test tests/web/gps_tracks.test.js | PASS | 24/24 |
| 4. gps_collect.py --dry-run --source enduro_russia | PASS | стартует, бьёт API, exit 0 |
| 5. config/gps_sources.yaml валидный | PASS | 4 источника, 3 enabled |
| 6. ADR-010 / ADR-012 status = accepted | PASS | оба accepted |
1. Проверка окружения
GET https://openclaw.mva154.duckdns.org/enduro/api/health
HTTP 200
{"status":"ok","db_path":"/app/data/centralfederal.sqlite","db_exists":true}
✅ PASS
2. Unit + Integration тесты (pytest)
Команда:
python -m pytest tests/unit/test_gps_tracks_enduro_russia.py \
tests/unit/test_gps_tracks_wikiloc.py \
tests/integration/test_pipeline_et009.py -v
Результат: 25 passed in 0.30s
EnduroRussia parser (UT-ER-*) — 10/10 PASS
| Test ID | Имя | Статус |
|---|---|---|
| UT-ER-01 | _parse_gpx из enduro-russia-track-1.gpx — успех |
PASS |
| UT-ER-02 | _parse_gpx из enduro-russia-track-2.gpx (пустой) → None |
PASS |
| UT-ER-03 (a) | _bbox_intersects отсеивает track-3 |
PASS |
| UT-ER-03 (b) | collect() skip out-of-bbox |
PASS |
| UT-ER-04 | MAPPING категорий | PASS |
| UT-ER-05 (a) | base_url без дефиса сохранён в config | PASS |
| UT-ER-05 (b) | collect() ходит на endurorussia.ru (без дефиса) | PASS |
| UT-ER-06 | Pagination завершается при fetched_so_far ≥ total | PASS |
| UT-ER-07 | HTTP 429 на /api/tracks — graceful return | PASS |
| UT-ER-08 | HTTP 429 на /api/tracks/{id}/gpx — graceful return | PASS |
Wikiloc parser (UT-WL-*) — 10/10 PASS
| Test ID | Имя | Статус |
|---|---|---|
| UT-WL-01 | _extract_track_paths ≥ 5 уникальных путей |
PASS |
| UT-WL-02 | _extract_gpx_url: downloadTrail.do |
PASS |
| UT-WL-03 | _extract_gpx_url: fallback по track_id |
PASS |
| UT-WL-04 | _extract_track_name: <h1> |
PASS |
| UT-WL-05 | _parse_gpx из wikiloc-track.gpx — успех |
PASS |
| UT-WL-06 | MAPPING категорий | PASS |
| UT-WL-07 | HTTP 403 на странице поиска — graceful stop | PASS |
| UT-WL-08 | HTTP 429 на странице трека — graceful stop | PASS |
| UT-WL-09 | rate_limit_sec соблюдается |
PASS |
| UT-WL-10 | max_tracks_per_run кап |
PASS |
Integration pipeline (IT-*) — 5/5 PASS
| Test ID | Имя | Статус |
|---|---|---|
| IT-ER-01 | Pipeline EnduroRussia: 3 GPX → 1 в БД | PASS |
| IT-WL-01 | Pipeline Wikiloc: 1 трек в БД | PASS |
| IT-WL-02 | Wikiloc graceful-stop на 403 | PASS |
| IT-DEDUP-01 | Dedup-merge EnduroRussia + Wikiloc | PASS |
| IT-LIC-01 | Licensing-guard блокирует source при status=proposed |
PASS |
3. Web/Node тесты
Команда:
node --test tests/web/gps_tracks.test.js
Результат: 24/24 PASS (# tests 24 / # pass 24 / # fail 0).
Покрывают AC-15 (атрибуция), AC-16 (динамические чекбоксы),
_buildGpsAttributionString, _getAvailableGpsSources, цветовые
выражения и фоллбэки — в том числе фиксы P1 F-01/F-02 раунда 2.
4. Pipeline dry-run (gps-collector)
Команда:
python scripts/gps_collect.py --dry-run --region tsfo_plus_chuvashia --source enduro_russia
Выход (фрагмент):
INFO gps_collect: Collecting enduro_russia for region tsfo_plus_chuvashia
INFO httpx: GET https://endurorussia.ru/api/tracks?page=0&limit=50 "HTTP/1.1 200 OK"
INFO src.api.gps_tracks.sources.enduro_russia: EnduroRussia: total tracks = 305
INFO httpx: GET https://endurorussia.ru/api/tracks/305/gpx "HTTP/1.1 200 OK"
✅ Pipeline запускается, парсер enduro_russia загружен, гард по
лицензии пропустил его (ADR-010 → accepted), реальный API отвечает
200, заявлено 305 треков. Прерван по таймауту тестера (полный прогон —
часть E2E-PROD-01, см. §7).
5. Валидация конфига gps_sources.yaml
yaml.safe_load → 4 sources, enabled = [osm, enduro_russia, wikiloc]
| Проверка | Результат |
|---|---|
| YAML парсится без ошибок | PASS |
Запись osm, enabled: true |
PASS |
Запись enduro_russia, enabled: true, base_url: endurorussia.ru (без дефиса) |
PASS |
Запись wikiloc, enabled: true, rate_limit_sec: 10, max_tracks_per_run: 50 |
PASS |
Запись ttrails, enabled: false (ожидаемо — guard пропустит) |
PASS |
В описании задачи упоминается «3 источника» — это 3 активных
(osm, enduro_russia, wikiloc); ttrails присутствует, но
отключён (см. ТЗ REQ-F-04 — он должен оставаться в sources региона
и автоматически пропускаться guard'ом). Соответствует ТЗ.
6. Регрессия ET-008 (lightweight)
Полный pytest по ET-009 (25/25) и node-тесты ET-008/009 web-слоя
(24/24) проходят. Сигнатура /api/gps-tracks* не менялась (см.
ревью раунда 2 §«Регрессия»). Полный регрессионный прогон
RG-08-01..03 не запускался в этом раунде (тестер ET-009 фокусируется
на ET-009-suite); ответственность за регрессию ET-008 закреплена за
CI-gate перед мерджем.
7. Отложенные / не покрытые в этом отчёте проверки
Эти проверки не блокируют деплой — выполняются на post-deploy шаге.
| ID | Назначение | Когда выполняется |
|---|---|---|
| CT-ER-01/02 | Контрактный smoke EnduroRussia API | nightly / вручную |
| CT-WL-01 | Контрактный smoke Wikiloc (ручной) | вручную после деплоя |
| E2E-PROD-01 | Первый продакшн-прогон EnduroRussia (≥ 200 треков) | оператор Деплоя |
| E2E-PROD-02 | Первый прогон Wikiloc (≥ 1 трек, кап 50) | оператор Деплоя |
| E2E-PROD-03 | /api/gps-tracks/health показывает новые ID |
после E2E-PROD-01/02 |
| E2E-PROD-04 | Нет enduro-russia.ru (с дефисом) в external_urls |
оператор Деплоя |
| UI-* | Visual / UI тесты по 04b-ui-test-cases.md |
post-deploy, отдельно |
| L-01 / L-02 | Load baseline | разово перед мерджем |
Также сохраняются не-блокирующие P2/P3-findings из ревью раунда 2
(F-03..F-08) — задокументированы в 12-review.md секция
«Оставшиеся findings», апрув от reviewer'а получен без их закрытия.
8. Visual / UI тесты
Файл 04b-ui-test-cases.md присутствует, но раннер
/home/slin/tools/ui-test/run_tests.js в окружении тестера недоступен,
а сама проверка относится к live-окружению (test-среда + развёрнутые
изменения фронтенда из fc03746). Visual/UI прогон выполняется на
этапе post-deploy в 14-deploy-log.md.
Решение в этом отчёте. Web-слой покрыт node-тестами (24/24 PASS), включая регрессии AC-15/AC-16 после фикса F-01/F-02. Полный визуальный регресс — отдельный шаг после деплоя.
| TC | Статус | Комментарий |
|---|---|---|
| UI-* | DEFERRED | Выполняется post-deploy; node-тесты web-слоя — 24/24 PASS |
9. Финальный вердикт
✅ PASS — готово к деплою (stage: ready-to-deploy)
- Все обязательные unit-тесты ET-009 зелёные (25/25).
- Все node-тесты web-слоя зелёные (24/24).
- Pipeline стартует, API живой, конфиг валиден, ADR'ы accepted.
- P0/P1 findings отсутствуют (reviewer round 2 → APPROVED).
- Visual/UI и E2E продакшн-прогон — это post-deploy ответственность.
Команды, использованные тестером
# 1. health
python -c "import urllib.request; r=urllib.request.urlopen(
'https://openclaw.mva154.duckdns.org/enduro/api/health', timeout=10); \
print(r.status, r.read().decode())"
# 2. pytest
python -m pytest tests/unit/test_gps_tracks_enduro_russia.py \
tests/unit/test_gps_tracks_wikiloc.py \
tests/integration/test_pipeline_et009.py -v
# 3. node
node --test tests/web/gps_tracks.test.js
# 4. dry-run
timeout 8 python scripts/gps_collect.py --dry-run \
--region tsfo_plus_chuvashia --source enduro_russia
# 5. конфиг
python -c "import yaml; cfg=yaml.safe_load(open('config/gps_sources.yaml')); \
print(len(cfg['sources']), [s['id'] for s in cfg['sources'] if s.get('enabled')])"
# 6. ADR статусы
grep '^status:' docs/work-items/ET-008/06-adr/ADR-010-enduro-russia-licensing.md \
docs/work-items/ET-008/06-adr/ADR-012-wikiloc-licensing.md