From 00be464c05d736b8f69905bd0974591ffa9867e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Charvet=20=E9=BB=91=E7=93=9C?= Date: Wed, 7 Jul 2021 08:59:16 +0100 Subject: [PATCH] Fix #3996 (#4051) * Fix #3996 * Don't delete any message when duplicate handles --- moto/sqs/responses.py | 23 +++++++++++++++++++---- tests/test_sqs/test_sqs.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/moto/sqs/responses.py b/moto/sqs/responses.py index 591c8a2e6..8c68df147 100644 --- a/moto/sqs/responses.py +++ b/moto/sqs/responses.py @@ -17,6 +17,7 @@ from .exceptions import ( InvalidAttributeName, MessageNotInflight, ReceiptHandleIsInvalid, + BatchEntryIdsNotDistinct, ) from .models import sqs_backends from .utils import parse_message_attributes, extract_input_message_attributes @@ -330,7 +331,8 @@ class SQSResponse(BaseResponse): """ queue_name = self._get_queue_name() - message_ids = [] + receipts = [] + for index in range(1, 11): # Loop through looking for messages receipt_key = "DeleteMessageBatchRequestEntry.{0}.ReceiptHandle".format( @@ -341,12 +343,25 @@ class SQSResponse(BaseResponse): # Found all messages break - self.sqs_backend.delete_message(queue_name, receipt_handle[0]) - message_user_id_key = "DeleteMessageBatchRequestEntry.{0}.Id".format(index) message_user_id = self.querystring.get(message_user_id_key)[0] - message_ids.append(message_user_id) + receipts.append( + {"receipt_handle": receipt_handle[0], "msg_user_id": message_user_id} + ) + receipt_seen = set() + for receipt_and_id in receipts: + receipt = receipt_and_id["receipt_handle"] + if receipt in receipt_seen: + raise BatchEntryIdsNotDistinct(receipt_and_id["msg_user_id"]) + receipt_seen.add(receipt) + + for receipt_and_id in receipts: + self.sqs_backend.delete_message( + queue_name, receipt_and_id["receipt_handle"] + ) + + message_ids = [r["msg_user_id"] for r in receipts] template = self.response_template(DELETE_MESSAGE_BATCH_RESPONSE) return template.render(message_ids=message_ids) diff --git a/tests/test_sqs/test_sqs.py b/tests/test_sqs/test_sqs.py index 41de7e7c3..f92bfa6bb 100644 --- a/tests/test_sqs/test_sqs.py +++ b/tests/test_sqs/test_sqs.py @@ -1714,6 +1714,34 @@ def test_send_message_batch(): ) +@mock_sqs +def test_delete_message_batch_with_duplicates(): + client = boto3.client("sqs", region_name="us-east-1") + response = client.create_queue(QueueName="test-queue") + queue_url = response["QueueUrl"] + client.send_message(QueueUrl=queue_url, MessageBody="coucou") + + messages = client.receive_message( + QueueUrl=queue_url, WaitTimeSeconds=0, VisibilityTimeout=0 + )["Messages"] + assert messages, "at least one msg" + entries = [ + {"Id": msg["MessageId"], "ReceiptHandle": msg["ReceiptHandle"]} + for msg in [messages[0], messages[0]] + ] + + with pytest.raises(ClientError) as e: + client.delete_message_batch(QueueUrl=queue_url, Entries=entries) + ex = e.value + assert ex.response["Error"]["Code"] == "BatchEntryIdsNotDistinct" + + # no messages are deleted + messages = client.receive_message(QueueUrl=queue_url, WaitTimeSeconds=0).get( + "Messages", [] + ) + assert messages, "message still in the queue" + + @mock_sqs def test_message_attributes_in_receive_message(): sqs = boto3.resource("sqs", region_name="us-east-1")