/* * 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.listener; import com.amazonaws.services.sqs.AmazonSQSAsync; import com.amazonaws.services.sqs.model.GetQueueAttributesRequest; import com.amazonaws.services.sqs.model.GetQueueAttributesResult; import com.amazonaws.services.sqs.model.GetQueueUrlRequest; import com.amazonaws.services.sqs.model.GetQueueUrlResult; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.ArgumentCaptor; import org.slf4j.Logger; import org.springframework.cloud.aws.messaging.listener.AbstractMessageListenerContainer.QueueAttributes; import org.springframework.cloud.aws.messaging.listener.annotation.SqsListener; import org.springframework.cloud.aws.messaging.support.destination.DynamicQueueUrlDestinationResolver; import org.springframework.context.support.StaticApplicationContext; import org.springframework.messaging.core.CachingDestinationResolverProxy; import org.springframework.messaging.core.DestinationResolutionException; import org.springframework.messaging.core.DestinationResolver; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.withSettings; /** * @author Agim Emruli * @author Alain Sahli * @since 1.0 */ public class MessageListenerContainerTest { @Rule public final ExpectedException expectedException = ExpectedException.none(); @Test public void testAfterPropertiesSetIsSettingActiveFlag() throws Exception { AbstractMessageListenerContainer container = new StubAbstractMessageListenerContainer(); container.setAmazonSqs(mock(AmazonSQSAsync.class, withSettings().stubOnly())); container.setMessageHandler(mock(QueueMessageHandler.class)); container.afterPropertiesSet(); assertTrue(container.isActive()); } @Test public void testAmazonSqsNullThrowsException() throws Exception { this.expectedException.expect(IllegalStateException.class); this.expectedException.expectMessage("amazonSqs must not be null"); AbstractMessageListenerContainer container = new StubAbstractMessageListenerContainer(); container.setMessageHandler(mock(QueueMessageHandler.class)); container.afterPropertiesSet(); } @Test public void testMessageHandlerNullThrowsException() throws Exception { this.expectedException.expect(IllegalStateException.class); this.expectedException.expectMessage("messageHandler must not be null"); AbstractMessageListenerContainer container = new StubAbstractMessageListenerContainer(); container.setAmazonSqs(mock(AmazonSQSAsync.class, withSettings().stubOnly())); container.afterPropertiesSet(); } @Test public void testDestinationResolverIsCreatedIfNull() throws Exception { AbstractMessageListenerContainer container = new StubAbstractMessageListenerContainer(); container.setAmazonSqs(mock(AmazonSQSAsync.class, withSettings().stubOnly())); container.setMessageHandler(mock(QueueMessageHandler.class)); container.afterPropertiesSet(); DestinationResolver<String> destinationResolver = container.getDestinationResolver(); assertNotNull(destinationResolver); assertTrue(CachingDestinationResolverProxy.class.isInstance(destinationResolver)); } @Test public void testDisposableBeanResetActiveFlag() throws Exception { AbstractMessageListenerContainer container = new StubAbstractMessageListenerContainer(); container.setAmazonSqs(mock(AmazonSQSAsync.class, withSettings().stubOnly())); container.setMessageHandler(mock(QueueMessageHandler.class)); container.afterPropertiesSet(); container.destroy(); assertFalse(container.isActive()); } @Test public void testSetAndGetBeanName() throws Exception { AbstractMessageListenerContainer container = new StubAbstractMessageListenerContainer(); container.setBeanName("test"); assertEquals("test", container.getBeanName()); } @Test public void testCustomDestinationResolverSet() throws Exception { AbstractMessageListenerContainer container = new StubAbstractMessageListenerContainer(); container.setAmazonSqs(mock(AmazonSQSAsync.class, withSettings().stubOnly())); container.setMessageHandler(mock(QueueMessageHandler.class)); DestinationResolver<String> destinationResolver = mock(DynamicQueueUrlDestinationResolver.class); container.setDestinationResolver(destinationResolver); container.afterPropertiesSet(); assertEquals(destinationResolver, container.getDestinationResolver()); } @Test public void testMaxNumberOfMessages() throws Exception { AbstractMessageListenerContainer container = new StubAbstractMessageListenerContainer(); assertNull(container.getMaxNumberOfMessages()); container.setMaxNumberOfMessages(23); assertEquals(new Integer(23), container.getMaxNumberOfMessages()); } @Test public void testVisibilityTimeout() throws Exception { AbstractMessageListenerContainer container = new StubAbstractMessageListenerContainer(); assertNull(container.getVisibilityTimeout()); container.setVisibilityTimeout(32); assertEquals(new Integer(32), container.getVisibilityTimeout()); } @Test public void testWaitTimeout() throws Exception { AbstractMessageListenerContainer container = new StubAbstractMessageListenerContainer(); assertNull(container.getWaitTimeOut()); container.setWaitTimeOut(42); assertEquals(new Integer(42), container.getWaitTimeOut()); } @Test public void testIsAutoStartup() throws Exception { AbstractMessageListenerContainer container = new StubAbstractMessageListenerContainer(); assertTrue(container.isAutoStartup()); container.setAutoStartup(false); assertFalse(container.isAutoStartup()); } @Test public void testGetAndSetPhase() throws Exception { AbstractMessageListenerContainer container = new StubAbstractMessageListenerContainer(); assertEquals(Integer.MAX_VALUE, container.getPhase()); container.setPhase(23); assertEquals(23L, container.getPhase()); } @Test public void testIsActive() throws Exception { AbstractMessageListenerContainer container = new StubAbstractMessageListenerContainer(); AmazonSQSAsync mock = mock(AmazonSQSAsync.class, withSettings().stubOnly()); container.setAmazonSqs(mock); container.setMessageHandler(mock(QueueMessageHandler.class)); container.afterPropertiesSet(); when(mock.getQueueUrl(new GetQueueUrlRequest().withQueueName("testQueue"))). thenReturn(new GetQueueUrlResult().withQueueUrl("http://testQueue.amazonaws.com")); container.start(); assertTrue(container.isRunning()); container.stop(); assertFalse(container.isRunning()); //Container can still be active an restarted later (e.g. paused for a while) assertTrue(container.isActive()); } @Test public void receiveMessageRequests_withOneElement_created() throws Exception { AbstractMessageListenerContainer container = new StubAbstractMessageListenerContainer(); AmazonSQSAsync mock = mock(AmazonSQSAsync.class, withSettings().stubOnly()); QueueMessageHandler messageHandler = new QueueMessageHandler(); container.setAmazonSqs(mock); container.setMessageHandler(mock(QueueMessageHandler.class)); container.setMessageHandler(messageHandler); StaticApplicationContext applicationContext = new StaticApplicationContext(); applicationContext.registerSingleton("messageListener", MessageListener.class); container.setMaxNumberOfMessages(11); container.setVisibilityTimeout(22); container.setWaitTimeOut(33); messageHandler.setApplicationContext(applicationContext); when(mock.getQueueUrl(new GetQueueUrlRequest().withQueueName("testQueue"))). thenReturn(new GetQueueUrlResult().withQueueUrl("http://testQueue.amazonaws.com")); when(mock.getQueueAttributes(any(GetQueueAttributesRequest.class))).thenReturn(new GetQueueAttributesResult()); messageHandler.afterPropertiesSet(); container.afterPropertiesSet(); container.start(); Map<String, QueueAttributes> registeredQueues = container.getRegisteredQueues(); assertEquals("http://testQueue.amazonaws.com", registeredQueues.get("testQueue").getReceiveMessageRequest().getQueueUrl()); assertEquals(11L, registeredQueues.get("testQueue").getReceiveMessageRequest().getMaxNumberOfMessages().longValue()); assertEquals(22L, registeredQueues.get("testQueue").getReceiveMessageRequest().getVisibilityTimeout().longValue()); assertEquals(33L, registeredQueues.get("testQueue").getReceiveMessageRequest().getWaitTimeSeconds().longValue()); } @Test public void receiveMessageRequests_withMultipleElements_created() throws Exception { AbstractMessageListenerContainer container = new StubAbstractMessageListenerContainer(); AmazonSQSAsync mock = mock(AmazonSQSAsync.class, withSettings().stubOnly()); container.setAmazonSqs(mock); StaticApplicationContext applicationContext = new StaticApplicationContext(); QueueMessageHandler messageHandler = new QueueMessageHandler(); messageHandler.setApplicationContext(applicationContext); container.setMessageHandler(messageHandler); applicationContext.registerSingleton("messageListener", MessageListener.class); applicationContext.registerSingleton("anotherMessageListener", AnotherMessageListener.class); container.setMaxNumberOfMessages(11); container.setVisibilityTimeout(22); container.setWaitTimeOut(33); when(mock.getQueueUrl(new GetQueueUrlRequest().withQueueName("testQueue"))). thenReturn(new GetQueueUrlResult().withQueueUrl("http://testQueue.amazonaws.com")); when(mock.getQueueUrl(new GetQueueUrlRequest().withQueueName("anotherTestQueue"))). thenReturn(new GetQueueUrlResult().withQueueUrl("http://anotherTestQueue.amazonaws.com")); when(mock.getQueueAttributes(any(GetQueueAttributesRequest.class))).thenReturn(new GetQueueAttributesResult()); messageHandler.afterPropertiesSet(); container.afterPropertiesSet(); container.start(); Map<String, QueueAttributes> registeredQueues = container.getRegisteredQueues(); assertEquals("http://testQueue.amazonaws.com", registeredQueues.get("testQueue").getReceiveMessageRequest().getQueueUrl()); assertEquals(11L, registeredQueues.get("testQueue").getReceiveMessageRequest().getMaxNumberOfMessages().longValue()); assertEquals(22L, registeredQueues.get("testQueue").getReceiveMessageRequest().getVisibilityTimeout().longValue()); assertEquals(33L, registeredQueues.get("testQueue").getReceiveMessageRequest().getWaitTimeSeconds().longValue()); assertEquals("http://anotherTestQueue.amazonaws.com", registeredQueues.get("anotherTestQueue").getReceiveMessageRequest().getQueueUrl()); assertEquals(11L, registeredQueues.get("anotherTestQueue").getReceiveMessageRequest().getMaxNumberOfMessages().longValue()); assertEquals(22L, registeredQueues.get("anotherTestQueue").getReceiveMessageRequest().getVisibilityTimeout().longValue()); assertEquals(33L, registeredQueues.get("anotherTestQueue").getReceiveMessageRequest().getWaitTimeSeconds().longValue()); } @Test public void testStartCallsDoStartMethod() throws Exception { final CountDownLatch countDownLatch = new CountDownLatch(1); AbstractMessageListenerContainer container = new AbstractMessageListenerContainer() { @Override protected void doStart() { countDownLatch.countDown(); } @Override protected void doStop() { throw new UnsupportedOperationException("not supported yet"); } }; AmazonSQSAsync mock = mock(AmazonSQSAsync.class, withSettings().stubOnly()); container.setAmazonSqs(mock); container.setMessageHandler(mock(QueueMessageHandler.class)); container.afterPropertiesSet(); when(mock.getQueueUrl(new GetQueueUrlRequest().withQueueName("testQueue"))). thenReturn(new GetQueueUrlResult().withQueueUrl("http://testQueue.amazonaws.com")); container.start(); try { assertTrue(countDownLatch.await(10, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { fail("Expected doStart() method to be called"); } } @Test public void testStopCallsDoStopMethod() throws Exception { final CountDownLatch countDownLatch = new CountDownLatch(1); AbstractMessageListenerContainer container = new AbstractMessageListenerContainer() { @Override protected void doStart() { // do nothing in this case } @Override protected void doStop() { countDownLatch.countDown(); } }; AmazonSQSAsync mock = mock(AmazonSQSAsync.class, withSettings().stubOnly()); container.setAmazonSqs(mock); container.setMessageHandler(mock(QueueMessageHandler.class)); container.afterPropertiesSet(); when(mock.getQueueUrl(new GetQueueUrlRequest().withQueueName("testQueue"))). thenReturn(new GetQueueUrlResult().withQueueUrl("http://testQueue.amazonaws.com")); container.start(); container.stop(); try { assertTrue(countDownLatch.await(10, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { fail("Expected doStart() method to be called"); } } @Test public void testStopCallsDoStopMethodWithRunnable() throws Exception { final CountDownLatch countDownLatch = new CountDownLatch(1); AbstractMessageListenerContainer container = new AbstractMessageListenerContainer() { @Override protected void doStart() { // do nothing in this case } @Override protected void doStop() { countDownLatch.countDown(); } }; AmazonSQSAsync mock = mock(AmazonSQSAsync.class, withSettings().stubOnly()); container.setAmazonSqs(mock); container.setMessageHandler(mock(QueueMessageHandler.class)); container.afterPropertiesSet(); when(mock.getQueueUrl(new GetQueueUrlRequest().withQueueName("testQueue"))). thenReturn(new GetQueueUrlResult().withQueueUrl("http://testQueue.amazonaws.com")); container.start(); container.stop(new Runnable() { @Override public void run() { try { assertTrue(countDownLatch.await(10, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { fail("Expected doStart() method to be called"); } } }); } @Test public void doDestroy_WhenContainerIsDestroyed_shouldBeCalled() throws Exception { // Arrange DestroyAwareAbstractMessageListenerContainer abstractMessageListenerContainer = new DestroyAwareAbstractMessageListenerContainer(); // Act abstractMessageListenerContainer.destroy(); // Assert assertTrue(abstractMessageListenerContainer.isDestroyCalled()); } @Test public void receiveMessageRequests_withDestinationResolverThrowingException_shouldLogWarningAndNotCreateRequest() throws Exception { // Arrange AbstractMessageListenerContainer container = new StubAbstractMessageListenerContainer(); Logger loggerMock = container.getLogger(); AmazonSQSAsync mock = mock(AmazonSQSAsync.class, withSettings().stubOnly()); container.setAmazonSqs(mock); StaticApplicationContext applicationContext = new StaticApplicationContext(); QueueMessageHandler messageHandler = new QueueMessageHandler(); messageHandler.setApplicationContext(applicationContext); container.setMessageHandler(messageHandler); applicationContext.registerSingleton("messageListener", MessageListener.class); applicationContext.registerSingleton("anotherMessageListener", AnotherMessageListener.class); when(mock.getQueueUrl(new GetQueueUrlRequest().withQueueName("testQueue"))). thenThrow(new DestinationResolutionException("Queue not found")); when(mock.getQueueUrl(new GetQueueUrlRequest().withQueueName("anotherTestQueue"))). thenReturn(new GetQueueUrlResult().withQueueUrl("http://anotherTestQueue.amazonaws.com")); when(mock.getQueueAttributes(any(GetQueueAttributesRequest.class))).thenReturn(new GetQueueAttributesResult()); messageHandler.afterPropertiesSet(); container.afterPropertiesSet(); // Act container.start(); // Assert ArgumentCaptor<String> logMsgArgCaptor = ArgumentCaptor.forClass(String.class); verify(loggerMock).warn(logMsgArgCaptor.capture()); Map<String, QueueAttributes> registeredQueues = container.getRegisteredQueues(); assertFalse(registeredQueues.containsKey("testQueue")); assertEquals("Ignoring queue with name 'testQueue' as it does not exist.", logMsgArgCaptor.getValue()); assertEquals("http://anotherTestQueue.amazonaws.com", registeredQueues.get("anotherTestQueue").getReceiveMessageRequest().getQueueUrl()); } private static class StubAbstractMessageListenerContainer extends AbstractMessageListenerContainer { private final Logger mock = mock(Logger.class); @Override protected void doStart() { } @Override protected void doStop() { } @Override protected Logger getLogger() { return this.mock; } } private static class MessageListener { @SuppressWarnings({"UnusedDeclaration", "EmptyMethod"}) @SqsListener("testQueue") public void listenerMethod(String ignore) { } } private static class AnotherMessageListener { @SuppressWarnings({"UnusedDeclaration", "EmptyMethod"}) @SqsListener("anotherTestQueue") public void listenerMethod(String ignore) { } } private static class DestroyAwareAbstractMessageListenerContainer extends AbstractMessageListenerContainer { private boolean destroyCalled; private boolean isDestroyCalled() { return this.destroyCalled; } @Override protected void doStart() { } @Override protected void doStop() { } @Override protected void doDestroy() { this.destroyCalled = true; } } }