Repository: getmoto/moto

Issue:
SNS.create_topic should be indempodent
Per the [AWS SNS documentation](http://docs.aws.amazon.com/sns/latest/api/API_CreateTopic.html) the CreateTopic action should be idempotent.

Expected:
- create_topic should not overwrite an existing topic which already exists

Results:
- topic is overwritten without checking if topic already exists
- https://github.com/spulec/moto/blob/master/moto/sns/models.py#L197

Failing example test code:
```python
import boto3, os, logging, moto
from unittest import TestCase

@moto.mock_sns
@moto.mock_sqs
class MotoSNSTopicsShouldBeIndempodent(TestCase):
    '''
    Reproduction steps:
        1) SNS Topic is created
        2) SQS queue is subscribed to SNS Topic
        3) create_topic() is called
        4) SQS queue is not subscribed to SNS Topic as it should
    '''
    def setUp(self):
        logging.getLogger('boto3').setLevel(logging.CRITICAL)
        logging.getLogger('botocore').setLevel(logging.CRITICAL)
        logging.getLogger('nose').setLevel(logging.CRITICAL)

        self.queueName = "ReceivingQueue"
        self.topicName = "PublishingTopic"
        self.sqs_client = boto3.client("sqs")
        self.sns_client = boto3.client("sns")

        # 1) SNS Topic is created
        self.sns_topic_arn = self.sns_client.create_topic(Name=self.topicName)['TopicArn']
        self.sqs_queue = self.sqs_client.create_queue(QueueName=self.queueName)['QueueUrl']


        sqs_queue_attr = self.sqs_client.get_queue_attributes(
            QueueUrl = self.sqs_queue,
            AttributeNames = ['QueueArn']
        )

        self.sqs_queue_arn = sqs_queue_attr['Attributes']['QueueArn']
        # 2) SQS queue is subscribed to SNS Topic
        subscribe = self.sns_client.subscribe(
            TopicArn = self.sns_topic_arn,
            Protocol = 'sqs',
            Endpoint = self.sqs_queue_arn
        )

    def test_publish_message_create_topic_publish_message(self):
        self.sns_client.publish(TopicArn=self.sns_topic_arn, Message="message one")
        self.assertEqual(1, self._get_number_of_messages() )
        #one message published; one received by sqs
        #3) create_topic() is called
        self.sns_client.create_topic(Name=self.topicName)
        self.sns_client.publish(TopicArn=self.sns_topic_arn, Message="message two")
        self.assertEqual(2, self._get_number_of_messages() )
        #4) SQS queue is not subscribed to SNS Topic as it should
        #should return 2 but, 1 is returned

    def _get_number_of_messages(self):
        return int(self.sqs_client.get_queue_attributes(
            QueueUrl = self.sqs_queue,
            AttributeNames = ['ApproximateNumberOfMessages']
        )['Attributes']['ApproximateNumberOfMessages'])
```

I'm working on a PR now


Discussion:
Good spot, should be an easy fix :smile:

Resolving patch:
diff --git a/moto/sns/models.py b/moto/sns/models.py
--- a/moto/sns/models.py
+++ b/moto/sns/models.py
@@ -193,9 +193,12 @@ def update_sms_attributes(self, attrs):
         self.sms_attributes.update(attrs)
 
     def create_topic(self, name):
-        topic = Topic(name, self)
-        self.topics[topic.arn] = topic
-        return topic
+        candidate_topic = Topic(name, self)
+        if candidate_topic.arn in self.topics:
+            return self.topics[candidate_topic.arn]
+        else:
+            self.topics[candidate_topic.arn] = candidate_topic
+            return candidate_topic
 
     def _get_values_nexttoken(self, values_map, next_token=None):
         if next_token is None:


Test patch:
diff --git a/tests/test_sns/test_topics_boto3.py b/tests/test_sns/test_topics_boto3.py
--- a/tests/test_sns/test_topics_boto3.py
+++ b/tests/test_sns/test_topics_boto3.py
@@ -31,6 +31,29 @@ def test_create_and_delete_topic():
     topics = topics_json["Topics"]
     topics.should.have.length_of(0)
 
+@mock_sns
+def test_create_topic_should_be_indempodent():
+    conn = boto3.client("sns", region_name="us-east-1")
+    topic_arn = conn.create_topic(Name="some-topic")['TopicArn']
+    conn.set_topic_attributes(
+        TopicArn=topic_arn,
+        AttributeName="DisplayName",
+        AttributeValue="should_be_set"
+    )
+    topic_display_name = conn.get_topic_attributes(
+        TopicArn=topic_arn
+    )['Attributes']['DisplayName']
+    topic_display_name.should.be.equal("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")
+
+
 
 @mock_sns
 def test_get_missing_topic():