268 lines
12 KiB
Bash
Executable File
268 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
||
# tests/quick_test.sh — Быстрая проверка shared-sqs (smoke test)
|
||
# Created: 2026-04-09
|
||
# Updated: 2026-04-11 — полная поддержка JWT (nubes api_token), все 17 SQS команд,
|
||
# TagQueue/UntagQueue/ListQueueTags/ChangeMessageVisibilityBatch,
|
||
# UI API с авторизацией через Bearer JWT.
|
||
# Покрывает: health, admin CRUD, все SQS команды, UI API с JWT.
|
||
# Требования: curl, aws CLI, python3
|
||
# Запуск:
|
||
# bash tests/quick_test.sh
|
||
# BASE_URL=https://qu.kube5s.ru ADMIN_TOKEN=... NUBES_JWT=... bash tests/quick_test.sh
|
||
|
||
set -uo pipefail
|
||
|
||
BASE_URL="${BASE_URL:-https://qu.kube5s.ru}"
|
||
ADMIN_TOKEN="${ADMIN_TOKEN:-sqs-admin-7a7d8bd0c060a75c198d48680f34077a}"
|
||
NUBES_JWT="${NUBES_JWT:-eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoLWFwaSIsInN1YiI6IjAxOTllMzI1LTFjZGYtN2NkYS05MzE5LWU1MzAyYTg1ZTI5MSIsImV4cCI6MTc4NjkzMjI2MCwiaWF0IjoxNzcxMzgwMjYwLCJqdGkiOiIzOTQ3ZTgyMy0yNjljLTQ0MTAtYmU0My1iNGVkNTc1Njg0ZTQiLCJhdXRoX3RpbWUiOjAsInR5cCI6IiIsImF6cCI6IiIsInNlc3Npb25fc3RhdGUiOiIiLCJhY3IiOiIiLCJhbGxvd2VkLW9yaWdpbnMiOm51bGwsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6bnVsbH0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpudWxsfX0sInNjb3BlIjoiIiwic2lkIjoiIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJuYW1lIjoiIiwiQ2xpZW50SUQiOiIiLCJncm91cHMiOm51bGwsInByZWZlcnJlZF91c2VybmFtZSI6IiIsImdpdmVuX25hbWUiOiIiLCJmYW1pbHlfbmFtZSI6IiIsImVtYWlsIjoidGF6ZXRAbmFyb2QucnUifQ.hzpIIqNWkKIoYUXDaLY7DLyGKH70rz0ZTqanv19qxF10i3N1t1g_KknA4Qsw1MduTyLzIz7y5SRSr4PSQ1gzR0vB_C0GudSFUhyBNNKkS4ClhRDWW9eN_IIEljbiJMLQi2L07XJ7Y5DQ0sIHRAPLkreCDFMKQ0yTCrKoScCJIDuUqzaTcOaX-hfjaxW8iV0SZMDxl0C5O3tke0btxkaLBaAcWH0V-1yu2r2m29fyU33FqikF0xAcDXiuZphfsrShKQYArZjKAphYCP_Vpmr-1sdjinkn8sPSk1qZny0rka8G6WVZUGaZSOnW8SYNLVUwdqtuQmK-Y18o7U0Suzrsjg}"
|
||
REGION="us-east-1"
|
||
TS=$(date +%s)
|
||
|
||
PASS=0
|
||
FAIL=0
|
||
|
||
ok() { echo " ✅ $1"; PASS=$((PASS+1)); }
|
||
fail() { echo " ❌ $1"; FAIL=$((FAIL+1)); }
|
||
|
||
check() {
|
||
local label="$1" body="$2" pattern="$3"
|
||
if echo "$body" | grep -qE "$pattern"; then ok "$label"; else fail "$label: $(echo "$body" | head -3)"; fi
|
||
}
|
||
|
||
check_not() {
|
||
local label="$1" body="$2" pattern="$3"
|
||
if echo "$body" | grep -qE "$pattern"; then fail "$label"; else ok "$label"; fi
|
||
}
|
||
|
||
check_http() {
|
||
local label="$1" want="$2" got="$3"
|
||
if [[ "$got" == "$want" ]]; then ok "$label (HTTP $got)"; else fail "$label — ожидалось $want, получено $got"; fi
|
||
}
|
||
|
||
# sqs — AWS CLI враппер
|
||
sqs() {
|
||
local ak="$1" sk="$2"; shift 2
|
||
AWS_ACCESS_KEY_ID="$ak" AWS_SECRET_ACCESS_KEY="$sk" AWS_DEFAULT_REGION="$REGION" \
|
||
aws --endpoint-url "$BASE_URL" --output json sqs "$@" 2>&1
|
||
}
|
||
|
||
# admin — Admin API запрос с Bearer admin token
|
||
admin() {
|
||
local method="$1" path="$2" body="${3:-}"
|
||
if [[ -n "$body" ]]; then
|
||
curl -sf --max-time 15 -X "$method" \
|
||
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d "$body" "${BASE_URL}${path}" 2>&1
|
||
else
|
||
curl -sf --max-time 15 -X "$method" \
|
||
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
||
"${BASE_URL}${path}" 2>&1
|
||
fi
|
||
}
|
||
|
||
# ui — UI API запрос с Bearer JWT (nubes токен)
|
||
ui() {
|
||
local method="$1" path="$2" body="${3:-}"
|
||
if [[ -n "$body" ]]; then
|
||
curl -sf --max-time 15 -X "$method" \
|
||
-H "Authorization: Bearer $NUBES_JWT" \
|
||
-H "Content-Type: application/json" \
|
||
-d "$body" "${BASE_URL}/ui/api${path}" 2>&1
|
||
else
|
||
curl -sf --max-time 15 -X "$method" \
|
||
-H "Authorization: Bearer $NUBES_JWT" \
|
||
"${BASE_URL}/ui/api${path}" 2>&1
|
||
fi
|
||
}
|
||
|
||
echo "════════════════════════════════════════"
|
||
echo " shared-sqs Quick Test"
|
||
echo " Endpoint: $BASE_URL"
|
||
echo "════════════════════════════════════════"
|
||
echo ""
|
||
|
||
# ── 1. Health ──
|
||
echo "── 1. Health ──"
|
||
R=$(curl -sf --max-time 10 "${BASE_URL}/health" 2>&1)
|
||
check "GET /health → ok" "$R" "[Oo][Kk]|status"
|
||
echo ""
|
||
|
||
# ── 2. UI API авторизация (JWT auth) ──
|
||
echo "── 2. UI API авторизация ──"
|
||
R=$(curl -sf --max-time 15 -X POST \
|
||
-H "Content-Type: application/json" \
|
||
-d "{\"token\":\"$NUBES_JWT\"}" \
|
||
"${BASE_URL}/ui/api/auth" 2>&1)
|
||
check "POST /ui/api/auth → tenant_id" "$R" "tenant_id"
|
||
UI_TID=$(echo "$R" | python3 -c "import sys,json; print(json.load(sys.stdin).get('tenant_id',''))" 2>/dev/null || true)
|
||
echo " UI Tenant ID: $UI_TID"
|
||
echo ""
|
||
|
||
# ── 3. Создание тенанта через Admin API ──
|
||
echo "── 3. Admin API — создание тенанта ──"
|
||
RESP=$(admin POST /admin/tenants '{"name":"quick-'"$TS"'","max_queues":10}')
|
||
check "POST /admin/tenants → access_key" "$RESP" "access_key"
|
||
AK=$(echo "$RESP" | python3 -c "import sys,json; print(json.load(sys.stdin)['access_key'])")
|
||
SK=$(echo "$RESP" | python3 -c "import sys,json; print(json.load(sys.stdin)['secret_key'])")
|
||
TID=$(echo "$RESP" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
|
||
echo " Tenant ID: $TID"
|
||
echo " Access Key: $AK"
|
||
echo ""
|
||
|
||
QNAME="quick-q-$TS"
|
||
QURL="${BASE_URL}/${TID}/${QNAME}"
|
||
|
||
# ── 4. SQS Queue CRUD ──
|
||
echo "── 4. SQS Queue CRUD ──"
|
||
R=$(sqs "$AK" "$SK" create-queue --queue-name "$QNAME")
|
||
check "CreateQueue → QueueUrl" "$R" "QueueUrl"
|
||
|
||
R=$(sqs "$AK" "$SK" list-queues)
|
||
check "ListQueues → очередь в списке" "$R" "$QNAME"
|
||
|
||
R=$(sqs "$AK" "$SK" get-queue-url --queue-name "$QNAME")
|
||
check "GetQueueUrl → QueueUrl" "$R" "QueueUrl"
|
||
|
||
R=$(sqs "$AK" "$SK" get-queue-attributes --queue-url "$QURL" --attribute-names All)
|
||
check "GetQueueAttributes → VisibilityTimeout" "$R" "VisibilityTimeout"
|
||
|
||
R=$(sqs "$AK" "$SK" set-queue-attributes --queue-url "$QURL" --attributes '{"VisibilityTimeout":"60"}' 2>&1 && echo "OK" || echo "FAIL")
|
||
check "SetQueueAttributes → OK" "$R" "OK"
|
||
echo ""
|
||
|
||
# ── 5. TagQueue / UntagQueue / ListQueueTags ──
|
||
echo "── 5. Tags API ──"
|
||
R=$(sqs "$AK" "$SK" tag-queue --queue-url "$QURL" --tags env=test,owner=qa 2>&1 && echo "OK" || echo "FAIL")
|
||
check "TagQueue → OK" "$R" "OK"
|
||
|
||
R=$(sqs "$AK" "$SK" list-queue-tags --queue-url "$QURL")
|
||
check "ListQueueTags → env=test" "$R" "env|test"
|
||
|
||
R=$(sqs "$AK" "$SK" untag-queue --queue-url "$QURL" --tag-keys env 2>&1 && echo "OK" || echo "FAIL")
|
||
check "UntagQueue → OK" "$R" "OK"
|
||
|
||
R=$(sqs "$AK" "$SK" list-queue-tags --queue-url "$QURL")
|
||
check_not "ListQueueTags → env удалён" "$R" '"env"'
|
||
echo ""
|
||
|
||
# ── 6. Сообщения: Send / Receive / Delete ──
|
||
echo "── 6. Send / Receive / Delete ──"
|
||
R=$(sqs "$AK" "$SK" send-message --queue-url "$QURL" --message-body "hello-$TS")
|
||
check "SendMessage → MessageId" "$R" "MessageId"
|
||
check "SendMessage → MD5" "$R" "MD5OfMessageBody"
|
||
|
||
R=$(sqs "$AK" "$SK" receive-message --queue-url "$QURL" --visibility-timeout 30)
|
||
check "ReceiveMessage → тело" "$R" "hello-$TS"
|
||
RECEIPT=$(echo "$R" | python3 -c "import sys,json; msgs=json.load(sys.stdin).get('Messages',[]); print(msgs[0]['ReceiptHandle'] if msgs else '')" 2>/dev/null || true)
|
||
|
||
if [[ -n "$RECEIPT" ]]; then
|
||
R=$(sqs "$AK" "$SK" change-message-visibility --queue-url "$QURL" --receipt-handle "$RECEIPT" --visibility-timeout 60 2>&1 && echo "OK" || echo "FAIL")
|
||
check "ChangeMessageVisibility → OK" "$R" "OK"
|
||
|
||
sqs "$AK" "$SK" delete-message --queue-url "$QURL" --receipt-handle "$RECEIPT" >/dev/null 2>&1
|
||
ok "DeleteMessage → без ошибок"
|
||
else
|
||
fail "ReceiptHandle не получен"
|
||
fi
|
||
echo ""
|
||
|
||
# ── 7. Batch операции ──
|
||
echo "── 7. Batch ──"
|
||
R=$(sqs "$AK" "$SK" send-message-batch --queue-url "$QURL" \
|
||
--entries '[{"Id":"b1","MessageBody":"batch-1"},{"Id":"b2","MessageBody":"batch-2"},{"Id":"b3","MessageBody":"batch-3"}]')
|
||
check "SendMessageBatch → Successful" "$R" "Successful"
|
||
|
||
R=$(sqs "$AK" "$SK" receive-message --queue-url "$QURL" --max-number-of-messages 3)
|
||
RECEIPTS=$(echo "$R" | python3 -c "import sys,json; msgs=json.load(sys.stdin).get('Messages',[]); print('\n'.join(m['ReceiptHandle'] for m in msgs))" 2>/dev/null || true)
|
||
|
||
# ChangeMessageVisibilityBatch
|
||
if [[ -n "$RECEIPTS" ]]; then
|
||
CMV_ENTRIES=$(echo "$RECEIPTS" | python3 -c "
|
||
import sys
|
||
entries = []
|
||
for i, rh in enumerate(sys.stdin.read().strip().split('\n'), 1):
|
||
if rh:
|
||
entries.append('{\"Id\":\"cmv%d\",\"ReceiptHandle\":\"%s\",\"VisibilityTimeout\":60}' % (i, rh))
|
||
print('[' + ','.join(entries) + ']')
|
||
" 2>/dev/null || echo "[]")
|
||
if [[ "$CMV_ENTRIES" != "[]" ]]; then
|
||
R=$(sqs "$AK" "$SK" change-message-visibility-batch --queue-url "$QURL" --entries "$CMV_ENTRIES")
|
||
check "ChangeMessageVisibilityBatch → Successful" "$R" "Successful"
|
||
fi
|
||
|
||
DEL_ENTRIES=$(echo "$RECEIPTS" | python3 -c "
|
||
import sys
|
||
entries = []
|
||
for i, rh in enumerate(sys.stdin.read().strip().split('\n'), 1):
|
||
if rh:
|
||
entries.append('{\"Id\":\"d%d\",\"ReceiptHandle\":\"%s\"}' % (i, rh))
|
||
print('[' + ','.join(entries) + ']')
|
||
" 2>/dev/null || echo "[]")
|
||
if [[ "$DEL_ENTRIES" != "[]" ]]; then
|
||
R=$(sqs "$AK" "$SK" delete-message-batch --queue-url "$QURL" --entries "$DEL_ENTRIES")
|
||
check "DeleteMessageBatch → Successful" "$R" "Successful"
|
||
fi
|
||
fi
|
||
echo ""
|
||
|
||
# ── 8. PurgeQueue ──
|
||
echo "── 8. PurgeQueue ──"
|
||
sqs "$AK" "$SK" send-message --queue-url "$QURL" --message-body "purge-me" >/dev/null 2>&1 || true
|
||
R=$(sqs "$AK" "$SK" purge-queue --queue-url "$QURL" 2>&1 && echo "OK" || echo "FAIL")
|
||
check "PurgeQueue → OK" "$R" "OK"
|
||
echo ""
|
||
|
||
# ── 9. UI API с JWT ──
|
||
echo "── 9. UI API с JWT ──"
|
||
R=$(ui GET /health)
|
||
check "GET /ui/api/health → ok" "$R" "ok|status"
|
||
|
||
if [[ -n "$UI_TID" ]]; then
|
||
R=$(ui GET "/tenants/${UI_TID}/queues")
|
||
check "UI GET /tenants/{id}/queues → ответ" "$R" "\[|\]|name|queues"
|
||
|
||
R=$(ui POST "/tenants/${UI_TID}/queues" '{"name":"ui-q-'"$TS"'"}')
|
||
check "UI POST /queues → создана" "$R" "ui-q-$TS|name"
|
||
|
||
R=$(ui POST "/tenants/${UI_TID}/queues/ui-q-${TS}/messages" '{"body":"ui-msg-'"$TS"'"}')
|
||
check "UI POST /messages → id" "$R" '"id"'
|
||
|
||
R=$(ui GET "/tenants/${UI_TID}/queues/ui-q-${TS}/messages")
|
||
check "UI GET /messages → тело" "$R" "ui-msg-$TS"
|
||
check_not "UI GET /messages → нет receipt_handle" "$R" "receipt_handle"
|
||
|
||
R=$(ui DELETE "/tenants/${UI_TID}/queues/ui-q-${TS}/messages" "")
|
||
check_not "UI DELETE /messages (purge) → сообщение исчезло" \
|
||
"$(ui GET "/tenants/${UI_TID}/queues/ui-q-${TS}/messages")" "ui-msg-$TS"
|
||
|
||
HTTP=$(curl -sf --max-time 15 -o /dev/null -w "%{http_code}" -X DELETE \
|
||
-H "Authorization: Bearer $NUBES_JWT" \
|
||
"${BASE_URL}/ui/api/tenants/${UI_TID}/queues/ui-q-${TS}")
|
||
if [[ "$HTTP" == "204" || "$HTTP" == "200" ]]; then
|
||
ok "UI DELETE /queues/ui-q → HTTP $HTTP"
|
||
else
|
||
fail "UI DELETE /queues/ui-q → HTTP $HTTP (ожидалось 200/204)"
|
||
fi
|
||
else
|
||
fail "UI API: JWT auth не дал tenant_id — пропускаем UI тесты"
|
||
fi
|
||
echo ""
|
||
|
||
# ── 10. DeleteQueue ──
|
||
echo "── 10. DeleteQueue ──"
|
||
R=$(sqs "$AK" "$SK" delete-queue --queue-url "$QURL" 2>&1 && echo "OK" || echo "FAIL")
|
||
check "DeleteQueue → OK" "$R" "OK"
|
||
echo ""
|
||
|
||
# ── Cleanup ──
|
||
echo "── Cleanup ──"
|
||
admin DELETE "/admin/tenants/$TID" >/dev/null 2>&1 && ok "DELETE тенанта" || fail "DELETE тенанта"
|
||
echo ""
|
||
|
||
echo "════════════════════════════════════════"
|
||
printf " Результат: ✅ %d ❌ %d\n" "$PASS" "$FAIL"
|
||
echo "════════════════════════════════════════"
|
||
|
||
[[ $FAIL -eq 0 ]] && exit 0 || exit 1
|