private void doListenerWithExceptionTest(CountDownLatch latch, Object listener) throws Exception {
   container = createContainer(listener);
   if (acknowledgeMode.isTransactionAllowed()) {
     // Should only need one message if it is going to fail
     for (int i = 0; i < concurrentConsumers; i++) {
       template.convertAndSend(queue.getName(), i + "foo");
     }
   } else {
     for (int i = 0; i < messageCount; i++) {
       template.convertAndSend(queue.getName(), i + "foo");
     }
   }
   try {
     boolean waited = latch.await(10 + Math.max(1, messageCount / 10), TimeUnit.SECONDS);
     assertTrue("Timed out waiting for message", waited);
   } finally {
     // Wait for broker communication to finish before trying to stop
     // container
     Thread.sleep(300L);
     container.shutdown();
     Thread.sleep(300L);
   }
   if (acknowledgeMode.isTransactionAllowed()) {
     assertNotNull(template.receiveAndConvert(queue.getName()));
   } else {
     assertNull(template.receiveAndConvert(queue.getName()));
   }
 }
  @After
  public void clear() throws Exception {
    // Wait for broker communication to finish before trying to stop container
    Thread.sleep(300L);
    logger.debug("Shutting down at end of test");
    if (container != null) {
      container.shutdown();
    }

    ((DisposableBean) template.getConnectionFactory()).destroy();
  }
  private void doTest(int concurrentConsumers, ContainerConfigurer configurer) {
    int messageCount = 10;
    RabbitTemplate template = new RabbitTemplate();
    CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
    connectionFactory.setHost("localhost");
    connectionFactory.setChannelCacheSize(concurrentConsumers);
    connectionFactory.setPort(BrokerTestUtils.getPort());
    template.setConnectionFactory(connectionFactory);
    SimpleMessageConverter messageConverter = new SimpleMessageConverter();
    messageConverter.setCreateMessageIds(true);
    template.setMessageConverter(messageConverter);
    for (int i = 0; i < messageCount; i++) {
      template.convertAndSend(queue1.getName(), new Integer(i));
      template.convertAndSend(queue2.getName(), new Integer(i));
    }
    final SimpleMessageListenerContainer container =
        new SimpleMessageListenerContainer(connectionFactory);
    final CountDownLatch latch = new CountDownLatch(messageCount * 2);
    PojoListener listener = new PojoListener(latch);
    container.setMessageListener(new MessageListenerAdapter(listener));
    container.setAcknowledgeMode(AcknowledgeMode.AUTO);
    container.setChannelTransacted(true);
    container.setConcurrentConsumers(concurrentConsumers);
    configurer.configure(container);
    container.afterPropertiesSet();
    container.start();
    try {
      int timeout = Math.min(1 + messageCount / concurrentConsumers, 30);
      boolean waited = latch.await(timeout, TimeUnit.SECONDS);
      logger.info("All messages recovered: " + waited);
      assertEquals(concurrentConsumers, container.getActiveConsumerCount());
      assertTrue("Timed out waiting for messages", waited);
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      throw new IllegalStateException("unexpected interruption");
    } finally {
      container.shutdown();
      assertEquals(0, container.getActiveConsumerCount());
    }
    assertNull(template.receiveAndConvert(queue1.getName()));
    assertNull(template.receiveAndConvert(queue2.getName()));

    connectionFactory.destroy();
  }
 @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()));
 }
  private void doTestRetry(
      int messageCount, int txSize, int failFrequency, int concurrentConsumers, boolean stateful)
      throws Exception {

    int failedMessageCount =
        messageCount / failFrequency + (messageCount % failFrequency == 0 ? 0 : 1);

    RabbitTemplate template = createTemplate(concurrentConsumers);
    for (int i = 0; i < messageCount; i++) {
      template.convertAndSend(queue.getName(), i);
    }

    final SimpleMessageListenerContainer container =
        new SimpleMessageListenerContainer(template.getConnectionFactory());
    PojoListener listener = new PojoListener(failFrequency);
    container.setMessageListener(new MessageListenerAdapter(listener));
    container.setAcknowledgeMode(AcknowledgeMode.AUTO);
    container.setChannelTransacted(true);
    container.setTxSize(txSize);
    container.setConcurrentConsumers(concurrentConsumers);

    final CountDownLatch latch = new CountDownLatch(failedMessageCount);
    container.setAdviceChain(new Advice[] {createRetryInterceptor(latch, stateful)});

    container.setQueueNames(queue.getName());
    container.afterPropertiesSet();
    container.start();

    try {

      int timeout = Math.min(1 + 2 * messageCount / concurrentConsumers, 30);

      final int count = messageCount;
      logger.debug("Waiting for messages with timeout = " + timeout + " (s)");
      Executors.newSingleThreadExecutor()
          .execute(
              () -> {
                while (container.getActiveConsumerCount() > 0) {
                  try {
                    Thread.sleep(100L);
                  } catch (InterruptedException e) {
                    latch.countDown();
                    Thread.currentThread().interrupt();
                    return;
                  }
                }
                for (int i = 0; i < count; i++) {
                  latch.countDown();
                }
              });
      boolean waited = latch.await(timeout, TimeUnit.SECONDS);
      logger.info("All messages recovered: " + waited);
      assertEquals(concurrentConsumers, container.getActiveConsumerCount());
      assertTrue("Timed out waiting for messages", waited);

      // Retried each failure 3 times (default retry policy)...
      assertEquals(3 * failedMessageCount, listener.getCount());

      // All failed messages recovered
      assertEquals(null, template.receiveAndConvert(queue.getName()));

    } finally {
      container.shutdown();
      ((DisposableBean) template.getConnectionFactory()).destroy();

      assertEquals(0, container.getActiveConsumerCount());
    }
  }