402 lines
16 KiB
YAML
402 lines
16 KiB
YAML
---
|
||
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"
|
||
---
|