Netpulse_SasS/scripts/dbtest.sh
byrsapty ec4b2cd54b
All checks were successful
CI / hygiene (push) Successful in 10s
CI / web (push) Successful in 1m18s
CI / server (push) Successful in 1m54s
CI / agent (push) Successful in 1m1s
Тиха година й драбина: вада окремо, вибір окремо
Асиметрія: аварія о 21:59 ескалювала всю ніч, о 22:01 не ескалювала
ніколи. Дві хвилини різниці — протилежні наслідки, причому гірший
(повна тиша) виглядав як тиша справна.

ВАДА. targets() повертав порожньо в тиху годину, а взведення читало це
як «немає куди слати». Взводять лише новий алерт, тож драбина не
з'являлась уже ніколи: тиха година вимикала механізм саме тоді, коли
перше сповіщення не спрацювало. Тепер targets() розрізняє «каналів
немає» і «канали є, просто зараз ніч».

ВИБІР. 0072 додає respect_quiet_hours на драбину:
  false (типово, як діяло) — драбина пробивається;
  true  — сходинка відкладається до ранку і НЕ витрачається.
Залежить від того, чи є в кабінету нічна зміна — це вирішує кабінет.
disaster пробивається за будь-якого значення, як і в targets().

Відлік драбини — від першого сповіщення, а не від started_at: інакше
для розглушеного алерту вона протухла б ще у вікні.

І сам прогін проти бази брехав: dbtest.sh котив схему готовим образом
(старі міграції), а тести брав із нового дерева. Тепер міграції з того
ж дерева. 64 міграції, усе зелене.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 18:08:27 +03:00

111 lines
6.1 KiB
Bash
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.

#!/bin/sh
# Прогін тестів проти СПРАВЖНЬОЇ бази.
#
# ЧОМУ ЦЕ ОКРЕМИЙ СКРИПТ
#
# Тести проти бази мовчки пропускаються без NETPULSE_TEST_DSN — і саме
# тому вони півтора року нічого не перевіряли: `go test ./...` показував
# «ok», а всередині кожного з них стояв t.Skip. «Пропущено» в підсумку
# виглядає рівно як «пройдено», і це найдорожча тиха відмова в проєкті:
# перевірка ізоляції кабінетів, стелі тарифу, гасіння алертів і драбин
# ескалації існували, компілювались і не виконувались.
#
# scripts/check.sh лишається швидким (без Docker і без бази) — його
# ганяють на кожну правку. Цей скрипт повільніший і потребує Postgres,
# тож викликається окремо: перед розгортанням і в CI.
#
# БАЗА МУСИТЬ БУТИ ОДНОРАЗОВОЮ. Тести пишуть, видаляють і перемикають
# ролі, а перед ними ще й котяться міграції — зокрема ті, яких у робочій
# базі ще не має бути. І це не побажання в коментарі: рівно так гине
# бойова база, коли в профілі шелла лишився експортований
# NETPULSE_TEST_DSN зі вчорашнього налагодження. Тому нижче стоїть
# перевірка імені, а не заклик до обережності.
#
# ВИКОРИСТАННЯ
# scripts/dbtest.sh # підніме свій Postgres
# NETPULSE_TEST_DSN=... scripts/dbtest.sh # проти готової бази,
# # ім'я якої містить probe/test
#
set -u
SRC="$(cd "$(dirname "$0")/.." && pwd)"
OWN_DB=0
NAME=""
# Ім'я бази має саме казати, що вона одноразова. Перевірка навмисно
# дурна й невідмикна: розумніша (маркерна таблиця, прапорець згоди)
# перекладає рішення на людину рівно в той момент, коли людина поспішає.
guard_disposable() {
db=$(printf '%s' "$1" | sed -e 's/?.*$//' -e 's#.*/##')
case "$db" in
*probe*|*test*) return 0 ;;
esac
echo "!!! NETPULSE_TEST_DSN вказує на базу «$db»." >&2
echo " Тести пишуть, видаляють і котять міграції — база мусить бути" >&2
echo " одноразовою, і її імʼя має містити «probe» або «test»." >&2
echo " Якщо це чернетка — перейменуйте базу. Якщо ні — ви щойно мало" >&2
echo " не накотили міграції на робочу базу." >&2
exit 1
}
if [ -z "${NETPULSE_TEST_DSN:-}" ]; then
# Своя база на час прогону. Порт випадковий-таки ні: фіксований, але
# нетиповий, щоб не зіткнутись із локальним Postgres розробника.
PORT=${NETPULSE_TEST_PORT:-55433}
# Імʼя з номером процесу: два прогони поруч (другий термінал, дві
# задачі на одному раннері) інакше вбивали б бази один одному, і
# падіння виглядало б як помилка зʼєднання нізвідки.
NAME="netpulse-dbtest-$$"
echo "== піднімаю одноразовий Postgres :$PORT"
docker run -d --name "$NAME" -p "$PORT:5432" \
-e POSTGRES_USER=netpulse -e POSTGRES_PASSWORD=probe \
-e POSTGRES_DB=netpulse_probe \
timescale/timescaledb:2.17.2-pg16 >/dev/null || exit 1
OWN_DB=1
NETPULSE_TEST_DSN="postgres://netpulse:probe@127.0.0.1:$PORT/netpulse_probe?sslmode=disable"
export NETPULSE_TEST_DSN
n=0
until docker exec "$NAME" pg_isready -h 127.0.0.1 -U netpulse >/dev/null 2>&1; do
n=$((n+1)); [ "$n" -gt 60 ] && { echo "база не піднялась"; exit 1; }
sleep 1
done
else
guard_disposable "$NETPULSE_TEST_DSN"
fi
# Своя база зноситься лише після ЗЕЛЕНОГО прогону. Після червоного вона
# лишається: подивитись, що саме опинилось у таблицях, — єдиний спосіб
# зрозуміти половину падінь, а знесена база забирає цю можливість рівно
# тоді, коли вона потрібна.
cleanup() {
[ "$OWN_DB" = 1 ] || return 0
if [ "${rc:-1}" = 0 ]; then
docker rm -f "$NAME" >/dev/null 2>&1
else
echo
echo "база лишилась для розбору: docker exec -it $NAME psql -U netpulse netpulse_probe"
echo "прибрати: docker rm -f $NAME"
fi
return 0
}
trap cleanup EXIT INT TERM
# Міграції котяться З ЦЬОГО Ж ДЕРЕВА (go run), а не готовим образом — і
# це не дрібниця. Образ зібрано з розгорнутого коду, тож він знає лише
# старі міграції, і тести нового коду йшли б проти старої схеми: падіння
# виглядало б як «немає такого стовпця», хоч стовпець у гілці є. Один
# такий прогін уже збрехав саме так.
echo "== накат міграцій"
( cd "$SRC/server" && NETPULSE_DSN="$NETPULSE_TEST_DSN" go run ./cmd/netpulse-migrate ) || exit 1
echo "== тести"
( cd "$SRC/server" && go test ./internal/... -count=1 )
rc=$?
echo
if [ "$rc" = 0 ]; then
echo "усе зелене проти бази"
else
echo "!!! тести проти бази не пройшли"
fi
exit $rc