From 2d47e8642571e596a07ff540a3c2e15500f65453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Sat, 15 Aug 2026 09:25:32 +0400 Subject: [PATCH] =?UTF-8?q?HISTORY:=20=D0=BF=D0=BE=D0=BB=D0=BD=D0=B0=D1=8F?= =?UTF-8?q?=20=D1=80=D0=B5=D0=B3=D1=80=D0=B5=D1=81=D1=81=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=92=D0=9C=20=E2=80=94=20api=5Ftest=2022/22,?= =?UTF-8?q?=20sdk=5Ftest=2015/15;=20=D1=84=D0=BB=D0=B0=D0=BF=20fifo=5Fdlq?= =?UTF-8?q?=5Fprobe=20=D1=80=D0=B0=D0=B7=D0=BE=D0=B1=D1=80=D0=B0=D0=BD=20(?= =?UTF-8?q?=D0=B3=D0=BE=D0=BD=D0=BA=D0=B0=20=D1=82=D0=B5=D1=81=D1=82=D0=B0?= =?UTF-8?q?,=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81=205/5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/dlq_deterministic_probe.py | 72 ++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 tests/dlq_deterministic_probe.py diff --git a/tests/dlq_deterministic_probe.py b/tests/dlq_deterministic_probe.py new file mode 100644 index 0000000..9e0e080 --- /dev/null +++ b/tests/dlq_deterministic_probe.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +"""Детерминированная проверка DLQ-переноса (без гонок тайминга): +после каждой доставки ждём истечения visibility + тик PeriodicTasks (2.5с). +Если 5/5 PASS — сервис корректен, флап fifo_dlq_probe — гонка теста.""" +import json +import time +import uuid + +import boto3 +from botocore.config import Config + +ENDPOINT = "https://sqs.containerk8s.dev.nubes.ru" +REGION = "us-east-1" +sqs = boto3.client("sqs", endpoint_url=ENDPOINT, region_name=REGION, + config=Config(connect_timeout=10, read_timeout=30, retries={"max_attempts": 0})) + + +def drain(url, n=10): + msgs = [] + while True: + b = sqs.receive_message(QueueUrl=url, MaxNumberOfMessages=n).get("Messages", []) + if not b: + break + msgs.extend(b) + return msgs + + +def run(i): + uid = str(uuid.uuid4())[:8] + dlq_name = "dlqdet-%s-%d" % (uid, i) + main_name = "maindet-%s-%d" % (uid, i) + dlq_url = sqs.create_queue(QueueName=dlq_name)["QueueUrl"] + tenant = dlq_url.split("/")[-2] + arn = "arn:aws:sqs:%s:%s:%s" % (REGION, tenant, dlq_name) + policy = json.dumps({"deadLetterTargetArn": arn, "maxReceiveCount": "2"}) + main_url = sqs.create_queue( + QueueName=main_name, + Attributes={"VisibilityTimeout": "1", "RedrivePolicy": policy}, + )["QueueUrl"] + sqs.send_message(QueueUrl=main_url, MessageBody="to-dlq") + + r1 = sqs.receive_message(QueueUrl=main_url, MaxNumberOfMessages=1).get("Messages", []) + time.sleep(2.5) # visibility истёк + тик вернул (Retry=1) + r2 = sqs.receive_message(QueueUrl=main_url, MaxNumberOfMessages=1).get("Messages", []) + time.sleep(2.5) # visibility истёк + тик: Retry=2 >= maxReceiveCount=2 -> DLQ + r3 = sqs.receive_message(QueueUrl=main_url, MaxNumberOfMessages=1).get("Messages", []) + time.sleep(2.0) + dlq_msgs = drain(dlq_url) + main_left = drain(main_url) + + ok = (len(r1) == 1 and len(r2) == 1 and len(r3) == 0 + and len(dlq_msgs) == 1 and dlq_msgs[0]["Body"] == "to-dlq" + and len(main_left) == 0) + print("run %d: r1=%d r2=%d r3=%d dlq=%d main_left=%d -> %s" + % (i, len(r1), len(r2), len(r3), len(dlq_msgs), len(main_left), + "PASS" if ok else "FAIL"), flush=True) + try: + sqs.delete_queue(QueueUrl=main_url) + sqs.delete_queue(QueueUrl=dlq_url) + except Exception: + pass + return ok + + +ok = 0 +for i in range(1, 6): + try: + if run(i): + ok += 1 + except Exception as e: + print("run %d: EXC %s %s" % (i, type(e).__name__, str(e)[:120]), flush=True) +print("TOTAL: %d/5 PASS" % ok, flush=True)