Files
enduro-trails/docs/work-items/ET-012/04-test-plan.yaml
claude-bot eb9adbc930
All checks were successful
CI / lint (push) Successful in 5s
CI / test (push) Successful in 7s
CI / build (push) Successful in 2s
analyst(ET): auto-commit from analyst run_id=72
2026-06-04 06:00:55 +00:00

402 lines
16 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.
---
type: test-plan
work_item_id: ET-012
title: "Test Plan: Показывать пользовательские треки с зума z5"
version: 1
status: draft
created_at: 2026-06-04
updated_at: 2026-06-04
authors:
- "agent:analyst"
related:
- "ET-008"
- "ET-009"
- "ET-011"
scope_note: >
ET-012 опускает порог видимости слоя публичных GPS-треков с z8 до z5.
Изменения локализованы:
- backend mvt.py: zoom-tier для z5/z6 (min_length, limit, tolerance);
- frontend gps_tracks.js: константа GPS_TRACKS_MIN_ZOOM=5,
line-width stops для z5 в основном слое и halo;
- index.html: текст hint «Зум 5+».
Тест-план фокусируется на:
(1) корректности новых zoom-tier'ов в build_gps_mvt и _simplify_coords;
(2) что endpoint отдаёт нормально-размерные MVT на z5-z7;
(3) что клиент действительно показывает слой на z5-z7;
(4) что регрессий ET-008/009/011 нет;
(5) что производительность не уплыла.
test_suites:
- name: unit-mvt-zoom-tiers
type: unit
description: "Тиры min_length_m и limit в build_gps_mvt по зумам"
cases:
- id: UT-Z5-01
name: "z=5: треки < 10 км отфильтровываются"
input: |
Mock rows: 10 треков, длина = [500, 2000, 3000, 8000, 12000, 15000, 25000, 50000, 80000, 120000].
Вызов build_gps_mvt(rows, z=5, x=19, y=9).
expected: |
В MVT попадают только треки длиной >= 10000 м, т.е. ровно 6 features.
- id: UT-Z5-02
name: "z=5: limit=1500"
input: |
Mock rows: 2000 треков длиной 15 км каждый (все пройдут min_length).
expected: |
В MVT попадают первые 1500 features, остальные отбрасываются.
- id: UT-Z6-01
name: "z=6: треки < 5 км отфильтровываются"
input: |
Mock rows: 5 треков, длина = [1000, 3000, 5000, 7000, 10000].
expected: |
В MVT 3 features (5000, 7000, 10000).
- id: UT-Z6-02
name: "z=6: limit=2000"
input: |
Mock rows: 2500 треков длиной 6 км каждый.
expected: |
В MVT 2000 features.
- id: UT-Z7-01
name: "z=7: регрессия — поведение до ET-012"
input: |
Mock rows: 4 трека [1000, 2000, 3000, 5000].
expected: |
В MVT 3 features (2000, 3000, 5000), как раньше.
- id: UT-Z8-01
name: "z=8: регрессия — нет min_length-фильтра"
input: |
Mock rows: 4 трека [500, 1000, 2000, 5000].
expected: |
В MVT 4 features, limit=8000.
- id: UT-Z12-01
name: "z=12: регрессия — limit=25000, без min_length"
input: |
Mock rows: 100 треков любой длины.
expected: |
В MVT 100 features.
- name: unit-mvt-simplify
type: unit
description: "Tolerance Douglas-Peucker по зумам в _simplify_coords"
cases:
- id: UT-SIMP-Z5-01
name: "z=5: прямая линия 100 точек → ≤ 5 точек"
input: |
coords = [(37.0 + i*0.001, 55.0 + i*0.001) for i in range(100)]
(приблизительно прямая ~10 км по диагонали)
expected: |
len(_simplify_coords(coords, 5)) <= 5
- id: UT-SIMP-Z5-02
name: "z=5: зигзаг с амплитудой < tolerance → 2 точки"
input: |
coords = зигзаг 100 точек, амплитуда 0.01° (~1 км)
expected: |
len(_simplify_coords(coords, 5)) == 2 (только концы)
- id: UT-SIMP-Z6-01
name: "z=6: зигзаг 5 км → видны крупные пики"
input: |
coords = зигзаг 100 точек, амплитуда 0.05° (~5 км)
expected: |
len(_simplify_coords(coords, 6)) > 5
- id: UT-SIMP-Z7-01
name: "z=7: регрессия — tolerance = 0.008"
input: |
coords = зигзаг 100 точек, амплитуда 0.005° (~500 м)
expected: |
len(_simplify_coords(coords, 7)) близок к до-ET-012 значению
(округлённо в пределах +/-1).
- id: UT-SIMP-Z10-01
name: "z=10: регрессия — tolerance = 0.0005"
input: |
coords = зигзаг 100 точек, амплитуда 0.001° (~100 м)
expected: |
Поведение совпадает с до-ET-012 (контрольный snapshot).
- id: UT-SIMP-Z12-01
name: "z=12: регрессия — без упрощения"
input: |
coords = 100 точек
expected: |
_simplify_coords(coords, 12) is coords (или эквивалент)
- id: UT-SIMP-EDGE-01
name: "Слишком мало точек → возвращаем как есть"
input: |
coords = [(37.0, 55.0), (37.001, 55.001)] (2 точки)
expected: |
На любом zoom — функция возвращает [(37.0, 55.0), (37.001, 55.001)].
- id: UT-SIMP-EDGE-02
name: "DP схлопнул до < 2 точек → возвращаем оригинал"
input: |
coords = 100 одинаковых точек (вырожденный трек)
expected: |
Функция возвращает оригинальный coords, не пустой список.
- name: integration-tile-endpoint
type: integration
description: "Endpoint /api/gps-tracks/tiles/{z}/{x}/{y}.mvt на z=5..7"
cases:
- id: IT-Z5-01
name: "Тайл z=5 над Москвой: 200, тело > 0, < 200 KB"
input: |
Test DB: 50 треков по ЦФО, длина 12..30 км каждый.
GET /api/gps-tracks/tiles/5/19/9.mvt
expected: |
status 200,
Content-Type 'application/x-protobuf',
0 < len(body) < 200_000
- id: IT-Z5-02
name: "Тайл z=5 с большой БД: limit держит размер"
input: |
Test DB: 200 треков по ЦФО, длина 12..30 км.
GET /api/gps-tracks/tiles/5/19/9.mvt
expected: |
status 200,
len(body) < 200_000,
mapbox_vector_tile.decode(body)['gps_tracks']['features'] <= 1500
- id: IT-Z5-03
name: "Тайл z=5 над пустым регионом: пустое тело"
input: |
Test DB: те же 50 треков по ЦФО.
GET /api/gps-tracks/tiles/5/4/12.mvt (Тихий океан)
expected: |
status 200,
len(body) == 0
- id: IT-Z6-01
name: "Тайл z=6 над Москвой: больше фич, чем z=5"
input: |
Test DB: 100 треков, длина 4..20 км.
GET /api/gps-tracks/tiles/6/38/19.mvt
expected: |
status 200,
features_count(z=6) >= features_count(z=5) для того же региона,
len(body) < 200_000
- id: IT-Z7-01
name: "Тайл z=7 над Москвой: регрессия + плюс короткие треки"
input: |
GET /api/gps-tracks/tiles/7/77/39.mvt с теми же 100 треками.
expected: |
status 200,
features_count(z=7) >= features_count(z=6),
features_count(z=7) <= 3000
- id: IT-CACHE-01
name: "LRU-кэш: второй запрос — X-Cache: HIT"
input: |
GET /api/gps-tracks/tiles/5/19/9.mvt дважды подряд.
expected: |
1-й ответ: header X-Cache: MISS.
2-й ответ: header X-Cache: HIT, тело идентично 1-му.
- id: IT-CACHE-02
name: "Сброс кэша через /cache/clear"
input: |
GET tiles/5/19/9.mvt → POST /api/gps-tracks/cache/clear → GET tiles/5/19/9.mvt
expected: |
1-й ответ MISS, 2-й (после clear) MISS.
- id: IT-REGRESS-Z8-01
name: "Регрессия z=8: контракт MVT не изменился"
input: |
GET /api/gps-tracks/tiles/8/154/79.mvt на тестовой БД.
(Тайл-координаты выбраны над Москвой.)
expected: |
features_count(z=8) точно совпадает с snapshot до ET-012
(записывается в tests/fixtures/gps-tracks/mvt-z8-snapshot.json).
- id: IT-REGRESS-Z10-01
name: "Регрессия z=10"
input: |
GET /api/gps-tracks/tiles/10/617/319.mvt
expected: |
features_count(z=10) совпадает с snapshot до ET-012.
- id: IT-VALID-01
name: "z вне диапазона — 400"
input: |
GET /api/gps-tracks/tiles/-1/0/0.mvt и tiles/23/0/0.mvt
expected: |
status 400, detail 'Invalid z'
- name: integration-api-geojson-cutoff
type: integration
description: "GeoJSON-слой не изменился"
cases:
- id: IT-GEO-01
name: "GET /api/gps-tracks?bbox=… работает как раньше"
input: |
GET /api/gps-tracks?bbox=37,55,38,56&limit=500
expected: |
status 200,
FeatureCollection с features, total_in_bbox, returned, truncated —
контракт идентичен ET-009.
- name: performance
type: performance
description: "Производительность build_gps_mvt на z=5"
marker: "@pytest.mark.perf"
cases:
- id: PERF-Z5-01
name: "build_gps_mvt на z=5 при 500 треках"
input: |
Test DB: 500 треков длиной 12-25 км по ЦФО.
10 повторных вызовов build_gps_mvt(rows, 5, 19, 9).
expected: |
avg time <= 200 ms,
p95 time <= 500 ms на CI-runner (метрика M-6).
- id: PERF-Z5-02
name: "build_gps_mvt на z=5 при 5000 треках (стресс)"
input: |
Test DB: 5000 треков, разные длины.
5 повторных вызовов.
expected: |
p95 time <= 1500 ms.
- id: PERF-ENDPOINT-01
name: "Endpoint p95 на z=5 (cold)"
input: |
10 cold-запросов tile-endpoint (после cache clear) на test-БД.
expected: |
p95 <= 700 ms.
- id: PERF-ENDPOINT-02
name: "Endpoint p95 на z=5 (hot, кэш)"
input: |
100 повторных запросов одного тайла после прогрева.
expected: |
p95 <= 50 ms.
- name: regression-existing
type: regression
description: "Регрессия ET-008 / ET-009 / ET-011"
cases:
- id: RG-08-01
name: "Все unit-тесты ET-008 проходят"
input: "pytest tests/unit/test_gps_*.py -v (за исключением новых ET-012)"
expected: "exit-code 0"
- id: RG-09-01
name: "Все unit-тесты ET-009 (parser EnduroRussia/Wikiloc)"
input: "pytest tests/unit/test_gps_tracks_enduro_russia.py tests/unit/test_gps_tracks_wikiloc.py -v"
expected: "exit-code 0"
- id: RG-11-01
name: "Тесты ET-011 download GPX"
input: "pytest tests/integration/test_gps_download.py -v"
expected: "exit-code 0"
- id: RG-INT-01
name: "Все integration-тесты"
input: "pytest tests/integration/ -v"
expected: "exit-code 0"
- name: ui-playwright
type: ui
description: "Playwright UI-тесты на test-среде"
reference: "04b-ui-test-cases.md"
cases:
- id: UI-LINK-01
name: "См. 04b-ui-test-cases.md — TC-UI-01-Z5..TC-UI-12-Z5-Q"
expected: "Каждый TC выполняется и check-visual подтверждается оператором."
- name: manual-deploy-validation
type: e2e
description: "Ручная проверка в test-среде после деплоя"
marker: "manual"
cases:
- id: E2E-DEPLOY-01
name: "Включить слой и поставить zoom=5"
steps:
- "Открыть https://openclaw.mva154.duckdns.org/enduro/"
- "Open DevTools, в Console: localStorage.clear() для чистого старта"
- "Click #terrain-toggle"
- "Click #public-tracks-cb (включить)"
- "В Console: window._map.setZoom(5); window._map.setCenter([37.6, 55.7])"
- "Ждать 3 секунды"
- "Visual: видны линии публичных треков"
- "Зафиксировать скриншот в 14-deploy-log.md"
- id: E2E-DEPLOY-02
name: "Network: размер тайла z=5"
steps:
- "В DevTools Network отфильтровать по 'tiles/5'"
- "Проверить: каждый ответ ≤ 200 KB (Size column)"
- "Зафиксировать в 14-deploy-log.md"
- id: E2E-DEPLOY-03
name: "Уменьшить зум до z=4 — hint показывается"
steps:
- "window._map.setZoom(4)"
- "Visual: hint 'Зум 5+' появился"
- "На карте нет линий публичных треков"
- id: E2E-DEPLOY-04
name: "Зум z=12 — переход на GeoJSON"
steps:
- "window._map.setZoom(12)"
- "Wait 1.5s"
- "В DevTools Network отфильтровать по '/api/gps-tracks?bbox'"
- "Запрос ушёл, status 200"
- "На карте видны линии, но из GeoJSON-source (gps-tracks-layer-geo)"
- id: E2E-DEPLOY-05
name: "Регрессия: popup и скачивание GPX"
steps:
- "window._map.setZoom(8)"
- "Кликнуть по треку из источника osm"
- "Popup открылся, в нём есть кнопка 'Скачать GPX'"
- "Клик по кнопке скачивает .gpx файл (ET-011 контракт)"
test_data:
fixtures_dir: "tests/fixtures/gps-tracks/"
fixtures:
- name: "mvt-z8-snapshot.json"
description: "Snapshot число features в тайле z=8/154/79 над Москвой до ET-012 (для IT-REGRESS-Z8-01)"
- name: "mvt-z10-snapshot.json"
description: "Аналогично для z=10/617/319 (IT-REGRESS-Z10-01)"
notes:
- "Snapshot'ы создаются разово до начала разработки ET-012 на текущем состоянии test-БД и кладутся в репо."
- "Для unit-тестов использовать sqlite3.Row mock — реальная БД не нужна."
test_environment:
unit:
- "pytest tmp_path для временной sqlite (по необходимости)"
- "Mock sqlite3.Row через unittest.mock или фабрика"
integration:
- "Test sqlite БД с фикстурными треками из existing ET-008/009 фабрик"
- "FastAPI TestClient для endpoint вызовов"
performance:
- "Маркер @pytest.mark.perf, не в обычном CI"
- "Запуск перед merge: pytest -m perf"
e2e:
- "Test-среда https://openclaw.mva154.duckdns.org/enduro/"
- "Реальная БД после ET-009 прогона"
- "UI-тесты — см. 04b-ui-test-cases.md (Playwright)"
ci_gates:
- "Unit-тесты UT-Z*-* и UT-SIMP-* — обязательны (AC-11, AC-12)"
- "Integration IT-Z*-*, IT-CACHE-*, IT-REGRESS-* — обязательны (AC-13)"
- "Регрессия RG-* — обязательна (AC-14)"
- "Performance PERF-Z5-01 — обязателен перед merge (AC-19)"
- "UI-тесты — запуск после деплоя, фиксация в 13-test-report.md"
- "E2E-DEPLOY-* — ручные шаги в 14-deploy-log.md"
---