208 lines
9.7 KiB
Bash
Executable File
208 lines
9.7 KiB
Bash
Executable File
#!/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="test-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\":\"t-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" = "t-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\":\"t-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/t-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/t-crud-fn-${RUN_ID} → 200"
|
||
GOT_NAME=$(json_field "$BODY" name)
|
||
[ "$GOT_NAME" = "t-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/t-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/t-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/t-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
|