/* * Copyright 2014-2015 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.amqp.rabbit.listener; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.springframework.amqp.core.Message; import org.springframework.amqp.core.MessageListener; import org.springframework.amqp.core.Queue; import org.springframework.amqp.rabbit.core.RabbitAdmin; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.rabbit.junit.BrokerRunning; import org.springframework.amqp.utils.test.TestUtils; import org.springframework.beans.DirectFieldAccessor; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author Gary Russell * @author Artem Bilan * @since 1.3 */ public class ListenFromAutoDeleteQueueTests { @Rule public BrokerRunning brokerIsRunning = BrokerRunning.isRunning(); private SimpleMessageListenerContainer listenerContainer1; private SimpleMessageListenerContainer listenerContainer2; private ConfigurableApplicationContext context; private static BlockingQueue<Message> queue = new LinkedBlockingQueue<Message>(); private Queue expiringQueue; @Before public void setup() { this.context = new ClassPathXmlApplicationContext(this.getClass().getSimpleName() + "-context.xml", this.getClass()); this.listenerContainer1 = context.getBean("container1", SimpleMessageListenerContainer.class); this.listenerContainer2 = context.getBean("container2", SimpleMessageListenerContainer.class); this.expiringQueue = context.getBean("xExpires", Queue.class); } @After public void tearDown() { if (this.context != null) { this.context.close(); } } @Test public void testStopStart() throws Exception { RabbitTemplate template = context.getBean(RabbitTemplate.class); template.convertAndSend("testContainerWithAutoDeleteQueues", "anon", "foo"); assertNotNull(queue.poll(10, TimeUnit.SECONDS)); this.listenerContainer1.stop(); RabbitAdmin admin = spy(TestUtils.getPropertyValue(this.listenerContainer1, "rabbitAdmin", RabbitAdmin.class)); new DirectFieldAccessor(this.listenerContainer1).setPropertyValue("rabbitAdmin", admin); this.listenerContainer1.start(); template.convertAndSend("testContainerWithAutoDeleteQueues", "anon", "foo"); assertNotNull(queue.poll(10, TimeUnit.SECONDS)); verify(admin, times(1)).initialize(); // should only be called by one of the consumers } @Test public void testStopStartConditionalDeclarations() throws Exception { RabbitTemplate template = context.getBean(RabbitTemplate.class); this.listenerContainer2.start(); template.convertAndSend("otherExchange", "otherAnon", "foo"); assertNotNull(queue.poll(10, TimeUnit.SECONDS)); this.listenerContainer2.stop(); this.listenerContainer2.start(); template.convertAndSend("otherExchange", "otherAnon", "foo"); assertNotNull(queue.poll(10, TimeUnit.SECONDS)); } @Test public void testRedeclareXExpiresQueue() throws Exception { RabbitTemplate template = context.getBean(RabbitTemplate.class); template.convertAndSend(this.expiringQueue.getName(), "foo"); assertNotNull(queue.poll(10, TimeUnit.SECONDS)); SimpleMessageListenerContainer listenerContainer = context.getBean("container3", SimpleMessageListenerContainer.class); listenerContainer.stop(); RabbitAdmin admin = spy(TestUtils.getPropertyValue(listenerContainer, "rabbitAdmin", RabbitAdmin.class)); new DirectFieldAccessor(listenerContainer).setPropertyValue("rabbitAdmin", admin); int n = 0; while (admin.getQueueProperties(this.expiringQueue.getName()) != null && n < 100) { Thread.sleep(100); n++; } assertTrue(n < 100); listenerContainer.start(); template.convertAndSend(this.expiringQueue.getName(), "foo"); assertNotNull(queue.poll(10, TimeUnit.SECONDS)); verify(admin, atLeastOnce()).initialize(); // with short x-expires, both consumers might redeclare } @Test public void testAutoDeclareFalse() throws Exception { RabbitTemplate template = context.getBean(RabbitTemplate.class); template.convertAndSend("testContainerWithAutoDeleteQueues", "anon2", "foo"); assertNotNull(queue.poll(10, TimeUnit.SECONDS)); SimpleMessageListenerContainer listenerContainer = context.getBean("container4", SimpleMessageListenerContainer.class); listenerContainer.stop(); RabbitAdmin admin = spy(TestUtils.getPropertyValue(listenerContainer, "rabbitAdmin", RabbitAdmin.class)); new DirectFieldAccessor(listenerContainer).setPropertyValue("rabbitAdmin", admin); listenerContainer = spy(listenerContainer); //Prevent a long 'passiveDeclare' process BlockingQueueConsumer consumer = mock(BlockingQueueConsumer.class); doThrow(RuntimeException.class).when(consumer).start(); // when(consumer.getBackOffExecution()).thenReturn(mock(BackOffExecution.class)); when(listenerContainer.createBlockingQueueConsumer()).thenReturn(consumer); listenerContainer.start(); listenerContainer.stop(); verify(admin, never()).initialize(); // should not be called since 'autoDeclare = false' } public static class Listener implements MessageListener { @Override public void onMessage(Message message) { queue.add(message); } } }