Files
fission-console/scripts/test_stress.sh
T

161 lines
5.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# test_stress.sh — стресс-тест параллельного использования:
# COUNT пользователей создают функции параллельно
# LIST изоляция: каждый видит только свои функции
# Invoke стресс: INVOKE_COUNT параллельных invoke для livetest@test.local (watched namespace)
# Cleanup: удаляем namespace-ы тест-пользователей, функции livetest — через API DELETE.
set -uo pipefail
ROOT_DIR=$(cd "$(dirname "$0")" && pwd)
source "${ROOT_DIR}/lib.sh"
NS_CLEANUP_SCRIPT="${ROOT_DIR}/cleanup_test_namespaces.sh"
RUN_ID=$(mk_run_id)
COUNT="${1:-8}"
TMP=$(mktemp -d)
INVOKE_SUB="livetest@test.local"
INVOKE_COUNT=8
declare -a SUBS=()
for i in $(seq 1 "$COUNT"); do
SUBS+=("stress-${RUN_ID}-u${i}@test.local")
done
declare -a INVOKE_FNS=()
for i in $(seq 1 "$INVOKE_COUNT"); do
INVOKE_FNS+=("sinv-${RUN_ID}-${i}")
done
cleanup() {
rm -rf "$TMP" 2>/dev/null || true
if [ -x "$NS_CLEANUP_SCRIPT" ] && [ "${#SUBS[@]}" -gt 0 ]; then
KUBECTL_DIRECT=1 "$NS_CLEANUP_SCRIPT" "${SUBS[@]}" >/dev/null 2>&1 || true
fi
for fn in "${INVOKE_FNS[@]}"; do
curl -s -X DELETE "${BASE}/functions/${fn}" -H "X-Auth-Token: ${INVOKE_SUB}" > /dev/null 2>&1 || true
done
}
trap cleanup EXIT
echo ""
echo "========================================"
echo " test_stress.sh run=$RUN_ID users=$COUNT invoke_parallel=$INVOKE_COUNT"
echo "========================================"
JS_CODE='module.exports = async function() { return { status: 200, body: "stress-ok" }; }'
# ── Шаг 1: параллельное создание ─────────────────────────────────────────────
echo ""
echo ">>> [1/3] $COUNT пользователей создают функции параллельно..."
for i in $(seq 1 "$COUNT"); do
(
SUB="${SUBS[$((i-1))]}"
FN="stress-fn-${RUN_ID}"
R=$(curl -s -w "\n%{http_code}" --max-time 60 -X POST "${BASE}/functions" \
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" \
-d "{\"name\":\"${FN}\",\"language\":\"nodejs\",\"code\":$(printf '%s' "$JS_CODE" | json_escape)}" \
2>/dev/null)
CODE=$(echo "$R" | tail -1)
echo "$i:$CODE" > "${TMP}/create-$i"
) &
done
wait
CREATE_OK=0
CREATE_FAIL=0
for i in $(seq 1 "$COUNT"); do
CODE=$(cut -d: -f2 "${TMP}/create-$i" 2>/dev/null || echo "000")
if [ "$CODE" = "201" ] || [ "$CODE" = "200" ]; then
CREATE_OK=$((CREATE_OK+1))
else
CREATE_FAIL=$((CREATE_FAIL+1))
echo " user$i: CREATE HTTP $CODE"
fi
done
[ "$CREATE_FAIL" -eq 0 ] \
&& pass "Параллельный CREATE: все $COUNT пользователей → 201" \
|| fail "Параллельный CREATE: $CREATE_FAIL/$COUNT упали"
# ── Шаг 2: изоляция LIST ─────────────────────────────────────────────────────
echo ""
echo ">>> [2/3] Изоляция: каждый видит только свою функцию"
ISO_OK=0
for i in $(seq 1 "$COUNT"); do
SUB="${SUBS[$((i-1))]}"
FN="stress-fn-${RUN_ID}"
LIST=$(curl -s --max-time 20 "${BASE}/functions" -H "X-Auth-Token: ${SUB}")
OWN_COUNT=$(printf '%s' "$LIST" | python3 -c "
import json, sys
try:
fns = json.load(sys.stdin)
print(sum(1 for f in fns if f.get('metadata',{}).get('name','') == '${FN}'))
except:
print(0)" 2>/dev/null)
TOTAL_COUNT=$(json_len "$LIST")
if [ "${OWN_COUNT:-0}" -eq 1 ] && [ "${TOTAL_COUNT:-0}" -eq 1 ]; then
ISO_OK=$((ISO_OK+1))
else
echo " user$i: own=$OWN_COUNT total=$TOTAL_COUNT"
fi
done
[ "$ISO_OK" -eq "$COUNT" ] \
&& pass "Изоляция: все $COUNT пользователей видят только свои функции" \
|| fail "Изоляция: только $ISO_OK/$COUNT OK"
# ── Шаг 3: параллельный invoke (livetest — watched namespace) ─────────────────
echo ""
echo ">>> [3/3] $INVOKE_COUNT параллельных invoke для livetest@test.local"
INV_JS='module.exports = async function() { return { status: 200, body: "sinv-ok" }; }'
for i in $(seq 1 "$INVOKE_COUNT"); do
FN_I="${INVOKE_FNS[$((i-1))]}"
curl -s -X POST "${BASE}/functions" \
-H "X-Auth-Token: ${INVOKE_SUB}" -H "Content-Type: application/json" \
-d "{\"name\":\"${FN_I}\",\"language\":\"nodejs\",\"code\":$(printf '%s' "$INV_JS" | json_escape)}" > /dev/null
done
echo "Ждём прогрева $INVOKE_COUNT функций..."
for i in $(seq 1 "$INVOKE_COUNT"); do
FN_I="${INVOKE_FNS[$((i-1))]}"
for try in $(seq 1 12); do
R=$(curl -s --max-time 30 -X POST "${BASE}/functions/${FN_I}/invoke" \
-H "X-Auth-Token: ${INVOKE_SUB}" -H "Content-Type: application/json" -d '{}')
ST=$(json_field "$R" status)
[ "$ST" = "200" ] && break
echo " прогрев функции $i/$INVOKE_COUNT: попытка $try/12..."
sleep 5
done
echo " функция $i/$INVOKE_COUNT — готова"
done
for i in $(seq 1 "$INVOKE_COUNT"); do
(
FN_I="${INVOKE_FNS[$((i-1))]}"
R=$(curl -s --max-time 30 -X POST "${BASE}/functions/${FN_I}/invoke" \
-H "X-Auth-Token: ${INVOKE_SUB}" -H "Content-Type: application/json" -d '{}')
ST=$(json_field "$R" status)
echo "$i:$ST" > "${TMP}/sinvoke-$i"
) &
done
wait
SINV_OK=0
SINV_FAIL=0
for i in $(seq 1 "$INVOKE_COUNT"); do
CODE=$(cut -d: -f2 "${TMP}/sinvoke-$i" 2>/dev/null || echo "MISS")
[ "$CODE" = "200" ] && SINV_OK=$((SINV_OK+1)) || SINV_FAIL=$((SINV_FAIL+1))
done
[ "$SINV_FAIL" -le 1 ] \
&& pass "Параллельный INVOKE (livetest): $SINV_OK/$INVOKE_COUNT OK" \
|| fail "Параллельный INVOKE (livetest): $SINV_FAIL/$INVOKE_COUNT упали"
print_summary