Reject empty SNS messages
diff --git a/localstack/services/sns/sns_listener.py b/localstack/services/sns/sns_listener.py
index 75183ac4b84c2..5705315300025 100644
--- a/localstack/services/sns/sns_listener.py
+++ b/localstack/services/sns/sns_listener.py
@@ -165,6 +165,12 @@ def forward_request(self, method, path, data, headers):
             elif req_action == "Publish":
                 if req_data.get("Subject") == [""]:
                     return make_error(code=400, code_string="InvalidParameter", message="Subject")
+                if not req_data.get("Message") or all(
+                    not message for message in req_data.get("Message")
+                ):
+                    return make_error(
+                        code=400, code_string="InvalidParameter", message="Empty message"
+                    )
                 sns_backend = SNSBackend.get()
                 # No need to create a topic to send SMS or single push notifications with SNS
                 # but we can't mock a sending so we only return that it went well
diff --git a/tests/integration/fixtures.py b/tests/integration/fixtures.py
index 4f54a72bd35eb..e1b0dc00fb2c3 100644
--- a/tests/integration/fixtures.py
+++ b/tests/integration/fixtures.py
@@ -29,6 +29,7 @@
     from mypy_boto3_secretsmanager import SecretsManagerClient
     from mypy_boto3_ses import SESClient
     from mypy_boto3_sns import SNSClient
+    from mypy_boto3_sns.type_defs import GetTopicAttributesResponseTypeDef
     from mypy_boto3_sqs import SQSClient
     from mypy_boto3_ssm import SSMClient
     from mypy_boto3_stepfunctions import SFNClient
@@ -229,13 +230,29 @@ def sqs_queue(sqs_create_queue):
 
 
 @pytest.fixture
-def sns_topic(sns_client):
-    # TODO: add fixture factories
-    topic_name = "test-topic-%s" % short_uid()
-    response = sns_client.create_topic(Name=topic_name)
-    topic_arn = response["TopicArn"]
-    yield sns_client.get_topic_attributes(TopicArn=topic_arn)
-    sns_client.delete_topic(TopicArn=topic_arn)
+def sns_create_topic(sns_client):
+    topic_arns = []
+
+    def _create_topic(**kwargs):
+        if "Name" not in kwargs:
+            kwargs["Name"] = "test-topic-%s" % short_uid()
+        response = sns_client.create_topic(**kwargs)
+        topic_arns.append(response["TopicArn"])
+        return response
+
+    yield _create_topic
+
+    for topic_arn in topic_arns:
+        try:
+            sns_client.delete_topic(TopicArn=topic_arn)
+        except Exception as e:
+            LOG.debug("error cleaning up topic %s: %s", topic_arn, e)
+
+
+@pytest.fixture
+def sns_topic(sns_client, sns_create_topic) -> "GetTopicAttributesResponseTypeDef":
+    topic_arn = sns_create_topic()["TopicArn"]
+    return sns_client.get_topic_attributes(TopicArn=topic_arn)
 
 
 @pytest.fixture
diff --git a/tests/integration/test_sns.py b/tests/integration/test_sns.py
index e61fcde24f874..7020cff5c6ac5 100644
--- a/tests/integration/test_sns.py
+++ b/tests/integration/test_sns.py
@@ -1068,3 +1068,20 @@ def test_not_found_error_on_get_subscription_attributes(self):
         # cleanup
         self.sns_client.delete_topic(TopicArn=topic_arn)
         self.sqs_client.delete_queue(QueueUrl=queue_url)
+
+
+def test_empty_sns_message(sns_client, sqs_client, sns_topic, sqs_queue):
+    topic_arn = sns_topic["Attributes"]["TopicArn"]
+    queue_arn = sqs_client.get_queue_attributes(QueueUrl=sqs_queue, AttributeNames=["QueueArn"])[
+        "Attributes"
+    ]["QueueArn"]
+    sns_client.subscribe(TopicArn=topic_arn, Protocol="sqs", Endpoint=queue_arn)
+    with pytest.raises(ClientError) as e:
+        sns_client.publish(Message="", TopicArn=topic_arn)
+    assert e.match("Empty message")
+    assert (
+        sqs_client.get_queue_attributes(
+            QueueUrl=sqs_queue, AttributeNames=["ApproximateNumberOfMessages"]
+        )["Attributes"]["ApproximateNumberOfMessages"]
+        == "0"
+    )

Currently, empty SNS messages are permitted, this diverges from AWS behavior.

This PR introduces a check if the message is empty, and adds a test to check if an empty message is successfully rejected.
Also a TODO was acted upon to add a sns_create_topic fixture to create multiple topics if necessary.

Test also passes against AWS.

Fixes #5096 