From 8d527743d5010feb70adcfe1f5b6c7d50bfa66e5 Mon Sep 17 00:00:00 2001 From: gruebel Date: Fri, 11 Oct 2019 17:58:48 +0200 Subject: [PATCH] Add sns.list_tags_for_resource --- IMPLEMENTATION_COVERAGE.md | 4 ++-- moto/sns/models.py | 9 +++++++- moto/sns/responses.py | 35 ++++++++++++++++++++++++++++- tests/test_sns/test_topics_boto3.py | 31 +++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 4 deletions(-) diff --git a/IMPLEMENTATION_COVERAGE.md b/IMPLEMENTATION_COVERAGE.md index 764df13d1..62565a067 100644 --- a/IMPLEMENTATION_COVERAGE.md +++ b/IMPLEMENTATION_COVERAGE.md @@ -5866,7 +5866,7 @@ - [ ] update_job ## sns -48% implemented +52% implemented - [ ] add_permission - [ ] check_if_phone_number_is_opted_out - [ ] confirm_subscription @@ -5886,7 +5886,7 @@ - [X] list_platform_applications - [X] list_subscriptions - [ ] list_subscriptions_by_topic -- [ ] list_tags_for_resource +- [x] list_tags_for_resource - [X] list_topics - [ ] opt_in_phone_number - [X] publish diff --git a/moto/sns/models.py b/moto/sns/models.py index 92e6c61de..d7f15338b 100644 --- a/moto/sns/models.py +++ b/moto/sns/models.py @@ -44,6 +44,8 @@ class Topic(BaseModel): self.subscriptions_confimed = 0 self.subscriptions_deleted = 0 + self._tags = {} + def publish(self, message, subject=None, message_attributes=None): message_id = six.text_type(uuid.uuid4()) subscriptions, _ = self.sns_backend.list_subscriptions(self.arn) @@ -277,7 +279,7 @@ class SNSBackend(BaseBackend): def update_sms_attributes(self, attrs): self.sms_attributes.update(attrs) - def create_topic(self, name, attributes=None): + def create_topic(self, name, attributes=None, tags=None): fails_constraints = not re.match(r'^[a-zA-Z0-9_-]{1,256}$', name) if fails_constraints: raise InvalidParameterValue("Topic names must be made up of only uppercase and lowercase ASCII letters, numbers, underscores, and hyphens, and must be between 1 and 256 characters long.") @@ -285,6 +287,8 @@ class SNSBackend(BaseBackend): if attributes: for attribute in attributes: setattr(candidate_topic, camelcase_to_underscores(attribute), attributes[attribute]) + if tags: + candidate_topic._tags = tags if candidate_topic.arn in self.topics: return self.topics[candidate_topic.arn] else: @@ -499,6 +503,9 @@ class SNSBackend(BaseBackend): raise SNSInvalidParameter("Invalid parameter: FilterPolicy: Match value must be String, number, true, false, or null") + def list_tags_for_resource(self, resource_arn): + return self.topics[resource_arn]._tags + sns_backends = {} for region in Session().get_available_regions('sns'): diff --git a/moto/sns/responses.py b/moto/sns/responses.py index 578c5ea65..7cc085be1 100644 --- a/moto/sns/responses.py +++ b/moto/sns/responses.py @@ -30,6 +30,10 @@ class SNSResponse(BaseResponse): in attributes ) + def _get_tags(self): + tags = self._get_list_prefix('Tags.member') + return {tag['key']: tag['value'] for tag in tags} + def _parse_message_attributes(self, prefix='', value_namespace='Value.'): message_attributes = self._get_object_map( 'MessageAttributes.entry', @@ -85,7 +89,8 @@ class SNSResponse(BaseResponse): def create_topic(self): name = self._get_param('Name') attributes = self._get_attributes() - topic = self.backend.create_topic(name, attributes) + tags = self._get_tags() + topic = self.backend.create_topic(name, attributes, tags) if self.request_json: return json.dumps({ @@ -691,6 +696,18 @@ class SNSResponse(BaseResponse): template = self.response_template(CONFIRM_SUBSCRIPTION_TEMPLATE) return template.render(sub_arn='{0}:68762e72-e9b1-410a-8b3b-903da69ee1d5'.format(arn)) + def list_tags_for_resource(self): + arn = self._get_param('ResourceArn') + + if arn not in self.backend.topics: + error_response = self._error('ResourceNotFound', 'Resource does not exist') + return error_response, dict(status=404) + + result = self.backend.list_tags_for_resource(arn) + + template = self.response_template(LIST_TAGS_FOR_RESOURCE_TEMPLATE) + return template.render(tags=result) + CREATE_TOPIC_TEMPLATE = """ @@ -1072,3 +1089,19 @@ CONFIRM_SUBSCRIPTION_TEMPLATE = """ + + + {% for name, value in tags.items() %} + + {{ name }} + {{ value }} + + {% endfor %} + + + + 97fa763f-861b-5223-a946-20251f2a42e2 + +""" diff --git a/tests/test_sns/test_topics_boto3.py b/tests/test_sns/test_topics_boto3.py index 870fa6f6e..4a994e724 100644 --- a/tests/test_sns/test_topics_boto3.py +++ b/tests/test_sns/test_topics_boto3.py @@ -44,6 +44,37 @@ def test_create_topic_with_attributes(): attributes['DisplayName'].should.equal('test-topic') +@mock_sns +def test_create_topic_with_tags(): + conn = boto3.client("sns", region_name="us-east-1") + conn.create_topic( + Name='some-topic-with-attribute', + Tags=[ + { + 'Key': 'tag_key_1', + 'Value': 'tag_value_1' + }, + { + 'Key': 'tag_key_2', + 'Value': 'tag_value_2' + } + ] + ) + topics_json = conn.list_topics() + topic_arn = topics_json["Topics"][0]['TopicArn'] + + conn.list_tags_for_resource(ResourceArn=topic_arn)['Tags'].should.equal([ + { + 'Key': 'tag_key_1', + 'Value': 'tag_value_1' + }, + { + 'Key': 'tag_key_2', + 'Value': 'tag_value_2' + } + ]) + + @mock_sns def test_create_topic_should_be_indempodent(): conn = boto3.client("sns", region_name="us-east-1")