Techdebt: Replace sure with regular assertions in SNS (#6621)

This commit is contained in:
kbalk 2023-08-10 14:07:41 -04:00 committed by GitHub
parent 38bd1af4d3
commit e9f5a64f0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 819 additions and 838 deletions

View File

@ -1,10 +1,10 @@
import boto3
from botocore.exceptions import ClientError
from moto import mock_sns
import sure # noqa # pylint: disable=unused-import
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
import pytest
from moto import mock_sns
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
@mock_sns
def test_create_platform_application():
@ -18,7 +18,7 @@ def test_create_platform_application():
},
)
application_arn = response["PlatformApplicationArn"]
application_arn.should.equal(
assert application_arn == (
f"arn:aws:sns:us-east-1:{ACCOUNT_ID}:app/APNS/my-application"
)
@ -38,20 +38,17 @@ def test_get_platform_application_attributes():
attributes = conn.get_platform_application_attributes(PlatformApplicationArn=arn)[
"Attributes"
]
attributes.should.equal(
{
"PlatformCredential": "platform_credential",
"PlatformPrincipal": "platform_principal",
}
)
assert attributes == {
"PlatformCredential": "platform_credential",
"PlatformPrincipal": "platform_principal",
}
@mock_sns
def test_get_missing_platform_application_attributes():
conn = boto3.client("sns", region_name="us-east-1")
conn.get_platform_application_attributes.when.called_with(
PlatformApplicationArn="a-fake-arn"
).should.throw(ClientError)
with pytest.raises(ClientError):
conn.get_platform_application_attributes(PlatformApplicationArn="a-fake-arn")
@mock_sns
@ -72,7 +69,7 @@ def test_set_platform_application_attributes():
attributes = conn.get_platform_application_attributes(PlatformApplicationArn=arn)[
"Attributes"
]
attributes.should.equal(
assert attributes == (
{"PlatformCredential": "platform_credential", "PlatformPrincipal": "other"}
)
@ -89,7 +86,7 @@ def test_list_platform_applications():
applications_response = conn.list_platform_applications()
applications = applications_response["PlatformApplications"]
applications.should.have.length_of(2)
assert len(applications) == 2
@mock_sns
@ -104,14 +101,14 @@ def test_delete_platform_application():
applications_response = conn.list_platform_applications()
applications = applications_response["PlatformApplications"]
applications.should.have.length_of(2)
assert len(applications) == 2
application_arn = applications[0]["PlatformApplicationArn"]
conn.delete_platform_application(PlatformApplicationArn=application_arn)
applications_response = conn.list_platform_applications()
applications = applications_response["PlatformApplications"]
applications.should.have.length_of(1)
assert len(applications) == 1
@mock_sns
@ -130,8 +127,9 @@ def test_create_platform_endpoint():
)
endpoint_arn = endpoint["EndpointArn"]
endpoint_arn.should.contain(
assert (
f"arn:aws:sns:us-east-1:{ACCOUNT_ID}:endpoint/APNS/my-application/"
in endpoint_arn
)
@ -150,12 +148,13 @@ def test_create_duplicate_platform_endpoint():
Attributes={"Enabled": "false"},
)
conn.create_platform_endpoint.when.called_with(
PlatformApplicationArn=application_arn,
Token="some_unique_id",
CustomUserData="some user data",
Attributes={"Enabled": "true"},
).should.throw(ClientError)
with pytest.raises(ClientError):
conn.create_platform_endpoint(
PlatformApplicationArn=application_arn,
Token="some_unique_id",
CustomUserData="some user data",
Attributes={"Enabled": "true"},
)
@mock_sns
@ -182,7 +181,7 @@ def test_create_duplicate_platform_endpoint_with_same_attributes():
)
endpoint_arn = endpoint["EndpointArn"]
endpoint_arn.should.equal(created_endpoint_arn)
assert endpoint_arn == created_endpoint_arn
@mock_sns
@ -205,9 +204,9 @@ def test_get_list_endpoints_by_platform_application():
PlatformApplicationArn=application_arn
)["Endpoints"]
endpoint_list.should.have.length_of(1)
endpoint_list[0]["Attributes"]["CustomUserData"].should.equal("some data")
endpoint_list[0]["EndpointArn"].should.equal(endpoint_arn)
assert len(endpoint_list) == 1
assert endpoint_list[0]["Attributes"]["CustomUserData"] == "some data"
assert endpoint_list[0]["EndpointArn"] == endpoint_arn
@mock_sns
@ -227,7 +226,7 @@ def test_get_endpoint_attributes():
endpoint_arn = endpoint["EndpointArn"]
attributes = conn.get_endpoint_attributes(EndpointArn=endpoint_arn)["Attributes"]
attributes.should.equal(
assert attributes == (
{"Token": "some_unique_id", "Enabled": "false", "CustomUserData": "some data"}
)
@ -235,21 +234,23 @@ def test_get_endpoint_attributes():
@mock_sns
def test_get_non_existent_endpoint_attributes():
conn = boto3.client("sns", region_name="us-east-1")
endpoint_arn = "arn:aws:sns:us-east-1:123456789012:endpoint/APNS/my-application/c1f76c42-192a-4e75-b04f-a9268ce2abf3"
endpoint_arn = (
"arn:aws:sns:us-east-1:123456789012:endpoint/APNS/my-application"
"/c1f76c42-192a-4e75-b04f-a9268ce2abf3"
)
with pytest.raises(conn.exceptions.NotFoundException) as excinfo:
conn.get_endpoint_attributes(EndpointArn=endpoint_arn)
error = excinfo.value.response["Error"]
error["Type"].should.equal("Sender")
error["Code"].should.equal("NotFound")
error["Message"].should.equal("Endpoint does not exist")
assert error["Type"] == "Sender"
assert error["Code"] == "NotFound"
assert error["Message"] == "Endpoint does not exist"
@mock_sns
def test_get_missing_endpoint_attributes():
conn = boto3.client("sns", region_name="us-east-1")
conn.get_endpoint_attributes.when.called_with(
EndpointArn="a-fake-arn"
).should.throw(ClientError)
with pytest.raises(ClientError):
conn.get_endpoint_attributes(EndpointArn="a-fake-arn")
@mock_sns
@ -272,7 +273,7 @@ def test_set_endpoint_attributes():
EndpointArn=endpoint_arn, Attributes={"CustomUserData": "other data"}
)
attributes = conn.get_endpoint_attributes(EndpointArn=endpoint_arn)["Attributes"]
attributes.should.equal(
assert attributes == (
{"Token": "some_unique_id", "Enabled": "false", "CustomUserData": "other data"}
)
@ -291,15 +292,25 @@ def test_delete_endpoint():
Attributes={"Enabled": "true"},
)
conn.list_endpoints_by_platform_application(PlatformApplicationArn=application_arn)[
"Endpoints"
].should.have.length_of(1)
assert (
len(
conn.list_endpoints_by_platform_application(
PlatformApplicationArn=application_arn
)["Endpoints"]
)
== 1
)
conn.delete_endpoint(EndpointArn=endpoint["EndpointArn"])
conn.list_endpoints_by_platform_application(PlatformApplicationArn=application_arn)[
"Endpoints"
].should.have.length_of(0)
assert (
len(
conn.list_endpoints_by_platform_application(
PlatformApplicationArn=application_arn
)["Endpoints"]
)
== 0
)
@mock_sns
@ -341,9 +352,10 @@ def test_publish_to_disabled_platform_endpoint():
endpoint_arn = endpoint["EndpointArn"]
conn.publish.when.called_with(
Message="some message", MessageStructure="json", TargetArn=endpoint_arn
).should.throw(ClientError)
with pytest.raises(ClientError):
conn.publish(
Message="some message", MessageStructure="json", TargetArn=endpoint_arn
)
@mock_sns
@ -355,11 +367,11 @@ def test_set_sms_attributes():
)
response = conn.get_sms_attributes()
response.should.contain("attributes")
response["attributes"].should.contain("DefaultSMSType")
response["attributes"].should.contain("test")
response["attributes"]["DefaultSMSType"].should.equal("Transactional")
response["attributes"]["test"].should.equal("test")
assert "attributes" in response
assert "DefaultSMSType" in response["attributes"]
assert "test" in response["attributes"]
assert response["attributes"]["DefaultSMSType"] == "Transactional"
assert response["attributes"]["test"] == "test"
@mock_sns
@ -371,10 +383,10 @@ def test_get_sms_attributes_filtered():
)
response = conn.get_sms_attributes(attributes=["DefaultSMSType"])
response.should.contain("attributes")
response["attributes"].should.contain("DefaultSMSType")
response["attributes"].should_not.contain("test")
response["attributes"]["DefaultSMSType"].should.equal("Transactional")
assert "attributes" in response
assert "DefaultSMSType" in response["attributes"]
assert "test" not in response["attributes"]
assert response["attributes"]["DefaultSMSType"] == "Transactional"
@mock_sns
@ -395,6 +407,6 @@ def test_delete_endpoints_of_delete_app():
with pytest.raises(conn.exceptions.NotFoundException) as excinfo:
conn.get_endpoint_attributes(EndpointArn=endpoint_arn)
error = excinfo.value.response["Error"]
error["Type"].should.equal("Sender")
error["Code"].should.equal("NotFound")
error["Message"].should.equal("Endpoint does not exist")
assert error["Type"] == "Sender"
assert error["Code"] == "NotFound"
assert error["Message"] == "Endpoint does not exist"

