diff --git a/spring-cloud/pom.xml b/spring-cloud/pom.xml
index fd023a5ea5..e6d78f292d 100644
--- a/spring-cloud/pom.xml
+++ b/spring-cloud/pom.xml
@@ -18,6 +18,7 @@
spring-cloud-gateway
spring-cloud-stream
spring-cloud-connectors-heroku
+ spring-cloud-aws
pom
diff --git a/spring-cloud/spring-cloud-aws/README.md b/spring-cloud/spring-cloud-aws/README.md
new file mode 100644
index 0000000000..c5f58159c8
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/README.md
@@ -0,0 +1,21 @@
+# Spring Cloud AWS
+
+#### Running the Integration Tests
+
+To run the Integration Tests, we need to have an AWS account and have API keys generated for programmatic access. Edit
+the `application.properties` file to add the following properties:
+
+```
+cloud.aws.credentials.accessKey=YourAccessKey
+cloud.aws.credentials.secretKey=YourSecretKey
+cloud.aws.region.static=us-east-1
+```
+
+To test automatic DataSource creation from RDS instance, we also need to create an RDS instance in the AWS account.
+Let's say that the RDS instance is called `spring-cloud-test-db` having the master password `se3retpass`, then we need
+to write the following in `application.properties`:
+
+```
+cloud.aws.rds.spring-cloud-test-db
+cloud.aws.rds.spring-cloud-test-db.password=se3retpass
+```
diff --git a/spring-cloud/spring-cloud-aws/pom.xml b/spring-cloud/spring-cloud-aws/pom.xml
new file mode 100644
index 0000000000..632e050d92
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/pom.xml
@@ -0,0 +1,91 @@
+
+
+ 4.0.0
+
+ com.baeldung.spring.cloud
+ spring-cloud-aws
+ 0.0.1-SNAPSHOT
+ jar
+
+ Spring Cloud AWS
+ Spring Cloud AWS Examples
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 1.5.8.RELEASE
+
+
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ Dalston.SR4
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.cloud
+ spring-cloud-starter-aws
+
+
+ org.springframework.cloud
+ spring-cloud-starter-aws-jdbc
+
+
+ org.springframework.cloud
+ spring-cloud-starter-aws-messaging
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ org.postgresql
+ postgresql
+
+
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring-cloud.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ maven-surefire-plugin
+
+
+ **/*IntegrationTest.java
+
+
+
+
+
+
+
+
+
diff --git a/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/SpringCloudAwsApplication.java b/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/SpringCloudAwsApplication.java
new file mode 100644
index 0000000000..2c3909b3eb
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/SpringCloudAwsApplication.java
@@ -0,0 +1,12 @@
+package com.baeldung.spring.cloud.aws;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SpringCloudAwsApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SpringCloudAwsApplication.class, args);
+ }
+}
diff --git a/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/config/SpringCloudAwsConfig.java b/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/config/SpringCloudAwsConfig.java
new file mode 100644
index 0000000000..85dcd05c86
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/config/SpringCloudAwsConfig.java
@@ -0,0 +1,22 @@
+package com.baeldung.spring.cloud.aws.config;
+
+import com.amazonaws.services.sns.AmazonSNS;
+import com.amazonaws.services.sqs.AmazonSQSAsync;
+import org.springframework.cloud.aws.messaging.core.NotificationMessagingTemplate;
+import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SpringCloudAwsConfig {
+
+ @Bean
+ public QueueMessagingTemplate queueMessagingTemplate(AmazonSQSAsync amazonSQSAsync) {
+ return new QueueMessagingTemplate(amazonSQSAsync);
+ }
+
+ @Bean
+ public NotificationMessagingTemplate notificationMessagingTemplate(AmazonSNS amazonSNS) {
+ return new NotificationMessagingTemplate(amazonSNS);
+ }
+}
diff --git a/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/s3/SpringCloudS3.java b/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/s3/SpringCloudS3.java
new file mode 100644
index 0000000000..cfad6e904f
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/s3/SpringCloudS3.java
@@ -0,0 +1,52 @@
+package com.baeldung.spring.cloud.aws.s3;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.core.io.WritableResource;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+
+@Component
+public class SpringCloudS3 {
+
+ @Autowired
+ ResourceLoader resourceLoader;
+
+ @Autowired
+ ResourcePatternResolver resourcePatternResolver;
+
+ public void downloadS3Object(String s3Url) throws IOException {
+ Resource resource = resourceLoader.getResource(s3Url);
+ File downloadedS3Object = new File(resource.getFilename());
+ try (InputStream inputStream = resource.getInputStream()) {
+ Files.copy(inputStream, downloadedS3Object.toPath(), StandardCopyOption.REPLACE_EXISTING);
+ }
+ }
+
+ public void uploadFileToS3(File file, String s3Url) throws IOException {
+ WritableResource resource = (WritableResource) resourceLoader.getResource(s3Url);
+ try (OutputStream outputStream = resource.getOutputStream()) {
+ Files.copy(file.toPath(), outputStream);
+ }
+ }
+
+ public void downloadMultipleS3Objects(String s3UrlPattern) throws IOException {
+ Resource[] allFileMatchingPatten = this.resourcePatternResolver.getResources(s3UrlPattern);
+ for (Resource resource : allFileMatchingPatten) {
+ String fileName = resource.getFilename();
+ fileName = fileName.substring(0, fileName.lastIndexOf("/") + 1);
+ File downloadedS3Object = new File(fileName);
+ try (InputStream inputStream = resource.getInputStream()) {
+ Files.copy(inputStream, downloadedS3Object.toPath(), StandardCopyOption.REPLACE_EXISTING);
+ }
+ }
+ }
+}
diff --git a/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/sns/SNSEndpointController.java b/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/sns/SNSEndpointController.java
new file mode 100644
index 0000000000..7c78fcbe37
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/sns/SNSEndpointController.java
@@ -0,0 +1,36 @@
+package com.baeldung.spring.cloud.aws.sns;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.aws.messaging.config.annotation.NotificationMessage;
+import org.springframework.cloud.aws.messaging.config.annotation.NotificationSubject;
+import org.springframework.cloud.aws.messaging.endpoint.NotificationStatus;
+import org.springframework.cloud.aws.messaging.endpoint.annotation.NotificationMessageMapping;
+import org.springframework.cloud.aws.messaging.endpoint.annotation.NotificationSubscriptionMapping;
+import org.springframework.cloud.aws.messaging.endpoint.annotation.NotificationUnsubscribeConfirmationMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/topic-subscriber")
+public class SNSEndpointController {
+
+ private static final Logger logger = LoggerFactory.getLogger(SNSEndpointController.class);
+
+ @NotificationMessageMapping
+ public void receiveNotification(@NotificationMessage String message, @NotificationSubject String subject) {
+ logger.info("Received message: {}, having subject: {}", message, subject);
+ }
+
+ @NotificationUnsubscribeConfirmationMapping
+ public void confirmSubscriptionMessage(NotificationStatus notificationStatus) {
+ logger.info("Unsubscribed from Topic");
+ notificationStatus.confirmSubscription();
+ }
+
+ @NotificationSubscriptionMapping
+ public void confirmUnsubscribeMessage(NotificationStatus notificationStatus) {
+ logger.info("Subscribed to Topic");
+ notificationStatus.confirmSubscription();
+ }
+}
diff --git a/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/sns/SNSMessageSender.java b/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/sns/SNSMessageSender.java
new file mode 100644
index 0000000000..58cb03644b
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/sns/SNSMessageSender.java
@@ -0,0 +1,16 @@
+package com.baeldung.spring.cloud.aws.sns;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.aws.messaging.core.NotificationMessagingTemplate;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SNSMessageSender {
+
+ @Autowired
+ NotificationMessagingTemplate notificationMessagingTemplate;
+
+ public void send(String topicName, Object message, String subject) {
+ notificationMessagingTemplate.sendNotification(topicName, message, subject);
+ }
+}
diff --git a/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/sqs/SpringCloudSQS.java b/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/sqs/SpringCloudSQS.java
new file mode 100644
index 0000000000..d2a5fcf9ca
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/main/java/com/baeldung/spring/cloud/aws/sqs/SpringCloudSQS.java
@@ -0,0 +1,46 @@
+package com.baeldung.spring.cloud.aws.sqs;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
+import org.springframework.cloud.aws.messaging.listener.annotation.SqsListener;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.messaging.handler.annotation.Header;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.CountDownLatch;
+
+@Component
+@Lazy
+public class SpringCloudSQS {
+
+ private static final Logger logger = LoggerFactory.getLogger(SpringCloudSQS.class);
+
+ static final String QUEUE_NAME = "spring-cloud-test-queue";
+
+ /*
+ * CountDownLatch is added to wait for messages
+ * during integration test
+ */
+ CountDownLatch countDownLatch;
+
+ public void setCountDownLatch(CountDownLatch countDownLatch) {
+ this.countDownLatch = countDownLatch;
+ }
+
+ @Autowired
+ QueueMessagingTemplate queueMessagingTemplate;
+
+ @SqsListener(QUEUE_NAME)
+ public void receiveMessage(String message, @Header("SenderId") String senderId) {
+ logger.info("Received message: {}, having SenderId: {}", message, senderId);
+ if (countDownLatch != null) {
+ countDownLatch.countDown();
+ }
+ }
+
+ public void send(String queueName, Object message) {
+ queueMessagingTemplate.convertAndSend(queueName, message);
+ }
+}
diff --git a/spring-cloud/spring-cloud-aws/src/main/resources/application.properties b/spring-cloud/spring-cloud-aws/src/main/resources/application.properties
new file mode 100644
index 0000000000..a769b70ddd
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/main/resources/application.properties
@@ -0,0 +1,14 @@
+cloud.aws.credentials.accessKey=YourAccessKey
+cloud.aws.credentials.secretKey=YourSecretKey
+cloud.aws.region.static=us-east-1
+
+cloud.aws.rds.spring-cloud-test-db
+cloud.aws.rds.spring-cloud-test-db.password=se3retpass
+
+# These 3 properties are optional
+cloud.aws.rds.spring-cloud-test-db.username=testuser
+cloud.aws.rds.spring-cloud-test-db.readReplicaSupport=true
+cloud.aws.rds.spring-cloud-test-db.databaseName=test
+
+# Disable auto cloudfromation
+cloud.aws.stack.auto=false
diff --git a/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/SpringCloudAwsTestUtil.java b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/SpringCloudAwsTestUtil.java
new file mode 100644
index 0000000000..fe10eb6f15
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/SpringCloudAwsTestUtil.java
@@ -0,0 +1,73 @@
+package com.baeldung.spring.cloud.aws;
+
+import com.amazonaws.auth.AWSCredentials;
+import com.amazonaws.auth.AWSCredentialsProvider;
+import com.amazonaws.auth.AWSStaticCredentialsProvider;
+import com.amazonaws.auth.BasicAWSCredentials;
+import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.s3.AmazonS3ClientBuilder;
+import com.amazonaws.services.sns.AmazonSNS;
+import com.amazonaws.services.sns.AmazonSNSClientBuilder;
+import com.amazonaws.services.sqs.AmazonSQS;
+import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import org.junit.BeforeClass;
+
+/**
+ * This class is needed only for testing. This is because we need to
+ * create AWS resources before Spring's Application context is created
+ * in a {@link BeforeClass} method. Since Autowired dependencies don't
+ * work in static context, we will use this class for AWS clients.
+ */
+public class SpringCloudAwsTestUtil {
+
+ private static String awsAccessKey;
+ private static String awsSecretKey;
+ private static String defaultRegion;
+
+ static {
+ try {
+ InputStream is = SpringCloudAwsTestUtil.class.getResourceAsStream("/application.properties");
+ Properties properties = new Properties();
+ properties.load(is);
+ awsAccessKey = properties.getProperty("cloud.aws.credentials.accessKey");
+ awsSecretKey = properties.getProperty("cloud.aws.credentials.secretKey");
+ defaultRegion = properties.getProperty("cloud.aws.region.static");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static AWSCredentials awsCredentials() {
+ return new BasicAWSCredentials(awsAccessKey, awsSecretKey);
+ }
+
+ public static AWSCredentialsProvider awsCredentialsProvider() {
+ return new AWSStaticCredentialsProvider(awsCredentials());
+ }
+
+ public static AmazonS3 amazonS3() {
+ return AmazonS3ClientBuilder.standard()
+ .withCredentials(awsCredentialsProvider())
+ .withRegion(defaultRegion)
+ .build();
+ }
+
+ public static AmazonSNS amazonSNS() {
+ return AmazonSNSClientBuilder.standard()
+ .withCredentials(awsCredentialsProvider())
+ .withRegion(defaultRegion)
+ .build();
+ }
+
+ public static AmazonSQS amazonSQS() {
+ return AmazonSQSClientBuilder.standard()
+ .withCredentials(awsCredentialsProvider())
+ .withRegion(defaultRegion)
+ .build();
+ }
+}
diff --git a/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/rds/SpringCloudRDSIntegrationTest.java b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/rds/SpringCloudRDSIntegrationTest.java
new file mode 100644
index 0000000000..9e163d6dc4
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/rds/SpringCloudRDSIntegrationTest.java
@@ -0,0 +1,46 @@
+package com.baeldung.spring.cloud.aws.rds;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@SpringBootTest
+@RunWith(SpringRunner.class)
+public class SpringCloudRDSIntegrationTest {
+
+ @Autowired
+ DataSource dataSource;
+
+ @Test
+ public void whenDataSourceCreated_thenSuccess() {
+ assertThat(dataSource).isNotNull();
+ }
+
+ @Test
+ public void givenDataSource_whenConnectionCreated_thenSuccess() throws SQLException {
+ Connection connection = dataSource.getConnection();
+ assertThat(connection).isNotNull();
+ }
+
+ @Test
+ public void givenConnection_whenQueryExecuted_thenSuccess() throws SQLException {
+ Connection connection = dataSource.getConnection();
+ Statement statement = connection.createStatement();
+ ResultSet resultSet = statement.executeQuery("SELECT 1");
+ while (resultSet.next()) {
+ int result = resultSet.getInt(1);
+ assertThat(result).isEqualTo(1);
+ }
+ connection.close();
+ }
+}
diff --git a/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/s3/SpringCloudS3IntegrationTest.java b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/s3/SpringCloudS3IntegrationTest.java
new file mode 100644
index 0000000000..a866287dec
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/s3/SpringCloudS3IntegrationTest.java
@@ -0,0 +1,101 @@
+package com.baeldung.spring.cloud.aws.s3;
+
+import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.s3.model.ListObjectsV2Result;
+import com.amazonaws.services.s3.model.S3ObjectSummary;
+import com.baeldung.spring.cloud.aws.SpringCloudAwsTestUtil;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@SpringBootTest
+@RunWith(SpringRunner.class)
+@TestPropertySource("classpath:application-test.properties")
+public class SpringCloudS3IntegrationTest {
+
+ @Autowired
+ private SpringCloudS3 springCloudS3;
+
+ private static String bucketName;
+ private static String testFileToDownload;
+ private static String testFileToUpload;
+
+ private static String[] filesWithSimilarName;
+ private static List similarNameFiles;
+
+ @BeforeClass
+ public static void setupResources() throws IOException {
+
+ bucketName = UUID.randomUUID().toString();
+ testFileToDownload = "test-file-download.txt";
+ testFileToUpload = "test-file-upload.txt";
+
+ filesWithSimilarName = new String[] { "foo/hello-apple.txt", "foo/hello-orange.txt", "bar/hello-grapes.txt", };
+
+ similarNameFiles = new ArrayList<>();
+ for (String name : filesWithSimilarName) {
+ similarNameFiles.add(new File(name.substring(0, name.lastIndexOf("/") + 1)));
+ }
+
+ Files.write(Paths.get(testFileToUpload), "Hello World Uploaded!".getBytes());
+
+ AmazonS3 amazonS3 = SpringCloudAwsTestUtil.amazonS3();
+ amazonS3.createBucket(bucketName);
+
+ amazonS3.putObject(bucketName, testFileToDownload, "Hello World");
+
+ for (String s3Key : filesWithSimilarName) {
+ amazonS3.putObject(bucketName, s3Key, "Hello World");
+ }
+ }
+
+ @Test
+ public void whenS3ObjectDownloaded_thenSuccess() throws IOException {
+ String s3Url = "s3://" + bucketName + "/" + testFileToDownload;
+ springCloudS3.downloadS3Object(s3Url);
+ assertThat(new File(testFileToDownload)).exists();
+ }
+
+ @Test
+ public void whenS3ObjectUploaded_thenSuccess() throws IOException {
+ String s3Url = "s3://" + bucketName + "/" + testFileToUpload;
+ File file = new File(testFileToUpload);
+ springCloudS3.uploadFileToS3(file, s3Url);
+ }
+
+ @Test
+ public void whenMultipleS3ObjectsDownloaded_thenSuccess() throws IOException {
+ String s3Url = "s3://" + bucketName + "/**/hello-*.txt";
+ springCloudS3.downloadMultipleS3Objects(s3Url);
+ similarNameFiles.forEach(f -> assertThat(f).exists());
+ }
+
+ @AfterClass
+ public static void cleanUpResources() {
+ AmazonS3 amazonS3 = SpringCloudAwsTestUtil.amazonS3();
+ ListObjectsV2Result listObjectsV2Result = amazonS3.listObjectsV2(bucketName);
+ for (S3ObjectSummary objectSummary : listObjectsV2Result.getObjectSummaries()) {
+ amazonS3.deleteObject(bucketName, objectSummary.getKey());
+ }
+ amazonS3.deleteBucket(bucketName);
+
+ new File(testFileToDownload).delete();
+ new File(testFileToUpload).delete();
+ similarNameFiles.forEach(File::delete);
+ }
+}
diff --git a/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sns/SNSEndpointControllerUnitTest.java b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sns/SNSEndpointControllerUnitTest.java
new file mode 100644
index 0000000000..14958570e2
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sns/SNSEndpointControllerUnitTest.java
@@ -0,0 +1,38 @@
+package com.baeldung.spring.cloud.aws.sns;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.cloud.aws.messaging.endpoint.NotificationStatus;
+
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+
+public class SNSEndpointControllerUnitTest {
+
+ SNSEndpointController snsEndpointController;
+
+ @Before
+ public void setUp() {
+ snsEndpointController = new SNSEndpointController();
+ }
+
+ @Test
+ public void whenReceivedNotificationInvoked_thenSuccess() {
+ snsEndpointController.receiveNotification("Message", "Subject");
+ }
+
+ @Test
+ public void whenConfirmUnsubscribeReturned_thenSuccess() {
+ NotificationStatus notificationStatus = mock(NotificationStatus.class);
+ doNothing().when(notificationStatus).confirmSubscription();
+ snsEndpointController.confirmUnsubscribeMessage(notificationStatus);
+ }
+
+ @Test
+ public void whenConfirmSubscriptionReturned_thenSuccess() {
+ NotificationStatus notificationStatus = mock(NotificationStatus.class);
+ doNothing().when(notificationStatus).confirmSubscription();
+ snsEndpointController.confirmSubscriptionMessage(notificationStatus);
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sns/SpringCloudSNSIntegrationTest.java b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sns/SpringCloudSNSIntegrationTest.java
new file mode 100644
index 0000000000..e1f23d5c76
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sns/SpringCloudSNSIntegrationTest.java
@@ -0,0 +1,61 @@
+package com.baeldung.spring.cloud.aws.sns;
+
+import java.util.UUID;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import com.amazonaws.services.sns.AmazonSNS;
+import com.amazonaws.services.sns.model.CreateTopicResult;
+import com.baeldung.spring.cloud.aws.SpringCloudAwsTestUtil;
+import com.baeldung.spring.cloud.aws.sqs.Greeting;
+
+@SpringBootTest
+@RunWith(SpringRunner.class)
+@TestPropertySource("classpath:application-test.properties")
+public class SpringCloudSNSIntegrationTest {
+
+ @Autowired
+ private SNSMessageSender snsMessageSender;
+
+ private static String topicName;
+ private static String topicArn;
+
+ @BeforeClass
+ public static void setupAwsResources() {
+
+ topicName = UUID.randomUUID().toString();
+
+ AmazonSNS amazonSNS = SpringCloudAwsTestUtil.amazonSNS();
+
+ CreateTopicResult result = amazonSNS.createTopic(topicName);
+ topicArn = result.getTopicArn();
+ }
+
+ @Test
+ public void whenMessagePublished_thenSuccess() {
+ String subject = "Test Message";
+ String message = "Hello World";
+ snsMessageSender.send(topicName, message, subject);
+ }
+
+ @Test
+ public void whenConvertedMessagePublished_thenSuccess() {
+ String subject = "Test Message";
+ Greeting message = new Greeting("Helo", "World");
+ snsMessageSender.send(topicName, message, subject);
+ }
+
+ @AfterClass
+ public static void cleanupAwsResources() {
+ AmazonSNS amazonSNS = SpringCloudAwsTestUtil.amazonSNS();
+ amazonSNS.deleteTopic(topicArn);
+ }
+
+}
diff --git a/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sqs/Greeting.java b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sqs/Greeting.java
new file mode 100644
index 0000000000..3d14d55f14
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sqs/Greeting.java
@@ -0,0 +1,63 @@
+package com.baeldung.spring.cloud.aws.sqs;
+
+public class Greeting {
+ private String message;
+ private String name;
+
+ public Greeting() {
+
+ }
+
+ public Greeting(String mesage, String name) {
+ this.message = mesage;
+ this.name = name;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((message == null) ? 0 : message.hashCode());
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Greeting other = (Greeting) obj;
+ if (message == null) {
+ if (other.message != null)
+ return false;
+ } else if (!message.equals(other.message))
+ return false;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sqs/SpringCloudSQSIntegrationTest.java b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sqs/SpringCloudSQSIntegrationTest.java
new file mode 100644
index 0000000000..76d2fd7c0d
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/test/java/com/baeldung/spring/cloud/aws/sqs/SpringCloudSQSIntegrationTest.java
@@ -0,0 +1,135 @@
+package com.baeldung.spring.cloud.aws.sqs;
+
+import com.amazonaws.services.sqs.AmazonSQS;
+import com.amazonaws.services.sqs.model.CreateQueueResult;
+import com.amazonaws.services.sqs.model.PurgeQueueRequest;
+import com.amazonaws.services.sqs.model.ReceiveMessageRequest;
+import com.amazonaws.services.sqs.model.ReceiveMessageResult;
+import com.baeldung.spring.cloud.aws.SpringCloudAwsTestUtil;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.io.IOException;
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@SpringBootTest
+@RunWith(SpringRunner.class)
+@TestPropertySource("classpath:application-test.properties")
+public class SpringCloudSQSIntegrationTest {
+
+ private static final Logger logger = LoggerFactory.getLogger(SpringCloudSQSIntegrationTest.class);
+
+ @Autowired
+ @Lazy
+ private SpringCloudSQS springCloudSQS;
+
+ private static String receiveQueueName;
+ private static String receiveQueueUrl;
+
+ private static String sendQueueName;
+ private static String sendQueueURl;
+
+ @BeforeClass
+ public static void setupAwsResources() {
+
+ sendQueueName = UUID.randomUUID().toString();
+ receiveQueueName = SpringCloudSQS.QUEUE_NAME;
+
+ AmazonSQS amazonSQS = SpringCloudAwsTestUtil.amazonSQS();
+
+ CreateQueueResult receiveQueue = amazonSQS.createQueue(receiveQueueName);
+ receiveQueueUrl = receiveQueue.getQueueUrl();
+
+ CreateQueueResult sendQueue = amazonSQS.createQueue(sendQueueName);
+ sendQueueURl = sendQueue.getQueueUrl();
+ }
+
+ @Test
+ public void whenMessageSentAndVerified_thenSuccess() throws InterruptedException {
+
+ String message = "Hello World";
+ springCloudSQS.send(sendQueueName, message);
+
+ AmazonSQS amazonSQS = SpringCloudAwsTestUtil.amazonSQS();
+
+ ReceiveMessageRequest request = new ReceiveMessageRequest(sendQueueURl);
+ request.setMaxNumberOfMessages(1);
+
+ ReceiveMessageResult result = null;
+ do {
+ result = amazonSQS.receiveMessage(request);
+ if (result.getMessages().size() == 0) {
+ logger.info("Message not received at first time, waiting for 1 second");
+ }
+ } while (result.getMessages().size() == 0);
+ assertThat(result.getMessages().get(0).getBody()).isEqualTo(message);
+
+ // Delete message so that it doen't interfere with other test
+ amazonSQS.deleteMessage(sendQueueURl, result.getMessages().get(0).getReceiptHandle());
+
+ }
+
+ @Test
+ public void whenConvertedMessageSentAndVerified_thenSuccess() throws InterruptedException, IOException {
+
+ Greeting message = new Greeting("Hello", "World");
+ springCloudSQS.send(sendQueueName, message);
+
+ AmazonSQS amazonSQS = SpringCloudAwsTestUtil.amazonSQS();
+
+ ReceiveMessageRequest request = new ReceiveMessageRequest(sendQueueURl);
+ request.setMaxNumberOfMessages(1);
+
+ ReceiveMessageResult result = null;
+ do {
+ result = amazonSQS.receiveMessage(request);
+ if (result.getMessages().size() == 0) {
+ logger.info("Message not received at first time, waiting for 1 second");
+ }
+ } while (result.getMessages().size() == 0);
+ assertThat(new ObjectMapper().readValue(result.getMessages().get(0).getBody(), Greeting.class)).isEqualTo(message);
+
+ // Delete message so that it doen't interfere with other test
+ amazonSQS.deleteMessage(sendQueueURl, result.getMessages().get(0).getReceiptHandle());
+ }
+
+ @Test
+ public void givenMessageSent_whenMessageReceived_thenSuccess() throws InterruptedException {
+ CountDownLatch countDownLatch = new CountDownLatch(5);
+ springCloudSQS.setCountDownLatch(countDownLatch);
+
+ AmazonSQS amazonSQS = SpringCloudAwsTestUtil.amazonSQS();
+ for (int i = 0; i < 5; i++) {
+ amazonSQS.sendMessage(receiveQueueUrl, "Hello World " + i);
+ logger.info("Sent message {}, waiting for 1 second", i + 1);
+ Thread.sleep(1000L);
+ }
+ countDownLatch.await();
+ }
+
+ @AfterClass
+ public static void cleanupAwsResources() {
+ AmazonSQS amazonSQS = SpringCloudAwsTestUtil.amazonSQS();
+ PurgeQueueRequest receiveQueuePurge = new PurgeQueueRequest(receiveQueueUrl);
+ amazonSQS.purgeQueue(receiveQueuePurge);
+ amazonSQS.deleteQueue(receiveQueueUrl);
+
+ PurgeQueueRequest sendQueuePurge = new PurgeQueueRequest(sendQueueURl);
+ amazonSQS.purgeQueue(sendQueuePurge);
+ amazonSQS.deleteQueue(sendQueueURl);
+ }
+}
diff --git a/spring-cloud/spring-cloud-aws/src/test/resources/application-test.properties b/spring-cloud/spring-cloud-aws/src/test/resources/application-test.properties
new file mode 100644
index 0000000000..0d3d90b03a
--- /dev/null
+++ b/spring-cloud/spring-cloud-aws/src/test/resources/application-test.properties
@@ -0,0 +1,4 @@
+# Don't try to create DataSouce when running tests which don't need a DataSource
+spring.autoconfigure.exclude=\
+ org.springframework.cloud.aws.autoconfigure.jdbc.AmazonRdsDatabaseAutoConfiguration,\
+ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration