How to test AWS SNS locally?

2020-06-03 08:44发布

问题:

I want to use Amazon SNS service. And I want to have an ability to subscribe an http rest to SNS topic to receive notifications.

However locally my application has URL as localhost So it's impossible for me to test application behavior locally.

I found one article about using ngrok server, to use some public IP instead of local.

However it doesn't seem to be a good solution for me.

Do you have any ideas how I could have a working SNS subscriber locally?

回答1:

You could also use ngrok to expose your localhost publicly.

They way it works is it creates a subdomain dynamically and tunnels all request to your machine on the desired port.

Picture this scenario, I have a nginx running on localhost:8080. I open my terminal and run ngrok 8080, it will take my terminal session and log my public url, like 'as78fh.ngrok.com'.

If I go on another computer, open the browser and navigate to as78fh.ngrok.com/register the request gets served from my localhost:8080/register through the tunnel back to the internet.

I use it for lots of tricky developments, like email webhooks, github integrations and, of course, amazon sns.



回答2:

Take a look at one of fake SNS implementations in GitHub, such as s12v/sns:

Fake Amazon Simple Notification Service (SNS) for testing. Supports:

  • Create/List/Delete topics
  • Subscribe endpoint
  • Publish message
  • Subscription persistence
  • Integrations with (Fake-)SQS, File, HTTP, RabbitMQ, Slack


回答3:

I like ngrok but you pay to have a fixed external address, if you want to do it for free you could use a spare email account inbox to send Email-JSON sns. Then an IMAP library to access it, read the emails and pipe the data.



回答4:

I wrote a small library that mimics AWS SNS and I think it fits to your needs. Here is an example of the usage in Java:

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.sns.AmazonSNS;
import com.amazonaws.services.sns.AmazonSNSAsyncClientBuilder;
import io.github.gilbertojrequena.bonsai_sns.server.BonsaiSnsEnvironment;
import io.github.gilbertojrequena.bonsai_sns.server.BonsaiSnsServer;
import io.github.gilbertojrequena.bonsai_sns.server.Subscription;
import io.github.gilbertojrequena.bonsai_sns.server.Topic;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class SNSTest {

    private BonsaiSnsServer server;
    private AmazonSNS snsClient;

    @Before
    public void setup() {
        // start your app at 8080

        server = new BonsaiSnsServer.Builder()
            .withAccountId(123456789L)
            .withPort(7979)
            .withRegion("someRegion")
            .withBonsaiSnsEnvironmentDefinition(
                BonsaiSnsEnvironment.Companion.definition()
                    .withTopic(
                        Topic.Companion.definition()
                            .withName("name")
                            .withSubscription(
                                Subscription.Companion.definition()
                                    .withEndpoint("http:/localhost:8080/endpoint")
                                    .withProtocol("http")
                                    .withAttribute("a", "b")
                            )
                    )
            ).start();

        snsClient = AmazonSNSAsyncClientBuilder.standard()
            .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("accessKey", "secretKey")))
            .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration("http://localhost:7979", "someRegion"))
            .build();
    }

    @After
    public void shutdown() {
        server.stop();
    }

    @Test
    public void testSomething() {
        snsClient.publish("arn:aws:sns:someRegion:123456789:name", "message");
        // assertions
    }
}