tests: тест-скрипты v2 — полный сьют PASS=8 FAIL=0

- lib.sh: утилиты (json_field, wait_invoke, print_summary)
- run_all.sh: запуск всех скриптов + финальная сводка
- pre_cleanup.sh: очистка тест-namespace-ов перед прогоном
- test_auth.sh: 14/14 PASS — авторизация, namespace детерминизм
- test_functions_crud.sh: 29/29 PASS — CRUD, валидация, >1MB
- test_ttl.sh: 10/10 PASS — TTL=15m/1h/2d, невалидные
- test_isolation.sh: 11/11 PASS — изоляция пользователей
- test_update.sh: 10/10 PASS — PUT /code v1→v2→v3 (livetest)
- test_invoke.sh: 9/9 PASS — NodeJS/Python invoke (livetest)
- test_stress.sh: 3/3 PASS — 8 пользователей параллельно (livetest)
- test_linters.sh: 31/31 PASS — синтаксис 5 языков
This commit is contained in:
Naeel
2026-05-03 14:02:24 +03:00
parent f18508d2cb
commit c1e3039d15
11 changed files with 1152 additions and 0 deletions
+207
View File
@@ -0,0 +1,207 @@
#!/usr/bin/env bash
# test_functions_crud.sh — тестирует CRUD операции с функциями:
# POST /functions, GET /functions, GET /functions/{name},
# DELETE /functions/{name}, валидация имён, дубликаты, размер кода.
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)
SUB="crud-${RUN_ID}@test.local"
cleanup() {
if [ -x "$NS_CLEANUP_SCRIPT" ]; then
KUBECTL_DIRECT=1 "$NS_CLEANUP_SCRIPT" "$SUB" >/dev/null 2>&1 || true
fi
}
trap cleanup EXIT
echo ""
echo "========================================"
echo " test_functions_crud.sh run=$RUN_ID"
echo "========================================"
JS_CODE='module.exports = async function(ctx) { return { status: 200, body: "crud-ok" }; }'
# ── CREATE ───────────────────────────────────────────────────────────────────
echo ""
echo ">>> CREATE: базовый nodejs → 201"
R=$(curl -s -w "\n%{http_code}" -X POST "${BASE}/functions" \
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" \
-d "{\"name\":\"crud-fn-${RUN_ID}\",\"language\":\"nodejs\",\"code\":$(printf '%s' "$JS_CODE" | json_escape)}")
CODE=$(echo "$R" | tail -1)
BODY=$(echo "$R" | sed '$d')
check_http "$CODE" "201" "CREATE nodejs → 201"
FN_NAME=$(json_field "$BODY" name)
FN_ROUTE=$(json_field "$BODY" route)
FN_PKG=$(json_field "$BODY" package)
[ "$FN_NAME" = "crud-fn-${RUN_ID}" ] && pass "CREATE: name в ответе" || fail "CREATE: name='$FN_NAME'"
printf '%s' "$FN_ROUTE" | grep -q '/' && pass "CREATE: route непустой" || fail "CREATE: route='$FN_ROUTE'"
[ -n "$FN_PKG" ] && pass "CREATE: package непустой" || fail "CREATE: package пустой"
echo ""
echo ">>> CREATE: дубликат → 409"
R=$(curl -s -w "\n%{http_code}" -X POST "${BASE}/functions" \
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" \
-d "{\"name\":\"crud-fn-${RUN_ID}\",\"language\":\"nodejs\",\"code\":$(printf '%s' "$JS_CODE" | json_escape)}")
check_http "$(echo "$R" | tail -1)" "409" "CREATE дубликат → 409"
echo ""
echo ">>> CREATE: без name → 400"
R=$(curl -s -w "\n%{http_code}" -X POST "${BASE}/functions" \
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" \
-d '{"language":"nodejs","code":"x"}')
check_http "$(echo "$R" | tail -1)" "400" "CREATE без name → 400"
echo ""
echo ">>> CREATE: без language → 400"
R=$(curl -s -w "\n%{http_code}" -X POST "${BASE}/functions" \
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" \
-d '{"name":"no-lang","code":"x"}')
check_http "$(echo "$R" | tail -1)" "400" "CREATE без language → 400"
echo ""
echo ">>> CREATE: без code → 400"
R=$(curl -s -w "\n%{http_code}" -X POST "${BASE}/functions" \
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" \
-d '{"name":"no-code","language":"nodejs"}')
check_http "$(echo "$R" | tail -1)" "400" "CREATE без code → 400"
echo ""
echo ">>> CREATE: невалидный язык → 400"
R=$(curl -s -w "\n%{http_code}" -X POST "${BASE}/functions" \
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" \
-d '{"name":"bad-lang","language":"cobol","code":"x"}')
check_http "$(echo "$R" | tail -1)" "400" "CREATE язык=cobol → 400"
echo ""
echo ">>> CREATE: валидация имени"
# Заглавная буква
R=$(curl -s -w "\n%{http_code}" -X POST "${BASE}/functions" \
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" \
-d '{"name":"BadName","language":"nodejs","code":"x"}')
check_http "$(echo "$R" | tail -1)" "400" "CREATE имя с заглавной → 400"
# Начинается с дефиса
R=$(curl -s -w "\n%{http_code}" -X POST "${BASE}/functions" \
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" \
-d '{"name":"-bad","language":"nodejs","code":"x"}')
check_http "$(echo "$R" | tail -1)" "400" "CREATE имя с ведущим дефисом → 400"
# Заканчивается дефисом
R=$(curl -s -w "\n%{http_code}" -X POST "${BASE}/functions" \
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" \
-d '{"name":"bad-","language":"nodejs","code":"x"}')
check_http "$(echo "$R" | tail -1)" "400" "CREATE имя с завершающим дефисом → 400"
# Пробел в имени
R=$(curl -s -w "\n%{http_code}" -X POST "${BASE}/functions" \
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" \
-d '{"name":"bad name","language":"nodejs","code":"x"}')
check_http "$(echo "$R" | tail -1)" "400" "CREATE имя с пробелом → 400"
# 58 символов — должно быть 400 (лимит 57)
NAME58=$(python3 -c "print('a'*58)")
R=$(curl -s -w "\n%{http_code}" -X POST "${BASE}/functions" \
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" \
-d "{\"name\":\"${NAME58}\",\"language\":\"nodejs\",\"code\":\"x\"}")
check_http "$(echo "$R" | tail -1)" "400" "CREATE имя 58 символов → 400"
# 57 символов — должно быть 201
NAME57=$(python3 -c "print('a'*57)")
R=$(curl -s -w "\n%{http_code}" -X POST "${BASE}/functions" \
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" \
-d "{\"name\":\"${NAME57}\",\"language\":\"nodejs\",\"code\":$(printf '%s' "$JS_CODE" | json_escape)}")
check_http "$(echo "$R" | tail -1)" "201" "CREATE имя 57 символов → 201"
echo ""
echo ">>> CREATE: код > 1MB → 400 или 413"
# Используем pipe чтобы избежать Argument list too long
R=$(python3 -c "
import json, sys
payload = json.dumps({'name':'big-code','language':'nodejs','code':'x'*(1024*1024+1)})
print(payload)
" | curl -s -w "\n%{http_code}" -X POST "${BASE}/functions" \
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" \
--data-binary @- --max-time 30)
CODE=$(echo "$R" | tail -1)
( [ "$CODE" = "400" ] || [ "$CODE" = "413" ] || [ "$CODE" = "000" ] ) \
&& pass "CREATE код > 1MB → отклонён ($CODE)" \
|| fail "CREATE код > 1MB → got $CODE"
# ── LIST ─────────────────────────────────────────────────────────────────────
echo ""
echo ">>> LIST: GET /functions → 200, массив"
R=$(curl -s -w "\n%{http_code}" "${BASE}/functions" -H "X-Auth-Token: ${SUB}")
CODE=$(echo "$R" | tail -1)
BODY=$(echo "$R" | sed '$d')
check_http "$CODE" "200" "LIST GET /functions → 200"
COUNT=$(json_len "$BODY")
[ "${COUNT:-0}" -ge 1 ] && pass "LIST: содержит ≥1 функцию (создали выше)" || fail "LIST: пустой массив count=$COUNT"
echo ""
echo ">>> LIST: новый пользователь → пустой массив"
EMPTY_USER="empty-${RUN_ID}@test.local"
R=$(curl -s -w "\n%{http_code}" "${BASE}/functions" -H "X-Auth-Token: ${EMPTY_USER}")
CODE=$(echo "$R" | tail -1)
BODY=$(echo "$R" | sed '$d')
check_http "$CODE" "200" "LIST новый пользователь → 200"
COUNT=$(json_len "$BODY")
[ "${COUNT:-99}" -eq 0 ] && pass "LIST новый пользователь → []" || fail "LIST новый пользователь → count=$COUNT"
# ── GET ──────────────────────────────────────────────────────────────────────
echo ""
echo ">>> GET: /functions/{name} → 200"
R=$(curl -s -w "\n%{http_code}" "${BASE}/functions/crud-fn-${RUN_ID}" \
-H "X-Auth-Token: ${SUB}")
CODE=$(echo "$R" | tail -1)
BODY=$(echo "$R" | sed '$d')
check_http "$CODE" "200" "GET /functions/crud-fn-${RUN_ID} → 200"
GOT_NAME=$(json_field "$BODY" name)
[ "$GOT_NAME" = "crud-fn-${RUN_ID}" ] && pass "GET: name совпадает" || fail "GET: name='$GOT_NAME'"
GOT_ENV=$(json_field "$BODY" environment)
[ -n "$GOT_ENV" ] && pass "GET: environment непустой ($GOT_ENV)" || fail "GET: environment пустой"
echo ""
echo ">>> GET: несуществующая функция → 404"
R=$(curl -s -w "\n%{http_code}" "${BASE}/functions/does-not-exist-xyz" \
-H "X-Auth-Token: ${SUB}")
check_http "$(echo "$R" | tail -1)" "404" "GET несуществующая → 404"
# ── DELETE ───────────────────────────────────────────────────────────────────
echo ""
echo ">>> DELETE: /functions/{name} → 200"
R=$(curl -s -w "\n%{http_code}" -X DELETE "${BASE}/functions/crud-fn-${RUN_ID}" \
-H "X-Auth-Token: ${SUB}")
CODE=$(echo "$R" | tail -1)
BODY=$(echo "$R" | sed '$d')
check_http "$CODE" "200" "DELETE crud-fn → 200"
DELETED=$(json_field "$BODY" deleted)
[ "$DELETED" = "True" ] || [ "$DELETED" = "true" ] && pass "DELETE: deleted=true" || fail "DELETE: deleted='$DELETED'"
echo ""
echo ">>> DELETE: повторное удаление → 404"
R=$(curl -s -w "\n%{http_code}" -X DELETE "${BASE}/functions/crud-fn-${RUN_ID}" \
-H "X-Auth-Token: ${SUB}")
check_http "$(echo "$R" | tail -1)" "404" "DELETE повторное → 404"
echo ""
echo ">>> GET: после DELETE → 404"
R=$(curl -s -w "\n%{http_code}" "${BASE}/functions/crud-fn-${RUN_ID}" \
-H "X-Auth-Token: ${SUB}")
check_http "$(echo "$R" | tail -1)" "404" "GET после DELETE → 404"
echo ""
echo ">>> DELETE: несуществующая функция → 404"
R=$(curl -s -w "\n%{http_code}" -X DELETE "${BASE}/functions/does-not-exist-xyz" \
-H "X-Auth-Token: ${SUB}")
check_http "$(echo "$R" | tail -1)" "404" "DELETE несуществующая → 404"
print_summary