Skip to content

Commit 41a5ebb

Browse files
author
Miguel Gagliardo
authored
fix adding tags to SQS queues when value is an empty string (localstack#4365)
1 parent 59af78d commit 41a5ebb

File tree

2 files changed

+66
-21
lines changed

2 files changed

+66
-21
lines changed

localstack/services/sqs/sqs_listener.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ def forward_request(self, method, path, data, headers):
290290
)
291291

292292
elif action == "SetQueueAttributes":
293-
# TODO remove this function if we stop using ElasticMQ entirely
293+
# TODO remove this function if we stop using ElasticMQ
294294
queue_url = _queue_url(path, req_data, headers)
295295
if SQS_BACKEND_IMPL == "elasticmq":
296296
forward_attrs = _set_queue_attributes(queue_url, req_data)
@@ -300,7 +300,11 @@ def forward_request(self, method, path, data, headers):
300300
method, path, headers, req_data, forward_attrs
301301
)
302302

303+
elif action == "TagQueue":
304+
req_data = self.fix_missing_tag_values(req_data)
305+
303306
elif action == "CreateQueue":
307+
req_data = self.fix_missing_tag_values(req_data)
304308
changed_attrs = _fix_dlq_arn_in_attributes(req_data)
305309
if changed_attrs:
306310
return _get_attributes_forward_request(
@@ -457,6 +461,21 @@ def get_message_attributes_md5(cls, req_data):
457461

458462
return message_attr_hash
459463

464+
# Fixes tags with empty strings as value
465+
def fix_missing_tag_values(self, req_data):
466+
keys_matched = []
467+
for k, v in req_data.items():
468+
match = re.match(r"^Tag\.(\d+)\.Key", k)
469+
if match:
470+
index = match.group(1)
471+
tag_val = "Tag.{}.Value".format(index)
472+
if tag_val not in req_data.keys():
473+
keys_matched.append(tag_val)
474+
if keys_matched:
475+
for tag_val in keys_matched:
476+
req_data[tag_val] = ""
477+
return req_data
478+
460479

461480
# instantiate listener
462481
UPDATE_SQS = ProxyListenerSQS()

tests/integration/test_sqs.py

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import datetime
22
import json
33
import os
4+
import random
45
import time
56
import unittest
67

@@ -58,6 +59,7 @@
5859

5960
THIS_FOLDER = os.path.dirname(os.path.realpath(__file__))
6061
TEST_LAMBDA_ECHO_FILE = os.path.join(THIS_FOLDER, "lambdas", "lambda_echo.py")
62+
TEST_LAMBDA_TAGS = {"tag1": "value1", "tag2": "value2", "tag3": ""}
6163

6264
TEST_MESSAGE_ATTRIBUTES = {
6365
"City": {
@@ -461,7 +463,8 @@ def test_get_specific_queue_attribute_response(self):
461463
AttributeNames=["MessageRetentionPeriod", "RedrivePolicy"],
462464
)
463465
supported_attribute_get = self.client.get_queue_attributes(
464-
QueueUrl=queue_url, AttributeNames=["QueueArn"]
466+
QueueUrl=queue_url,
467+
AttributeNames=["QueueArn"],
465468
)
466469
# assertion
467470
self.assertTrue("MessageRetentionPeriod" in unsupported_attribute_get["Attributes"].keys())
@@ -895,31 +898,25 @@ def test_fifo_queue_send_multiple_messages_multiple_single_receives(self):
895898
# clean up
896899
self.client.delete_queue(QueueUrl=queue_url)
897900

901+
# Not the same to create a queue with tags than tagging an existing queue
902+
def test_create_queue_with_tags(self):
903+
queue_name = "queue-{}".format(short_uid())
904+
response = self.client.create_queue(
905+
QueueName=queue_name,
906+
tags=TEST_LAMBDA_TAGS,
907+
)
908+
self.assertEqual(200, response["ResponseMetadata"]["HTTPStatusCode"])
909+
self.check_tagged_queue(response["QueueUrl"])
910+
898911
def test_tag_untag_queue(self):
899912
queue_name = "queue-{}".format(short_uid())
900913
queue_url = self.client.create_queue(QueueName=queue_name)["QueueUrl"]
901-
902914
response = self.client.tag_queue(
903-
QueueUrl=queue_url, Tags={"tag1": "value1", "tag2": "value2"}
915+
QueueUrl=queue_url,
916+
Tags=TEST_LAMBDA_TAGS,
904917
)
905918
self.assertEqual(200, response["ResponseMetadata"]["HTTPStatusCode"])
906-
907-
response = self.client.list_queue_tags(QueueUrl=queue_url)
908-
self.assertEqual(200, response["ResponseMetadata"]["HTTPStatusCode"])
909-
self.assertIn("tag1", response["Tags"])
910-
self.assertIn("tag2", response["Tags"])
911-
912-
response = self.client.untag_queue(QueueUrl=queue_url, TagKeys=["tag2"])
913-
self.assertEqual(200, response["ResponseMetadata"]["HTTPStatusCode"])
914-
915-
response = self.client.list_queue_tags(QueueUrl=queue_url)
916-
self.assertIn("tag1", response["Tags"])
917-
self.assertNotIn("tag2", response["Tags"])
918-
self.assertEqual(200, response["ResponseMetadata"]["HTTPStatusCode"])
919-
920-
# clean up
921-
self.client.untag_queue(QueueUrl=queue_url, TagKeys=["tag1"])
922-
self.client.delete_queue(QueueUrl=queue_url)
919+
self.check_tagged_queue(queue_url)
923920

924921
def test_posting_to_queue_with_trailing_slash(self):
925922
queue_name = "queue-{}".format(short_uid())
@@ -1029,3 +1026,32 @@ def receive_dlq(self, queue_url, assert_error_details=False, assert_receive_coun
10291026
# probably in or around this commit:
10301027
# https://github.com/spulec/moto/commit/6da4905da940e25e317db60b7657ea632f58ef1d
10311028
# self.assertEqual(str(assert_receive_count), msg_attrs.get('ApproximateReceiveCount'))
1029+
1030+
def check_tagged_queue(self, queue_url):
1031+
response = self.client.list_queue_tags(QueueUrl=queue_url)
1032+
self.assertEqual(200, response["ResponseMetadata"]["HTTPStatusCode"])
1033+
tags_keys_as_list = list(TEST_LAMBDA_TAGS.keys())
1034+
1035+
for key in tags_keys_as_list:
1036+
self.assertIn(key, response["Tags"])
1037+
1038+
random_tag_key = random.choice(tags_keys_as_list)
1039+
# Pop random chosen tag key from list
1040+
tags_keys_as_list.pop(tags_keys_as_list.index(random_tag_key))
1041+
1042+
response = self.client.untag_queue(QueueUrl=queue_url, TagKeys=[random_tag_key])
1043+
self.assertEqual(200, response["ResponseMetadata"]["HTTPStatusCode"])
1044+
1045+
response = self.client.list_queue_tags(QueueUrl=queue_url)
1046+
self.assertEqual(200, response["ResponseMetadata"]["HTTPStatusCode"])
1047+
self.assertNotIn(random_tag_key, response["Tags"])
1048+
1049+
for key in tags_keys_as_list:
1050+
self.assertIn(key, response["Tags"])
1051+
1052+
# Clean up
1053+
self.client.untag_queue(
1054+
QueueUrl=queue_url,
1055+
TagKeys=tags_keys_as_list,
1056+
)
1057+
self.client.delete_queue(QueueUrl=queue_url)

0 commit comments

Comments
 (0)