Files
clickstream-ch-kafka-supers…/docs/TEST_PLAN.md
T
ddadminandClaude Fable 5 ac7a973504 feat(airflow): пульт стал world_init, добавлен DAG world_next_day (#4)
- Зачем:
  - список DAG'ов должен читаться лесенкой ddl_init → world_init →
    world_next_day, а путь менти — проходиться пустыми формами
    (issue #4, спека редизайна пути менти, решения 2–3).
- Что:
  - generator_control переименован в world_init, дефолт операции —
    import; next-day ушёл из выпадашки в отдельный DAG;
  - новый беспараметрный world_next_day: расписание */30 * * * *,
    создаётся на паузе, catchup=False, max_active_runs=1; общие
    задачи вынесены в airflow/dags/utils/startup_history_tasks.py;
  - доки и контрактные тесты обновлены синхронно; быстрый старт
    README — без make ddl, схему создаёт DAG ddl_init.
- Проверка:
  - make test (210 + 31) и make lint зелёные;
  - живая приёмка на чистом стенде: world_init пустой формой
    импортировал эталонный мир за 217 с (3 дня, 280 437 событий),
    world_next_day после снятия с паузы добавляет ровно один день
    за прогон, дашборд Superset собирается.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 21:45:02 +03:00

293 lines
11 KiB
Markdown
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.
# План тестирования стенда (Smoke + Full)
Документ описывает два контура проверки системы:
- быстрый `smoke` для регрессий после изменений;
- полный `full` для финальной валидации end-to-end.
## Цель
Проверить, что стек `Kafka + ClickHouse + Airflow + Superset + Prometheus/Grafana`:
- стабильно поднимается;
- загружает данные по пути `startup-history/backfill -> Kafka -> STG -> ODS/DDS/DM`;
- корректно обрабатывает «грязные» записи (ошибки фиксируются в ODS, пайплайн не падает);
- отдает метрики и дашборды мониторинга.
## Общие принципы
- Для smoke и CI явно задаём служебный профиль `ci`.
- Полный прогон выполняем отдельно через `PROFILE=daily-wave`.
- Основной ручной путь запуска — через Airflow DAG `world_init` с пустой формой.
- Консольный чистый прогон `make generated-history-analytics` остаётся коротким
повторяемым сценарием для smoke и CI.
- Критерий успеха: не только `Success` DAG, но и проверки данных/ошибок/мониторинга.
---
## Контур A: Smoke (быстрый)
Ожидаемая длительность: ~10-20 минут.
### A.1 Подготовка окружения
```bash
# Чистый быстрый прогон: backfill -> Kafka -> STG -> ODS -> DDS -> DM -> Superset
PROFILE=ci make generated-history-analytics
# Поднять остальные UI-сервисы после чистого прогона
make up
# Проверка контейнеров
docker compose ps
```
Ожидаем:
- `airflow-init` в `Exited (0)`;
- остальные сервисы в `Up` (включая `superset`, `prometheus`, `grafana`, `kafka-exporter`, `statsd-exporter`).
### A.2 Проверка стартовой истории в STG
Проверки:
```bash
# STG не пустой
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 \
--query "
SELECT 'browser_raw' AS table, count() AS cnt FROM stg.browser_raw
UNION ALL
SELECT 'location_raw', count() FROM stg.location_raw
UNION ALL
SELECT 'device_raw', count() FROM stg.device_raw
UNION ALL
SELECT 'geo_raw', count() FROM stg.geo_raw
"
```
Ожидаем: во всех 4 таблицах `cnt > 0`.
### A.3 Проверки слоев
Проверки:
```bash
# ODS / DDS / DM
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 \
--query "
SELECT 'ods.browser_event' AS table, count() AS cnt FROM ods.browser_event
UNION ALL
SELECT 'dds.event', count() FROM dds.event
UNION ALL
SELECT 'dds.click', count() FROM dds.click
UNION ALL
SELECT 'dm.dq_summary', count() FROM dm.dq_summary
"
# Базовая целостность DDS (ожидаем 0 orphan-событий)
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 \
--query "
SELECT countIf(click_id IS NOT NULL AND click_id NOT IN (SELECT click_id FROM dds.click)) AS orphan_events
FROM dds.event
"
```
Ожидаем:
- `ods.browser_event`, `dds.event`, `dm.dq_summary` > 0;
- `orphan_events = 0`.
### A.4 Smoke мониторинга
```bash
# Prometheus targets
curl -s http://localhost:9090/api/v1/targets | grep -o '"health":"[^"]*"'
# Grafana health
curl -s -u admin:admin http://localhost:3000/api/health
# Дашборды по UID
curl -s -u admin:admin "http://localhost:3000/api/dashboards/uid/clickhouse-overview" | grep -o '"title":"[^"]*"'
curl -s -u admin:admin "http://localhost:3000/api/dashboards/uid/kafka-overview" | grep -o '"title":"[^"]*"'
curl -s -u admin:admin "http://localhost:3000/api/dashboards/uid/airflow-overview" | grep -o '"title":"[^"]*"'
```
Критерий успеха smoke:
- сервисы подняты;
- стартовая история доведена до DM;
- данные проходят до DM;
- мониторинг и дашборды доступны.
---
## Контур B: Full (полный)
Ожидаемая длительность: ~30-60 минут.
### B.1 Полная стартовая история и ETL
```bash
# История на 3 суток с видимой суточной волной
PROFILE=daily-wave make generated-history-analytics
make up
```
### B.2 Проверка объемов и DQ
```bash
# Диапазон модельного времени в витрине
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 --query "
SELECT min(event_ts) AS min_event_ts, max(event_ts) AS max_event_ts, count() AS events
FROM dm.v_events_enriched
"
# Сводка по слоям
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 --query "
SELECT 'STG' as layer, sum(rows) as total_rows FROM (
SELECT count() as rows FROM stg.browser_raw UNION ALL
SELECT count() FROM stg.location_raw UNION ALL
SELECT count() FROM stg.device_raw UNION ALL
SELECT count() FROM stg.geo_raw
) UNION ALL
SELECT 'ODS', sum(rows) FROM (
SELECT count() FROM ods.browser_event UNION ALL
SELECT count() FROM ods.location_event UNION ALL
SELECT count() FROM ods.device_by_click UNION ALL
SELECT count() FROM ods.geo_by_click
) UNION ALL
SELECT 'DDS', sum(rows) FROM (
SELECT count() FROM dds.event UNION ALL
SELECT count() FROM dds.click
)"
# DQ summary
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 \
--query "SELECT * FROM dm.dq_summary ORDER BY layer, table_name, check_name"
```
Критерии успеха full:
- STG заполнен по всем 4 потокам;
- ODS/DDS/DM заполнены;
- диапазон `event_ts` соответствует созданной стартовой истории;
- `dm.dq_summary` не пуста и содержит метрики всех слоев.
### B.3 Тест восстановления stop/start
```bash
# Остановить без удаления данных
docker compose stop
# Проверить volumes
docker volume ls | grep -E 'clickhouse-data|kafka-data|pgmeta|grafana_lib|superset_data|superset_config'
# Поднять обратно
docker compose start
# Проверить, что данные сохранились
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 \
--query "SELECT count() FROM dds.event"
```
---
## Сценарий C: «Грязные» данные не валят пайплайн
Цель: доказать, что невалидные записи фиксируются в `ods.*_errors`, а ETL завершается успешно.
Предусловие: выполнен `Контур A` или `Контур B` (в STG уже есть валидные данные).
### C.1 Инъекция невалидных записей в STG
```bash
# browser: невалидные UUID и timestamp
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 \
--query "INSERT INTO stg.browser_raw (raw) VALUES ('{\"event_id\":\"bad-uuid\",\"event_timestamp\":\"bad-ts\",\"click_id\":\"bad-click\",\"event_type\":\"pageview\"}')"
# location: невалидный event_id
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 \
--query "INSERT INTO stg.location_raw (raw) VALUES ('{\"event_id\":\"bad-uuid\",\"page_url\":\"https://example.com\"}')"
# device: невалидные click_id и user_domain_id
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 \
--query "INSERT INTO stg.device_raw (raw) VALUES ('{\"click_id\":\"bad-uuid\",\"user_domain_id\":\"bad-uuid\",\"device_type\":\"Mobile\"}')"
# geo: невалидные click_id и координаты
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 \
--query "INSERT INTO stg.geo_raw (raw) VALUES ('{\"click_id\":\"bad-uuid\",\"geo_latitude\":\"abc\",\"geo_longitude\":\"def\"}')"
```
### C.2 Повторный ETL
```bash
docker compose exec -T airflow-webserver airflow dags trigger etl_pipeline \
--conf '{"full_refresh": true}'
```
Ожидаем: DAG `etl_pipeline` завершен в `Success`.
### C.3 Ассерты по ошибкам
```bash
# Ошибки должны попасть в *_errors таблицы
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 \
--query "
SELECT 'browser_event_errors' AS table, count() AS cnt FROM ods.browser_event_errors
UNION ALL
SELECT 'location_event_errors', count() FROM ods.location_event_errors
UNION ALL
SELECT 'device_by_click_errors', count() FROM ods.device_by_click_errors
UNION ALL
SELECT 'geo_by_click_errors', count() FROM ods.geo_by_click_errors
"
# При этом пайплайн продолжает давать бизнес-слой
docker compose exec -T clickhouse clickhouse-client --user=default --password=123456 \
--query "SELECT count() FROM dds.event"
```
Критерии успеха сценария C:
- `etl_pipeline` не падает;
- хотя бы одна `*_errors` таблица увеличилась;
- `dds.event` остается непустой (валидные данные продолжают обрабатываться).
---
## Проверка алертов (фактический набор)
Проверяем, что в Grafana загружены именно текущие provisioned-правила:
```bash
curl -s -u admin:admin http://localhost:3000/api/v1/provisioning/alert-rules | grep -o '"title":"[^"]*"'
```
Ожидаемые правила:
- ClickHouse:
- `ClickHouse Failed Queries Rate`
- `ClickHouse Memory Resident High`
- `ClickHouse Parts Active High`
- Airflow:
- `Airflow Scheduler Down`
- `Airflow Queue Backlog`
- `High Task Failure Rate`
- `High DAG Parse Time`
- Kafka:
- `Kafka Broker Down`
- `Kafka Consumer Lag High`
- `Kafka No Messages Produced`
---
## Финальный чек-лист приемки
- `Smoke` проходит стабильно после изменений в коде.
- `Full` проходит перед демонстрацией/релизом.
- Сценарий `Грязные данные` подтверждает, что ошибки локализуются в ODS и не ломают ETL.
- Метрики и дашборды доступны, алерты совпадают с текущей конфигурацией provisioning.