From 9cde807dda441b27454be35fe64378dee24d006c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Fri, 14 Aug 2026 17:45:37 +0400 Subject: [PATCH] =?UTF-8?q?tests:=20=D1=84=D0=B8=D0=BA=D1=81=20invalid=5Fc?= =?UTF-8?q?ases=20(=D0=BE=D1=87=D0=B5=D1=80=D0=B5=D0=B4=D0=B8=20=D1=83?= =?UTF-8?q?=D0=B4=D0=B0=D0=BB=D1=8F=D1=8E=D1=82=D1=81=D1=8F=20=D0=BF=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B5=20=D1=81=D1=86=D0=B5=D0=BD=D0=B0=D1=80=D0=B8?= =?UTF-8?q?=D0=B5=D0=B2)=20+=20=D0=BF=D0=BE=D0=BB=D0=BD=D1=8B=D0=B5=20AWS-?= =?UTF-8?q?=D0=BA=D0=BE=D0=B4=D1=8B=20=D0=B2=20EXPECTED=5FCODES=20+=20inva?= =?UTF-8?q?lid=5Fprobe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/invalid_probe.py | 70 ++++++++++++++++++++++++++++++++++++++++++ tests/load_test.py | 64 +++++++++++++++++++++++++------------- 2 files changed, 113 insertions(+), 21 deletions(-) create mode 100644 tests/invalid_probe.py diff --git a/tests/invalid_probe.py b/tests/invalid_probe.py new file mode 100644 index 0000000..fd81d0c --- /dev/null +++ b/tests/invalid_probe.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +"""Временный замер: точная копия invalid_cases из load_test.py + подсчёт кодов. +Цель: выяснить фактическое распределение кодов в самом тесте.""" +import boto3 +import collections +import random + +from botocore.config import Config +from botocore.exceptions import ClientError + +ENDPOINT = "https://sqs.containerk8s.dev.nubes.ru" + +sqs = boto3.client( + "sqs", + endpoint_url=ENDPOINT, + region_name="us-east-1", + config=Config(connect_timeout=10, read_timeout=25, retries={"max_attempts": 2}), +) + +res = collections.Counter() + + +def invalid_cases(): + cases = [] + cases.append(lambda: sqs.send_message(QueueUrl=ENDPOINT + "/no-such-queue", MessageBody="x")) + cases.append(lambda: sqs.receive_message(QueueUrl=ENDPOINT + "/no-such-queue")) + cases.append(lambda: sqs.delete_queue(QueueUrl=ENDPOINT + "/no-such-queue")) + cases.append(lambda: sqs.get_queue_url(QueueName="no-such-queue-load-test")) + cases.append(lambda: sqs.delete_message(QueueUrl=ENDPOINT + "/no-such-queue", ReceiptHandle="broken")) + q = sqs.create_queue(QueueName="invalid-%d" % random.randint(0, 10**9))["QueueUrl"] + try: + cases.append(lambda: sqs.set_queue_attributes(QueueUrl=q, Attributes={"VisibilityTimeout": "43201"})) + cases.append(lambda: sqs.set_queue_attributes(QueueUrl=q, Attributes={"VisibilityTimeout": "not-a-number"})) + cases.append(lambda: sqs.set_queue_attributes(QueueUrl=q, Attributes={"BadAttribute": "1"})) + + def purge_twice(): + sqs.purge_queue(QueueUrl=q) + sqs.purge_queue(QueueUrl=q) + + cases.append(purge_twice) + cases.append(lambda: sqs.send_message_batch(QueueUrl=q, Entries=[{"Id": str(i), "MessageBody": "x"} for i in range(11)])) + cases.append(lambda: sqs.send_message_batch(QueueUrl=q, Entries=[{"Id": "dup", "MessageBody": "a"}, {"Id": "dup", "MessageBody": "b"}])) + cases.append(lambda: sqs.send_message_batch(QueueUrl=q, Entries=[])) + cases.append(lambda: sqs.send_message(QueueUrl=q, MessageBody="")) + cases.append(lambda: sqs.send_message(QueueUrl=q, MessageBody="x" * (300 * 1024))) + fq = sqs.create_queue(QueueName="invalid-%d.fifo" % random.randint(0, 10**9), Attributes={"FifoQueue": "true"})["QueueUrl"] + try: + cases.append(lambda: sqs.send_message(QueueUrl=fq, MessageBody="x", MessageDeduplicationId="d")) + finally: + sqs.delete_queue(QueueUrl=fq) + finally: + sqs.delete_queue(QueueUrl=q) + + for c in cases: + try: + c() + res["PASS-не отклонено"] += 1 + except ClientError as e: + res[e.response.get("Error", {}).get("Code", "Unknown")] += 1 + except Exception as e: + res[type(e).__name__] += 1 + + +N = 100 +for _ in range(N): + invalid_cases() + +print("cycles=%d" % N) +for k, v in sorted(res.items(), key=lambda x: -x[1]): + print("%s: %d" % (k, v)) diff --git a/tests/load_test.py b/tests/load_test.py index ab02a61..abb7537 100644 --- a/tests/load_test.py +++ b/tests/load_test.py @@ -58,6 +58,14 @@ EXPECTED_CODES = { "MessageTooLong", "InvalidMessageContents", "AWS.SimpleQueueService.NonExistentQueue", + "AWS.SimpleQueueService.InvalidParameterValue", + "AWS.SimpleQueueService.InvalidAttributeName", + "AWS.SimpleQueueService.InvalidAttributeValue", + "AWS.SimpleQueueService.PurgeQueueInProgress", + "AWS.SimpleQueueService.TooManyEntriesInBatchRequest", + "AWS.SimpleQueueService.BatchEntryIdsNotDistinct", + "AWS.SimpleQueueService.EmptyBatchRequest", + "AWS.SimpleQueueService.InvalidBatchEntryId", } stats = { @@ -208,9 +216,16 @@ def invalid_cases(sqs): cases.append(lambda: sqs.get_queue_url(QueueName="no-such-queue-load-test")) # битый ReceiptHandle cases.append(lambda: sqs.delete_message(QueueUrl=ENDPOINT + "/no-such-queue", ReceiptHandle="broken")) - # некорректные атрибуты - q = sqs.create_queue(QueueName=f"invalid-{random.randint(0, 10**9)}")["QueueUrl"] + + # ФИКС: раньше delete_queue стоял в finally и выполнялся ДО прогона сценариев — + # сценарии атрибутов/batch/purge/300KB/FIFO тестировали УДАЛЁННУЮ очередь + # (NonExistentQueue) вместо заявленных нарушений. Теперь очереди создаются + # до прогона и удаляются ПОСЛЕ него. + q = None + fq = None try: + # некорректные атрибуты + q = sqs.create_queue(QueueName=f"invalid-{random.randint(0, 10**9)}")["QueueUrl"] cases.append(lambda: sqs.set_queue_attributes(QueueUrl=q, Attributes={"VisibilityTimeout": "43201"})) cases.append(lambda: sqs.set_queue_attributes(QueueUrl=q, Attributes={"VisibilityTimeout": "not-a-number"})) cases.append(lambda: sqs.set_queue_attributes(QueueUrl=q, Attributes={"BadAttribute": "1"})) @@ -229,27 +244,34 @@ def invalid_cases(sqs): cases.append(lambda: sqs.send_message(QueueUrl=q, MessageBody="x" * (300 * 1024))) # FIFO без MessageGroupId fq = sqs.create_queue(QueueName=f"invalid-{random.randint(0, 10**9)}.fifo", Attributes={"FifoQueue": "true"})["QueueUrl"] - try: - cases.append(lambda: sqs.send_message(QueueUrl=fq, MessageBody="x", MessageDeduplicationId="d")) - finally: - sqs.delete_queue(QueueUrl=fq) - finally: - sqs.delete_queue(QueueUrl=q) + cases.append(lambda: sqs.send_message(QueueUrl=fq, MessageBody="x", MessageDeduplicationId="d")) - for c in cases: - t0 = time.time() - try: - c() - bump("soft_warn") - except ClientError as e: - add_latency(time.time() - t0) - code = e.response.get("Error", {}).get("Code", "Unknown") - if code in EXPECTED_CODES: - record_expected(e) - else: + for c in cases: + t0 = time.time() + try: + c() + bump("soft_warn") + except ClientError as e: + add_latency(time.time() - t0) + code = e.response.get("Error", {}).get("Code", "Unknown") + if code in EXPECTED_CODES: + record_expected(e) + else: + record_unexpected(e) + except Exception as e: record_unexpected(e) - except Exception as e: - record_unexpected(e) + finally: + # Очереди удаляются ПОСЛЕ прогона сценариев. + if fq is not None: + try: + sqs.delete_queue(QueueUrl=fq) + except ClientError: + pass + if q is not None: + try: + sqs.delete_queue(QueueUrl=q) + except ClientError: + pass def worker(wid):