Repository: localstack/localstack

Issue:
Unable to send SMS with SNS
```
peter@nefilim ~ $ aws --endpoint-url=http://localhost:4575 sns publish --message="hello world" --phone-number="+15551239110"
An error occurred (NotFound) when calling the Publish operation: Topic does not exist
```

this works perfectly fine against AWS, from the docs:

```
       --phone-number (string)
          The phone number to which you want to deliver an  SMS  message.  Use
          E.164 format.

          If you don't specify a value for the PhoneNumber parameter, you must
          specify a value for the TargetArn or TopicArn parameters.
```


Discussion:
Recently a change was made in order to force a topic to exist before publising in it #1331.
I think we need to check that a phone-number is not in the request data before throwing this exception. Do you have time to write a PR for this ? If not I can do It early next week I think.

Resolving patch:
diff --git a/localstack/services/sns/sns_listener.py b/localstack/services/sns/sns_listener.py
--- a/localstack/services/sns/sns_listener.py
+++ b/localstack/services/sns/sns_listener.py
@@ -64,9 +64,12 @@ def forward_request(self, method, path, data, headers):
             elif req_action == 'DeleteTopic':
                 do_delete_topic(topic_arn)
             elif req_action == 'Publish':
-                if topic_arn not in SNS_SUBSCRIPTIONS.keys():
-                    return make_error(code=404, code_string='NotFound', message='Topic does not exist')
-                publish_message(topic_arn, req_data)
+                # No need to create a topic to send SMS with SNS
+                # but we can't mock a sending so we only return that it went well
+                if 'PhoneNumber' not in req_data:
+                    if topic_arn not in SNS_SUBSCRIPTIONS.keys():
+                        return make_error(code=404, code_string='NotFound', message='Topic does not exist')
+                    publish_message(topic_arn, req_data)
                 # return response here because we do not want the request to be forwarded to SNS backend
                 return make_response(req_action)
 


Test patch:
diff --git a/tests/integration/test_sns.py b/tests/integration/test_sns.py
--- a/tests/integration/test_sns.py
+++ b/tests/integration/test_sns.py
@@ -11,78 +11,75 @@
 TEST_TOPIC_NAME = 'TestTopic_snsTest'
 TEST_QUEUE_NAME = 'TestQueue_snsTest'
 
-TEST_TOPIC_RAW_NAME = 'TestTopic_snsTest_raw'
-TEST_QUEUE_RAW_NAME = 'TestQueue_snsTest_raw'
-
 
 class SNSTest(unittest.TestCase):
 
-    def test_publish_unicode_chars(self):
-        sqs_client = aws_stack.connect_to_service('sqs')
-        sns_client = aws_stack.connect_to_service('sns')
+    def setUp(self):
+        self.sqs_client = aws_stack.connect_to_service('sqs')
+        self.sns_client = aws_stack.connect_to_service('sns')
+        self.topic_arn = self.sns_client.create_topic(Name=TEST_TOPIC_NAME)['TopicArn']
+        self.queue_url = self.sqs_client.create_queue(QueueName=TEST_QUEUE_NAME)['QueueUrl']
 
-        # create SNS topic and connect it to an SQS queue
-        topic = sns_client.create_topic(Name=TEST_TOPIC_NAME)
-        queue = sqs_client.create_queue(QueueName=TEST_QUEUE_NAME)
-        topic_arn = topic['TopicArn']
-        queue_url = queue['QueueUrl']
+    def tearDown(self):
+        self.sqs_client.delete_queue(QueueUrl=self.queue_url)
+        self.sns_client.delete_topic(TopicArn=self.topic_arn)
+
+    def test_publish_unicode_chars(self):
+        # connect the SNS topic to the SQS queue
         queue_arn = aws_stack.sqs_queue_arn(TEST_QUEUE_NAME)
