Skip to content

Commit 69d4d34

Browse files
authored
SNS: fix Subscribe idempotency due to RawMessageDelivery casing (#12420)
1 parent 8ef146e commit 69d4d34

File tree

4 files changed

+19
-18
lines changed

4 files changed

+19
-18
lines changed

localstack-core/localstack/services/sns/provider.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import base64
2+
import copy
23
import functools
34
import json
45
import logging
@@ -696,26 +697,29 @@ def subscribe(
696697
"Invalid parameter: Invalid parameter: Endpoint Reason: FIFO SQS Queues can not be subscribed to standard SNS topics"
697698
)
698699

699-
if attributes:
700-
for attr_name, attr_value in attributes.items():
700+
sub_attributes = copy.deepcopy(attributes) if attributes else None
701+
if sub_attributes:
702+
for attr_name, attr_value in sub_attributes.items():
701703
validate_subscription_attribute(
702704
attribute_name=attr_name,
703705
attribute_value=attr_value,
704706
topic_arn=topic_arn,
705707
endpoint=endpoint,
706708
is_subscribe_call=True,
707709
)
710+
if raw_msg_delivery := sub_attributes.get("RawMessageDelivery"):
711+
sub_attributes["RawMessageDelivery"] = raw_msg_delivery.lower()
708712

709713
# An endpoint may only be subscribed to a topic once. Subsequent
710714
# subscribe calls do nothing (subscribe is idempotent), except if its attributes are different.
711715
for existing_topic_subscription in store.topic_subscriptions.get(topic_arn, []):
712716
sub = store.subscriptions.get(existing_topic_subscription, {})
713717
if sub.get("Endpoint") == endpoint:
714-
if attributes:
718+
if sub_attributes:
715719
# validate the subscription attributes aren't different
716720
for attr in sns_constants.VALID_SUBSCRIPTION_ATTR_NAME:
717721
# if a new attribute is present and different from an existent one, raise
718-
if (new_attr := attributes.get(attr)) and sub.get(attr) != new_attr:
722+
if (new_attr := sub_attributes.get(attr)) and sub.get(attr) != new_attr:
719723
raise InvalidParameterException(
720724
"Invalid parameter: Attributes Reason: Subscription already exists with different attributes"
721725
)
@@ -738,25 +742,22 @@ def subscribe(
738742
FilterPolicyScope="MessageAttributes", # default value, will be overridden if set
739743
SubscriptionPrincipal=principal, # dummy value, could be fetched with a call to STS?
740744
)
741-
if attributes:
742-
subscription.update(attributes)
743-
if "FilterPolicy" in attributes:
745+
if sub_attributes:
746+
subscription.update(sub_attributes)
747+
if "FilterPolicy" in sub_attributes:
744748
filter_policy = (
745-
json.loads(attributes["FilterPolicy"]) if attributes["FilterPolicy"] else None
749+
json.loads(sub_attributes["FilterPolicy"])
750+
if sub_attributes["FilterPolicy"]
751+
else None
746752
)
747753
if filter_policy:
748754
validator = FilterPolicyValidator(
749-
scope=attributes.get("FilterPolicyScope", "MessageAttributes"),
755+
scope=subscription.get("FilterPolicyScope", "MessageAttributes"),
750756
is_subscribe_call=True,
751757
)
752758
validator.validate_filter_policy(filter_policy)
753759

754-
store.subscription_filter_policy[subscription_arn] = (
755-
json.loads(attributes["FilterPolicy"]) if attributes["FilterPolicy"] else None
756-
)
757-
758-
if raw_msg_delivery := attributes.get("RawMessageDelivery"):
759-
subscription["RawMessageDelivery"] = raw_msg_delivery.lower()
760+
store.subscription_filter_policy[subscription_arn] = filter_policy
760761

761762
store.subscriptions[subscription_arn] = subscription
762763

tests/aws/services/sns/test_sns.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1045,7 +1045,7 @@ def subscribe_queue_to_topic(attributes: dict = None) -> dict:
10451045

10461046
subscribe_resp = subscribe_queue_to_topic(
10471047
{
1048-
"RawMessageDelivery": "true",
1048+
"RawMessageDelivery": "True",
10491049
}
10501050
)
10511051
snapshot.match("subscribe", subscribe_resp)

tests/aws/services/sns/test_sns.snapshot.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3721,7 +3721,7 @@
37213721
}
37223722
},
37233723
"tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_subscribe_idempotency": {
3724-
"recorded-date": "15-09-2023, 17:29:11",
3724+
"recorded-date": "20-03-2025, 17:16:39",
37253725
"recorded-content": {
37263726
"subscribe": {
37273727
"SubscriptionArn": "arn:<partition>:sns:<region>:111111111111:<resource:4>:<resource:1>",

tests/aws/services/sns/test_sns.validation.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
"last_validated_date": "2023-08-24T21:27:58+00:00"
7070
},
7171
"tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_subscribe_idempotency": {
72-
"last_validated_date": "2023-09-15T15:29:11+00:00"
72+
"last_validated_date": "2025-03-20T17:16:39+00:00"
7373
},
7474
"tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_subscribe_with_invalid_protocol": {
7575
"last_validated_date": "2023-08-24T21:27:50+00:00"

0 commit comments

Comments
 (0)