Нормализовать переводы строк в LF
Решение по TD-STYLE-ANALYZERS: LF — инструменты проекта (Python/Node) пишут LF, CRLF-.sh не работают на Linux CI (sh scripts/ci.sh), большинство файлов уже были LF. Добавлен .gitattributes (* text=auto eol=lf, бинарные исключения), .editorconfig переведён на lf, 1029 файлов конвертированы, git add --renormalize. Из индекса убраны закравшиеся archive/**/__pycache__/*.pyc.
This commit is contained in:
+54
-54
@@ -1,54 +1,54 @@
|
||||
# Нагрузочный смоук-тест API Deal (`scripts/loadtest/`)
|
||||
|
||||
Минимальный прогон «есть ли жизнь и как быстро отвечает» по читающим ручкам API
|
||||
(этап 12, пакет C). Внешних сервисов и записывающих операций нет — только логин
|
||||
и чтение, БД не мутируется.
|
||||
|
||||
## Сценарий
|
||||
|
||||
1. `POST /api/auth/login` `{login, password}` — сессия (`deal_session`).
|
||||
2. В цикле: `GET /api/containers`, затем `GET /api/cards`.
|
||||
3. Метрики: число запросов, ошибки (не-200), RPS, средняя/p95/max латентность.
|
||||
|
||||
Учётные данные по умолчанию — `admin` / `admin` (dev-дефолт bootstrap тенанта).
|
||||
|
||||
## Вариант A — bash + curl (зависимостей нет, кроме curl)
|
||||
|
||||
```bash
|
||||
bash scripts/loadtest/api-loadtest.sh
|
||||
|
||||
# пример с параметрами
|
||||
BASE_URL=http://localhost:5080 LOGIN=admin PASSWORD=admin \
|
||||
DURATION_SECONDS=20 PAUSE_SECONDS=0.1 \
|
||||
bash scripts/loadtest/api-loadtest.sh
|
||||
```
|
||||
|
||||
Переменные окружения: `BASE_URL` (по умолчанию `http://localhost:5080`),
|
||||
`LOGIN`/`PASSWORD`, `DURATION_SECONDS` (15), `PAUSE_SECONDS` (0.2), `CURL_TIMEOUT` (5).
|
||||
Код возврата: `0` — без ошибок, `1` — ошибка логина/конфигурации, `2` — были не-200.
|
||||
|
||||
## Вариант B — k6 (если установлен)
|
||||
|
||||
```bash
|
||||
k6 run scripts/loadtest/deal-loadtest.js
|
||||
BASE_URL=http://localhost:5080 VUS=10 DURATION=30s \
|
||||
k6 run scripts/loadtest/deal-loadtest.js
|
||||
```
|
||||
|
||||
Скрипт логинится один раз в `setup()` и раздаёт куку виртуальным пользователям;
|
||||
пороги проваливают прогон при доле ошибок > 1% или p95 > 500 мс.
|
||||
|
||||
## Как поднять API для прогона
|
||||
|
||||
- **dev (полный стек)**: `docker compose -f deploy/compose.dev.yml up -d --build`,
|
||||
затем прогон против `http://localhost:5080`; после — `docker compose -f deploy/compose.dev.yml down`.
|
||||
- **dev (только core + Postgres)**: см. техдок §13 «Быстрый старт» (Postgres :5433, API :5080).
|
||||
- Прогон короткий (по умолчанию 15–20 с) — это смоук, а не полноценный бенчмарк.
|
||||
|
||||
## Замечания
|
||||
|
||||
- В PROD включён rate-limit (`api` — 600/мин на тенанта, `auth` — 10/мин на IP),
|
||||
поэтому длительные прогоны делайте на dev-стенде или поднимите лимит.
|
||||
- Метрики перфа сервисов дополнительно смотрите в Prometheus/Grafana (профиль
|
||||
`observability`): `http_server_request_duration_seconds_*`, RPS/p95 на дашборде
|
||||
`Deal-Metrics-Overview` (см. техдок §7).
|
||||
# Нагрузочный смоук-тест API Deal (`scripts/loadtest/`)
|
||||
|
||||
Минимальный прогон «есть ли жизнь и как быстро отвечает» по читающим ручкам API
|
||||
(этап 12, пакет C). Внешних сервисов и записывающих операций нет — только логин
|
||||
и чтение, БД не мутируется.
|
||||
|
||||
## Сценарий
|
||||
|
||||
1. `POST /api/auth/login` `{login, password}` — сессия (`deal_session`).
|
||||
2. В цикле: `GET /api/containers`, затем `GET /api/cards`.
|
||||
3. Метрики: число запросов, ошибки (не-200), RPS, средняя/p95/max латентность.
|
||||
|
||||
Учётные данные по умолчанию — `admin` / `admin` (dev-дефолт bootstrap тенанта).
|
||||
|
||||
## Вариант A — bash + curl (зависимостей нет, кроме curl)
|
||||
|
||||
```bash
|
||||
bash scripts/loadtest/api-loadtest.sh
|
||||
|
||||
# пример с параметрами
|
||||
BASE_URL=http://localhost:5080 LOGIN=admin PASSWORD=admin \
|
||||
DURATION_SECONDS=20 PAUSE_SECONDS=0.1 \
|
||||
bash scripts/loadtest/api-loadtest.sh
|
||||
```
|
||||
|
||||
Переменные окружения: `BASE_URL` (по умолчанию `http://localhost:5080`),
|
||||
`LOGIN`/`PASSWORD`, `DURATION_SECONDS` (15), `PAUSE_SECONDS` (0.2), `CURL_TIMEOUT` (5).
|
||||
Код возврата: `0` — без ошибок, `1` — ошибка логина/конфигурации, `2` — были не-200.
|
||||
|
||||
## Вариант B — k6 (если установлен)
|
||||
|
||||
```bash
|
||||
k6 run scripts/loadtest/deal-loadtest.js
|
||||
BASE_URL=http://localhost:5080 VUS=10 DURATION=30s \
|
||||
k6 run scripts/loadtest/deal-loadtest.js
|
||||
```
|
||||
|
||||
Скрипт логинится один раз в `setup()` и раздаёт куку виртуальным пользователям;
|
||||
пороги проваливают прогон при доле ошибок > 1% или p95 > 500 мс.
|
||||
|
||||
## Как поднять API для прогона
|
||||
|
||||
- **dev (полный стек)**: `docker compose -f deploy/compose.dev.yml up -d --build`,
|
||||
затем прогон против `http://localhost:5080`; после — `docker compose -f deploy/compose.dev.yml down`.
|
||||
- **dev (только core + Postgres)**: см. техдок §13 «Быстрый старт» (Postgres :5433, API :5080).
|
||||
- Прогон короткий (по умолчанию 15–20 с) — это смоук, а не полноценный бенчмарк.
|
||||
|
||||
## Замечания
|
||||
|
||||
- В PROD включён rate-limit (`api` — 600/мин на тенанта, `auth` — 10/мин на IP),
|
||||
поэтому длительные прогоны делайте на dev-стенде или поднимите лимит.
|
||||
- Метрики перфа сервисов дополнительно смотрите в Prometheus/Grafana (профиль
|
||||
`observability`): `http_server_request_duration_seconds_*`, RPS/p95 на дашборде
|
||||
`Deal-Metrics-Overview` (см. техдок §7).
|
||||
|
||||
@@ -1,98 +1,98 @@
|
||||
#!/usr/bin/env bash
|
||||
# Простой нагрузочный смоук-тест API Deal (этап 12, пакет C).
|
||||
#
|
||||
# Что делает: логинится (по умолчанию admin/admin), затем в цикле дёргает два
|
||||
# читающих эндпоинта — GET /api/containers и GET /api/cards — до истечения
|
||||
# DURATION_SECONDS, замеряя HTTP-код и время ответа. В конце печатает сводку:
|
||||
# число запросов, ошибки (не 200), RPS, средняя/p95-латентность (сек).
|
||||
#
|
||||
# Зависимости: только bash и curl. Ничего не пишет в БД; читающие ручки.
|
||||
#
|
||||
# Запуск (из корня репозитория, dev-API на :5080):
|
||||
# bash scripts/loadtest/api-loadtest.sh
|
||||
# BASE_URL=http://localhost:5080 LOGIN=admin PASSWORD=admin \
|
||||
# DURATION_SECONDS=20 PAUSE_SECONDS=0.1 bash scripts/loadtest/api-loadtest.sh
|
||||
#
|
||||
# Переменные окружения:
|
||||
# BASE_URL базовый URL API (по умолчанию http://localhost:5080)
|
||||
# LOGIN/PASSWORD учётные данные тенанта (по умолчанию admin/admin — dev-дефолт bootstrap)
|
||||
# DURATION_SECONDS длительность прогона, с (по умолчанию 15)
|
||||
# PAUSE_SECONDS пауза между итерациями, с (по умолчанию 0.2)
|
||||
# CURL_TIMEOUT таймаут запроса, с (по умолчанию 5)
|
||||
#
|
||||
# Внимание: в PROD включён rate-limit (api-политика — 600/мин на тенанта). Для
|
||||
# нагрузочного прогона используйте dev-стенд или поднимите лимит.
|
||||
set -euo pipefail
|
||||
|
||||
BASE_URL="${BASE_URL:-http://localhost:5080}"
|
||||
LOGIN="${LOGIN:-admin}"
|
||||
PASSWORD="${PASSWORD:-admin}"
|
||||
DURATION_SECONDS="${DURATION_SECONDS:-15}"
|
||||
PAUSE_SECONDS="${PAUSE_SECONDS:-0.2}"
|
||||
CURL_TIMEOUT="${CURL_TIMEOUT:-5}"
|
||||
|
||||
command -v curl >/dev/null 2>&1 || { echo "Ошибка: нужен curl" >&2; exit 127; }
|
||||
|
||||
tmp_dir="$(mktemp -d)"
|
||||
cookie_jar="${tmp_dir}/cookies.txt"
|
||||
lat_file="${tmp_dir}/latencies.txt"
|
||||
trap 'rm -rf "${tmp_dir}"' EXIT
|
||||
|
||||
login_code="$(curl -sS -o "${tmp_dir}/login.json" -w '%{http_code}' \
|
||||
-c "${cookie_jar}" -H 'Content-Type: application/json' \
|
||||
-d "{\"login\":\"${LOGIN}\",\"password\":\"${PASSWORD}\"}" \
|
||||
--max-time "${CURL_TIMEOUT}" "${BASE_URL}/api/auth/login" || true)"
|
||||
[ -n "${login_code}" ] || login_code="000"
|
||||
|
||||
if [ "${login_code}" != "200" ]; then
|
||||
echo "LOGIN FAILED (HTTP ${login_code}): $(cat "${tmp_dir}/login.json" 2>/dev/null)" >&2
|
||||
echo "Проверьте BASE_URL=${BASE_URL} и что API поднят." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "login OK (${LOGIN}) → прогон ${DURATION_SECONDS} с, пауза ${PAUSE_SECONDS} с"
|
||||
|
||||
started_at="$(date +%s)"
|
||||
end_at=$((started_at + DURATION_SECONDS))
|
||||
total=0
|
||||
errors=0
|
||||
|
||||
while [ "$(date +%s)" -lt "${end_at}" ]; do
|
||||
for path in /api/containers /api/cards; do
|
||||
result="$(curl -sS -o /dev/null -w '%{http_code} %{time_total}' \
|
||||
-b "${cookie_jar}" --max-time "${CURL_TIMEOUT}" "${BASE_URL}${path}" || true)"
|
||||
[ -n "${result}" ] || result="000 0"
|
||||
code="${result%% *}"
|
||||
elapsed="${result##* }"
|
||||
total=$((total + 1))
|
||||
if [ "${code}" != "200" ]; then
|
||||
errors=$((errors + 1))
|
||||
echo " ! ${path} → HTTP ${code}" >&2
|
||||
fi
|
||||
echo "${elapsed}" >> "${lat_file}"
|
||||
done
|
||||
sleep "${PAUSE_SECONDS}"
|
||||
done
|
||||
|
||||
elapsed_total=$(( $(date +%s) - started_at ))
|
||||
[ "${elapsed_total}" -lt 1 ] && elapsed_total=1
|
||||
|
||||
if [ "${total}" -eq 0 ]; then
|
||||
echo "Запросов не сделано (DURATION_SECONDS слишком мал?)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
avg="$(awk '{sum += $1} END {printf "%.4f", sum / NR}' "${lat_file}")"
|
||||
p95_index=$(( (total * 95 + 99) / 100 ))
|
||||
p95="$(sort -n "${lat_file}" | sed -n "${p95_index}p")"
|
||||
max="$(sort -n "${lat_file}" | tail -n 1)"
|
||||
rps="$(awk -v n="${total}" -v d="${elapsed_total}" 'BEGIN {printf "%.2f", n / d}')"
|
||||
|
||||
echo "---------------------------------------------"
|
||||
echo "запросов: ${total}"
|
||||
echo "ошибок: ${errors}"
|
||||
echo "длительность: ${elapsed_total} с"
|
||||
echo "RPS: ${rps}"
|
||||
echo "латентность: avg=${avg}s p95=${p95}s max=${max}s"
|
||||
echo "---------------------------------------------"
|
||||
|
||||
[ "${errors}" -eq 0 ] || exit 2
|
||||
#!/usr/bin/env bash
|
||||
# Простой нагрузочный смоук-тест API Deal (этап 12, пакет C).
|
||||
#
|
||||
# Что делает: логинится (по умолчанию admin/admin), затем в цикле дёргает два
|
||||
# читающих эндпоинта — GET /api/containers и GET /api/cards — до истечения
|
||||
# DURATION_SECONDS, замеряя HTTP-код и время ответа. В конце печатает сводку:
|
||||
# число запросов, ошибки (не 200), RPS, средняя/p95-латентность (сек).
|
||||
#
|
||||
# Зависимости: только bash и curl. Ничего не пишет в БД; читающие ручки.
|
||||
#
|
||||
# Запуск (из корня репозитория, dev-API на :5080):
|
||||
# bash scripts/loadtest/api-loadtest.sh
|
||||
# BASE_URL=http://localhost:5080 LOGIN=admin PASSWORD=admin \
|
||||
# DURATION_SECONDS=20 PAUSE_SECONDS=0.1 bash scripts/loadtest/api-loadtest.sh
|
||||
#
|
||||
# Переменные окружения:
|
||||
# BASE_URL базовый URL API (по умолчанию http://localhost:5080)
|
||||
# LOGIN/PASSWORD учётные данные тенанта (по умолчанию admin/admin — dev-дефолт bootstrap)
|
||||
# DURATION_SECONDS длительность прогона, с (по умолчанию 15)
|
||||
# PAUSE_SECONDS пауза между итерациями, с (по умолчанию 0.2)
|
||||
# CURL_TIMEOUT таймаут запроса, с (по умолчанию 5)
|
||||
#
|
||||
# Внимание: в PROD включён rate-limit (api-политика — 600/мин на тенанта). Для
|
||||
# нагрузочного прогона используйте dev-стенд или поднимите лимит.
|
||||
set -euo pipefail
|
||||
|
||||
BASE_URL="${BASE_URL:-http://localhost:5080}"
|
||||
LOGIN="${LOGIN:-admin}"
|
||||
PASSWORD="${PASSWORD:-admin}"
|
||||
DURATION_SECONDS="${DURATION_SECONDS:-15}"
|
||||
PAUSE_SECONDS="${PAUSE_SECONDS:-0.2}"
|
||||
CURL_TIMEOUT="${CURL_TIMEOUT:-5}"
|
||||
|
||||
command -v curl >/dev/null 2>&1 || { echo "Ошибка: нужен curl" >&2; exit 127; }
|
||||
|
||||
tmp_dir="$(mktemp -d)"
|
||||
cookie_jar="${tmp_dir}/cookies.txt"
|
||||
lat_file="${tmp_dir}/latencies.txt"
|
||||
trap 'rm -rf "${tmp_dir}"' EXIT
|
||||
|
||||
login_code="$(curl -sS -o "${tmp_dir}/login.json" -w '%{http_code}' \
|
||||
-c "${cookie_jar}" -H 'Content-Type: application/json' \
|
||||
-d "{\"login\":\"${LOGIN}\",\"password\":\"${PASSWORD}\"}" \
|
||||
--max-time "${CURL_TIMEOUT}" "${BASE_URL}/api/auth/login" || true)"
|
||||
[ -n "${login_code}" ] || login_code="000"
|
||||
|
||||
if [ "${login_code}" != "200" ]; then
|
||||
echo "LOGIN FAILED (HTTP ${login_code}): $(cat "${tmp_dir}/login.json" 2>/dev/null)" >&2
|
||||
echo "Проверьте BASE_URL=${BASE_URL} и что API поднят." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "login OK (${LOGIN}) → прогон ${DURATION_SECONDS} с, пауза ${PAUSE_SECONDS} с"
|
||||
|
||||
started_at="$(date +%s)"
|
||||
end_at=$((started_at + DURATION_SECONDS))
|
||||
total=0
|
||||
errors=0
|
||||
|
||||
while [ "$(date +%s)" -lt "${end_at}" ]; do
|
||||
for path in /api/containers /api/cards; do
|
||||
result="$(curl -sS -o /dev/null -w '%{http_code} %{time_total}' \
|
||||
-b "${cookie_jar}" --max-time "${CURL_TIMEOUT}" "${BASE_URL}${path}" || true)"
|
||||
[ -n "${result}" ] || result="000 0"
|
||||
code="${result%% *}"
|
||||
elapsed="${result##* }"
|
||||
total=$((total + 1))
|
||||
if [ "${code}" != "200" ]; then
|
||||
errors=$((errors + 1))
|
||||
echo " ! ${path} → HTTP ${code}" >&2
|
||||
fi
|
||||
echo "${elapsed}" >> "${lat_file}"
|
||||
done
|
||||
sleep "${PAUSE_SECONDS}"
|
||||
done
|
||||
|
||||
elapsed_total=$(( $(date +%s) - started_at ))
|
||||
[ "${elapsed_total}" -lt 1 ] && elapsed_total=1
|
||||
|
||||
if [ "${total}" -eq 0 ]; then
|
||||
echo "Запросов не сделано (DURATION_SECONDS слишком мал?)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
avg="$(awk '{sum += $1} END {printf "%.4f", sum / NR}' "${lat_file}")"
|
||||
p95_index=$(( (total * 95 + 99) / 100 ))
|
||||
p95="$(sort -n "${lat_file}" | sed -n "${p95_index}p")"
|
||||
max="$(sort -n "${lat_file}" | tail -n 1)"
|
||||
rps="$(awk -v n="${total}" -v d="${elapsed_total}" 'BEGIN {printf "%.2f", n / d}')"
|
||||
|
||||
echo "---------------------------------------------"
|
||||
echo "запросов: ${total}"
|
||||
echo "ошибок: ${errors}"
|
||||
echo "длительность: ${elapsed_total} с"
|
||||
echo "RPS: ${rps}"
|
||||
echo "латентность: avg=${avg}s p95=${p95}s max=${max}s"
|
||||
echo "---------------------------------------------"
|
||||
|
||||
[ "${errors}" -eq 0 ] || exit 2
|
||||
|
||||
@@ -1,56 +1,56 @@
|
||||
// Нагрузочный смоук-тест API Deal на k6 (этап 12, пакет C) — альтернатива
|
||||
// scripts/loadtest/api-loadtest.sh, если в системе есть k6.
|
||||
//
|
||||
// Логин — в setup() (один раз), затем виртуальные пользователи в цикле читают
|
||||
// GET /api/containers и GET /api/cards. Пороги (thresholds) проваливают прогон
|
||||
// при доле ошибок > 1% или p95 > 500 мс.
|
||||
//
|
||||
// Запуск (API dev на :5080):
|
||||
// k6 run scripts/loadtest/deal-loadtest.js
|
||||
// BASE_URL=http://localhost:5080 VUS=10 DURATION=30s k6 run scripts/loadtest/deal-loadtest.js
|
||||
//
|
||||
// Переменные окружения: BASE_URL, LOGIN, PASSWORD, VUS, DURATION.
|
||||
// Внимание: в PROD включён rate-limit (api — 600/мин на тенанта) — гоняйте на dev.
|
||||
|
||||
import http from 'k6/http';
|
||||
import { check, sleep } from 'k6';
|
||||
|
||||
const BASE_URL = __ENV.BASE_URL || 'http://localhost:5080';
|
||||
const LOGIN = __ENV.LOGIN || 'admin';
|
||||
const PASSWORD = __ENV.PASSWORD || 'admin';
|
||||
|
||||
export const options = {
|
||||
vus: __ENV.VUS ? Number(__ENV.VUS) : 5,
|
||||
duration: __ENV.DURATION || '20s',
|
||||
thresholds: {
|
||||
http_req_failed: ['rate<0.01'],
|
||||
http_req_duration: ['p(95)<500'],
|
||||
},
|
||||
};
|
||||
|
||||
export function setup() {
|
||||
const res = http.post(
|
||||
`${BASE_URL}/api/auth/login`,
|
||||
JSON.stringify({ login: LOGIN, password: PASSWORD }),
|
||||
{ headers: { 'Content-Type': 'application/json' } }
|
||||
);
|
||||
if (res.status !== 200) {
|
||||
throw new Error(`login failed: HTTP ${res.status} — ${res.body}`);
|
||||
}
|
||||
const cookies = res.cookies['deal_session'];
|
||||
const session = cookies && cookies.length ? cookies[0].value : '';
|
||||
if (!session) {
|
||||
throw new Error('login succeeded but deal_session cookie is missing');
|
||||
}
|
||||
return { session };
|
||||
}
|
||||
|
||||
export default function (data) {
|
||||
const params = { headers: { Cookie: `deal_session=${data.session}` } };
|
||||
const paths = ['/api/containers', '/api/cards'];
|
||||
for (const path of paths) {
|
||||
const res = http.get(`${BASE_URL}${path}`, params);
|
||||
check(res, { [`${path} → 200`]: (r) => r.status === 200 });
|
||||
}
|
||||
sleep(0.2);
|
||||
}
|
||||
// Нагрузочный смоук-тест API Deal на k6 (этап 12, пакет C) — альтернатива
|
||||
// scripts/loadtest/api-loadtest.sh, если в системе есть k6.
|
||||
//
|
||||
// Логин — в setup() (один раз), затем виртуальные пользователи в цикле читают
|
||||
// GET /api/containers и GET /api/cards. Пороги (thresholds) проваливают прогон
|
||||
// при доле ошибок > 1% или p95 > 500 мс.
|
||||
//
|
||||
// Запуск (API dev на :5080):
|
||||
// k6 run scripts/loadtest/deal-loadtest.js
|
||||
// BASE_URL=http://localhost:5080 VUS=10 DURATION=30s k6 run scripts/loadtest/deal-loadtest.js
|
||||
//
|
||||
// Переменные окружения: BASE_URL, LOGIN, PASSWORD, VUS, DURATION.
|
||||
// Внимание: в PROD включён rate-limit (api — 600/мин на тенанта) — гоняйте на dev.
|
||||
|
||||
import http from 'k6/http';
|
||||
import { check, sleep } from 'k6';
|
||||
|
||||
const BASE_URL = __ENV.BASE_URL || 'http://localhost:5080';
|
||||
const LOGIN = __ENV.LOGIN || 'admin';
|
||||
const PASSWORD = __ENV.PASSWORD || 'admin';
|
||||
|
||||
export const options = {
|
||||
vus: __ENV.VUS ? Number(__ENV.VUS) : 5,
|
||||
duration: __ENV.DURATION || '20s',
|
||||
thresholds: {
|
||||
http_req_failed: ['rate<0.01'],
|
||||
http_req_duration: ['p(95)<500'],
|
||||
},
|
||||
};
|
||||
|
||||
export function setup() {
|
||||
const res = http.post(
|
||||
`${BASE_URL}/api/auth/login`,
|
||||
JSON.stringify({ login: LOGIN, password: PASSWORD }),
|
||||
{ headers: { 'Content-Type': 'application/json' } }
|
||||
);
|
||||
if (res.status !== 200) {
|
||||
throw new Error(`login failed: HTTP ${res.status} — ${res.body}`);
|
||||
}
|
||||
const cookies = res.cookies['deal_session'];
|
||||
const session = cookies && cookies.length ? cookies[0].value : '';
|
||||
if (!session) {
|
||||
throw new Error('login succeeded but deal_session cookie is missing');
|
||||
}
|
||||
return { session };
|
||||
}
|
||||
|
||||
export default function (data) {
|
||||
const params = { headers: { Cookie: `deal_session=${data.session}` } };
|
||||
const paths = ['/api/containers', '/api/cards'];
|
||||
for (const path of paths) {
|
||||
const res = http.get(`${BASE_URL}${path}`, params);
|
||||
check(res, { [`${path} → 200`]: (r) => r.status === 200 });
|
||||
}
|
||||
sleep(0.2);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user