// Copyright (c) 2007-Present Pivotal Software, Inc. All rights reserved. // // This software, the RabbitMQ Java client library, is triple-licensed under the // Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2 // ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see // LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2. For the ASL, // please see LICENSE-APACHE2. // // This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, // either express or implied. See the LICENSE file for specific language governing // rights and limitations of this software. // // If you have any questions regarding licensing, please contact us at // info@rabbitmq.com. package com.rabbitmq.client.test.functional; 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 java.io.IOException; import java.util.Arrays; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import com.rabbitmq.client.*; import org.junit.Test; import com.rabbitmq.client.test.BrokerTestCase; public class Recover extends BrokerTestCase { String queue; final byte[] body = "message".getBytes(); public void createResources() throws IOException { AMQP.Queue.DeclareOk ok = channel.queueDeclare(); queue = ok.getQueue(); } static interface RecoverCallback { void recover(Channel channel) throws IOException; } // The AMQP specification under-specifies the behaviour when // requeue=false. So we can't really test any scenarios for // requeue=false. void verifyRedeliverOnRecover(RecoverCallback call) throws IOException, InterruptedException { QueueingConsumer consumer = new QueueingConsumer(channel); channel.basicConsume(queue, false, consumer); // require acks. channel.basicPublish("", queue, new AMQP.BasicProperties.Builder().build(), body); QueueingConsumer.Delivery delivery = consumer.nextDelivery(); assertTrue("consumed message body not as sent", Arrays.equals(body, delivery.getBody())); // Don't ack it, and get it redelivered to the same consumer call.recover(channel); QueueingConsumer.Delivery secondDelivery = consumer.nextDelivery(5000); assertNotNull("timed out waiting for redelivered message", secondDelivery); assertTrue("consumed (redelivered) message body not as sent", Arrays.equals(body, delivery.getBody())); } void verifyNoRedeliveryWithAutoAck(RecoverCallback call) throws IOException, InterruptedException { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference<byte[]> bodyReference = new AtomicReference<byte[]>(); Consumer consumer = new DefaultConsumer(channel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { bodyReference.set(body); latch.countDown(); } }; channel.basicConsume(queue, true, consumer); // auto ack. channel.basicPublish("", queue, new AMQP.BasicProperties.Builder().build(), body); assertTrue(latch.await(5, TimeUnit.SECONDS)); assertTrue("consumed message body not as sent", Arrays.equals(body, bodyReference.get())); call.recover(channel); assertNull("should be no message available", channel.basicGet(queue, true)); } final RecoverCallback recoverSync = new RecoverCallback() { public void recover(Channel channel) throws IOException { channel.basicRecover(true); } }; final RecoverCallback recoverSyncConvenience = new RecoverCallback() { public void recover(Channel channel) throws IOException { channel.basicRecover(); } }; @Test public void redeliveryOnRecover() throws IOException, InterruptedException { verifyRedeliverOnRecover(recoverSync); } @Test public void redeliverOnRecoverConvenience() throws IOException, InterruptedException { verifyRedeliverOnRecover(recoverSyncConvenience); } @Test public void noRedeliveryWithAutoAck() throws IOException, InterruptedException { verifyNoRedeliveryWithAutoAck(recoverSync); } @Test public void requeueFalseNotSupported() throws Exception { try { channel.basicRecover(false); fail("basicRecover(false) should not be supported"); } catch(IOException ioe) { checkShutdownSignal(AMQP.NOT_IMPLEMENTED, ioe); } } }