View File

@ -1,9 +1,9 @@
import boto3
import json
import sure # noqa # pylint: disable=unused-import
import boto3
from botocore.exceptions import ClientError
import pytest
from moto import mock_sns, mock_sqs
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
@ -17,8 +17,8 @@ def test_publish_batch_unknown_topic():
PublishBatchRequestEntries=[{"Id": "id_1", "Message": "1"}],
)
err = exc.value.response["Error"]
err["Code"].should.equal("NotFound")
err["Message"].should.equal("Topic does not exist")
assert err["Code"] == "NotFound"
assert err["Message"] == "Topic does not exist"
@mock_sns
@ -34,10 +34,8 @@ def test_publish_batch_too_many_items():
],
)
err = exc.value.response["Error"]
err["Code"].should.equal("TooManyEntriesInBatchRequest")
err["Message"].should.equal(
"The batch request contains more entries than permissible."
)
assert err["Code"] == "TooManyEntriesInBatchRequest"
assert err["Message"] == "The batch request contains more entries than permissible."
@mock_sns
@ -53,9 +51,9 @@ def test_publish_batch_non_unique_ids():
],
)
err = exc.value.response["Error"]
err["Code"].should.equal("BatchEntryIdsNotDistinct")
err["Message"].should.equal(
"Two or more batch entries in the request have the same Id."
assert err["Code"] == "BatchEntryIdsNotDistinct"
assert (
err["Message"] == "Two or more batch entries in the request have the same Id."
)
@ -73,8 +71,8 @@ def test_publish_batch_fifo_without_message_group_id():
PublishBatchRequestEntries=[{"Id": "id_2", "Message": "2"}],
)
err = exc.value.response["Error"]
err["Code"].should.equal("InvalidParameter")
err["Message"].should.equal(
assert err["Code"] == "InvalidParameter"
assert err["Message"] == (
"Invalid parameter: The MessageGroupId parameter is required for FIFO topics"
)
@ -90,20 +88,21 @@ def test_publish_batch_standard_with_message_group_id():
]
resp = client.publish_batch(TopicArn=topic_arn, PublishBatchRequestEntries=entries)
resp.should.have.key("Successful").length_of(2)
assert len(resp["Successful"]) == 2
for message_status in resp["Successful"]:
message_status.should.have.key("MessageId")
[m["Id"] for m in resp["Successful"]].should.equal(["id_1", "id_3"])
assert "MessageId" in message_status
assert [m["Id"] for m in resp["Successful"]] == ["id_1", "id_3"]
resp.should.have.key("Failed").length_of(1)
resp["Failed"][0].should.equal(
{
"Id": "id_2",
"Code": "InvalidParameter",
"Message": "Invalid parameter: MessageGroupId Reason: The request includes MessageGroupId parameter that is not valid for this topic type",
"SenderFault": True,
}
)
assert len(resp["Failed"]) == 1
assert resp["Failed"][0] == {
"Id": "id_2",
"Code": "InvalidParameter",
"Message": (
"Invalid parameter: MessageGroupId Reason: The request includes "
"MessageGroupId parameter that is not valid for this topic type"
),
"SenderFault": True,
}
@mock_sns
@ -129,22 +128,22 @@ def test_publish_batch_to_sqs():
resp = client.publish_batch(TopicArn=topic_arn, PublishBatchRequestEntries=entries)
resp.should.have.key("Successful").length_of(3)
assert len(resp["Successful"]) == 3
messages = queue.receive_messages(MaxNumberOfMessages=3)
messages.should.have.length_of(3)
assert len(messages) == 3
messages = [json.loads(m.body) for m in messages]
for m in messages:
for key in list(m.keys()):
for message in messages:
for key in list(message.keys()):
if key not in ["Message", "Subject", "MessageAttributes"]:
del m[key]
del message[key]
messages.should.contain({"Message": "1"})
messages.should.contain({"Message": "2", "Subject": "subj2"})
messages.should.contain(
assert {"Message": "1"} in messages
assert {"Message": "2", "Subject": "subj2"} in messages
assert (
{"Message": "3", "MessageAttributes": {"a": {"Type": "String", "Value": "v"}}}
)
) in messages
@mock_sqs
@ -173,7 +172,7 @@ def test_publish_batch_to_sqs_raw():
]
resp = client.publish_batch(TopicArn=topic_arn, PublishBatchRequestEntries=entries)
resp.should.have.key("Successful").length_of(2)
assert len(resp["Successful"]) == 2
received = queue.receive_messages(
MaxNumberOfMessages=10, MessageAttributeNames=["All"]
@ -181,5 +180,5 @@ def test_publish_batch_to_sqs_raw():
messages = [(message.body, message.message_attributes) for message in received]
messages.should.contain(("foo", None))
messages.should.contain(("bar", {"a": {"StringValue": "v", "DataType": "String"}}))
assert ("foo", None) in messages
assert ("bar", {"a": {"StringValue": "v", "DataType": "String"}}) in messages

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,20 @@
"""Test the different server responses."""
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
import sure # noqa # pylint: disable=unused-import
import moto.server as server
"""
Test the different server responses
"""
def test_sns_server_get():
backend = server.create_backend_app("sns")
test_client = backend.test_client()
topic_data = test_client.action_data("CreateTopic", Name="testtopic")
topic_data.should.contain("CreateTopicResult")
topic_data.should.contain(
assert "CreateTopicResult" in topic_data
assert (
f"<TopicArn>arn:aws:sns:us-east-1:{ACCOUNT_ID}:testtopic</TopicArn>"
)
) in topic_data
topics_data = test_client.action_data("ListTopics")
topics_data.should.contain("ListTopicsResult")
topic_data.should.contain(
assert "ListTopicsResult" in topics_data
assert (
f"<TopicArn>arn:aws:sns:us-east-1:{ACCOUNT_ID}:testtopic</TopicArn>"
)
) in topics_data

View File

@ -1,6 +1,6 @@
import boto3
import json
import sure # noqa # pylint: disable=unused-import
import boto3
import pytest
from moto import mock_cloudformation, mock_sns
@ -16,25 +16,25 @@ def test_sns_topic():
sns = boto3.client("sns", region_name="us-west-1")
topics = sns.list_topics()["Topics"]
topics.should.have.length_of(1)
assert len(topics) == 1
topic_arn = topics[0]["TopicArn"]
topic_arn.should.contain("my_topics")
assert "my_topics" in topic_arn
subscriptions = sns.list_subscriptions()["Subscriptions"]
subscriptions.should.have.length_of(1)
assert len(subscriptions) == 1
subscription = subscriptions[0]
subscription["TopicArn"].should.equal(topic_arn)
subscription["Protocol"].should.equal("https")
subscription["SubscriptionArn"].should.contain(topic_arn)
subscription["Endpoint"].should.equal("https://example.com")
assert subscription["TopicArn"] == topic_arn
assert subscription["Protocol"] == "https"
assert topic_arn in subscription["SubscriptionArn"]
assert subscription["Endpoint"] == "https://example.com"
stack = cf.describe_stacks(StackName="test_stack")["Stacks"][0]
topic_name_output = [x for x in stack["Outputs"] if x["OutputKey"] == "topic_name"][
0
]
topic_name_output["OutputValue"].should.equal("my_topics")
assert topic_name_output["OutputValue"] == "my_topics"
topic_arn_output = [x for x in stack["Outputs"] if x["OutputKey"] == "topic_arn"][0]
topic_arn_output["OutputValue"].should.equal(topic_arn)
assert topic_arn_output["OutputValue"] == topic_arn
@mock_cloudformation
@ -47,7 +47,7 @@ def test_sns_update_topic():
sns = boto3.client("sns", region_name="us-west-1")
topics = sns.list_topics()["Topics"]
topics.should.have.length_of(1)
assert len(topics) == 1
dummy_template["Resources"]["MySNSTopic"]["Properties"]["Subscription"][0][
"Endpoint"
@ -56,17 +56,17 @@ def test_sns_update_topic():
cf.update_stack(StackName="test_stack", TemplateBody=sns_template_json)
topics = sns.list_topics()["Topics"]
topics.should.have.length_of(1)
assert len(topics) == 1
topic_arn = topics[0]["TopicArn"]
topic_arn.should.contain("my_topics")
assert "my_topics" in topic_arn
subscriptions = sns.list_subscriptions()["Subscriptions"]
subscriptions.should.have.length_of(1)
assert len(subscriptions) == 1
subscription = subscriptions[0]
subscription["TopicArn"].should.equal(topic_arn)
subscription["Protocol"].should.equal("https")
subscription["SubscriptionArn"].should.contain(topic_arn)
subscription["Endpoint"].should.equal("https://example-updated.com")
assert subscription["TopicArn"] == topic_arn
assert subscription["Protocol"] == "https"
assert topic_arn in subscription["SubscriptionArn"]
assert subscription["Endpoint"] == "https://example-updated.com"
@mock_cloudformation
@ -80,7 +80,7 @@ def test_sns_update_remove_topic(with_properties):
sns = boto3.client("sns", region_name="us-west-1")
topics = sns.list_topics()["Topics"]
topics.should.have.length_of(1)
assert len(topics) == 1
dummy_template["Resources"].pop("MySNSTopic")
dummy_template.pop("Outputs")
@ -88,7 +88,7 @@ def test_sns_update_remove_topic(with_properties):
cf.update_stack(StackName="test_stack", TemplateBody=sns_template_json)
topics = sns.list_topics()["Topics"]
topics.should.have.length_of(0)
assert len(topics) == 0
@mock_cloudformation
@ -101,12 +101,12 @@ def test_sns_delete_topic(with_properties):
sns = boto3.client("sns", region_name="us-west-1")
topics = sns.list_topics()["Topics"]
topics.should.have.length_of(1)
assert len(topics) == 1
cf.delete_stack(StackName="test_stack")
topics = sns.list_topics()["Topics"]
topics.should.have.length_of(0)
assert len(topics) == 0
def get_template(with_properties):

View File

@ -1,8 +1,6 @@
import boto3
import json
import sure # noqa # pylint: disable=unused-import
import boto3
from botocore.exceptions import ClientError
import pytest
@ -22,10 +20,10 @@ def test_subscribe_sms():
arn = resp["TopicArn"]
resp = client.subscribe(TopicArn=arn, Protocol="sms", Endpoint="+15551234567")
resp.should.have.key("SubscriptionArn")
assert "SubscriptionArn" in resp
resp = client.subscribe(TopicArn=arn, Protocol="sms", Endpoint="+15/55-123.4567")
resp.should.have.key("SubscriptionArn")
assert "SubscriptionArn" in resp
@mock_sns
@ -42,7 +40,7 @@ def test_double_subscription():
TopicArn=arn, Protocol="sqs", Endpoint="arn:aws:sqs:elasticmq:000000000000:foo"
)
resp1["SubscriptionArn"].should.equal(resp2["SubscriptionArn"])
assert resp1["SubscriptionArn"] == resp2["SubscriptionArn"]
@mock_sns
@ -56,19 +54,29 @@ def test_subscribe_bad_sms():
# Test invalid number
client.subscribe(TopicArn=arn, Protocol="sms", Endpoint="NAA+15551234567")
except ClientError as err:
err.response["Error"]["Code"].should.equal("InvalidParameter")
assert err.response["Error"]["Code"] == "InvalidParameter"
client.subscribe.when.called_with(
TopicArn=arn, Protocol="sms", Endpoint="+15--551234567"
).should.throw(ClientError, "Invalid SMS endpoint: +15--551234567")
with pytest.raises(ClientError) as client_err:
client.subscribe(TopicArn=arn, Protocol="sms", Endpoint="+15--551234567")
assert (
client_err.value.response["Error"]["Message"]
== "Invalid SMS endpoint: +15--551234567"
)
client.subscribe.when.called_with(
TopicArn=arn, Protocol="sms", Endpoint="+15551234567."
).should.throw(ClientError, "Invalid SMS endpoint: +15551234567.")
with pytest.raises(ClientError) as client_err:
client.subscribe(TopicArn=arn, Protocol="sms", Endpoint="+15551234567.")
assert (
client_err.value.response["Error"]["Message"]
== "Invalid SMS endpoint: +15551234567."
)
client.subscribe.when.called_with(
TopicArn=arn, Protocol="sms", Endpoint="/+15551234567"
).should.throw(ClientError, "Invalid SMS endpoint: /+15551234567")
with pytest.raises(ClientError) as client_err:
assert client.subscribe(TopicArn=arn, Protocol="sms", Endpoint="/+15551234567")
assert (
client_err.value.response["Error"]["Message"]
== "Invalid SMS endpoint: /+15551234567"
)
@mock_sns
@ -81,19 +89,19 @@ def test_creating_subscription():
conn.subscribe(TopicArn=topic_arn, Protocol="http", Endpoint="http://example.com/")
subscriptions = conn.list_subscriptions()["Subscriptions"]
subscriptions.should.have.length_of(1)
assert len(subscriptions) == 1
subscription = subscriptions[0]
subscription["TopicArn"].should.equal(topic_arn)
subscription["Protocol"].should.equal("http")
subscription["SubscriptionArn"].should.contain(topic_arn)
subscription["Endpoint"].should.equal("http://example.com/")
assert subscription["TopicArn"] == topic_arn
assert subscription["Protocol"] == "http"
assert topic_arn in subscription["SubscriptionArn"]
assert subscription["Endpoint"] == "http://example.com/"
# Now unsubscribe the subscription
conn.unsubscribe(SubscriptionArn=subscription["SubscriptionArn"])
# And there should be zero subscriptions left
subscriptions = conn.list_subscriptions()["Subscriptions"]
subscriptions.should.have.length_of(0)
assert len(subscriptions) == 0
@mock_sns
@ -108,13 +116,13 @@ def test_unsubscribe_from_deleted_topic():
)
subscriptions = client.list_subscriptions()["Subscriptions"]
subscriptions.should.have.length_of(1)
assert len(subscriptions) == 1
subscription = subscriptions[0]
subscription_arn = subscription["SubscriptionArn"]
subscription["TopicArn"].should.equal(topic_arn)
subscription["Protocol"].should.equal("http")
subscription_arn.should.contain(topic_arn)
subscription["Endpoint"].should.equal("http://example.com/")
assert subscription["TopicArn"] == topic_arn
assert subscription["Protocol"] == "http"
assert topic_arn in subscription_arn
assert subscription["Endpoint"] == "http://example.com/"
# Now delete the topic
client.delete_topic(TopicArn=topic_arn)
@ -122,17 +130,17 @@ def test_unsubscribe_from_deleted_topic():
# And there should now be 0 topics
topics_json = client.list_topics()
topics = topics_json["Topics"]
topics.should.have.length_of(0)
assert len(topics) == 0
# as per the documentation deleting a topic deletes all the subscriptions
subscriptions = client.list_subscriptions()["Subscriptions"]
subscriptions.should.have.length_of(0)
assert len(subscriptions) == 0
# Now delete hanging subscription
client.unsubscribe(SubscriptionArn=subscription_arn)
subscriptions = client.list_subscriptions()["Subscriptions"]
subscriptions.should.have.length_of(0)
assert len(subscriptions) == 0
# Deleting it again should not result in any error
client.unsubscribe(SubscriptionArn=subscription_arn)
@ -159,8 +167,8 @@ def test_getting_subscriptions_by_topic():
topic1_subscriptions = conn.list_subscriptions_by_topic(TopicArn=topic1_arn)[
"Subscriptions"
]
topic1_subscriptions.should.have.length_of(1)
topic1_subscriptions[0]["Endpoint"].should.equal("http://example1.com/")
assert len(topic1_subscriptions) == 1
assert topic1_subscriptions[0]["Endpoint"] == "http://example1.com/"
@mock_sns
@ -180,26 +188,24 @@ def test_subscription_paging():
)
all_subscriptions = conn.list_subscriptions()
all_subscriptions["Subscriptions"].should.have.length_of(DEFAULT_PAGE_SIZE)
assert len(all_subscriptions["Subscriptions"]) == DEFAULT_PAGE_SIZE
next_token = all_subscriptions["NextToken"]
next_token.should.equal(str(DEFAULT_PAGE_SIZE))
assert next_token == str(DEFAULT_PAGE_SIZE)
all_subscriptions = conn.list_subscriptions(NextToken=next_token)
all_subscriptions["Subscriptions"].should.have.length_of(int(DEFAULT_PAGE_SIZE / 3))
all_subscriptions.shouldnt.have("NextToken")
assert len(all_subscriptions["Subscriptions"]) == int(DEFAULT_PAGE_SIZE / 3)
assert "NextToken" not in all_subscriptions
topic1_subscriptions = conn.list_subscriptions_by_topic(TopicArn=topic1_arn)
topic1_subscriptions["Subscriptions"].should.have.length_of(DEFAULT_PAGE_SIZE)
assert len(topic1_subscriptions["Subscriptions"]) == DEFAULT_PAGE_SIZE
next_token = topic1_subscriptions["NextToken"]
next_token.should.equal(str(DEFAULT_PAGE_SIZE))
assert next_token == str(DEFAULT_PAGE_SIZE)
topic1_subscriptions = conn.list_subscriptions_by_topic(
TopicArn=topic1_arn, NextToken=next_token
)
topic1_subscriptions["Subscriptions"].should.have.length_of(
int(DEFAULT_PAGE_SIZE / 3)
)
topic1_subscriptions.shouldnt.have("NextToken")
assert len(topic1_subscriptions["Subscriptions"]) == int(DEFAULT_PAGE_SIZE / 3)
assert "NextToken" not in topic1_subscriptions
@mock_sns
@ -215,17 +221,17 @@ def test_subscribe_attributes():
SubscriptionArn=resp["SubscriptionArn"]
)
response.should.contain("Attributes")
assert "Attributes" in response
attributes = response["Attributes"]
attributes["PendingConfirmation"].should.equal("false")
attributes["ConfirmationWasAuthenticated"].should.equal("true")
attributes["Endpoint"].should.equal("http://test.com")
attributes["TopicArn"].should.equal(arn)
attributes["Protocol"].should.equal("http")
attributes["SubscriptionArn"].should.equal(resp["SubscriptionArn"])
attributes["Owner"].should.equal(str(ACCOUNT_ID))
attributes["RawMessageDelivery"].should.equal("false")
json.loads(attributes["EffectiveDeliveryPolicy"]).should.equal(
assert attributes["PendingConfirmation"] == "false"
assert attributes["ConfirmationWasAuthenticated"] == "true"
assert attributes["Endpoint"] == "http://test.com"
assert attributes["TopicArn"] == arn
assert attributes["Protocol"] == "http"
assert attributes["SubscriptionArn"] == resp["SubscriptionArn"]
assert attributes["Owner"] == str(ACCOUNT_ID)
assert attributes["RawMessageDelivery"] == "false"
assert json.loads(attributes["EffectiveDeliveryPolicy"]) == (
DEFAULT_EFFECTIVE_DELIVERY_POLICY
)
@ -272,28 +278,28 @@ def test_creating_subscription_with_attributes():
)
subscriptions = conn.list_subscriptions()["Subscriptions"]
subscriptions.should.have.length_of(1)
assert len(subscriptions) == 1
subscription = subscriptions[0]
subscription["TopicArn"].should.equal(topic_arn)
subscription["Protocol"].should.equal("http")
subscription["SubscriptionArn"].should.contain(topic_arn)
subscription["Endpoint"].should.equal("http://example.com/")
assert subscription["TopicArn"] == topic_arn
assert subscription["Protocol"] == "http"
assert topic_arn in subscription["SubscriptionArn"]
assert subscription["Endpoint"] == "http://example.com/"
# Test the subscription attributes have been set
subscription_arn = subscription["SubscriptionArn"]
attrs = conn.get_subscription_attributes(SubscriptionArn=subscription_arn)
attrs["Attributes"]["RawMessageDelivery"].should.equal("true")
attrs["Attributes"]["DeliveryPolicy"].should.equal(delivery_policy)
attrs["Attributes"]["FilterPolicy"].should.equal(filter_policy)
attrs["Attributes"]["SubscriptionRoleArn"].should.equal(subscription_role_arn)
assert attrs["Attributes"]["RawMessageDelivery"] == "true"
assert attrs["Attributes"]["DeliveryPolicy"] == delivery_policy
assert attrs["Attributes"]["FilterPolicy"] == filter_policy
assert attrs["Attributes"]["SubscriptionRoleArn"] == subscription_role_arn
# Now unsubscribe the subscription
conn.unsubscribe(SubscriptionArn=subscription["SubscriptionArn"])
# And there should be zero subscriptions left
subscriptions = conn.list_subscriptions()["Subscriptions"]
subscriptions.should.have.length_of(0)
assert len(subscriptions) == 0
# invalid attr name
with pytest.raises(ClientError):
@ -319,12 +325,12 @@ def test_delete_subscriptions_on_delete_topic():
)
subscriptions = conn.list_subscriptions()["Subscriptions"]
subscriptions.should.have.length_of(1)
assert len(subscriptions) == 1
conn.delete_topic(TopicArn=topic.get("TopicArn"))
subscriptions = conn.list_subscriptions()["Subscriptions"]
subscriptions.should.have.length_of(0)
assert len(subscriptions) == 0
@mock_sns
@ -337,16 +343,16 @@ def test_set_subscription_attributes():
conn.subscribe(TopicArn=topic_arn, Protocol="http", Endpoint="http://example.com/")
subscriptions = conn.list_subscriptions()["Subscriptions"]
subscriptions.should.have.length_of(1)
assert len(subscriptions) == 1
subscription = subscriptions[0]
subscription["TopicArn"].should.equal(topic_arn)
subscription["Protocol"].should.equal("http")
subscription["SubscriptionArn"].should.contain(topic_arn)
subscription["Endpoint"].should.equal("http://example.com/")
assert subscription["TopicArn"] == topic_arn
assert subscription["Protocol"] == "http"
assert topic_arn in subscription["SubscriptionArn"]
assert subscription["Endpoint"] == "http://example.com/"
subscription_arn = subscription["SubscriptionArn"]
attrs = conn.get_subscription_attributes(SubscriptionArn=subscription_arn)
attrs.should.have.key("Attributes")
assert "Attributes" in attrs
conn.set_subscription_attributes(
SubscriptionArn=subscription_arn,
AttributeName="RawMessageDelivery",
@ -384,9 +390,9 @@ def test_set_subscription_attributes():
attrs = conn.get_subscription_attributes(SubscriptionArn=subscription_arn)
attrs["Attributes"]["RawMessageDelivery"].should.equal("true")
attrs["Attributes"]["DeliveryPolicy"].should.equal(delivery_policy)
attrs["Attributes"]["FilterPolicy"].should.equal(filter_policy)
assert attrs["Attributes"]["RawMessageDelivery"] == "true"
assert attrs["Attributes"]["DeliveryPolicy"] == delivery_policy
assert attrs["Attributes"]["FilterPolicy"] == filter_policy
filter_policy_scope = "MessageBody"
conn.set_subscription_attributes(
@ -397,7 +403,7 @@ def test_set_subscription_attributes():
attrs = conn.get_subscription_attributes(SubscriptionArn=subscription_arn)
attrs["Attributes"]["FilterPolicyScope"].should.equal(filter_policy_scope)
assert attrs["Attributes"]["FilterPolicyScope"] == filter_policy_scope
# not existing subscription
with pytest.raises(ClientError):
@ -436,8 +442,8 @@ def test_subscribe_invalid_filter_policy():
)
err = err_info.value
err.response["Error"]["Code"].should.equal("InvalidParameter")
err.response["Error"]["Message"].should.equal(
assert err.response["Error"]["Code"] == "InvalidParameter"
assert err.response["Error"]["Message"] == (
"Invalid parameter: FilterPolicy: Filter policy is too complex"
)
@ -450,8 +456,8 @@ def test_subscribe_invalid_filter_policy():
)
err = err_info.value
err.response["Error"]["Code"].should.equal("InvalidParameter")
err.response["Error"]["Message"].should.equal(
assert err.response["Error"]["Code"] == "InvalidParameter"
assert err.response["Error"]["Message"] == (
"Invalid parameter: FilterPolicy: Match value must be String, number, true, false, or null"
)
@ -464,8 +470,8 @@ def test_subscribe_invalid_filter_policy():
)
err = err_info.value
err.response["Error"]["Code"].should.equal("InvalidParameter")
err.response["Error"]["Message"].should.equal(
assert err.response["Error"]["Code"] == "InvalidParameter"
assert err.response["Error"]["Message"] == (
"Invalid parameter: FilterPolicy: exists match pattern must be either true or false."
)
@ -478,8 +484,8 @@ def test_subscribe_invalid_filter_policy():
)
err = err_info.value
err.response["Error"]["Code"].should.equal("InvalidParameter")
err.response["Error"]["Message"].should.equal(
assert err.response["Error"]["Code"] == "InvalidParameter"
assert err.response["Error"]["Message"] == (
"Invalid parameter: FilterPolicy: Unrecognized match type error"
)
@ -492,7 +498,7 @@ def test_subscribe_invalid_filter_policy():
)
err = err_info.value
err.response["Error"]["Code"].should.equal("InternalFailure")
assert err.response["Error"]["Code"] == "InternalFailure"
with pytest.raises(ClientError) as err_info:
conn.subscribe(
@ -505,8 +511,8 @@ def test_subscribe_invalid_filter_policy():
)
err = err_info.value
err.response["Error"]["Code"].should.equal("InvalidParameter")
err.response["Error"]["Message"].should.equal(
assert err.response["Error"]["Code"] == "InvalidParameter"
assert err.response["Error"]["Message"] == (
"Invalid parameter: Attributes Reason: FilterPolicy: Value of < must be numeric\n at ..."
)
@ -523,8 +529,8 @@ def test_subscribe_invalid_filter_policy():
)
err = err_info.value
err.response["Error"]["Code"].should.equal("InvalidParameter")
err.response["Error"]["Message"].should.equal(
assert err.response["Error"]["Code"] == "InvalidParameter"
assert err.response["Error"]["Message"] == (
"Invalid parameter: Attributes Reason: FilterPolicy: Value of <= must be numeric\n at ..."
)
@ -537,9 +543,10 @@ def test_subscribe_invalid_filter_policy():
)
err = err_info.value
err.response["Error"]["Code"].should.equal("InvalidParameter")
err.response["Error"]["Message"].should.equal(
"Invalid parameter: Attributes Reason: FilterPolicy: Invalid member in numeric match: ]\n at ..."
assert err.response["Error"]["Code"] == "InvalidParameter"
assert err.response["Error"]["Message"] == (
"Invalid parameter: Attributes Reason: FilterPolicy: "
"Invalid member in numeric match: ]\n at ..."
)
with pytest.raises(ClientError) as err_info:
@ -553,9 +560,10 @@ def test_subscribe_invalid_filter_policy():
)
err = err_info.value
err.response["Error"]["Code"].should.equal("InvalidParameter")
err.response["Error"]["Message"].should.equal(
"Invalid parameter: Attributes Reason: FilterPolicy: Invalid member in numeric match: 50\n at ..."
assert err.response["Error"]["Code"] == "InvalidParameter"
assert err.response["Error"]["Message"] == (
"Invalid parameter: Attributes Reason: FilterPolicy: Invalid "
"member in numeric match: 50\n at ..."
)
with pytest.raises(ClientError) as err_info:
@ -567,8 +575,8 @@ def test_subscribe_invalid_filter_policy():
)
err = err_info.value
err.response["Error"]["Code"].should.equal("InvalidParameter")
err.response["Error"]["Message"].should.equal(
assert err.response["Error"]["Code"] == "InvalidParameter"
assert err.response["Error"]["Message"] == (
"Invalid parameter: Attributes Reason: FilterPolicy: Value of < must be numeric\n at ..."
)
@ -581,9 +589,10 @@ def test_subscribe_invalid_filter_policy():
)
err = err_info.value
err.response["Error"]["Code"].should.equal("InvalidParameter")
err.response["Error"]["Message"].should.equal(
"Invalid parameter: Attributes Reason: FilterPolicy: Unrecognized numeric range operator: 0\n at ..."
assert err.response["Error"]["Code"] == "InvalidParameter"
assert err.response["Error"]["Message"] == (
"Invalid parameter: Attributes Reason: FilterPolicy: "
"Unrecognized numeric range operator: 0\n at ..."
)
with pytest.raises(ClientError) as err_info:
@ -597,9 +606,10 @@ def test_subscribe_invalid_filter_policy():
)
err = err_info.value
err.response["Error"]["Code"].should.equal("InvalidParameter")
err.response["Error"]["Message"].should.equal(
"Invalid parameter: Attributes Reason: FilterPolicy: Too many elements in numeric expression\n at ..."
assert err.response["Error"]["Code"] == "InvalidParameter"
assert err.response["Error"]["Message"] == (
"Invalid parameter: Attributes Reason: FilterPolicy: Too many "
"elements in numeric expression\n at ..."
)
with pytest.raises(ClientError) as err_info:
@ -613,8 +623,8 @@ def test_subscribe_invalid_filter_policy():
)
err = err_info.value
err.response["Error"]["Code"].should.equal("InvalidParameter")
err.response["Error"]["Message"].should.equal(
assert err.response["Error"]["Code"] == "InvalidParameter"
assert err.response["Error"]["Message"] == (
"Invalid parameter: Attributes Reason: FilterPolicy: Bad numeric range operator: >\n at ..."
)
@ -629,8 +639,8 @@ def test_subscribe_invalid_filter_policy():
)
err = err_info.value
err.response["Error"]["Code"].should.equal("InvalidParameter")
err.response["Error"]["Message"].should.equal(
assert err.response["Error"]["Code"] == "InvalidParameter"
assert err.response["Error"]["Message"] == (
"Invalid parameter: Attributes Reason: FilterPolicy: Bottom must be less than top\n at ..."
)
@ -645,8 +655,8 @@ def test_subscribe_invalid_filter_policy():
)
err = err_info.value
err.response["Error"]["Code"].should.equal("InvalidParameter")
err.response["Error"]["Message"].should.equal(
assert err.response["Error"]["Code"] == "InvalidParameter"
assert err.response["Error"]["Message"] == (
"Invalid parameter: Attributes Reason: FilterPolicy: Value of < must be numeric\n at ..."
)
@ -660,9 +670,10 @@ def test_subscribe_invalid_filter_policy():
},
)
except ClientError as err:
err.response["Error"]["Code"].should.equal("InvalidParameter")
err.response["Error"]["Message"].should.equal(
"Invalid parameter: Filter policy scope MessageAttributes does not support nested filter policy"
assert err.response["Error"]["Code"] == "InvalidParameter"
assert err.response["Error"]["Message"] == (
"Invalid parameter: Filter policy scope MessageAttributes does "
"not support nested filter policy"
)
try:
@ -681,8 +692,8 @@ def test_subscribe_invalid_filter_policy():
Attributes={"FilterPolicy": json.dumps(filter_policy)},
)
except ClientError as err:
err.response["Error"]["Code"].should.equal("InvalidParameter")
err.response["Error"]["Message"].should.equal(
assert err.response["Error"]["Code"] == "InvalidParameter"
assert err.response["Error"]["Message"] == (
"Invalid parameter: FilterPolicy: Filter policy can not have more than 5 keys"
)
@ -696,8 +707,9 @@ def test_subscribe_invalid_filter_policy():
"key_d": {"key_e": ["value_one", "value_two", "value_three"]},
"key_f": ["value_one", "value_two", "value_three"],
}
# The first array has four values in a three-level nested key, and the second has three values in a two-level
# nested key. The total combination is calculated as follows:
# The first array has four values in a three-level nested key,
# and the second has three values in a two-level nested key. The
# total combination is calculated as follows:
# 3 x 4 x 2 x 3 x 1 x 3 = 216
conn.subscribe(
TopicArn=topic_arn,
@ -709,8 +721,8 @@ def test_subscribe_invalid_filter_policy():
},
)
except ClientError as err:
err.response["Error"]["Code"].should.equal("InvalidParameter")
err.response["Error"]["Message"].should.equal(
assert err.response["Error"]["Code"] == "InvalidParameter"
assert err.response["Error"]["Message"] == (
"Invalid parameter: FilterPolicy: Filter policy is too complex"
)
@ -720,8 +732,8 @@ def test_check_not_opted_out():
conn = boto3.client("sns", region_name="us-east-1")
response = conn.check_if_phone_number_is_opted_out(phoneNumber="+447428545375")
response.should.contain("isOptedOut")
response["isOptedOut"].should.be(False)
assert "isOptedOut" in response
assert response["isOptedOut"] is False
@mock_sns
@ -731,8 +743,8 @@ def test_check_opted_out():
conn = boto3.client("sns", region_name="us-east-1")
response = conn.check_if_phone_number_is_opted_out(phoneNumber="+447428545399")
response.should.contain("isOptedOut")
response["isOptedOut"].should.be(True)
assert "isOptedOut" in response
assert response["isOptedOut"] is True
@mock_sns
@ -749,8 +761,8 @@ def test_list_opted_out():
conn = boto3.client("sns", region_name="us-east-1")
response = conn.list_phone_numbers_opted_out()
response.should.contain("phoneNumbers")
len(response["phoneNumbers"]).should.be.greater_than(0)
assert "phoneNumbers" in response
assert len(response["phoneNumbers"]) > 0
@mock_sns
@ -763,8 +775,8 @@ def test_opt_in():
conn.opt_in_phone_number(phoneNumber=response["phoneNumbers"][0])
response = conn.list_phone_numbers_opted_out()
len(response["phoneNumbers"]).should.be.greater_than(0)
len(response["phoneNumbers"]).should.be.lower_than(current_len)
assert len(response["phoneNumbers"]) > 0
assert len(response["phoneNumbers"]) < current_len
@mock_sns
@ -774,7 +786,12 @@ def test_confirm_subscription():
conn.confirm_subscription(
TopicArn=response["TopicArn"],
Token="2336412f37fb687f5d51e6e241d59b68c4e583a5cee0be6f95bbf97ab8d2441cf47b99e848408adaadf4c197e65f03473d53c4ba398f6abbf38ce2e8ebf7b4ceceb2cd817959bcde1357e58a2861b05288c535822eb88cac3db04f592285249971efc6484194fc4a4586147f16916692",
Token=(
"2336412f37fb687f5d51e6e241d59b68c4e583a5cee0be6f95bbf97ab8d"
"2441cf47b99e848408adaadf4c197e65f03473d53c4ba398f6abbf38ce2"
"e8ebf7b4ceceb2cd817959bcde1357e58a2861b05288c535822eb88cac3"
"db04f592285249971efc6484194fc4a4586147f16916692"
),
AuthenticateOnUnsubscribe="true",
)
@ -783,15 +800,18 @@ def test_confirm_subscription():
def test_get_subscription_attributes_error_not_exists():
# given
client = boto3.client("sns", region_name="us-east-1")
sub_arn = f"arn:aws:sqs:us-east-1:{ACCOUNT_ID}:test-queue:66d97e76-31e5-444f-8fa7-b60b680d0d39"
sub_arn = (
f"arn:aws:sqs:us-east-1:{ACCOUNT_ID}:test-queue"
":66d97e76-31e5-444f-8fa7-b60b680d0d39"
)
# when
with pytest.raises(ClientError) as e:
with pytest.raises(ClientError) as exc:
client.get_subscription_attributes(SubscriptionArn=sub_arn)
# then
ex = e.value
ex.operation_name.should.equal("GetSubscriptionAttributes")
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(404)
ex.response["Error"]["Code"].should.contain("NotFound")
ex.response["Error"]["Message"].should.equal("Subscription does not exist")
exc_value = exc.value
assert exc_value.operation_name == "GetSubscriptionAttributes"
assert exc_value.response["ResponseMetadata"]["HTTPStatusCode"] == 404
assert "NotFound" in exc_value.response["Error"]["Code"]
assert exc_value.response["Error"]["Message"] == "Subscription does not exist"

View File

@ -1,13 +1,11 @@
import boto3
import json
import pytest
import sure # noqa # pylint: disable=unused-import
import boto3
from botocore.exceptions import ClientError
from moto import mock_sns
from moto.sns.models import DEFAULT_EFFECTIVE_DELIVERY_POLICY, DEFAULT_PAGE_SIZE
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
import pytest
@mock_sns
@ -18,8 +16,8 @@ def test_create_and_delete_topic():
topics_json = conn.list_topics()
topics = topics_json["Topics"]
topics.should.have.length_of(1)
topics[0]["TopicArn"].should.equal(
assert len(topics) == 1
assert topics[0]["TopicArn"] == (
f"arn:aws:sns:{conn._client_config.region_name}:{ACCOUNT_ID}:{topic_name}"
)
@ -32,7 +30,7 @@ def test_create_and_delete_topic():
# And there should now be 0 topics
topics_json = conn.list_topics()
topics = topics_json["Topics"]
topics.should.have.length_of(0)
assert len(topics) == 0
@mock_sns
@ -55,7 +53,7 @@ def test_create_topic_with_attributes():
topic_arn = topics_json["Topics"][0]["TopicArn"]
attributes = conn.get_topic_attributes(TopicArn=topic_arn)["Attributes"]
attributes["DisplayName"].should.equal("test-topic")
assert attributes["DisplayName"] == "test-topic"
@mock_sns
@ -70,7 +68,7 @@ def test_create_topic_with_tags():
)
topic_arn = response["TopicArn"]
conn.list_tags_for_resource(ResourceArn=topic_arn)["Tags"].should.equal(
assert conn.list_tags_for_resource(ResourceArn=topic_arn)["Tags"] == (
[
{"Key": "tag_key_1", "Value": "tag_value_1"},
{"Key": "tag_key_2", "Value": "tag_value_2"},
@ -88,22 +86,23 @@ def test_create_topic_should_be_indempodent():
topic_display_name = conn.get_topic_attributes(TopicArn=topic_arn)["Attributes"][
"DisplayName"
]
topic_display_name.should.be.equal("should_be_set")
assert topic_display_name == "should_be_set"
# recreate topic to prove indempodentcy
topic_arn = conn.create_topic(Name="some-topic")["TopicArn"]
topic_display_name = conn.get_topic_attributes(TopicArn=topic_arn)["Attributes"][
"DisplayName"
]
topic_display_name.should.be.equal("should_be_set")
assert topic_display_name == "should_be_set"
@mock_sns
def test_get_missing_topic():
conn = boto3.client("sns", region_name="us-east-1")
conn.get_topic_attributes.when.called_with(
TopicArn="arn:aws:sns:us-east-1:424242424242:a-fake-arn"
).should.throw(ClientError)
with pytest.raises(ClientError):
conn.get_topic_attributes(
TopicArn="arn:aws:sns:us-east-1:424242424242:a-fake-arn"
)
@mock_sns
@ -111,21 +110,21 @@ def test_create_topic_must_meet_constraints():
conn = boto3.client("sns", region_name="us-east-1")
common_random_chars = [":", ";", "!", "@", "|", "^", "%"]
for char in common_random_chars:
conn.create_topic.when.called_with(Name=f"no{char}_invalidchar").should.throw(
ClientError
)
conn.create_topic.when.called_with(Name="no spaces allowed").should.throw(
ClientError
)
with pytest.raises(ClientError):
conn.create_topic(Name=f"no{char}_invalidchar")
with pytest.raises(ClientError):
conn.create_topic(Name="no spaces allowed")
@mock_sns
def test_create_topic_should_be_of_certain_length():
conn = boto3.client("sns", region_name="us-east-1")
too_short = ""
conn.create_topic.when.called_with(Name=too_short).should.throw(ClientError)
with pytest.raises(ClientError):
conn.create_topic(Name=too_short)
too_long = "x" * 257
conn.create_topic.when.called_with(Name=too_long).should.throw(ClientError)
with pytest.raises(ClientError):
conn.create_topic(Name=too_long)
@mock_sns
@ -134,7 +133,7 @@ def test_create_topic_in_multiple_regions():
conn = boto3.client("sns", region_name=region)
topic_arn = conn.create_topic(Name="some-topic")["TopicArn"]
# We can find the topic
list(conn.list_topics()["Topics"]).should.have.length_of(1)
assert len(list(conn.list_topics()["Topics"])) == 1
# We can read the Topic details
topic = boto3.resource("sns", region_name=region).Topic(topic_arn)
@ -158,7 +157,7 @@ def test_topic_corresponds_to_region():
conn.create_topic(Name="some-topic")
topics_json = conn.list_topics()
topic_arn = topics_json["Topics"][0]["TopicArn"]
topic_arn.should.equal(f"arn:aws:sns:{region}:{ACCOUNT_ID}:some-topic")
assert topic_arn == f"arn:aws:sns:{region}:{ACCOUNT_ID}:some-topic"
@mock_sns
@ -170,42 +169,40 @@ def test_topic_attributes():
topic_arn = topics_json["Topics"][0]["TopicArn"]
attributes = conn.get_topic_attributes(TopicArn=topic_arn)["Attributes"]
attributes["TopicArn"].should.equal(
assert attributes["TopicArn"] == (
f"arn:aws:sns:{conn._client_config.region_name}:{ACCOUNT_ID}:some-topic"
)
attributes["Owner"].should.equal(ACCOUNT_ID)
json.loads(attributes["Policy"]).should.equal(
{
"Version": "2008-10-17",
"Id": "__default_policy_ID",
"Statement": [
{
"Effect": "Allow",
"Sid": "__default_statement_ID",
"Principal": {"AWS": "*"},
"Action": [
"SNS:GetTopicAttributes",
"SNS:SetTopicAttributes",
"SNS:AddPermission",
"SNS:RemovePermission",
"SNS:DeleteTopic",
"SNS:Subscribe",
"SNS:ListSubscriptionsByTopic",
"SNS:Publish",
"SNS:Receive",
],
"Resource": f"arn:aws:sns:us-east-1:{ACCOUNT_ID}:some-topic",
"Condition": {"StringEquals": {"AWS:SourceOwner": ACCOUNT_ID}},
}
],
}
)
attributes["DisplayName"].should.equal("")
attributes["SubscriptionsPending"].should.equal("0")
attributes["SubscriptionsConfirmed"].should.equal("0")
attributes["SubscriptionsDeleted"].should.equal("0")
attributes["DeliveryPolicy"].should.equal("")
json.loads(attributes["EffectiveDeliveryPolicy"]).should.equal(
assert attributes["Owner"] == ACCOUNT_ID
assert json.loads(attributes["Policy"]) == {
"Version": "2008-10-17",
"Id": "__default_policy_ID",
"Statement": [
{
"Effect": "Allow",
"Sid": "__default_statement_ID",
"Principal": {"AWS": "*"},
"Action": [
"SNS:GetTopicAttributes",
"SNS:SetTopicAttributes",
"SNS:AddPermission",
"SNS:RemovePermission",
"SNS:DeleteTopic",
"SNS:Subscribe",
"SNS:ListSubscriptionsByTopic",
"SNS:Publish",
"SNS:Receive",
],
"Resource": f"arn:aws:sns:us-east-1:{ACCOUNT_ID}:some-topic",
"Condition": {"StringEquals": {"AWS:SourceOwner": ACCOUNT_ID}},
}
],
}
assert attributes["DisplayName"] == ""
assert attributes["SubscriptionsPending"] == "0"
assert attributes["SubscriptionsConfirmed"] == "0"
assert attributes["SubscriptionsDeleted"] == "0"
assert attributes["DeliveryPolicy"] == ""
assert json.loads(attributes["EffectiveDeliveryPolicy"]) == (
DEFAULT_EFFECTIVE_DELIVERY_POLICY
)
@ -226,9 +223,9 @@ def test_topic_attributes():
)
attributes = conn.get_topic_attributes(TopicArn=topic_arn)["Attributes"]
attributes["Policy"].should.equal('{"foo":"bar"}')
attributes["DisplayName"].should.equal("My display name")
attributes["DeliveryPolicy"].should.equal(
assert attributes["Policy"] == '{"foo":"bar"}'
assert attributes["DisplayName"] == "My display name"
assert attributes["DeliveryPolicy"] == (
'{"http": {"defaultHealthyRetryPolicy": {"numRetries": 5}}}'
)
@ -243,14 +240,14 @@ def test_topic_paging():
topics_list = response["Topics"]
next_token = response["NextToken"]
len(topics_list).should.equal(DEFAULT_PAGE_SIZE)
int(next_token).should.equal(DEFAULT_PAGE_SIZE)
assert len(topics_list) == DEFAULT_PAGE_SIZE
assert int(next_token) == DEFAULT_PAGE_SIZE
response = conn.list_topics(NextToken=next_token)
topics_list = response["Topics"]
response.shouldnt.have("NextToken")
assert "NextToken" not in response
topics_list.should.have.length_of(int(DEFAULT_PAGE_SIZE / 2))
assert len(topics_list) == int(DEFAULT_PAGE_SIZE / 2)
@mock_sns
@ -266,69 +263,65 @@ def test_add_remove_permissions():
)
response = client.get_topic_attributes(TopicArn=topic_arn)
json.loads(response["Attributes"]["Policy"]).should.equal(
{
"Version": "2008-10-17",
"Id": "__default_policy_ID",
"Statement": [
{
"Effect": "Allow",
"Sid": "__default_statement_ID",
"Principal": {"AWS": "*"},
"Action": [
"SNS:GetTopicAttributes",
"SNS:SetTopicAttributes",
"SNS:AddPermission",
"SNS:RemovePermission",
"SNS:DeleteTopic",
"SNS:Subscribe",
"SNS:ListSubscriptionsByTopic",
"SNS:Publish",
"SNS:Receive",
],
"Resource": f"arn:aws:sns:us-east-1:{ACCOUNT_ID}:test-permissions",
"Condition": {"StringEquals": {"AWS:SourceOwner": ACCOUNT_ID}},
},
{
"Sid": "test",
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::999999999999:root"},
"Action": "SNS:Publish",
"Resource": f"arn:aws:sns:us-east-1:{ACCOUNT_ID}:test-permissions",
},
],
}
)
assert json.loads(response["Attributes"]["Policy"]) == {
"Version": "2008-10-17",
"Id": "__default_policy_ID",
"Statement": [
{
"Effect": "Allow",
"Sid": "__default_statement_ID",
"Principal": {"AWS": "*"},
"Action": [
"SNS:GetTopicAttributes",
"SNS:SetTopicAttributes",
"SNS:AddPermission",
"SNS:RemovePermission",
"SNS:DeleteTopic",
"SNS:Subscribe",
"SNS:ListSubscriptionsByTopic",
"SNS:Publish",
"SNS:Receive",
],
"Resource": f"arn:aws:sns:us-east-1:{ACCOUNT_ID}:test-permissions",
"Condition": {"StringEquals": {"AWS:SourceOwner": ACCOUNT_ID}},
},
{
"Sid": "test",
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::999999999999:root"},
"Action": "SNS:Publish",
"Resource": f"arn:aws:sns:us-east-1:{ACCOUNT_ID}:test-permissions",
},
],
}
client.remove_permission(TopicArn=topic_arn, Label="test")
response = client.get_topic_attributes(TopicArn=topic_arn)
json.loads(response["Attributes"]["Policy"]).should.equal(
{
"Version": "2008-10-17",
"Id": "__default_policy_ID",
"Statement": [
{
"Effect": "Allow",
"Sid": "__default_statement_ID",
"Principal": {"AWS": "*"},
"Action": [
"SNS:GetTopicAttributes",
"SNS:SetTopicAttributes",
"SNS:AddPermission",
"SNS:RemovePermission",
"SNS:DeleteTopic",
"SNS:Subscribe",
"SNS:ListSubscriptionsByTopic",
"SNS:Publish",
"SNS:Receive",
],
"Resource": f"arn:aws:sns:us-east-1:{ACCOUNT_ID}:test-permissions",
"Condition": {"StringEquals": {"AWS:SourceOwner": ACCOUNT_ID}},
}
],
}
)
assert json.loads(response["Attributes"]["Policy"]) == {
"Version": "2008-10-17",
"Id": "__default_policy_ID",
"Statement": [
{
"Effect": "Allow",
"Sid": "__default_statement_ID",
"Principal": {"AWS": "*"},
"Action": [
"SNS:GetTopicAttributes",
"SNS:SetTopicAttributes",
"SNS:AddPermission",
"SNS:RemovePermission",
"SNS:DeleteTopic",
"SNS:Subscribe",
"SNS:ListSubscriptionsByTopic",
"SNS:Publish",
"SNS:Receive",
],
"Resource": f"arn:aws:sns:us-east-1:{ACCOUNT_ID}:test-permissions",
"Condition": {"StringEquals": {"AWS:SourceOwner": ACCOUNT_ID}},
}
],
}
client.add_permission(
TopicArn=topic_arn,
@ -338,20 +331,18 @@ def test_add_remove_permissions():
)
response = client.get_topic_attributes(TopicArn=topic_arn)
json.loads(response["Attributes"]["Policy"])["Statement"][1].should.equal(
{
"Sid": "test",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::888888888888:root",
"arn:aws:iam::999999999999:root",
]
},
"Action": ["SNS:Publish", "SNS:Subscribe"],
"Resource": f"arn:aws:sns:us-east-1:{ACCOUNT_ID}:test-permissions",
}
)
assert json.loads(response["Attributes"]["Policy"])["Statement"][1] == {
"Sid": "test",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::888888888888:root",
"arn:aws:iam::999999999999:root",
]
},
"Action": ["SNS:Publish", "SNS:Subscribe"],
"Resource": f"arn:aws:sns:us-east-1:{ACCOUNT_ID}:test-permissions",
}
# deleting non existing permission should be successful
client.remove_permission(TopicArn=topic_arn, Label="non-existing")
@ -368,30 +359,36 @@ def test_add_permission_errors():
ActionName=["Publish"],
)
client.add_permission.when.called_with(
TopicArn=topic_arn,
Label="test",
AWSAccountId=["999999999999"],
ActionName=["AddPermission"],
).should.throw(ClientError, "Statement already exists")
with pytest.raises(ClientError) as client_err:
client.add_permission(
TopicArn=topic_arn,
Label="test",
AWSAccountId=["999999999999"],
ActionName=["AddPermission"],
)
assert client_err.value.response["Error"]["Message"] == "Statement already exists"
client.add_permission.when.called_with(
TopicArn=topic_arn + "-not-existing",
Label="test-2",
AWSAccountId=["999999999999"],
ActionName=["AddPermission"],
).should.throw(
ClientError,
"An error occurred (NotFound) when calling the AddPermission operation: Topic does not exist",
with pytest.raises(ClientError) as client_err:
client.add_permission(
TopicArn=topic_arn + "-not-existing",
Label="test-2",
AWSAccountId=["999999999999"],
ActionName=["AddPermission"],
)
assert client_err.value.response["Error"]["Code"] == "NotFound"
assert client_err.value.response["Error"]["Message"] == "Topic does not exist"
with pytest.raises(ClientError) as client_err:
client.add_permission(
TopicArn=topic_arn,
Label="test-2",
AWSAccountId=["999999999999"],
ActionName=["NotExistingAction"],
)
assert client_err.value.response["Error"]["Message"] == (
"Policy statement action out of service scope!"
)
client.add_permission.when.called_with(
TopicArn=topic_arn,
Label="test-2",
AWSAccountId=["999999999999"],
ActionName=["NotExistingAction"],
).should.throw(ClientError, "Policy statement action out of service scope!")
@mock_sns
def test_remove_permission_errors():
@ -404,12 +401,11 @@ def test_remove_permission_errors():
ActionName=["Publish"],
)
client.remove_permission.when.called_with(
TopicArn=topic_arn + "-not-existing", Label="test"
).should.throw(
ClientError,
"An error occurred (NotFound) when calling the RemovePermission operation: Topic does not exist",
)
with pytest.raises(ClientError) as client_err:
client.remove_permission(TopicArn=topic_arn + "-not-existing", Label="test")
assert client_err.value.response["Error"]["Code"] == "NotFound"
assert client_err.value.response["Error"]["Message"] == "Topic does not exist"
@mock_sns
@ -421,14 +417,14 @@ def test_tag_topic():
conn.tag_resource(
ResourceArn=topic_arn, Tags=[{"Key": "tag_key_1", "Value": "tag_value_1"}]
)
conn.list_tags_for_resource(ResourceArn=topic_arn)["Tags"].should.equal(
assert conn.list_tags_for_resource(ResourceArn=topic_arn)["Tags"] == (
[{"Key": "tag_key_1", "Value": "tag_value_1"}]
)
conn.tag_resource(
ResourceArn=topic_arn, Tags=[{"Key": "tag_key_2", "Value": "tag_value_2"}]
)
conn.list_tags_for_resource(ResourceArn=topic_arn)["Tags"].should.equal(
assert conn.list_tags_for_resource(ResourceArn=topic_arn)["Tags"] == (
[
{"Key": "tag_key_1", "Value": "tag_value_1"},
{"Key": "tag_key_2", "Value": "tag_value_2"},
@ -438,7 +434,7 @@ def test_tag_topic():
conn.tag_resource(
ResourceArn=topic_arn, Tags=[{"Key": "tag_key_1", "Value": "tag_value_X"}]
)
conn.list_tags_for_resource(ResourceArn=topic_arn)["Tags"].should.equal(
assert conn.list_tags_for_resource(ResourceArn=topic_arn)["Tags"] == (
[
{"Key": "tag_key_1", "Value": "tag_value_X"},
{"Key": "tag_key_2", "Value": "tag_value_2"},
@ -459,13 +455,13 @@ def test_untag_topic():
topic_arn = response["TopicArn"]
conn.untag_resource(ResourceArn=topic_arn, TagKeys=["tag_key_1"])
conn.list_tags_for_resource(ResourceArn=topic_arn)["Tags"].should.equal(
assert conn.list_tags_for_resource(ResourceArn=topic_arn)["Tags"] == (
[{"Key": "tag_key_2", "Value": "tag_value_2"}]
)
# removing a non existing tag should not raise any error
conn.untag_resource(ResourceArn=topic_arn, TagKeys=["not-existing-tag"])
conn.list_tags_for_resource(ResourceArn=topic_arn)["Tags"].should.equal(
assert conn.list_tags_for_resource(ResourceArn=topic_arn)["Tags"] == (
[{"Key": "tag_key_2", "Value": "tag_value_2"}]
)
@ -477,9 +473,9 @@ def test_list_tags_for_resource_error():
Name="some-topic-with-tags", Tags=[{"Key": "tag_key_1", "Value": "tag_value_X"}]
)
conn.list_tags_for_resource.when.called_with(
ResourceArn="not-existing-topic"
).should.throw(ClientError, "Resource does not exist")
with pytest.raises(ClientError) as client_err:
conn.list_tags_for_resource(ResourceArn="not-existing-topic")
assert client_err.value.response["Error"]["Message"] == "Resource does not exist"
@mock_sns
@ -490,22 +486,24 @@ def test_tag_resource_errors():
)
topic_arn = response["TopicArn"]
conn.tag_resource.when.called_with(
ResourceArn="not-existing-topic",
Tags=[{"Key": "tag_key_1", "Value": "tag_value_1"}],
).should.throw(ClientError, "Resource does not exist")
with pytest.raises(ClientError) as client_err:
conn.tag_resource(
ResourceArn="not-existing-topic",
Tags=[{"Key": "tag_key_1", "Value": "tag_value_1"}],
)
assert client_err.value.response["Error"]["Message"] == "Resource does not exist"
too_many_tags = [
{"Key": f"tag_key_{i}", "Value": f"tag_value_{i}"} for i in range(51)
]
conn.tag_resource.when.called_with(
ResourceArn=topic_arn, Tags=too_many_tags
).should.throw(
ClientError, "Could not complete request: tag quota of per resource exceeded"
with pytest.raises(ClientError) as client_err:
conn.tag_resource(ResourceArn=topic_arn, Tags=too_many_tags)
assert client_err.value.response["Error"]["Message"] == (
"Could not complete request: tag quota of per resource exceeded"
)
# when the request fails, the tags should not be updated
conn.list_tags_for_resource(ResourceArn=topic_arn)["Tags"].should.equal(
assert conn.list_tags_for_resource(ResourceArn=topic_arn)["Tags"] == (
[{"Key": "tag_key_1", "Value": "tag_value_X"}]
)
@ -517,9 +515,9 @@ def test_untag_resource_error():
Name="some-topic-with-tags", Tags=[{"Key": "tag_key_1", "Value": "tag_value_X"}]
)
conn.untag_resource.when.called_with(
ResourceArn="not-existing-topic", TagKeys=["tag_key_1"]
).should.throw(ClientError, "Resource does not exist")
with pytest.raises(ClientError) as client_err:
conn.untag_resource(ResourceArn="not-existing-topic", TagKeys=["tag_key_1"])
assert client_err.value.response["Error"]["Message"] == "Resource does not exist"
@mock_sns
@ -534,29 +532,32 @@ def test_create_fifo_topic():
try:
conn.create_topic(Name="test_topic", Attributes={"FifoTopic": "true"})
except ClientError as err:
err.response["Error"]["Code"].should.equal("InvalidParameterValue")
err.response["Error"]["Message"].should.equal(
"Fifo Topic names must end with .fifo and must be made up of only uppercase and lowercase ASCII letters, "
"numbers, underscores, and hyphens, and must be between 1 and 256 characters long."
assert err.response["Error"]["Code"] == "InvalidParameterValue"
assert err.response["Error"]["Message"] == (
"Fifo Topic names must end with .fifo and must be made up of only "
"uppercase and lowercase ASCII letters, numbers, underscores, "
"and hyphens, and must be between 1 and 256 characters long."
)
err.response["Error"]["Type"].should.equal("Sender")
assert err.response["Error"]["Type"] == "Sender"
try:
conn.create_topic(Name="test_topic.fifo")
except ClientError as err:
err.response["Error"]["Code"].should.equal("InvalidParameterValue")
err.response["Error"]["Message"].should.equal(
"Topic names must be made up of only uppercase and lowercase ASCII letters, numbers, underscores, "
assert err.response["Error"]["Code"] == "InvalidParameterValue"
assert err.response["Error"]["Message"] == (
"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."
)
try:
conn.create_topic(Name="topic.name.fifo", Attributes={"FifoTopic": "true"})
except ClientError as err:
err.response["Error"]["Code"].should.equal("InvalidParameterValue")
err.response["Error"]["Message"].should.equal(
"Fifo Topic names must end with .fifo and must be made up of only uppercase and lowercase ASCII letters, "
"numbers, underscores, and hyphens, and must be between 1 and 256 characters long."
assert err.response["Error"]["Code"] == "InvalidParameterValue"
assert err.response["Error"]["Message"] == (
"Fifo Topic names must end with .fifo and must be made up of only "
"uppercase and lowercase ASCII letters, numbers, underscores, "
"and hyphens, and must be between 1 and 256 characters long."
)
@ -566,22 +567,22 @@ def test_topic_kms_master_key_id_attribute():
resp = client.create_topic(Name="test-sns-no-key-attr")
topic_arn = resp["TopicArn"]
resp = client.get_topic_attributes(TopicArn=topic_arn)
resp["Attributes"].should_not.have.key("KmsMasterKeyId")
assert "KmsMasterKeyId" not in resp["Attributes"]
client.set_topic_attributes(
TopicArn=topic_arn, AttributeName="KmsMasterKeyId", AttributeValue="test-key"
)
resp = client.get_topic_attributes(TopicArn=topic_arn)
resp["Attributes"].should.have.key("KmsMasterKeyId")
resp["Attributes"]["KmsMasterKeyId"].should.equal("test-key")
assert "KmsMasterKeyId" in resp["Attributes"]
assert resp["Attributes"]["KmsMasterKeyId"] == "test-key"
resp = client.create_topic(
Name="test-sns-with-key-attr", Attributes={"KmsMasterKeyId": "key-id"}
)
topic_arn = resp["TopicArn"]
resp = client.get_topic_attributes(TopicArn=topic_arn)
resp["Attributes"].should.have.key("KmsMasterKeyId")
resp["Attributes"]["KmsMasterKeyId"].should.equal("key-id")
assert "KmsMasterKeyId" in resp["Attributes"]
assert resp["Attributes"]["KmsMasterKeyId"] == "key-id"
@mock_sns
@ -593,11 +594,11 @@ def test_topic_fifo_get_attributes():
topic_arn = resp["TopicArn"]
attributes = client.get_topic_attributes(TopicArn=topic_arn)["Attributes"]
attributes.should.have.key("FifoTopic")
attributes.should.have.key("ContentBasedDeduplication")
assert "FifoTopic" in attributes
assert "ContentBasedDeduplication" in attributes
attributes["FifoTopic"].should.equal("true")
attributes["ContentBasedDeduplication"].should.equal("false")
assert attributes["FifoTopic"] == "true"
assert attributes["ContentBasedDeduplication"] == "false"
client.set_topic_attributes(
TopicArn=topic_arn,
@ -605,7 +606,7 @@ def test_topic_fifo_get_attributes():
AttributeValue="true",
)
attributes = client.get_topic_attributes(TopicArn=topic_arn)["Attributes"]
attributes["ContentBasedDeduplication"].should.equal("true")
assert attributes["ContentBasedDeduplication"] == "true"
@mock_sns
@ -615,8 +616,8 @@ def test_topic_get_attributes():
topic_arn = resp["TopicArn"]
attributes = client.get_topic_attributes(TopicArn=topic_arn)["Attributes"]
attributes.should_not.have.key("FifoTopic")
attributes.should_not.have.key("ContentBasedDeduplication")
assert "FifoTopic" not in attributes
assert "ContentBasedDeduplication" not in attributes
@mock_sns
@ -628,5 +629,5 @@ def test_topic_get_attributes_with_fifo_false():
topic_arn = resp["TopicArn"]
attributes = client.get_topic_attributes(TopicArn=topic_arn)["Attributes"]
attributes.should_not.have.key("FifoTopic")
attributes.should_not.have.key("ContentBasedDeduplication")
assert "FifoTopic" not in attributes
assert "ContentBasedDeduplication" not in attributes

View File

@ -1,6 +1,7 @@
from moto.sns.utils import FilterPolicyMatcher
import pytest
from moto.sns.utils import FilterPolicyMatcher
def test_filter_policy_matcher_scope_sanity_check():
with pytest.raises(FilterPolicyMatcher.CheckException):