@Test public void testPublisherConfirmWithSendAndReceive() throws Exception { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference<CorrelationData> confirmCD = new AtomicReference<CorrelationData>(); templateWithConfirmsEnabled.setConfirmCallback( new ConfirmCallback() { @Override public void confirm(CorrelationData correlationData, boolean ack, String cause) { confirmCD.set(correlationData); latch.countDown(); } }); SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(this.connectionFactoryWithConfirmsEnabled); container.setQueueNames(ROUTE); container.setMessageListener( new MessageListenerAdapter( new Object() { @SuppressWarnings("unused") public String handleMessage(String in) { return in.toUpperCase(); } })); container.start(); CorrelationData correlationData = new CorrelationData("abc"); String result = (String) this.templateWithConfirmsEnabled.convertSendAndReceive( ROUTE, (Object) "message", correlationData); container.stop(); assertEquals("MESSAGE", result); assertTrue(latch.await(10, TimeUnit.SECONDS)); assertEquals(correlationData, confirmCD.get()); }
@Test public void testListenerSunnyDay() throws Exception { CountDownLatch latch = new CountDownLatch(messageCount); for (int i = 0; i < messageCount; i++) { template.convertAndSend(queue.getName(), i + "foo"); } SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(template.getConnectionFactory()); container.setMessageListener(new MessageListenerAdapter(new PojoListener(latch))); container.setChannelTransacted(transactional); container.setConcurrentConsumers(concurrentConsumers); container.setQueueName(queue.getName()); container.afterPropertiesSet(); container.start(); try { boolean waited = latch.await(50, TimeUnit.MILLISECONDS); assertFalse("Expected time out waiting for message", waited); container.stop(); Thread.sleep(500L); container.start(); if (transactional) { waited = latch.await(5, TimeUnit.SECONDS); assertTrue("Timed out waiting for message", waited); } else { waited = latch.await(500, TimeUnit.MILLISECONDS); // If non-transactional we half expect to lose messages assertFalse("Expected time out waiting for message", waited); } } finally { // Wait for broker communication to finish before trying to stop // container Thread.sleep(300L); container.shutdown(); } assertNull(template.receiveAndConvert(queue.getName())); }
/** Verifies that an up-stack RabbitTemplate uses the listener's channel (MessageListener). */ @SuppressWarnings("unchecked") @Test public void testMessageListener() throws Exception { ConnectionFactory mockConnectionFactory = mock(ConnectionFactory.class); Connection mockConnection = mock(Connection.class); final Channel onlyChannel = mock(Channel.class); when(onlyChannel.isOpen()).thenReturn(true); final CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(mockConnectionFactory); when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection); when(mockConnection.isOpen()).thenReturn(true); final AtomicReference<Exception> tooManyChannels = new AtomicReference<Exception>(); doAnswer( new Answer<Channel>() { boolean done; @Override public Channel answer(InvocationOnMock invocation) throws Throwable { if (!done) { done = true; return onlyChannel; } tooManyChannels.set(new Exception("More than one channel requested")); Channel channel = mock(Channel.class); when(channel.isOpen()).thenReturn(true); return channel; } }) .when(mockConnection) .createChannel(); final AtomicReference<Consumer> consumer = new AtomicReference<Consumer>(); doAnswer( new Answer<String>() { @Override public String answer(InvocationOnMock invocation) throws Throwable { consumer.set((Consumer) invocation.getArguments()[6]); return null; } }) .when(onlyChannel) .basicConsume( anyString(), anyBoolean(), anyString(), anyBoolean(), anyBoolean(), anyMap(), any(Consumer.class)); final CountDownLatch commitLatch = new CountDownLatch(1); doAnswer( new Answer<String>() { @Override public String answer(InvocationOnMock invocation) throws Throwable { commitLatch.countDown(); return null; } }) .when(onlyChannel) .txCommit(); final CountDownLatch latch = new CountDownLatch(1); SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(cachingConnectionFactory); container.setMessageListener( new MessageListener() { @Override public void onMessage(Message message) { RabbitTemplate rabbitTemplate = new RabbitTemplate(cachingConnectionFactory); rabbitTemplate.setChannelTransacted(true); // should use same channel as container rabbitTemplate.convertAndSend("foo", "bar", "baz"); latch.countDown(); } }); container.setQueueNames("queue"); container.setChannelTransacted(true); container.setShutdownTimeout(100); container.afterPropertiesSet(); container.start(); consumer .get() .handleDelivery( "qux", new Envelope(1, false, "foo", "bar"), new BasicProperties(), new byte[] {0}); assertTrue(latch.await(10, TimeUnit.SECONDS)); Exception e = tooManyChannels.get(); if (e != null) { throw e; } verify(mockConnection, Mockito.times(1)).createChannel(); assertTrue(commitLatch.await(10, TimeUnit.SECONDS)); verify(onlyChannel).txCommit(); verify(onlyChannel) .basicPublish( Mockito.anyString(), Mockito.anyString(), Mockito.anyBoolean(), Mockito.any(BasicProperties.class), Mockito.any(byte[].class)); // verify close() was never called on the channel DirectFieldAccessor dfa = new DirectFieldAccessor(cachingConnectionFactory); List<?> channels = (List<?>) dfa.getPropertyValue("cachedChannelsTransactional"); assertEquals(0, channels.size()); container.stop(); }
/** * Verifies that the listener channel is not exposed when so configured and up-stack * RabbitTemplate uses the additional channel. created when exposeListenerChannel is false * (ChannelAwareMessageListener). */ @SuppressWarnings("unchecked") @Test public void testChannelAwareMessageListenerDontExpose() throws Exception { ConnectionFactory mockConnectionFactory = mock(ConnectionFactory.class); Connection mockConnection = mock(Connection.class); final Channel firstChannel = mock(Channel.class); when(firstChannel.isOpen()).thenReturn(true); final Channel secondChannel = mock(Channel.class); when(secondChannel.isOpen()).thenReturn(true); final SingleConnectionFactory singleConnectionFactory = new SingleConnectionFactory(mockConnectionFactory); when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection); when(mockConnection.isOpen()).thenReturn(true); final AtomicReference<Exception> tooManyChannels = new AtomicReference<Exception>(); doAnswer( new Answer<Channel>() { boolean done; @Override public Channel answer(InvocationOnMock invocation) throws Throwable { if (!done) { done = true; return firstChannel; } return secondChannel; } }) .when(mockConnection) .createChannel(); final AtomicReference<Consumer> consumer = new AtomicReference<Consumer>(); doAnswer( new Answer<String>() { @Override public String answer(InvocationOnMock invocation) throws Throwable { consumer.set((Consumer) invocation.getArguments()[6]); return null; } }) .when(firstChannel) .basicConsume( anyString(), anyBoolean(), anyString(), anyBoolean(), anyBoolean(), anyMap(), any(Consumer.class)); final CountDownLatch commitLatch = new CountDownLatch(1); doAnswer( new Answer<String>() { @Override public String answer(InvocationOnMock invocation) throws Throwable { commitLatch.countDown(); return null; } }) .when(firstChannel) .txCommit(); final CountDownLatch latch = new CountDownLatch(1); final AtomicReference<Channel> exposed = new AtomicReference<Channel>(); SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(singleConnectionFactory); container.setMessageListener( new ChannelAwareMessageListener() { @Override public void onMessage(Message message, Channel channel) { exposed.set(channel); RabbitTemplate rabbitTemplate = new RabbitTemplate(singleConnectionFactory); rabbitTemplate.setChannelTransacted(true); // should use same channel as container rabbitTemplate.convertAndSend("foo", "bar", "baz"); latch.countDown(); } }); container.setQueueNames("queue"); container.setChannelTransacted(true); container.setExposeListenerChannel(false); container.setShutdownTimeout(100); container.afterPropertiesSet(); container.start(); consumer .get() .handleDelivery( "qux", new Envelope(1, false, "foo", "bar"), new BasicProperties(), new byte[] {0}); assertTrue(latch.await(10, TimeUnit.SECONDS)); Exception e = tooManyChannels.get(); if (e != null) { throw e; } // once for listener, once for exposed + 0 for template (used bound) verify(mockConnection, Mockito.times(2)).createChannel(); assertTrue(commitLatch.await(10, TimeUnit.SECONDS)); verify(firstChannel).txCommit(); verify(secondChannel).txCommit(); verify(secondChannel) .basicPublish( Mockito.anyString(), Mockito.anyString(), Mockito.anyBoolean(), Mockito.any(BasicProperties.class), Mockito.any(byte[].class)); assertSame(secondChannel, exposed.get()); verify(firstChannel, Mockito.never()).close(); verify(secondChannel, Mockito.times(1)).close(); container.stop(); }