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