-        sns_client.subscribe(TopicArn=topic_arn, Protocol='sqs', Endpoint=queue_arn)
+        self.sns_client.subscribe(TopicArn=self.topic_arn, Protocol='sqs', Endpoint=queue_arn)
 
         # publish message to SNS, receive it from SQS, assert that messages are equal
         message = u'ö§a1"_!?,. £$-'
-        sns_client.publish(TopicArn=topic_arn, Message=message)
-        msgs = sqs_client.receive_message(QueueUrl=queue_url)
+        self.sns_client.publish(TopicArn=self.topic_arn, Message=message)
+        msgs = self.sqs_client.receive_message(QueueUrl=self.queue_url)
         msg_received = msgs['Messages'][0]
         msg_received = json.loads(to_str(msg_received['Body']))
         msg_received = msg_received['Message']
         self.assertEqual(message, msg_received)
 
     def test_attribute_raw_subscribe(self):
-        sqs_client = aws_stack.connect_to_service('sqs')
-        sns_client = aws_stack.connect_to_service('sns')
-
         # create SNS topic and connect it to an SQS queue
-        topic = sns_client.create_topic(Name=TEST_TOPIC_RAW_NAME)
-        queue = sqs_client.create_queue(QueueName=TEST_QUEUE_RAW_NAME)
-        topic_arn = topic['TopicArn']
-        queue_url = queue['QueueUrl']
-        queue_arn = aws_stack.sqs_queue_arn(TEST_QUEUE_RAW_NAME)
-        sns_client.subscribe(
-            TopicArn=topic_arn,
+        queue_arn = aws_stack.sqs_queue_arn(TEST_QUEUE_NAME)
+        self.sns_client.subscribe(
+            TopicArn=self.topic_arn,
             Protocol='sqs',
             Endpoint=queue_arn,
             Attributes={'RawMessageDelivery': 'true'}
         )
 
         # fetch subscription information
-        subscription_list = sns_client.list_subscriptions()
+        subscription_list = self.sns_client.list_subscriptions()
 
         subscription_arn = ''
         for subscription in subscription_list['Subscriptions']:
-            if subscription['TopicArn'] == topic_arn:
+            if subscription['TopicArn'] == self.topic_arn:
                 subscription_arn = subscription['SubscriptionArn']
-        actual_attributes = sns_client.get_subscription_attributes(SubscriptionArn=subscription_arn)['Attributes']
+        actual_attributes = self.sns_client.get_subscription_attributes(SubscriptionArn=subscription_arn)['Attributes']
 
         # assert the attributes are well set
         self.assertTrue(actual_attributes['RawMessageDelivery'])
 
         # publish message to SNS, receive it from SQS, assert that messages are equal and that they are Raw
         message = u'This is a test message'
-        sns_client.publish(TopicArn=topic_arn, Message=message)
+        self.sns_client.publish(TopicArn=self.topic_arn, Message=message)
 
-        msgs = sqs_client.receive_message(QueueUrl=queue_url)
+        msgs = self.sqs_client.receive_message(QueueUrl=self.queue_url)
         msg_received = msgs['Messages'][0]
         self.assertEqual(message, msg_received['Body'])
 
     def test_unknown_topic_publish(self):
-        sns_client = aws_stack.connect_to_service('sns')
         fake_arn = 'arn:aws:sns:us-east-1:123456789012:i_dont_exist'
         message = u'This is a test message'
         try:
-            sns_client.publish(TopicArn=fake_arn, Message=message)
+            self.sns_client.publish(TopicArn=fake_arn, Message=message)
             self.fail('This call should not be successful as the topic does not exist')
         except ClientError as e:
             self.assertEqual(e.response['Error']['Code'], 'NotFound')
             self.assertEqual(e.response['Error']['Message'], 'Topic does not exist')
             self.assertEqual(e.response['ResponseMetadata']['HTTPStatusCode'], 404)
+
+    def test_publish_sms(self):
+        response = self.sns_client.publish(PhoneNumber='+33000000000', Message='This is a SMS')
+        self.assertTrue('MessageId' in response)
+        self.assertEqual(response['ResponseMetadata']['HTTPStatusCode'], 200)