fix(smoke): «ответа нет» ≠ «неверный код» — ретраи и честная формулировка в смоуке периметра МЕРА #3441
2 changed files with 221 additions and 23 deletions
|
|
@ -35,7 +35,35 @@ concurrency:
|
||||||
jobs:
|
jobs:
|
||||||
smoke:
|
smoke:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 5
|
# 11.09.2026: было 5 минут — теперь мало. В скрипте появились пауза между
|
||||||
|
# проверками (2 c) и повтор запроса, если ответа не пришло вовсе: обычный
|
||||||
|
# прогон вырос с ~89 c до ~175 c, а ХУДШИЙ случай — гораздо больше, потому
|
||||||
|
# что каждая неотвечающая проверка стоит до 3×15 c таймаута плюс паузы
|
||||||
|
# (~53 c против обычных ~2 c).
|
||||||
|
#
|
||||||
|
# 12.09.2026: 10 минут — тоже мало, и мало ровно в том сценарии, ради
|
||||||
|
# которого повтор писался. АРИФМЕТИКА ХУДШЕГО СЛУЧАЯ. Одна неотвечающая
|
||||||
|
# проверка сетевого класса = 3×15 c таймаута + 2 c и 4 c пауз ретрая + 2 c
|
||||||
|
# паузы между проверками = 53 c. Прод не отвечает целиком (DNS не
|
||||||
|
# резолвится, вход лежит) — мертвы ВСЕ проверки: 43 × 53 = 2279 c ≈ 38 мин.
|
||||||
|
# Откуда 43 (замер 12.09, зелёный прогон против прода — 43 PASS за 167 c):
|
||||||
|
# 42 обычные проверки + отдельная загрузка HTML лэндинга; 43-я, производный
|
||||||
|
# layout-чанк, при мёртвом ответе не запрашивается вовсе — запросов ровно
|
||||||
|
# столько же.
|
||||||
|
# В 10 минут помещалось ~8 мёртвых проверок из 43, дальше job убивали ДО
|
||||||
|
# печати FAIL-строк и итога — то есть лог терялся при полном отказе прода.
|
||||||
|
#
|
||||||
|
# Правка «повторяем только сетевой класс» (12.09) худший случай НЕ
|
||||||
|
# уменьшает: 15-секундный таймаут как раз сетевой (rc=28) и повторяется
|
||||||
|
# по-прежнему. Она удешевляет ДРУГОЙ сценарий — протухший/чужой сертификат
|
||||||
|
# (rc=60): отказ приходит сразу и без повторов. Замер 12.09 на
|
||||||
|
# expired.badssl.com, одна проверка при SMOKE_PAUSE=0 — 23 c на прежней
|
||||||
|
# голове (3 попытки + 6 c пауз) против <1 c теперь.
|
||||||
|
#
|
||||||
|
# 40 минут = 38 мин худшего случая + запас на чекаут и разброс сети.
|
||||||
|
# Цена промаха несимметрична: занятый раннер стоит дёшево (прогон daily +
|
||||||
|
# on-push), потерянный лог при полном отказе прода — дорого.
|
||||||
|
timeout-minutes: 40
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
|
|
|
||||||
|
|
@ -38,12 +38,137 @@ BASE_MERA="${SMOKE_MERA_BASE:-https://meraocenka.ru}"
|
||||||
BASE_MAIN="${SMOKE_MAIN_BASE:-https://gendsgn.ru}"
|
BASE_MAIN="${SMOKE_MAIN_BASE:-https://gendsgn.ru}"
|
||||||
|
|
||||||
fail=0
|
fail=0
|
||||||
|
noresp=0
|
||||||
|
|
||||||
|
# --- ТЕМП ЗАПРОСОВ И ПОВТОРЫ (11.09.2026) --------------------------------
|
||||||
|
#
|
||||||
|
# ЧТО СЛУЧИЛОСЬ. Прогон на голове main (a659b187) покраснел на двух последних
|
||||||
|
# проверках списка с кодом `000`. `000` у curl — это НЕ «пришёл неверный код»,
|
||||||
|
# а «ответа не было вовсе» (таймаут/обрыв). Периметр при этом был цел: те же
|
||||||
|
# пути, запрошенные вручную, отдавали 503 и 405 от приложения.
|
||||||
|
#
|
||||||
|
# ЗАМЕР (внешний IP, https://gendsgn.ru/trade-in/api/v1/me):
|
||||||
|
# серия без пауз — 5 обрывов из 12
|
||||||
|
# серия с паузой 0.5 c — 6 обрывов из 12
|
||||||
|
# серия с паузой 2 c — 0 обрывов из 8
|
||||||
|
# с самого хоста прода — 0 обрывов из 10 (все 401)
|
||||||
|
# То есть приложение отвечает, а частую серию запросов с одного внешнего
|
||||||
|
# адреса отбивает ВХОД (на хосте активен fail2ban). Смоук шлёт ~43 запроса
|
||||||
|
# подряд без пауз и попадает ровно под этот эффект — и падают именно
|
||||||
|
# ПОСЛЕДНИЕ проверки, потому что к концу серии счётчик уже набран.
|
||||||
|
#
|
||||||
|
# ОТСЮДА ДВА МЕХАНИЗМА, И НИ ОДИН НЕ ТРОГАЕТ САМИ ОЖИДАНИЯ:
|
||||||
|
# 1. Повтор ТОЛЬКО там, где ответа не было вовсе. Ответ с «не тем» кодом —
|
||||||
|
# это результат проверки, он не повторяется никогда: иначе ретрай
|
||||||
|
# маскировал бы настоящий регресс периметра, ради которого всё написано.
|
||||||
|
# 2. Пауза между проверками, чтобы серия не выглядела флудом.
|
||||||
|
#
|
||||||
|
# ПОЧЕМУ ПАУЗА 2 c, А НЕ МЕНЬШЕ. Это наименьшая величина, у которой есть
|
||||||
|
# замер: 0.5 c измеренно НЕ помогает (6 обрывов из 12 — не лучше, чем без
|
||||||
|
# пауз), 2 c даёт ноль обрывов, промежуточные значения никто не мерил, и
|
||||||
|
# взять их означало бы выдумать число. Цена ИЗМЕРЕНА, а не оценена: прогон
|
||||||
|
# целиком занимал 89 c и стал занимать 160 c (оба замера 11.09 с локальной
|
||||||
|
# машины, 43 проверки, все зелёные). Под это в воркфлоу периметра поднят
|
||||||
|
# timeout-minutes: неотвечающая проверка сетевого класса стоит 3×15 c таймаута
|
||||||
|
# + 2 c и 4 c пауз ретрая + 2 c паузы между проверками = 53 c, а худший случай
|
||||||
|
# (прод не отвечает вовсе — мертвы все 43) = 43 × 53 ≈ 2279 c ≈ 38 мин.
|
||||||
|
# Ни 5, ни 10 минут на него не хватало: job убивали ДО печати FAIL-строк и
|
||||||
|
# итога, то есть ровно там, где лог нужнее всего.
|
||||||
|
# Обе величины переопределяются из окружения — для отладки локально
|
||||||
|
# (`SMOKE_PAUSE=0 bash scripts/smoke-mera-perimeter.sh` даёт прежний темп).
|
||||||
|
SMOKE_PAUSE="${SMOKE_PAUSE:-2}"
|
||||||
|
SMOKE_ATTEMPTS="${SMOKE_ATTEMPTS:-3}"
|
||||||
|
|
||||||
|
# curl_try: запрос с повтором, если ответа не пришло ВООБЩЕ, и с паузой после.
|
||||||
|
#
|
||||||
|
# Признак «ответа не было» берём у самого curl — код возврата из СЕТЕВОГО
|
||||||
|
# класса (перечислен в константе NETWORK_RC ниже). Он строго эквивалентен
|
||||||
|
# `%{http_code}` = 000, но доступен ВСЕМ проверкам, включая те, которые
|
||||||
|
# http_code вообще не запрашивают: до этой правки обрыв в
|
||||||
|
# check_redirect_location читался как «Location не тот», а обрыв при загрузке
|
||||||
|
# лэндинга — как «сам лэндинг сломан». Один сторож в общей обёртке чинит все
|
||||||
|
# места сразу, а не только те две проверки, что покраснели.
|
||||||
|
#
|
||||||
|
# СЕТЕВОЙ КЛАСС — И ТОЛЬКО ОН. Коды живут в константе, а не в тексте
|
||||||
|
# комментария, чтобы описание и поведение не разъехались:
|
||||||
|
# 6 — DNS не разрешился
|
||||||
|
# 7 — соединение отвергнуто (вход лежит; REJECT у fail2ban выглядит так же)
|
||||||
|
# 28 — таймаут
|
||||||
|
# 35 — обрыв на TLS-хендшейке
|
||||||
|
# 52 — сервер закрыл соединение, не ответив
|
||||||
|
# 56 — обрыв при приёме ответа
|
||||||
|
# Общее у них ровно одно: ответа не получено, и повтор имеет шанс помочь —
|
||||||
|
# тот самый эффект входа, ради которого повтор и заведён.
|
||||||
|
#
|
||||||
|
# ОСТАЛЬНЫЕ КОДЫ НЕ ПОВТОРЯЕМ И НЕ ЗОВЁМ «ответа нет». Протухший, чужой или
|
||||||
|
# самоподписанный сертификат даёт rc=60 (замер 12.09: expired.badssl.com,
|
||||||
|
# self-signed.badssl.com, wrong.host.badssl.com — все три). Это ИЗМЕРЕННЫЙ
|
||||||
|
# отказ периметра, а не потерянный запрос: см. проверку 5b в шапке — без
|
||||||
|
# site-блока Caddy не выпускает сертификат, и клиент видит обрыв TLS вместо
|
||||||
|
# редиректа, ради этого проверка и написана. Отказ детерминирован: три попытки
|
||||||
|
# дадут тот же rc, потратив 6 c пауз, а результат уехал бы в колонку «не
|
||||||
|
# измеряли» — то есть регресс спрятался бы ровно там, где его надо показать.
|
||||||
|
NETWORK_RC=" 6 7 28 35 52 56 "
|
||||||
|
|
||||||
|
# Ответ, пришедший с «неправильным» кодом, для curl — успех (rc=0), повтора не
|
||||||
|
# будет; проверка отработает ровно так же, как до правки.
|
||||||
|
curl_try() {
|
||||||
|
local attempt=1 rc out
|
||||||
|
while :; do
|
||||||
|
out=$(curl "$@" 2>/dev/null)
|
||||||
|
rc=$?
|
||||||
|
{ [ "$rc" -eq 0 ] || [ "$attempt" -ge "$SMOKE_ATTEMPTS" ]; } && break
|
||||||
|
# Код вне сетевого класса — повторять нечего, отдаём rc наверх (см. NETWORK_RC).
|
||||||
|
case "$NETWORK_RC" in *" $rc "*) ;; *) break ;; esac
|
||||||
|
# Пауза растёт: 2 c, затем 4 c — ниже 2 c смысла нет (см. замер выше).
|
||||||
|
echo " RETRY: ответа нет (curl rc=$rc), попытка $((attempt + 1)) из $SMOKE_ATTEMPTS через $((attempt * 2)) c: $*" >&2
|
||||||
|
sleep "$((attempt * 2))"
|
||||||
|
attempt=$((attempt + 1))
|
||||||
|
done
|
||||||
|
[ "$SMOKE_PAUSE" = "0" ] || sleep "$SMOKE_PAUSE"
|
||||||
|
printf '%s' "$out"
|
||||||
|
return "$rc"
|
||||||
|
}
|
||||||
|
|
||||||
|
# curl_failed: красная строка, когда ответа не удалось получить у самого curl.
|
||||||
|
#
|
||||||
|
# За одним «rc != 0» прячутся ДВА разных диагноза, и путать их нельзя:
|
||||||
|
# - сетевой класс → «ответа нет»: цел ли периметр, мы не знаем, проверка НЕ
|
||||||
|
# измерилась (плюс счётчик noresp и отдельная строка в итоге);
|
||||||
|
# - всё остальное, прежде всего cert-класс (rc=60) → обычный FAIL: отказ
|
||||||
|
# ИЗМЕРЕН, это регресс периметра, искать надо конфиг, а не флап входа.
|
||||||
|
#
|
||||||
|
# rc печатается в ОБЕИХ ветках: строка RETRY при SMOKE_ATTEMPTS=1 не выводится
|
||||||
|
# вовсе, и без rc читатель красного лога не отличит «домена нет» (6) от
|
||||||
|
# «сертификат протух» (60) — а это диагнозы из разных отделов.
|
||||||
|
curl_failed() {
|
||||||
|
local desc="$1" url="$2" rc="$3" reason
|
||||||
|
fail=1
|
||||||
|
case "$NETWORK_RC" in
|
||||||
|
*" $rc "*)
|
||||||
|
echo "FAIL (ответа нет): $desc ($url — вход не отдал ответ после $SMOKE_ATTEMPTS попыток, curl rc=$rc;" \
|
||||||
|
"это НЕ измеренный код ответа, периметр этой проверкой НЕ проверен — повторите URL вручную)"
|
||||||
|
noresp=$((noresp + 1))
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
case "$rc" in
|
||||||
|
60|51|83) reason="TLS-сертификат отвергнут" ;;
|
||||||
|
58|77) reason="проблема с клиентским сертификатом/CA" ;;
|
||||||
|
*) reason="curl не выполнил запрос" ;;
|
||||||
|
esac
|
||||||
|
echo "FAIL: $desc ($url -> $reason (curl rc=$rc); ответ измерен как отказ, это не потерянный" \
|
||||||
|
"запрос — повтора не было, код вне сетевого класса «ответа нет»)"
|
||||||
|
}
|
||||||
|
|
||||||
check() {
|
check() {
|
||||||
local desc="$1" url="$2" expected="$3"
|
local desc="$1" url="$2" expected="$3"
|
||||||
local code
|
local code rc
|
||||||
code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 15 "$url" 2>/dev/null)
|
code=$(curl_try -s -o /dev/null -w '%{http_code}' --max-time 15 "$url")
|
||||||
if [ "$code" = "$expected" ]; then
|
rc=$?
|
||||||
|
if [ "$rc" -ne 0 ]; then
|
||||||
|
curl_failed "$desc" "$url" "$rc"
|
||||||
|
elif [ "$code" = "$expected" ]; then
|
||||||
echo "PASS: $desc ($url -> $code)"
|
echo "PASS: $desc ($url -> $code)"
|
||||||
else
|
else
|
||||||
echo "FAIL: $desc ($url -> got '${code:-<no response>}', expected $expected)"
|
echo "FAIL: $desc ($url -> got '${code:-<no response>}', expected $expected)"
|
||||||
|
|
@ -63,8 +188,13 @@ check() {
|
||||||
check_any() {
|
check_any() {
|
||||||
local desc="$1" url="$2"
|
local desc="$1" url="$2"
|
||||||
shift 2
|
shift 2
|
||||||
local code expected="$*"
|
local code rc expected="$*"
|
||||||
code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 15 "$url" 2>/dev/null)
|
code=$(curl_try -s -o /dev/null -w '%{http_code}' --max-time 15 "$url")
|
||||||
|
rc=$?
|
||||||
|
if [ "$rc" -ne 0 ]; then
|
||||||
|
curl_failed "$desc" "$url" "$rc"
|
||||||
|
return
|
||||||
|
fi
|
||||||
for want in "$@"; do
|
for want in "$@"; do
|
||||||
if [ "$code" = "$want" ]; then
|
if [ "$code" = "$want" ]; then
|
||||||
echo "PASS: $desc ($url -> $code)"
|
echo "PASS: $desc ($url -> $code)"
|
||||||
|
|
@ -77,11 +207,16 @@ check_any() {
|
||||||
|
|
||||||
check_post() {
|
check_post() {
|
||||||
local desc="$1" url="$2" body="$3" expected="$4" reject="${5:-}"
|
local desc="$1" url="$2" body="$3" expected="$4" reject="${5:-}"
|
||||||
local out code head_and_body
|
local out code head_and_body rc
|
||||||
# -i: заголовки попадают в вывод вместе с телом — по ним отличаем ответ
|
# -i: заголовки попадают в вывод вместе с телом — по ним отличаем ответ
|
||||||
# приложения от заглушки Caddy (см. $reject у вызова payments/notify).
|
# приложения от заглушки Caddy (см. $reject у вызова payments/notify).
|
||||||
out=$(curl -s -i -w '\n%{http_code}' --max-time 15 \
|
out=$(curl_try -s -i -w '\n%{http_code}' --max-time 15 \
|
||||||
-X POST -H 'Content-Type: application/json' -d "$body" "$url" 2>/dev/null)
|
-X POST -H 'Content-Type: application/json' -d "$body" "$url")
|
||||||
|
rc=$?
|
||||||
|
if [ "$rc" -ne 0 ]; then
|
||||||
|
curl_failed "$desc" "$url" "$rc"
|
||||||
|
return
|
||||||
|
fi
|
||||||
code=${out##*$'\n'}
|
code=${out##*$'\n'}
|
||||||
head_and_body=${out%$'\n'*}
|
head_and_body=${out%$'\n'*}
|
||||||
if [ "$code" != "$expected" ]; then
|
if [ "$code" != "$expected" ]; then
|
||||||
|
|
@ -111,8 +246,17 @@ check_post() {
|
||||||
# Ровно это и есть предмет проверки — что query дожила до цели.
|
# Ровно это и есть предмет проверки — что query дожила до цели.
|
||||||
check_redirect_location() {
|
check_redirect_location() {
|
||||||
local desc="$1" url="$2" expected_suffix="$3"
|
local desc="$1" url="$2" expected_suffix="$3"
|
||||||
local location
|
local location headers rc
|
||||||
location=$(curl -s -o /dev/null -D - --max-time 15 "$url" 2>/dev/null \
|
# Заголовки сначала забираем целиком, и только потом разбираем: при обрыве
|
||||||
|
# соединения grep по пустому выводу дал бы «Location: <none>» — красную
|
||||||
|
# строку про подмену цели редиректа там, где ответа не было вовсе.
|
||||||
|
headers=$(curl_try -s -o /dev/null -D - --max-time 15 "$url")
|
||||||
|
rc=$?
|
||||||
|
if [ "$rc" -ne 0 ]; then
|
||||||
|
curl_failed "$desc" "$url" "$rc"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
location=$(printf '%s' "$headers" \
|
||||||
| grep -i '^location:' | tr -d '\r' | sed 's/^[Ll]ocation: *//')
|
| grep -i '^location:' | tr -d '\r' | sed 's/^[Ll]ocation: *//')
|
||||||
case "$location" in
|
case "$location" in
|
||||||
"$expected_suffix"|*"$expected_suffix")
|
"$expected_suffix"|*"$expected_suffix")
|
||||||
|
|
@ -133,8 +277,13 @@ check_redirect_location() {
|
||||||
# смоук останется зелёным. Проверять надо ровно то, ради чего адрес открыт.
|
# смоук останется зелёным. Проверять надо ровно то, ради чего адрес открыт.
|
||||||
check_content_type() {
|
check_content_type() {
|
||||||
local desc="$1" url="$2" expected_prefix="$3"
|
local desc="$1" url="$2" expected_prefix="$3"
|
||||||
local out code ctype
|
local out code ctype rc
|
||||||
out=$(curl -s -o /dev/null -D - -w '%{http_code}' --max-time 15 "$url" 2>/dev/null)
|
out=$(curl_try -s -o /dev/null -D - -w '%{http_code}' --max-time 15 "$url")
|
||||||
|
rc=$?
|
||||||
|
if [ "$rc" -ne 0 ]; then
|
||||||
|
curl_failed "$desc" "$url" "$rc"
|
||||||
|
return
|
||||||
|
fi
|
||||||
code=${out##*$'
|
code=${out##*$'
|
||||||
'}
|
'}
|
||||||
ctype=$(printf '%s' "$out" | grep -i '^content-type:' | tr -d '
|
ctype=$(printf '%s' "$out" | grep -i '^content-type:' | tr -d '
|
||||||
|
|
@ -240,8 +389,13 @@ check "meraocenka.ru/_next/image — must 404 (не открываем опти
|
||||||
# (замер на проде 02.09.2026: 9 байт).
|
# (замер на проде 02.09.2026: 9 байт).
|
||||||
check_caddy_404() {
|
check_caddy_404() {
|
||||||
local desc="$1" url="$2"
|
local desc="$1" url="$2"
|
||||||
local out code size
|
local out code size rc
|
||||||
out=$(curl -s -o /dev/null -w '%{http_code} %{size_download}' --max-time 15 "$url" 2>/dev/null)
|
out=$(curl_try -s -o /dev/null -w '%{http_code} %{size_download}' --max-time 15 "$url")
|
||||||
|
rc=$?
|
||||||
|
if [ "$rc" -ne 0 ]; then
|
||||||
|
curl_failed "$desc" "$url" "$rc"
|
||||||
|
return
|
||||||
|
fi
|
||||||
code=${out%% *}
|
code=${out%% *}
|
||||||
size=${out##* }
|
size=${out##* }
|
||||||
if [ "$code" = "404" ] && [ "$size" = "0" ]; then
|
if [ "$code" = "404" ] && [ "$size" = "0" ]; then
|
||||||
|
|
@ -262,15 +416,23 @@ check_caddy_404 "meraocenka.ru — чанки /team не раздаются" \
|
||||||
# Обратная сторона того же матчера: статика САМОГО лэндинга обязана остаться
|
# Обратная сторона того же матчера: статика САМОГО лэндинга обязана остаться
|
||||||
# живой. Без этой строки «починка» вида «404 на весь chunks/app/» выглядела бы
|
# живой. Без этой строки «починка» вида «404 на весь chunks/app/» выглядела бы
|
||||||
# успешной, а публичный сайт молча остался бы без JS.
|
# успешной, а публичный сайт молча остался бы без JS.
|
||||||
layout_chunk=$(curl -s --max-time 15 "$BASE_MERA/" 2>/dev/null \
|
layout_html=$(curl_try -s --max-time 15 "$BASE_MERA/")
|
||||||
| grep -o '/trade-in/_next/static/chunks/app/layout-[^"]*\.js' | head -1)
|
layout_rc=$?
|
||||||
if [ -z "$layout_chunk" ]; then
|
if [ "$layout_rc" -ne 0 ]; then
|
||||||
# Пустая строка вместо пути дала бы запрос к корню и зелёную проверку ни о
|
# Обрыв на загрузке лэндинга раньше попадал в ветку «не нашёл чанк» и читался
|
||||||
# чём — поэтому это FAIL, а не «пропустим».
|
# как «сам лэндинг сломан» — диагноз, которого никто не измерял.
|
||||||
echo "FAIL: не нашёл layout-чанк в HTML лэндинга (сам лэндинг сломан?)"
|
curl_failed "HTML лэндинга (ищем в нём layout-чанк)" "$BASE_MERA/" "$layout_rc"
|
||||||
fail=1
|
|
||||||
else
|
else
|
||||||
check "meraocenka.ru — корневой layout-чанк лэндинга жив (200)" "$BASE_MERA$layout_chunk" 200
|
layout_chunk=$(printf '%s' "$layout_html" \
|
||||||
|
| grep -o '/trade-in/_next/static/chunks/app/layout-[^"]*\.js' | head -1)
|
||||||
|
if [ -z "$layout_chunk" ]; then
|
||||||
|
# Пустая строка вместо пути дала бы запрос к корню и зелёную проверку ни о
|
||||||
|
# чём — поэтому это FAIL, а не «пропустим».
|
||||||
|
echo "FAIL: не нашёл layout-чанк в HTML лэндинга (сам лэндинг сломан?)"
|
||||||
|
fail=1
|
||||||
|
else
|
||||||
|
check "meraocenka.ru — корневой layout-чанк лэндинга жив (200)" "$BASE_MERA$layout_chunk" 200
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 2d. Публичный API МЕРЫ (#2911). Ровно две ручки под /api/public/mera/*
|
# 2d. Публичный API МЕРЫ (#2911). Ровно две ручки под /api/public/mera/*
|
||||||
|
|
@ -411,6 +573,14 @@ check "trade-in payments/checkout — 401 anonymous (не публичный п
|
||||||
"$BASE_MAIN/trade-in/api/v1/trade-in/payments/checkout" 401
|
"$BASE_MAIN/trade-in/api/v1/trade-in/payments/checkout" 401
|
||||||
|
|
||||||
echo "========================================"
|
echo "========================================"
|
||||||
|
if [ "$noresp" -gt 0 ]; then
|
||||||
|
# Отдельная строка в итоге, а не только у самой проверки: читатель красного
|
||||||
|
# лога должен сразу видеть, что часть проверок НЕ ИЗМЕРИЛАСЬ, и не искать
|
||||||
|
# регресс периметра там, где ответа просто не было.
|
||||||
|
echo "БЕЗ ОТВЕТА: $noresp проверок не получили ответа даже после $SMOKE_ATTEMPTS попыток."
|
||||||
|
echo " Это не измеренный код ответа. Повторите эти URL вручную (и учтите, что"
|
||||||
|
echo " вход отбивает частые серии запросов с одного адреса — см. шапку скрипта)."
|
||||||
|
fi
|
||||||
if [ "$fail" -eq 0 ]; then
|
if [ "$fail" -eq 0 ]; then
|
||||||
echo "ALL CHECKS PASSED"
|
echo "ALL CHECKS PASSED"
|
||||||
else
|
else
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue