@Test public void testPublisherConfirmNotReceived() throws Exception { ConnectionFactory mockConnectionFactory = mock(ConnectionFactory.class); Connection mockConnection = mock(Connection.class); Channel mockChannel = mock(Channel.class); when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection); when(mockConnection.isOpen()).thenReturn(true); doReturn(new PublisherCallbackChannelImpl(mockChannel)).when(mockConnection).createChannel(); CachingConnectionFactory ccf = new CachingConnectionFactory(mockConnectionFactory); ccf.setPublisherConfirms(true); final RabbitTemplate template = new RabbitTemplate(ccf); final AtomicBoolean confirmed = new AtomicBoolean(); template.setConfirmCallback( new ConfirmCallback() { @Override public void confirm(CorrelationData correlationData, boolean ack, String cause) { confirmed.set(true); } }); template.convertAndSend(ROUTE, (Object) "message", new CorrelationData("abc")); Thread.sleep(5); Collection<CorrelationData> unconfirmed = template.getUnconfirmed(-1); assertEquals(1, unconfirmed.size()); assertEquals("abc", unconfirmed.iterator().next().getId()); assertFalse(confirmed.get()); }
/** - */ @Test public void test() throws Exception { ConnectionFactory mockConnectionFactory = mock(ConnectionFactory.class); Connection mockConnection = mock(Connection.class); Channel mockChannel = mock(Channel.class); when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection); when(mockConnection.isOpen()).thenReturn(true); when(mockConnection.createChannel()).thenReturn(mockChannel); when(mockChannel.isOpen()).thenReturn(true); Message msg = this.messageConverter.toMessage( createFieldChangedEvent( "/asset/assetMeter/crank-frame-dischargepressure", //$NON-NLS-1$ "/asset/assetMeter/crank-frame-dischargepressure", //$NON-NLS-1$ "/asset/compressor-2015", //$NON-NLS-1$ StringUtil.parseDate("2012-09-11T07:16:13"), // $NON-NLS-1$ null, null), null); final RabbitTemplate fieldChangedEventTemplate = new RabbitTemplate(new CachingConnectionFactory(mockConnectionFactory)); fieldChangedEventTemplate.convertAndSend("fieldchangedeventMainQ", msg); // $NON-NLS-1$ }
@Test public void testCloseInvalidConnection() throws Exception { com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock(com.rabbitmq.client.ConnectionFactory.class); com.rabbitmq.client.Connection mockConnection1 = mock(com.rabbitmq.client.Connection.class); com.rabbitmq.client.Connection mockConnection2 = mock(com.rabbitmq.client.Connection.class); when(mockConnectionFactory.newConnection((ExecutorService) null)) .thenReturn(mockConnection1) .thenReturn(mockConnection2); // simulate a dead connection when(mockConnection1.isOpen()).thenReturn(false); AbstractConnectionFactory connectionFactory = createConnectionFactory(mockConnectionFactory); Connection connection = connectionFactory.createConnection(); // the dead connection should be discarded connection.createChannel(false); verify(mockConnectionFactory, times(2)).newConnection((ExecutorService) null); verify(mockConnection2, times(1)).createChannel(); connectionFactory.destroy(); verify(mockConnection2, times(1)).close(); }
// AMQP-506 ConcurrentModificationException @Test public void testPublisherConfirmGetUnconfirmedConcurrency() throws Exception { ConnectionFactory mockConnectionFactory = mock(ConnectionFactory.class); Connection mockConnection = mock(Connection.class); Channel mockChannel = mock(Channel.class); when(mockChannel.isOpen()).thenReturn(true); final AtomicLong seq = new AtomicLong(); doAnswer( new Answer<Long>() { @Override public Long answer(InvocationOnMock invocation) throws Throwable { return seq.incrementAndGet(); } }) .when(mockChannel) .getNextPublishSeqNo(); when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection); when(mockConnection.isOpen()).thenReturn(true); doReturn(mockChannel).when(mockConnection).createChannel(); CachingConnectionFactory ccf = new CachingConnectionFactory(mockConnectionFactory); ccf.setPublisherConfirms(true); final RabbitTemplate template = new RabbitTemplate(ccf); final AtomicBoolean confirmed = new AtomicBoolean(); template.setConfirmCallback( new ConfirmCallback() { @Override public void confirm(CorrelationData correlationData, boolean ack, String cause) { confirmed.set(true); } }); ExecutorService exec = Executors.newSingleThreadExecutor(); final AtomicBoolean sentAll = new AtomicBoolean(); exec.execute( new Runnable() { @Override public void run() { for (int i = 0; i < 10000; i++) { template.convertAndSend(ROUTE, (Object) "message", new CorrelationData("abc")); } sentAll.set(true); } }); Collection<CorrelationData> unconfirmed = template.getUnconfirmed(-1); long t1 = System.currentTimeMillis(); while (!sentAll.get() && System.currentTimeMillis() < t1 + 20000) { unconfirmed = template.getUnconfirmed(-1); } assertTrue(sentAll.get()); assertFalse(confirmed.get()); }
@Test public void testReplyToOneDeepCustomCorrelationKey() throws Exception { ConnectionFactory mockConnectionFactory = mock(ConnectionFactory.class); Connection mockConnection = mock(Connection.class); Channel mockChannel = mock(Channel.class); when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection); when(mockConnection.isOpen()).thenReturn(true); when(mockConnection.createChannel()).thenReturn(mockChannel); final RabbitTemplate template = new RabbitTemplate(new SingleConnectionFactory(mockConnectionFactory)); template.setCorrelationKey(CORRELATION_HEADER); Queue replyQueue = new Queue("new.replyTo"); template.setReplyQueue(replyQueue); MessageProperties messageProperties = new MessageProperties(); messageProperties.setReplyTo("replyTo1"); messageProperties.setCorrelationId("saveThis".getBytes()); Message message = new Message("Hello, world!".getBytes(), messageProperties); final AtomicReference<String> replyTo = new AtomicReference<String>(); final AtomicReference<String> correlationId = new AtomicReference<String>(); doAnswer( new Answer<Object>() { public Object answer(InvocationOnMock invocation) throws Throwable { BasicProperties basicProps = (BasicProperties) invocation.getArguments()[4]; replyTo.set(basicProps.getReplyTo()); correlationId.set((String) basicProps.getHeaders().get(CORRELATION_HEADER)); MessageProperties springProps = new DefaultMessagePropertiesConverter() .toMessageProperties(basicProps, null, "UTF-8"); Message replyMessage = new Message("!dlrow olleH".getBytes(), springProps); template.onMessage(replyMessage); return null; } }) .when(mockChannel) .basicPublish( Mockito.any(String.class), Mockito.any(String.class), Mockito.anyBoolean(), Mockito.anyBoolean(), Mockito.any(BasicProperties.class), Mockito.any(byte[].class)); Message reply = template.sendAndReceive(message); assertNotNull(reply); assertNotNull(replyTo.get()); assertEquals("new.replyTo", replyTo.get()); assertNotNull(correlationId.get()); assertEquals("replyTo1", reply.getMessageProperties().getReplyTo()); assertTrue(!"saveThis".equals(correlationId.get())); assertEquals("replyTo1", reply.getMessageProperties().getReplyTo()); }
@Test public void testPublisherConfirmMultiple() throws Exception { ConnectionFactory mockConnectionFactory = mock(ConnectionFactory.class); Connection mockConnection = mock(Connection.class); Channel mockChannel = mock(Channel.class); when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection); when(mockConnection.isOpen()).thenReturn(true); PublisherCallbackChannelImpl callbackChannel = new PublisherCallbackChannelImpl(mockChannel); when(mockConnection.createChannel()).thenReturn(callbackChannel); final AtomicInteger count = new AtomicInteger(); doAnswer( new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { return count.incrementAndGet(); } }) .when(mockChannel) .getNextPublishSeqNo(); CachingConnectionFactory ccf = new CachingConnectionFactory(mockConnectionFactory); ccf.setPublisherConfirms(true); final RabbitTemplate template = new RabbitTemplate(ccf); final CountDownLatch latch = new CountDownLatch(2); template.setConfirmCallback( new ConfirmCallback() { @Override public void confirm(CorrelationData correlationData, boolean ack, String cause) { if (ack) { latch.countDown(); } } }); template.convertAndSend(ROUTE, (Object) "message", new CorrelationData("abc")); template.convertAndSend(ROUTE, (Object) "message", new CorrelationData("def")); callbackChannel.handleAck(2, true); assertTrue(latch.await(1000, TimeUnit.MILLISECONDS)); Collection<CorrelationData> unconfirmed = template.getUnconfirmed(-1); assertNull(unconfirmed); }
@Test public void testWithListenerRegisteredAfterOpen() throws IOException { com.rabbitmq.client.ConnectionFactory mockConnectionFactory = mock(com.rabbitmq.client.ConnectionFactory.class); com.rabbitmq.client.Connection mockConnection = mock(com.rabbitmq.client.Connection.class); when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection); final AtomicInteger called = new AtomicInteger(0); AbstractConnectionFactory connectionFactory = createConnectionFactory(mockConnectionFactory); Connection con = connectionFactory.createConnection(); assertEquals(0, called.get()); connectionFactory.setConnectionListeners( Arrays.asList( new ConnectionListener() { public void onCreate(Connection connection) { called.incrementAndGet(); } public void onClose(Connection connection) { called.decrementAndGet(); } })); assertEquals(1, called.get()); con.close(); assertEquals(1, called.get()); verify(mockConnection, never()).close(); connectionFactory.createConnection(); assertEquals(1, called.get()); connectionFactory.destroy(); assertEquals(0, called.get()); verify(mockConnection, atLeastOnce()).close(); verify(mockConnectionFactory, times(1)).newConnection((ExecutorService) null); }
/** * AMQP-262 Sets up a situation where we are processing 'multi' acks at the same time as adding a * new pending ack to the map. Test verifies we don't get a {@link * ConcurrentModificationException}. */ @SuppressWarnings({"rawtypes", "unchecked", "deprecation"}) @Test public void testConcurrentConfirms() throws Exception { ConnectionFactory mockConnectionFactory = mock(ConnectionFactory.class); Connection mockConnection = mock(Connection.class); Channel mockChannel = mock(Channel.class); when(mockChannel.getNextPublishSeqNo()).thenReturn(1L, 2L, 3L, 4L); when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection); when(mockConnection.isOpen()).thenReturn(true); final PublisherCallbackChannelImpl channel = new PublisherCallbackChannelImpl(mockChannel); when(mockConnection.createChannel()).thenReturn(channel); CachingConnectionFactory ccf = new CachingConnectionFactory(mockConnectionFactory); ccf.setPublisherConfirms(true); ccf.setChannelCacheSize(3); final RabbitTemplate template = new RabbitTemplate(ccf); final CountDownLatch first2SentOnThread1Latch = new CountDownLatch(1); final CountDownLatch delayAckProcessingLatch = new CountDownLatch(1); final CountDownLatch startedProcessingMultiAcksLatch = new CountDownLatch(1); final CountDownLatch waitForAll3AcksLatch = new CountDownLatch(3); final CountDownLatch allSentLatch = new CountDownLatch(1); final AtomicInteger acks = new AtomicInteger(); template.setConfirmCallback( new ConfirmCallback() { @Override public void confirm(CorrelationData correlationData, boolean ack, String cause) { try { startedProcessingMultiAcksLatch.countDown(); // delay processing here; ensures thread 2 put would be concurrent delayAckProcessingLatch.await(2, TimeUnit.SECONDS); // only delay first time through delayAckProcessingLatch.countDown(); waitForAll3AcksLatch.countDown(); acks.incrementAndGet(); } catch (InterruptedException e) { e.printStackTrace(); } } }); Executors.newSingleThreadExecutor() .execute( new Runnable() { @Override public void run() { template.convertAndSend(ROUTE, (Object) "message", new CorrelationData("abc")); template.convertAndSend(ROUTE, (Object) "message", new CorrelationData("def")); first2SentOnThread1Latch.countDown(); } }); Executors.newSingleThreadExecutor() .execute( new Runnable() { @Override public void run() { try { startedProcessingMultiAcksLatch.await(); template.convertAndSend(ROUTE, (Object) "message", new CorrelationData("ghi")); allSentLatch.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } } }); assertTrue(first2SentOnThread1Latch.await(10, TimeUnit.SECONDS)); // there should be no concurrent execution exception here channel.handleAck(2, true); assertTrue(allSentLatch.await(10, TimeUnit.SECONDS)); channel.handleAck(3, false); assertTrue(waitForAll3AcksLatch.await(10, TimeUnit.SECONDS)); assertEquals(3, acks.get()); // 3.3.1 client channel.basicConsume("foo", false, (Map) null, null); verify(mockChannel).basicConsume("foo", false, (Map) null, null); channel.basicQos(3, false); verify(mockChannel).basicQos(3, false); doReturn(true).when(mockChannel).flowBlocked(); assertTrue(channel.flowBlocked()); try { channel.flow(true); fail("Expected exception"); } catch (UnsupportedOperationException e) { } try { channel.getFlow(); fail("Expected exception"); } catch (UnsupportedOperationException e) { } // 3.2.4 client /* try { channel.basicConsume("foo", false, (Map) null, (Consumer) null); fail("Expected exception"); } catch (UnsupportedOperationException e) {} try { channel.basicQos(3, false); fail("Expected exception"); } catch (UnsupportedOperationException e) {} try { channel.flowBlocked(); fail("Expected exception"); } catch (UnsupportedOperationException e) {} channel.flow(true); verify(mockChannel).flow(true); channel.getFlow(); verify(mockChannel).getFlow(); */ }
/** * Tests that piggy-backed confirms (multiple=true) are distributed to the proper template. * * @throws Exception */ @Test public void testPublisherConfirmMultipleWithTwoListeners() throws Exception { ConnectionFactory mockConnectionFactory = mock(ConnectionFactory.class); Connection mockConnection = mock(Connection.class); Channel mockChannel = mock(Channel.class); when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection); when(mockConnection.isOpen()).thenReturn(true); PublisherCallbackChannelImpl callbackChannel = new PublisherCallbackChannelImpl(mockChannel); when(mockConnection.createChannel()).thenReturn(callbackChannel); final AtomicInteger count = new AtomicInteger(); doAnswer( new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { return count.incrementAndGet(); } }) .when(mockChannel) .getNextPublishSeqNo(); CachingConnectionFactory ccf = new CachingConnectionFactory(mockConnectionFactory); ccf.setPublisherConfirms(true); final RabbitTemplate template1 = new RabbitTemplate(ccf); final Set<String> confirms = new HashSet<String>(); final CountDownLatch latch1 = new CountDownLatch(1); template1.setConfirmCallback( new ConfirmCallback() { @Override public void confirm(CorrelationData correlationData, boolean ack, String cause) { if (ack) { confirms.add(correlationData.getId() + "1"); latch1.countDown(); } } }); final RabbitTemplate template2 = new RabbitTemplate(ccf); final CountDownLatch latch2 = new CountDownLatch(1); template2.setConfirmCallback( new ConfirmCallback() { @Override public void confirm(CorrelationData correlationData, boolean ack, String cause) { if (ack) { confirms.add(correlationData.getId() + "2"); latch2.countDown(); } } }); template1.convertAndSend(ROUTE, (Object) "message", new CorrelationData("abc")); template2.convertAndSend(ROUTE, (Object) "message", new CorrelationData("def")); template2.convertAndSend(ROUTE, (Object) "message", new CorrelationData("ghi")); callbackChannel.handleAck(3, true); assertTrue(latch1.await(1000, TimeUnit.MILLISECONDS)); assertTrue(latch2.await(1000, TimeUnit.MILLISECONDS)); Collection<CorrelationData> unconfirmed1 = template1.getUnconfirmed(-1); assertNull(unconfirmed1); Collection<CorrelationData> unconfirmed2 = template2.getUnconfirmed(-1); assertNull(unconfirmed2); assertTrue(confirms.contains("abc1")); assertTrue(confirms.contains("def2")); assertTrue(confirms.contains("ghi2")); assertEquals(3, confirms.size()); }
@Test public void testPublisherConfirmNotReceivedMultiThreads() throws Exception { ConnectionFactory mockConnectionFactory = mock(ConnectionFactory.class); Connection mockConnection = mock(Connection.class); Channel mockChannel1 = mock(Channel.class); Channel mockChannel2 = mock(Channel.class); when(mockChannel1.isOpen()).thenReturn(true); when(mockChannel2.isOpen()).thenReturn(true); when(mockChannel1.getNextPublishSeqNo()).thenReturn(1L, 2L, 3L, 4L); when(mockChannel2.getNextPublishSeqNo()).thenReturn(1L, 2L, 3L, 4L); when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection); when(mockConnection.isOpen()).thenReturn(true); PublisherCallbackChannelImpl channel1 = new PublisherCallbackChannelImpl(mockChannel1); PublisherCallbackChannelImpl channel2 = new PublisherCallbackChannelImpl(mockChannel2); when(mockConnection.createChannel()).thenReturn(channel1).thenReturn(channel2); CachingConnectionFactory ccf = new CachingConnectionFactory(mockConnectionFactory); ccf.setPublisherConfirms(true); ccf.setChannelCacheSize(3); final RabbitTemplate template = new RabbitTemplate(ccf); final AtomicBoolean confirmed = new AtomicBoolean(); template.setConfirmCallback( new ConfirmCallback() { @Override public void confirm(CorrelationData correlationData, boolean ack, String cause) { confirmed.set(true); } }); // Hold up the first thread so we get two channels final CountDownLatch threadLatch = new CountDownLatch(1); final CountDownLatch threadSentLatch = new CountDownLatch(1); // Thread 1 ExecutorService exec = Executors.newSingleThreadExecutor(); exec.execute( new Runnable() { @Override public void run() { template.execute( new ChannelCallback<Object>() { @Override public Object doInRabbit(Channel channel) throws Exception { try { threadLatch.await(10, TimeUnit.SECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } template.doSend( channel, "", ROUTE, new SimpleMessageConverter().toMessage("message", new MessageProperties()), false, new CorrelationData("def")); threadSentLatch.countDown(); return null; } }); } }); // Thread 2 template.convertAndSend(ROUTE, (Object) "message", new CorrelationData("abc")); // channel y threadLatch.countDown(); assertTrue(threadSentLatch.await(5, TimeUnit.SECONDS)); Collection<CorrelationData> unconfirmed = template.getUnconfirmed(-1); assertEquals(2, unconfirmed.size()); Set<String> ids = new HashSet<String>(); Iterator<CorrelationData> iterator = unconfirmed.iterator(); ids.add(iterator.next().getId()); ids.add(iterator.next().getId()); assertTrue(ids.remove("abc")); assertTrue(ids.remove("def")); assertFalse(confirmed.get()); DirectFieldAccessor dfa = new DirectFieldAccessor(template); Map<?, ?> pendingConfirms = (Map<?, ?>) dfa.getPropertyValue("pendingConfirms"); assertThat(pendingConfirms.size(), greaterThan(0)); // might use 2 or only 1 channel exec.shutdown(); assertTrue(exec.awaitTermination(10, TimeUnit.SECONDS)); ccf.destroy(); assertEquals(0, pendingConfirms.size()); }
/** 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(); }
@Test public void testReplyToThreeDeepCustomCorrelationKey() throws Exception { ConnectionFactory mockConnectionFactory = mock(ConnectionFactory.class); Connection mockConnection = mock(Connection.class); Channel mockChannel = mock(Channel.class); when(mockConnectionFactory.newConnection((ExecutorService) null)).thenReturn(mockConnection); when(mockConnection.isOpen()).thenReturn(true); when(mockConnection.createChannel()).thenReturn(mockChannel); final RabbitTemplate template = new RabbitTemplate(new SingleConnectionFactory(mockConnectionFactory)); template.setCorrelationKey(CORRELATION_HEADER); Queue replyQueue = new Queue("replyTo2"); template.setReplyQueue(replyQueue); MessageProperties messageProperties = new MessageProperties(); messageProperties.setReplyTo("replyTo1"); messageProperties.setCorrelationId("a".getBytes()); Message message = new Message("Hello, world!".getBytes(), messageProperties); final AtomicInteger count = new AtomicInteger(); final List<String> nestedReplyTo = new ArrayList<String>(); final List<String> nestedCorrelation = new ArrayList<String>(); doAnswer( new Answer<Object>() { public Object answer(InvocationOnMock invocation) throws Throwable { BasicProperties basicProps = (BasicProperties) invocation.getArguments()[4]; nestedReplyTo.add(basicProps.getReplyTo()); nestedCorrelation.add(basicProps.getCorrelationId()); MessageProperties springProps = new DefaultMessagePropertiesConverter() .toMessageProperties(basicProps, null, "UTF-8"); Message replyMessage = new Message("!dlrow olleH".getBytes(), springProps); if (count.incrementAndGet() < 2) { Message anotherMessage = new Message("Second".getBytes(), springProps); template.setReplyQueue(new Queue("replyTo3")); replyMessage = template.sendAndReceive(anotherMessage); nestedReplyTo.add(replyMessage.getMessageProperties().getReplyTo()); nestedCorrelation.add( (String) replyMessage.getMessageProperties().getHeaders().get(CORRELATION_HEADER)); } template.onMessage(replyMessage); return null; } }) .when(mockChannel) .basicPublish( Mockito.any(String.class), Mockito.any(String.class), Mockito.anyBoolean(), Mockito.anyBoolean(), Mockito.any(BasicProperties.class), Mockito.any(byte[].class)); Message reply = template.sendAndReceive(message); assertNotNull(reply); assertEquals(3, nestedReplyTo.size()); assertEquals("replyTo2", nestedReplyTo.get(0)); assertEquals("replyTo3", nestedReplyTo.get(1)); assertEquals("replyTo2", nestedReplyTo.get(2)); // intermediate reply assertEquals("replyTo1", reply.getMessageProperties().getReplyTo()); assertEquals("a", new String(reply.getMessageProperties().getCorrelationId(), "UTF-8")); }