/* * Copyright 2013-2014 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 * * http://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 org.springframework.cloud.aws.messaging; 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.cloud.aws.core.support.documentation.RuntimeUse; import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate; import org.springframework.cloud.aws.messaging.listener.Acknowledgment; import org.springframework.cloud.aws.messaging.listener.SqsMessageDeletionPolicy; import org.springframework.cloud.aws.messaging.listener.annotation.SqsListener; import org.springframework.messaging.handler.annotation.Header; import org.springframework.messaging.handler.annotation.Headers; import org.springframework.messaging.handler.annotation.MessageExceptionHandler; import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.messaging.support.MessageBuilder; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; /** * @author Agim Emruli * @author Alain Sahli * @since 1.0 */ @SuppressWarnings({"AbstractClassWithoutAbstractMethods", "SpringJavaAutowiringInspection"}) @RunWith(SpringJUnit4ClassRunner.class) public abstract class QueueListenerTest extends AbstractContainerTest { @Autowired private MessageListener messageListener; @Autowired private MessageListenerWithSendTo messageListenerWithSendTo; @Autowired private RedrivePolicyTestListener redrivePolicyTestListener; @Autowired private QueueMessagingTemplate queueMessagingTemplate; @Autowired private ManualDeletionPolicyTestListener manualDeletionPolicyTestListener; @Test public void messageMapping_singleMessageOnQueue_messageReceived() throws Exception { // Arrange this.messageListener.setCountDownLatch(new CountDownLatch(1)); this.messageListener.getReceivedMessages().clear(); // Act this.queueMessagingTemplate.send("QueueListenerTest", MessageBuilder.withPayload("Hello world!").build()); // Assert assertTrue(this.messageListener.getCountDownLatch().await(15, TimeUnit.SECONDS)); assertEquals("Hello world!", this.messageListener.getReceivedMessages().get(0)); } @Test public void send_simpleString_shouldBeReceivedWithoutDoubleQuotes() throws Exception { // Arrange this.messageListener.setCountDownLatch(new CountDownLatch(1)); this.messageListener.getReceivedMessages().clear(); // Act this.queueMessagingTemplate.convertAndSend("QueueListenerTest", "Hello world!"); // Assert assertTrue(this.messageListener.getCountDownLatch().await(15, TimeUnit.SECONDS)); assertEquals("Hello world!", this.messageListener.getReceivedMessages().get(0)); } @Test public void sendToAnnotation_WithAValidDestination_messageIsSent() throws Exception { // Arrange this.messageListener.setCountDownLatch(new CountDownLatch(1)); this.messageListener.getReceivedMessages().clear(); this.messageListenerWithSendTo.getReceivedMessages().clear(); // Act this.queueMessagingTemplate.convertAndSend("SendToQueue", "Please answer!"); // Assert assertTrue(this.messageListener.getCountDownLatch().await(15, TimeUnit.SECONDS)); assertEquals("Please answer!", this.messageListenerWithSendTo.getReceivedMessages().get(0)); assertEquals("PLEASE ANSWER!", this.messageListener.getReceivedMessages().get(0)); } @Test public void receiveMessage_withArgumentAnnotatedWithHeaderOrHeaders_shouldReceiveHeaderValues() throws Exception { // Arrange this.messageListener.setCountDownLatch(new CountDownLatch(1)); this.messageListener.getReceivedMessages().clear(); // Act ByteBuffer binaryValue = ByteBuffer.wrap("Binary value".getBytes()); int numberValue = 123456; String stringValue = "String value"; this.queueMessagingTemplate.send("QueueListenerTest", MessageBuilder.withPayload("Is the header received?") .setHeader("stringHeader", stringValue) .setHeader("numberHeader", numberValue) .setHeader("binaryHeader", binaryValue) .build()); // Assert assertTrue(this.messageListener.getCountDownLatch().await(15, TimeUnit.SECONDS)); assertNotNull(this.messageListener.getSenderId()); assertNotNull(this.messageListener.getAllHeaders()); assertEquals(stringValue, this.messageListener.getAllHeaders().get("stringHeader")); assertEquals(numberValue, this.messageListener.getAllHeaders().get("numberHeader")); assertEquals(binaryValue, this.messageListener.getAllHeaders().get("binaryHeader")); } @Test public void redrivePolicy_withMessageMappingThrowingAnException_messageShouldAppearInDeadLetterQueue() throws Exception { // Arrange CountDownLatch countDownLatch = new CountDownLatch(1); this.redrivePolicyTestListener.setCountDownLatch(countDownLatch); // Act this.queueMessagingTemplate.convertAndSend("QueueWithRedrivePolicy", "Hello"); // Assert assertTrue(countDownLatch.await(15, TimeUnit.SECONDS)); } @Test public void manualDeletion_withAcknowledgmentCalled_shouldSucceedAndDeleteMessage() throws Exception { // Act this.queueMessagingTemplate.convertAndSend("ManualDeletionQueue", "Message"); // Assert assertTrue(this.manualDeletionPolicyTestListener.getCountDownLatch().await(15, TimeUnit.SECONDS)); } public static class MessageListener { private static final Logger LOGGER = LoggerFactory.getLogger(MessageListener.class); private final List<String> receivedMessages = new ArrayList<>(); private CountDownLatch countDownLatch = new CountDownLatch(1); private String senderId; private Map<String, Object> allHeaders; @RuntimeUse @SqsListener("QueueListenerTest") public void receiveMessage(String message, @Header(value = "SenderId", required = false) String senderId, @Headers Map<String, Object> allHeaders) { LOGGER.debug("Received message with content {}", message); this.receivedMessages.add(message); this.senderId = senderId; this.allHeaders = allHeaders; this.getCountDownLatch().countDown(); } CountDownLatch getCountDownLatch() { return this.countDownLatch; } public void setCountDownLatch(CountDownLatch countDownLatch) { this.countDownLatch = countDownLatch; } public List<String> getReceivedMessages() { return this.receivedMessages; } public String getSenderId() { return this.senderId; } public Map<String, Object> getAllHeaders() { return Collections.unmodifiableMap(this.allHeaders); } } public static class MessageListenerWithSendTo { private static final Logger LOGGER = LoggerFactory.getLogger(MessageListener.class); private final List<String> receivedMessages = new ArrayList<>(); @RuntimeUse @SqsListener("SendToQueue") @SendTo("QueueListenerTest") public String receiveMessage(String message) { LOGGER.debug("Received message with content {}", message); this.receivedMessages.add(message); return message.toUpperCase(); } public List<String> getReceivedMessages() { return this.receivedMessages; } } public static class RedrivePolicyTestListener { private CountDownLatch countDownLatch = new CountDownLatch(1); public void setCountDownLatch(CountDownLatch countDownLatch) { this.countDownLatch = countDownLatch; } @RuntimeUse @SqsListener(value = "QueueWithRedrivePolicy", deletionPolicy = SqsMessageDeletionPolicy.NO_REDRIVE) public void receiveThrowingException(String message) { throw new RuntimeException(); } @RuntimeUse @SqsListener("DeadLetterQueue") public void receiveDeadLetters(String message) { this.countDownLatch.countDown(); } @MessageExceptionHandler(RuntimeException.class) public void handle() { // Empty body just to avoid unnecessary log output because no exception handler was found. } } public static class ManualDeletionPolicyTestListener { private final CountDownLatch countDownLatch = new CountDownLatch(1); @SqsListener(value = "ManualDeletionQueue", deletionPolicy = SqsMessageDeletionPolicy.NEVER) public void receive(String message, Acknowledgment acknowledgment) throws ExecutionException, InterruptedException { acknowledgment.acknowledge().get(); this.countDownLatch.countDown(); } public CountDownLatch getCountDownLatch() { return this.countDownLatch; } } }