tests: api_test.sh (CLI 22 проверки) + sdk_test.py (boto3 15 проверок)
This commit is contained in:
Executable
+125
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env bash
|
||||
# tests/api_test.sh — программная проверка SQS API (как сервис используют приложения).
|
||||
# Не консоль: aws cli = тот же SDK-путь (Signature V4), что у boto3/aws-sdk-go и др.
|
||||
#
|
||||
# Использование:
|
||||
# AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... ./tests/api_test.sh
|
||||
set -u
|
||||
|
||||
ENDPOINT="${ENDPOINT:-https://sqs.containerk8s.dev.nubes.ru}"
|
||||
REGION="${REGION:-us-east-1}"
|
||||
|
||||
PASS=0; FAIL=0
|
||||
ok() { PASS=$((PASS+1)); echo " ✅ $1"; }
|
||||
bad() { FAIL=$((FAIL+1)); echo " ❌ $1"; }
|
||||
|
||||
json() { python3 -c "import sys,json; d=json.load(sys.stdin); print($1)" 2>/dev/null; }
|
||||
|
||||
AWS=(aws --endpoint-url "$ENDPOINT" --region "$REGION")
|
||||
|
||||
if [[ -z "${AWS_ACCESS_KEY_ID:-}" || -z "${AWS_SECRET_ACCESS_KEY:-}" ]]; then
|
||||
echo "Нужны AWS_ACCESS_KEY_ID и AWS_SECRET_ACCESS_KEY"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
Q="api-test-$(date +%s)"
|
||||
QF="$Q.fifo"
|
||||
|
||||
echo "== Базовая очередь =="
|
||||
# ListQueues
|
||||
"${AWS[@]}" sqs list-queues >/dev/null 2>&1 && ok "ListQueues" || bad "ListQueues"
|
||||
|
||||
# CreateQueue
|
||||
CQ=$("${AWS[@]}" sqs create-queue --queue-name "$Q" 2>&1)
|
||||
QUEUE_URL=$(echo "$CQ" | json 'd["QueueUrl"]')
|
||||
[[ -n "$QUEUE_URL" ]] && ok "CreateQueue" || bad "CreateQueue: $CQ"
|
||||
|
||||
# GetQueueUrl — должен совпасть с URL из create-queue
|
||||
GUQ=$("${AWS[@]}" sqs get-queue-url --queue-name "$Q" 2>&1)
|
||||
GUQ_URL=$(echo "$GUQ" | json 'd["QueueUrl"]')
|
||||
[[ "$GUQ_URL" == "$QUEUE_URL" ]] && ok "GetQueueUrl" || bad "GetQueueUrl"
|
||||
|
||||
# GetQueueAttributes (All)
|
||||
GQA=$("${AWS[@]}" sqs get-queue-attributes --queue-url "$QUEUE_URL" --attribute-names All 2>&1)
|
||||
echo "$GQA" | grep -qF '"VisibilityTimeout"' && ok "GetQueueAttributes" || bad "GetQueueAttributes: $GQA"
|
||||
|
||||
# SetQueueAttributes (VisibilityTimeout=42) + проверка
|
||||
"${AWS[@]}" sqs set-queue-attributes --queue-url "$QUEUE_URL" --attributes VisibilityTimeout=42 >/dev/null 2>&1 \
|
||||
&& ok "SetQueueAttributes" || bad "SetQueueAttributes"
|
||||
GQA2=$("${AWS[@]}" sqs get-queue-attributes --queue-url "$QUEUE_URL" --attribute-names VisibilityTimeout 2>&1)
|
||||
echo "$GQA2" | grep -qF '"42"' && ok "SetQueueAttributes проверен (42)" || bad "VisibilityTimeout != 42"
|
||||
|
||||
# SendMessage
|
||||
"${AWS[@]}" sqs send-message --queue-url "$QUEUE_URL" --message-body "single-msg" >/dev/null 2>&1 \
|
||||
&& ok "SendMessage" || bad "SendMessage"
|
||||
|
||||
# SendMessageBatch (2 сообщения)
|
||||
SMB=$("${AWS[@]}" sqs send-message-batch --queue-url "$QUEUE_URL" \
|
||||
--entries Id=1,MessageBody=batch-1 Id=2,MessageBody=batch-2 2>&1)
|
||||
echo "$SMB" | grep -qF '"Successful"' && ok "SendMessageBatch (2)" || bad "SendMessageBatch: $SMB"
|
||||
|
||||
# ReceiveMessage (до 10) — должны прийти все 3
|
||||
for i in 1 2 3 4 5; do
|
||||
RM=$("${AWS[@]}" sqs receive-message --queue-url "$QUEUE_URL" --max-number-of-messages 10 2>&1)
|
||||
N=$(echo "$RM" | json 'len(d.get("Messages", []))')
|
||||
[[ -n "$N" && "$N" -gt 0 ]] && break
|
||||
sleep 1
|
||||
done
|
||||
N=$(echo "$RM" | json 'len(d.get("Messages", []))')
|
||||
[[ "$N" == "3" ]] && ok "ReceiveMessage (3 сообщения)" || bad "ReceiveMessage: получили $N"
|
||||
|
||||
# ChangeMessageVisibility по первому handle
|
||||
RH1=$(echo "$RM" | json 'd["Messages"][0]["ReceiptHandle"]')
|
||||
if [[ -n "$RH1" ]]; then
|
||||
"${AWS[@]}" sqs change-message-visibility --queue-url "$QUEUE_URL" --receipt-handle "$RH1" --visibility-timeout 1 >/dev/null 2>&1 \
|
||||
&& ok "ChangeMessageVisibility" || bad "ChangeMessageVisibility"
|
||||
fi
|
||||
|
||||
# DeleteMessage (первое) + DeleteMessageBatch (остальные два)
|
||||
"${AWS[@]}" sqs delete-message --queue-url "$QUEUE_URL" --receipt-handle "$RH1" >/dev/null 2>&1 \
|
||||
&& ok "DeleteMessage" || bad "DeleteMessage"
|
||||
RH2=$(echo "$RM" | json 'd["Messages"][1]["ReceiptHandle"]')
|
||||
RH3=$(echo "$RM" | json 'd["Messages"][2]["ReceiptHandle"]')
|
||||
if [[ -n "$RH2" && -n "$RH3" ]]; then
|
||||
DMB=$("${AWS[@]}" sqs delete-message-batch --queue-url "$QUEUE_URL" \
|
||||
--entries Id=1,ReceiptHandle="$RH2" Id=2,ReceiptHandle="$RH3" 2>&1)
|
||||
echo "$DMB" | grep -qF '"Successful"' && ok "DeleteMessageBatch (2)" || bad "DeleteMessageBatch: $DMB"
|
||||
fi
|
||||
|
||||
# TagQueue / ListQueueTags / UntagQueue
|
||||
"${AWS[@]}" sqs tag-queue --queue-url "$QUEUE_URL" --tags env=test,owner=api-test >/dev/null 2>&1 \
|
||||
&& ok "TagQueue" || bad "TagQueue"
|
||||
LQT=$("${AWS[@]}" sqs list-queue-tags --queue-url "$QUEUE_URL" 2>&1)
|
||||
echo "$LQT" | grep -qF '"env"' && echo "$LQT" | grep -qF '"api-test"' && ok "ListQueueTags" || bad "ListQueueTags: $LQT"
|
||||
"${AWS[@]}" sqs untag-queue --queue-url "$QUEUE_URL" --tag-keys env owner >/dev/null 2>&1 \
|
||||
&& ok "UntagQueue" || bad "UntagQueue"
|
||||
|
||||
# PurgeQueue
|
||||
"${AWS[@]}" sqs purge-queue --queue-url "$QUEUE_URL" >/dev/null 2>&1 \
|
||||
&& ok "PurgeQueue" || bad "PurgeQueue"
|
||||
|
||||
# DeleteQueue
|
||||
"${AWS[@]}" sqs delete-queue --queue-url "$QUEUE_URL" >/dev/null 2>&1 \
|
||||
&& ok "DeleteQueue" || bad "DeleteQueue"
|
||||
|
||||
echo "== FIFO-очередь =="
|
||||
CFQ=$("${AWS[@]}" sqs create-queue --queue-name "$QF" --attributes FifoQueue=true 2>&1)
|
||||
FIFO_URL=$(echo "$CFQ" | json 'd["QueueUrl"]')
|
||||
[[ -n "$FIFO_URL" ]] && ok "CreateQueue (FIFO)" || bad "CreateQueue FIFO: $CFQ"
|
||||
|
||||
"${AWS[@]}" sqs send-message --queue-url "$FIFO_URL" --message-body "fifo-msg" \
|
||||
--message-group-id g1 --message-deduplication-id d1 >/dev/null 2>&1 \
|
||||
&& ok "SendMessage (FIFO)" || bad "SendMessage FIFO"
|
||||
|
||||
RF=$("${AWS[@]}" sqs receive-message --queue-url "$FIFO_URL" --max-number-of-messages 1 2>&1)
|
||||
echo "$RF" | grep -qF '"fifo-msg"' && ok "ReceiveMessage (FIFO)" || bad "ReceiveMessage FIFO: $RF"
|
||||
RFH=$(echo "$RF" | json 'd["Messages"][0]["ReceiptHandle"]')
|
||||
[[ -n "$RFH" ]] && "${AWS[@]}" sqs delete-message --queue-url "$FIFO_URL" --receipt-handle "$RFH" >/dev/null 2>&1 \
|
||||
&& ok "DeleteMessage (FIFO)" || bad "DeleteMessage FIFO"
|
||||
|
||||
"${AWS[@]}" sqs delete-queue --queue-url "$FIFO_URL" >/dev/null 2>&1 \
|
||||
&& ok "DeleteQueue (FIFO)" || bad "DeleteQueue FIFO"
|
||||
|
||||
echo
|
||||
echo "Итог: PASS=$PASS FAIL=$FAIL"
|
||||
[[ $FAIL -eq 0 ]]
|
||||
@@ -0,0 +1,163 @@
|
||||
#!/usr/bin/env python3
|
||||
"""tests/sdk_test.py — программная проверка SQS API через boto3 (как реальное приложение).
|
||||
|
||||
Использование:
|
||||
AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... \
|
||||
ENDPOINT_URL=https://sqs.containerk8s.dev.nubes.ru python3 tests/sdk_test.py
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
import boto3
|
||||
from botocore.config import Config
|
||||
|
||||
ENDPOINT = os.environ.get("ENDPOINT_URL", "https://sqs.containerk8s.dev.nubes.ru")
|
||||
REGION = os.environ.get("REGION", "us-east-1")
|
||||
|
||||
PASS = 0
|
||||
FAIL = 0
|
||||
|
||||
|
||||
def ok(name):
|
||||
global PASS
|
||||
PASS += 1
|
||||
print(f" OK {name}")
|
||||
|
||||
|
||||
def bad(name, err=""):
|
||||
global FAIL
|
||||
FAIL += 1
|
||||
print(f" FAIL {name} {err}")
|
||||
|
||||
|
||||
def main():
|
||||
if not os.environ.get("AWS_ACCESS_KEY_ID") or not os.environ.get("AWS_SECRET_ACCESS_KEY"):
|
||||
print("Нужны AWS_ACCESS_KEY_ID и AWS_SECRET_ACCESS_KEY")
|
||||
return 1
|
||||
|
||||
# Таймауты на уровне SDK: запросы не зависают.
|
||||
cfg = Config(connect_timeout=10, read_timeout=20, retries={"max_attempts": 2})
|
||||
sqs = boto3.client("sqs", endpoint_url=ENDPOINT, region_name=REGION, config=cfg)
|
||||
|
||||
q = f"sdk-test-{int(time.time())}"
|
||||
qf = q + ".fifo"
|
||||
|
||||
def step(name, fn):
|
||||
try:
|
||||
fn()
|
||||
ok(name)
|
||||
except Exception as e:
|
||||
bad(name, f"— {type(e).__name__}: {e}")
|
||||
|
||||
url = {}
|
||||
|
||||
def list_queues():
|
||||
resp = sqs.list_queues()
|
||||
assert isinstance(resp.get("QueueUrls"), list)
|
||||
|
||||
def create_queue():
|
||||
url["u"] = sqs.create_queue(QueueName=q)["QueueUrl"]
|
||||
|
||||
def get_queue_url():
|
||||
assert sqs.get_queue_url(QueueName=q)["QueueUrl"] == url["u"]
|
||||
|
||||
def get_queue_attributes():
|
||||
attrs = sqs.get_queue_attributes(QueueUrl=url["u"], AttributeNames=["All"])["Attributes"]
|
||||
assert "VisibilityTimeout" in attrs
|
||||
|
||||
def set_queue_attributes():
|
||||
sqs.set_queue_attributes(QueueUrl=url["u"], Attributes={"VisibilityTimeout": "42"})
|
||||
vt = sqs.get_queue_attributes(QueueUrl=url["u"], AttributeNames=["VisibilityTimeout"])["Attributes"]["VisibilityTimeout"]
|
||||
assert vt == "42", f"VisibilityTimeout={vt}"
|
||||
|
||||
def send_message():
|
||||
sqs.send_message(QueueUrl=url["u"], MessageBody="sdk-single")
|
||||
|
||||
def send_message_batch():
|
||||
resp = sqs.send_message_batch(
|
||||
QueueUrl=url["u"],
|
||||
Entries=[{"Id": "1", "MessageBody": "sdk-batch-1"}, {"Id": "2", "MessageBody": "sdk-batch-2"}],
|
||||
)
|
||||
assert len(resp["Successful"]) == 2
|
||||
|
||||
received = {}
|
||||
|
||||
def receive_messages():
|
||||
msgs = None
|
||||
for _ in range(5):
|
||||
msgs = sqs.receive_message(QueueUrl=url["u"], MaxNumberOfMessages=10).get("Messages", [])
|
||||
if msgs:
|
||||
break
|
||||
time.sleep(1)
|
||||
assert len(msgs) == 3, f"получено {len(msgs)}"
|
||||
received["m"] = msgs
|
||||
|
||||
def change_visibility():
|
||||
sqs.change_message_visibility(
|
||||
QueueUrl=url["u"], ReceiptHandle=received["m"][0]["ReceiptHandle"], VisibilityTimeout=1
|
||||
)
|
||||
|
||||
def delete_message():
|
||||
sqs.delete_message(QueueUrl=url["u"], ReceiptHandle=received["m"][0]["ReceiptHandle"])
|
||||
|
||||
def delete_message_batch():
|
||||
resp = sqs.delete_message_batch(
|
||||
QueueUrl=url["u"],
|
||||
Entries=[
|
||||
{"Id": "1", "ReceiptHandle": received["m"][1]["ReceiptHandle"]},
|
||||
{"Id": "2", "ReceiptHandle": received["m"][2]["ReceiptHandle"]},
|
||||
],
|
||||
)
|
||||
assert len(resp["Successful"]) == 2
|
||||
|
||||
def tag_queue():
|
||||
sqs.tag_queue(QueueUrl=url["u"], Tags={"env": "sdk", "owner": "test"})
|
||||
tags = sqs.list_queue_tags(QueueUrl=url["u"]).get("Tags", {})
|
||||
assert tags.get("env") == "sdk"
|
||||
sqs.untag_queue(QueueUrl=url["u"], TagKeys=["env", "owner"])
|
||||
|
||||
def purge_queue():
|
||||
sqs.purge_queue(QueueUrl=url["u"])
|
||||
|
||||
def delete_queue():
|
||||
sqs.delete_queue(QueueUrl=url["u"])
|
||||
|
||||
def fifo_cycle():
|
||||
furl = sqs.create_queue(QueueName=qf, Attributes={"FifoQueue": "true"})["QueueUrl"]
|
||||
try:
|
||||
sqs.send_message(
|
||||
QueueUrl=furl, MessageBody="sdk-fifo",
|
||||
MessageGroupId="g1", MessageDeduplicationId="d1",
|
||||
)
|
||||
msgs = sqs.receive_message(QueueUrl=furl, MaxNumberOfMessages=1).get("Messages", [])
|
||||
assert msgs and msgs[0]["Body"] == "sdk-fifo"
|
||||
sqs.delete_message(QueueUrl=furl, ReceiptHandle=msgs[0]["ReceiptHandle"])
|
||||
finally:
|
||||
sqs.delete_queue(QueueUrl=furl)
|
||||
|
||||
print("== Стандартная очередь ==")
|
||||
step("list_queues", list_queues)
|
||||
step("create_queue", create_queue)
|
||||
step("get_queue_url", get_queue_url)
|
||||
step("get_queue_attributes", get_queue_attributes)
|
||||
step("set_queue_attributes", set_queue_attributes)
|
||||
step("send_message", send_message)
|
||||
step("send_message_batch", send_message_batch)
|
||||
step("receive_message (3)", receive_messages)
|
||||
step("change_message_visibility", change_visibility)
|
||||
step("delete_message", delete_message)
|
||||
step("delete_message_batch", delete_message_batch)
|
||||
step("tag/list/untag", tag_queue)
|
||||
step("purge_queue", purge_queue)
|
||||
step("delete_queue", delete_queue)
|
||||
|
||||
print("== FIFO-очередь ==")
|
||||
step("fifo: create/send/receive/delete", fifo_cycle)
|
||||
|
||||
print(f"\nИтог: PASS={PASS} FAIL={FAIL}")
|
||||
return 1 if FAIL else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user