9.7 KiB
type, work_item_id, title, version, status, created_at, updated_at, authors, tested_branch, tested_commits, verdict
| type | work_item_id | title | version | status | created_at | updated_at | authors | tested_branch | tested_commits | verdict | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| test-report | ET-008 | Test Report: GPS-треки с публичных платформ на карте | 3 | pass | 2026-06-01 | 2026-06-01 |
|
feature/ET-008-gps |
|
stage:ready-to-deploy |
Test Report — ET-008: GPS-треки с публичных платформ на карте (v3)
Вердикт: stage:ready-to-deploy
Коммит 1ffa178 закрывает последний P1-дефект (F-04 — структура
last_pipeline_run). Все 141 pytest и 22 JS unit-теста зелёные. Все
P0/P1 находки из code-review v2 устранены. E2E и UI-тесты пропущены по
инфраструктурным причинам (бэкенд ET-008 не задеплоен на тест-стенд,
UI-раннер /home/slin/tools/ui-test/run_tests.js недоступен) — это не
дефект кода; рекомендуется выполнить E2E-прогон сразу после деплоя.
Шаг 1 — Проверка окружения
| Endpoint | Статус | Детали |
|---|---|---|
GET /enduro/api/health |
✅ 200 OK | {"status":"ok","db_exists":true} |
GET /enduro/api/gps-tracks/health |
❌ 404 | ET-008 не задеплоен на стенд |
GET /enduro/api/gps-tracks?bbox=… |
❌ 404 | ET-008 не задеплоен на стенд |
GET /enduro/api/gps-tracks/tiles/…mvt |
❌ 404 | ET-008 не задеплоен на стенд |
| Фронтенд (HTML) | ✅ | #public-tracks-cb, #sheet-gps-filters, gps_tracks.js в разметке |
Бэкенд-роуты /api/gps-tracks/* возвращают 404 — статика ET-008
задеплоена, сервис не поднят. E2E и UI тесты выполнить невозможно до
деплоя.
Шаг 2 — Функциональные тесты (python -m pytest tests/ -v)
cd /repos/enduro-trails/src/api
python -m pytest ../../tests/ -v --tb=short
Результат: 141 passed, 0 failed, 7 warnings
| Сюита | Тестов | Результат |
|---|---|---|
tests/api/test_gps_tracks_dedup.py |
8 | ✅ PASS |
tests/api/test_gps_tracks_endpoint.py |
15 | ✅ PASS |
tests/api/test_gps_tracks_mvt.py |
9 | ✅ PASS |
tests/api/test_gps_tracks_sources_osm.py |
21 | ✅ PASS |
tests/integration/test_routing_barriers.py |
7 | ✅ PASS |
tests/unit/test_base_layer.py |
22 | ✅ PASS |
tests/unit/test_gpx_upload.py |
21 | ✅ PASS |
tests/unit/test_health.py |
1 | ✅ PASS |
tests/unit/test_poi_toggle.py |
10 | ✅ PASS |
tests/unit/test_unit_toggle.py |
18 | ✅ PASS |
tests/web/test_gps_tracks.py |
9 | ✅ PASS |
Предупреждения (7 шт.) — DeprecationWarning в mapbox_vector_tile.encode
(внешняя библиотека, некритично).
Шаг 3 — E2E тесты (Playwright)
SKIP — бэкенд ET-008 не задеплоен на тест-стенд; Playwright-сценарии
E-01, E-02 (pipeline smoke) и E-10…E-12 (UI-фильтры) выполнить
невозможно. Рекомендуется запустить после make deploy-test.
Шаг 4 — JS Unit-тесты (node --test)
node --test tests/web/gps_tracks.test.js
Результат: 22 passed, 0 failed
| Группа | Тестов | Результат |
|---|---|---|
F-05: _findGpsInsertPosition — приоритет слоёв |
9 | ✅ PASS |
Filters: начальное состояние window.gpsTracksLayer |
5 | ✅ PASS |
| Colors: палитра источников, активностей, fallback | 8 | ✅ PASS |
Шаг 5 — UI / Visual тесты (TC-UI-01…TC-UI-20)
SKIP — /home/slin/tools/ui-test/run_tests.js недоступен; бэкенд
ET-008 не отвечает на тест-стенде. Скриншоты TC-UI-01…TC-UI-20 не
сделаны.
Верификация фиксов из 12-review.md
Итоговая таблица
| Finding | Severity | v2 | v3 | Вердикт |
|---|---|---|---|---|
| F-01: GeoJSON props несовместимы с MVT | P0 | PASS | PASS | ✅ PASS |
F-02: length_m вместо length_km в GeoJSON |
P1 | PASS | PASS | ✅ PASS |
| F-03: OSM batch-fetch и activity_type не реализованы | P1 | PASS | PASS | ✅ PASS |
| F-04: Health endpoint несовместим с REQ-F-12 | P1 | ⚠️ WARN | PASS | ✅ PASS |
F-05: Z-order vs gpx-layer-* |
P1 | PASS | PASS | ✅ PASS |
tests/web/gps_tracks.test.js отсутствует |
— | PASS | PASS | ✅ PASS |
| F-06: Нет валидации площади bbox | P2 | follow-up | follow-up | ⏭ follow-up |
| F-07: Дефолт sources включает disabled | P2 | follow-up | follow-up | ⏭ follow-up |
| F-08: LRU-кэш — на самом деле FIFO | P2 | follow-up | follow-up | ⏭ follow-up |
| F-09…F-12: P3-находки | P3 | follow-up | follow-up | ⏭ follow-up |
F-04 [P1] → ✅ PASS (v2: ⚠️ WARN)
Коммит 1ffa178 реализует агрегацию строк pipeline_runs по
MAX(started_at) в полный контракт REQ-F-12:
# endpoint.py, gps_health()
cur.execute("""
SELECT started_at, finished_at, region_id, source_id,
status, tracks_new, errors_json
FROM pipeline_runs
WHERE started_at = (SELECT MAX(started_at) FROM pipeline_runs)
ORDER BY region_id, source_id
""")
# → агрегация в:
{
"started_at": "...", "finished_at": "...",
"regions": ["tsfo_plus_chuvashia"],
"sources_ok": ["osm", "enduro_russia"],
"sources_error": [{"source": "ttrails", ...}],
"tracks_added": 100
}
Тест test_i40_health_endpoint (обновлён) проверяет:
- наличие всех 6 обязательных полей (
started_at,finished_at,regions,sources_ok,sources_error,tracks_added); - типы (
list,int); - отсутствие сырых полей БД (
region_id,source_id); - конкретные агрегированные значения из фикстуры (2 региона, 2 ok-источника).
test_i40_health_empty_db подтверждает: при пустой БД — last_pipeline_run: null.
Детали: что проверяют ключевые тесты ET-008
| Тест-ID | Связанный AC / REQ | Что проверяется |
|---|---|---|
test_f01_f02_geojson_normalised_properties |
AC-04, REQ-F-10 | GeoJSON activity, source, length_km, activity_type |
test_i20_filter_by_activity |
AC-04 | фильтр ?activity=enduro возвращает только enduro |
test_i20_filter_by_source |
AC-04 | фильтр ?source=osm возвращает только OSM |
test_i21_truncation |
AC-04 | truncated=true, returned=500, total_in_bbox=1500 |
test_i22_invalid_bbox_returns_400 (7 param) |
AC-04 | 400 на невалидные bbox |
test_i30_mvt_tile_returns |
AC-05 | 200 application/x-protobuf, layer gps_tracks |
test_i31_cache_hit |
AC-05, REQ-NF-04 | X-Cache: HIT на повторный запрос |
test_i40_health_endpoint |
AC-06, REQ-F-12 | все поля health, агрегированный last_pipeline_run |
test_u13_merge_sources_on_upsert |
AC-03, REQ-F-08 | дедупликация: union sources |
test_u44_xxe_protection |
REQ-NF-01 | defusedxml блокирует XXE |
test_u45_meta_response_with_known_tag |
REQ-F-04, REQ-F-07 | OSM tag → activity_type |
test_gps_tracks_find_insert_position_priority_gpx_first |
AC-10, §7.1 | gpx-layer-* > route-* |
Открытые P2/P3 — follow-up (не меняют вердикт)
| Finding | Severity | Описание | Рекомендация |
|---|---|---|---|
| F-06 | P2 | Нет проверки площади bbox | Добавить max area ≤ 100°² в _parse_bbox() |
| F-07 | P2 | Дефолт sources содержит disabled-источники | Инициализировать из /api/gps-tracks/health.tracks_by_source |
| F-08 | P2 | LRU-кэш — на самом деле FIFO | OrderedDict с move_to_end при чтении |
| F-09 | P3 | save_user_field в YAML не читается кодом |
Обработать в upsert |
| F-10 | P3 | Лишний import pytest_asyncio |
Убрать |
| F-11 | P3 | MockRow(dict) вместо sqlite3.Row |
Рефактор тестов |
| F-12 | P3 | Лишняя проверка "source_priority" in existing.keys() |
Упростить |
Рекомендации для деплоя
После выполнения make deploy-test или docker compose up -d на тест-стенде
с веткой feature/ET-008-gps:
- Smoke API:
curl https://openclaw.mva154.duckdns.org/enduro/api/gps-tracks/health curl "https://openclaw.mva154.duckdns.org/enduro/api/gps-tracks?bbox=37.0,55.0,38.0,56.0&limit=5" - E2E Playwright: E-01 (pipeline smoke), E-02 (dedup), E-10…E-12 (filters).
- UI тесты: TC-UI-01…TC-UI-20 через
run_tests.js(при наличии раннера). - P2 follow-up можно закрыть отдельным PR после приёмки основного.