Skip to content

Commit

Permalink
Add @SqsTest annotation. (#235)
Browse files Browse the repository at this point in the history
  • Loading branch information
maciejwalkowiak authored Feb 14, 2022
1 parent cb1adcc commit f1692dd
Show file tree
Hide file tree
Showing 21 changed files with 828 additions and 40 deletions.
8 changes: 8 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
<module>spring-cloud-aws-integration-test</module>
<module>docs</module>
<module>spring-cloud-aws-samples</module>
<module>spring-cloud-aws-test</module>
</modules>

<dependencyManagement>
Expand Down Expand Up @@ -105,6 +106,13 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>1.16.3</version>

This comment has been minimized.

Copy link
@driverpt

driverpt Feb 19, 2022

Shouldn't this go into <properties> ?

<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down
5 changes: 5 additions & 0 deletions spring-cloud-aws-dependencies/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@
<artifactId>spring-cloud-aws-ses</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.awspring.cloud</groupId>
<artifactId>spring-cloud-aws-test</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<profiles>
Expand Down
24 changes: 21 additions & 3 deletions spring-cloud-aws-samples/spring-cloud-aws-sqs-sample/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
<artifactId>spring-boot-starter-json</artifactId>
</dependency>

<dependency>
<groupId>io.awspring.cloud</groupId>
<artifactId>spring-cloud-starter-aws-messaging</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand All @@ -30,14 +35,27 @@

<dependency>
<groupId>io.awspring.cloud</groupId>
<artifactId>spring-cloud-starter-aws-messaging</artifactId>
<artifactId>spring-cloud-aws-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>localstack</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2013-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.awspring.cloud.sqs.sample;

import java.time.LocalDate;

import io.awspring.cloud.messaging.core.QueueMessagingTemplate;

import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;

@Component
class MessageSender {

private final QueueMessagingTemplate queueMessagingTemplate;

MessageSender(QueueMessagingTemplate queueMessagingTemplate) {
this.queueMessagingTemplate = queueMessagingTemplate;
}

@EventListener(ApplicationReadyEvent.class)
public void sendMessage() {
this.queueMessagingTemplate.send("InfrastructureStack-spring-aws",
MessageBuilder.withPayload("Spring cloud Aws SQS sample!").build());
this.queueMessagingTemplate.convertAndSend("InfrastructureStack-aws-pojo",
new Person("Joe", "Doe", LocalDate.of(2000, 1, 12)));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2013-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.awspring.cloud.sqs.sample;

import io.awspring.cloud.messaging.listener.annotation.SqsListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Component;

@Component
class SampleListener {

private static final Logger LOGGER = LoggerFactory.getLogger(SampleListener.class);

@SqsListener("InfrastructureStack-spring-aws")
public void listenToMessage(String message) {
LOGGER.info("This is message you want to see: {}", message);
}

@SqsListener("InfrastructureStack-aws-pojo")
public void listenToPerson(Person person) {
LOGGER.info(person.toString());
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2013-2021 the original author or authors.
* Copyright 2013-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,50 +16,14 @@

package io.awspring.cloud.sqs.sample;

import java.time.LocalDate;

import io.awspring.cloud.messaging.core.QueueMessagingTemplate;
import io.awspring.cloud.messaging.listener.annotation.SqsListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.messaging.support.MessageBuilder;

@SpringBootApplication
public class SqsSampleApplication {

private final QueueMessagingTemplate queueMessagingTemplate;

SqsSampleApplication(QueueMessagingTemplate queueMessagingTemplate) {
this.queueMessagingTemplate = queueMessagingTemplate;
}

private static final Logger LOGGER = LoggerFactory.getLogger(SqsSampleApplication.class);

public static void main(String[] args) {
SpringApplication.run(SqsSampleApplication.class, args);
}

@EventListener(ApplicationReadyEvent.class)
public void sendMessage() {
this.queueMessagingTemplate.send("InfrastructureStack-spring-aws",
MessageBuilder.withPayload("Spring cloud Aws SQS sample!").build());
this.queueMessagingTemplate.convertAndSend("InfrastructureStack-aws-pojo",
new Person("Joe", "Doe", LocalDate.of(2000, 1, 12)));
}

@SqsListener("InfrastructureStack-spring-aws")
private void listenToMessage(String message) {
LOGGER.info("This is message you want to see: {}", message);
}

@SqsListener("InfrastructureStack-aws-pojo")
private void listenToPerson(Person person) {
LOGGER.info(person.toString());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright 2013-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.awspring.cloud.sqs.sample;

import java.io.IOException;

import io.awspring.cloud.messaging.core.QueueMessagingTemplate;
import io.awspring.cloud.test.sqs.SqsTest;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.localstack.LocalStackContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;

import static org.awaitility.Awaitility.await;
import static org.mockito.Mockito.verify;
import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SQS;

@SqsTest(properties = { "cloud.aws.credentials.access-key=noop", "cloud.aws.credentials.secret-key=noop",
"cloud.aws.region.static=eu-west-1" })
@Testcontainers
class SqsSampleApplicationTests {

This comment has been minimized.

Copy link
@driverpt

driverpt Feb 19, 2022

This runs best when this follows maven-failsafe-plugin


private static final String QUEUE_NAME = "InfrastructureStack-spring-aws";

// create an SQS locally running equivalent with Localstack and Testcontainers
@Container
static LocalStackContainer localstack = new LocalStackContainer(
DockerImageName.parse("localstack/localstack:0.14.0")).withServices(SQS).withReuse(true);

@Autowired
private QueueMessagingTemplate queueMessagingTemplate;

@SpyBean
private SampleListener sampleListener;

@BeforeAll
static void beforeAll() throws IOException, InterruptedException {
// create needed queues in SQS
localstack.execInContainer("awslocal", "sqs", "create-queue", "--queue-name", QUEUE_NAME);

This comment has been minimized.

Copy link
@driverpt

driverpt Feb 19, 2022

Why not just use SqsClient.createQueue ?

Also, why static and @BeforeAll ? I recommend creating in @BeforeEach and deleting in @AfterEach to ensure test data immutability

}

@Test
void receivesMessage() {
// send a message
queueMessagingTemplate.convertAndSend(QUEUE_NAME, "hello");

// verify that bean handling the message was invoked
await().untilAsserted(() -> verify(sampleListener).listenToMessage("hello"));

This comment has been minimized.

Copy link
@driverpt

driverpt Feb 19, 2022

By my experience, if you add more tests, this can start to go bad, because @SqsListener runs on separate Thread and you lose control. I suggest adding @DirtiesContext

}

@DynamicPropertySource
static void registerSqsProperties(DynamicPropertyRegistry registry) {
// overwrite SQS endpoint with one provided by Localstack
registry.add("cloud.aws.sqs.endpoint", () -> localstack.getEndpointOverride(SQS).toString());

This comment has been minimized.

Copy link
@driverpt

driverpt Feb 19, 2022

You should also add secretKey, accessKeyId and region

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>

<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>

<logger name="org.testcontainers" level="INFO"/>
<logger name="com.github.dockerjava" level="WARN"/>
<logger name="io.awspring" level="INFO"/>
</configuration>
78 changes: 78 additions & 0 deletions spring-cloud-aws-test/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2019 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.awspring.cloud</groupId>
<artifactId>spring-cloud-aws</artifactId>
<version>2.4.0-SNAPSHOT</version>
</parent>
<artifactId>spring-cloud-aws-test</artifactId>
<name>Spring Cloud AWS Test</name>
<description>Spring Cloud AWS Test</description>
<url>https://projects.spring.io/spring-cloud</url>

<properties>
<main.basedir>${basedir}/../..</main.basedir>
</properties>
<dependencies>
<dependency>
<groupId>io.awspring.cloud</groupId>
<artifactId>spring-cloud-aws-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>io.awspring.cloud</groupId>
<artifactId>spring-cloud-aws-messaging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
</dependency>

<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>localstack</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Loading

0 comments on commit f1692dd

Please sign in to comment.