test(generator): усилены проверки startup-history и Superset

- Зачем:
  - зелёный результат проверок должен означать фактический стык и точный контракт дашборда.
- Что:
  - проверка startup-history читает manifest, требует live seam и непустой ODS.
  - добавлен быстрый runtime gate для daily-wave и live-продолжения.
  - Superset sync ограничен целевым dashboard и сверяет существенные params.
- Проверка:
  - docker target tests; make generator-test; make generated-history-runtime-check.
This commit is contained in:
2026-07-05 21:32:51 +03:00
parent 9804d0beae
commit 00c97eb063
11 changed files with 500 additions and 23 deletions
+67 -9
View File
@@ -12,8 +12,9 @@ CLICKHOUSE_PASSWORD="${CLICKHOUSE_PASSWORD:-123456}"
GEN_MODEL_T0="${GEN_MODEL_T0:-2026-01-01T00:00:00+00:00}"
GEN_MODEL_T_END="${GEN_MODEL_T_END:-2026-01-01T06:00:00+00:00}"
REQUIRE_SUPERSET="${REQUIRE_SUPERSET:-1}"
CHECK_LIVE_SEAM="${CHECK_LIVE_SEAM:-auto}"
CHECK_LIVE_SEAM="${CHECK_LIVE_SEAM:-1}"
GEN_LIVE_CHECK_MINUTES="${GEN_LIVE_CHECK_MINUTES:-10}"
WAIT_LIVE_ROWS_SECONDS="${WAIT_LIVE_ROWS_SECONDS:-10}"
fail() {
echo "Ошибка: $*" >&2
@@ -50,11 +51,39 @@ CH_MODEL_T_END="$(clickhouse_datetime_literal "${GEN_MODEL_T_END}")"
[[ "${GEN_LIVE_CHECK_MINUTES}" =~ ^[0-9]+$ ]] \
|| fail "GEN_LIVE_CHECK_MINUTES должен быть целым числом минут"
[[ "${WAIT_LIVE_ROWS_SECONDS}" =~ ^[0-9]+$ ]] \
|| fail "WAIT_LIVE_ROWS_SECONDS должен быть целым числом секунд"
case "${CHECK_LIVE_SEAM}" in
0|1|auto) ;;
*) fail "CHECK_LIVE_SEAM должен быть 0, 1 или auto" ;;
esac
echo "=== Проверка startup-history manifest ==="
manifest_summary="$(${COMPOSE_BIN} run --rm --no-deps \
generator python -m clickstream_generator.startup_history_artifact kafka-manifest-summary)"
IFS=$'\t' read -r manifest_events manifest_visits manifest_users manifest_min_ts manifest_max_ts manifest_model_t0 manifest_model_t_end manifest_launch_profile <<< "${manifest_summary}"
[[ "${manifest_events}" =~ ^[0-9]+$ ]] || fail "не удалось прочитать startup-history manifest из Kafka"
[[ -n "${manifest_model_t0}" ]] || fail "startup-history manifest не содержит model_t0"
[[ -n "${manifest_model_t_end}" ]] || fail "startup-history manifest не содержит model_t_end"
CH_MODEL_T0="$(clickhouse_datetime_literal "${manifest_model_t0}")"
CH_MODEL_T_END="$(clickhouse_datetime_literal "${manifest_model_t_end}")"
expected_profile="${PROFILE:-${GEN_LAUNCH_PROFILE:-}}"
if [[ -n "${expected_profile}" && -n "${manifest_launch_profile}" && "${expected_profile}" != "${manifest_launch_profile}" ]]; then
fail "проверка запущена для профиля ${expected_profile}, но manifest от ${manifest_launch_profile}"
fi
echo "manifest_events=${manifest_events}"
echo "manifest_visits=${manifest_visits}"
echo "manifest_users=${manifest_users}"
echo "manifest_model_t0=${manifest_model_t0}"
echo "manifest_model_t_end=${manifest_model_t_end}"
echo "manifest_launch_profile=${manifest_launch_profile}"
echo "=== Проверка ClickHouse: данные генерации в DM ==="
stats_query="
@@ -271,7 +300,7 @@ echo "monotonic_ok=${contains_monotonic_ok}"
echo "confirmation_share=${contains_confirmation_share}"
should_check_live_seam="${CHECK_LIVE_SEAM}"
if [[ "${should_check_live_seam}" == "auto" ]]; then
if [[ "${should_check_live_seam}" != "0" ]]; then
live_rows_query="
WITH
toDateTime64('${CH_MODEL_T_END}', 6) AS t_end,
@@ -280,12 +309,25 @@ SELECT count()
FROM dds.event
WHERE event_ts >= t_end AND event_ts < t_live_end
FORMAT TabSeparated"
live_rows="$(ch_query "${live_rows_query}")"
[[ "${live_rows}" =~ ^[0-9]+$ ]] || fail "не удалось прочитать live-строки DDS после GEN_MODEL_T_END"
if (( live_rows > 0 )); then
should_check_live_seam="1"
else
should_check_live_seam="0"
live_rows=0
deadline=$((SECONDS + WAIT_LIVE_ROWS_SECONDS))
while true; do
live_rows="$(ch_query "${live_rows_query}")"
[[ "${live_rows}" =~ ^[0-9]+$ ]] || fail "не удалось прочитать live-строки DDS после GEN_MODEL_T_END"
if (( live_rows > 0 || SECONDS >= deadline )); then
break
fi
sleep 1
done
if [[ "${should_check_live_seam}" == "1" ]] && (( live_rows == 0 )); then
fail "live-продолжение не записало строки в первые ${GEN_LIVE_CHECK_MINUTES} минут после manifest model_t_end"
fi
if [[ "${CHECK_LIVE_SEAM}" == "auto" ]]; then
if (( live_rows > 0 )); then
should_check_live_seam="1"
else
should_check_live_seam="0"
fi
fi
fi
@@ -425,19 +467,35 @@ WITH
)
SELECT
(SELECT count() FROM crossing) AS crossing_visits,
(
SELECT count()
FROM ods.device_by_click AS d
INNER JOIN crossing AS c ON c.click_id = d.click_id
WHERE d.click_id IS NOT NULL
) AS ods_device_rows,
(
SELECT count()
FROM ods.geo_by_click AS g
INNER JOIN crossing AS c ON c.click_id = g.click_id
WHERE g.click_id IS NOT NULL
) AS ods_geo_rows,
(SELECT count() FROM device_conflicts) AS ods_device_conflicts,
(SELECT count() FROM geo_conflicts) AS ods_geo_conflicts
FORMAT TabSeparated"
ods_context="$(ch_query "${ods_context_query}")"
IFS=$'\t' read -r ods_crossing_visits ods_device_conflicts ods_geo_conflicts <<< "${ods_context}"
IFS=$'\t' read -r ods_crossing_visits ods_device_rows ods_geo_rows ods_device_conflicts ods_geo_conflicts <<< "${ods_context}"
[[ "${ods_crossing_visits}" =~ ^[0-9]+$ ]] || fail "не удалось прочитать ODS-проверку стыка"
(( ods_crossing_visits == crossing_visits )) \
|| fail "ODS и DDS нашли разное число переходящих визитов: ${ods_crossing_visits}/${crossing_visits}"
(( ods_device_rows > 0 )) || fail "ODS device пустой на стыке"
(( ods_geo_rows > 0 )) || fail "ODS geo пустой на стыке"
(( ods_device_conflicts == 0 )) || fail "ODS device конфликтует на стыке: ${ods_device_conflicts}"
(( ods_geo_conflicts == 0 )) || fail "ODS geo конфликтует на стыке: ${ods_geo_conflicts}"
echo "ods_device_rows=${ods_device_rows}"
echo "ods_geo_rows=${ods_geo_rows}"
echo "ods_device_conflicts=${ods_device_conflicts}"
echo "ods_geo_conflicts=${ods_geo_conflicts}"
else