// 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.fail; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.junit.Test; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Consumer; import com.rabbitmq.client.DefaultConsumer; import com.rabbitmq.client.test.BrokerTestCase; public class QueueLease extends BrokerTestCase { private final static String TEST_EXPIRE_QUEUE = "leaseq"; private final static String TEST_NORMAL_QUEUE = "noleaseq"; private final static String TEST_EXPIRE_REDECLARE_QUEUE = "equivexpire"; // Currently the expiration timer is very responsive but this may // very well change in the future, so tweak accordingly. private final static int QUEUE_EXPIRES = 1000; // msecs private final static int SHOULD_EXPIRE_WITHIN = 2000; /** * Verify that a queue with the 'x-expires` flag is actually deleted within * a sensible period of time after expiry. */ @Test public void queueExpires() throws IOException, InterruptedException { verifyQueueExpires(TEST_EXPIRE_QUEUE, true); } /** * Verify that the server does not delete normal queues... ;) */ @Test public void doesNotExpireOthers() throws IOException, InterruptedException { verifyQueueExpires(TEST_NORMAL_QUEUE, false); } @Test public void expireMayBeByte() throws IOException { Map<String, Object> args = new HashMap<String, Object>(); args.put("x-expires", (byte)100); try { channel.queueDeclare("expiresMayBeByte", false, true, false, args); } catch (IOException e) { fail("server did not accept x-expires of type byte"); } } @Test public void expireMayBeShort() throws IOException { Map<String, Object> args = new HashMap<String, Object>(); args.put("x-expires", (short)100); try { channel.queueDeclare("expiresMayBeShort", false, true, false, args); } catch (IOException e) { fail("server did not accept x-expires of type short"); } } @Test public void expireMayBeLong() throws IOException { Map<String, Object> args = new HashMap<String, Object>(); args.put("x-expires", 100L); try { channel.queueDeclare("expiresMayBeLong", false, true, false, args); } catch (IOException e) { fail("server did not accept x-expires of type long"); } } @Test public void expireMustBeGtZero() throws IOException { Map<String, Object> args = new HashMap<String, Object>(); args.put("x-expires", 0); try { channel.queueDeclare("expiresMustBeGtZero", false, false, false, args); fail("server accepted x-expires of zero ms."); } catch (IOException e) { checkShutdownSignal(AMQP.PRECONDITION_FAILED, e); } } @Test public void expireMustBePositive() throws IOException { Map<String, Object> args = new HashMap<String, Object>(); args.put("x-expires", -10); try { channel.queueDeclare("expiresMustBePositive", false, false, false, args); fail("server accepted negative x-expires."); } catch (IOException e) { checkShutdownSignal(AMQP.PRECONDITION_FAILED, e); } } /** * Verify that the server throws an error if the client redeclares a queue * with mismatching 'x-expires' values. */ @Test public void queueRedeclareEquivalence() throws IOException { Map<String, Object> args1 = new HashMap<String, Object>(); args1.put("x-expires", 10000); Map<String, Object> args2 = new HashMap<String, Object>(); args2.put("x-expires", 20000); channel.queueDeclare(TEST_EXPIRE_REDECLARE_QUEUE, false, false, false, args1); try { channel.queueDeclare(TEST_EXPIRE_REDECLARE_QUEUE, false, false, false, args2); fail("Able to redeclare queue with mismatching expire flags."); } catch (IOException e) { checkShutdownSignal(AMQP.PRECONDITION_FAILED, e); } } @Test public void activeQueueDeclareExtendsLease() throws InterruptedException, IOException { Map<String, Object> args = new HashMap<String, Object>(); args.put("x-expires", QUEUE_EXPIRES); channel.queueDeclare(TEST_EXPIRE_QUEUE, false, false, false, args); Thread.sleep(QUEUE_EXPIRES * 3 / 4); try { channel.queueDeclare(TEST_EXPIRE_QUEUE, false, false, false, args); } catch (IOException e) { checkShutdownSignal(AMQP.NOT_FOUND, e); fail("Queue expired before active re-declaration."); } Thread.sleep(QUEUE_EXPIRES * 3 / 4); try { channel.queueDeclarePassive(TEST_EXPIRE_QUEUE); } catch (IOException e) { checkShutdownSignal(AMQP.NOT_FOUND, e); fail("Queue expired: active re-declaration did not extend lease."); } } @Test public void passiveQueueDeclareExtendsLease() throws InterruptedException, IOException { Map<String, Object> args = new HashMap<String, Object>(); args.put("x-expires", QUEUE_EXPIRES); channel.queueDeclare(TEST_EXPIRE_QUEUE, false, false, false, args); Thread.sleep(QUEUE_EXPIRES * 3 / 4); try { channel.queueDeclarePassive(TEST_EXPIRE_QUEUE); } catch (IOException e) { checkShutdownSignal(AMQP.NOT_FOUND, e); fail("Queue expired before before passive re-declaration."); } Thread.sleep(QUEUE_EXPIRES * 3 / 4); try { channel.queueDeclarePassive(TEST_EXPIRE_QUEUE); } catch (IOException e) { checkShutdownSignal(AMQP.NOT_FOUND, e); fail("Queue expired: passive redeclaration did not extend lease."); } } @Test public void expiresWithConsumers() throws InterruptedException, IOException { Map<String, Object> args = new HashMap<String, Object>(); args.put("x-expires", QUEUE_EXPIRES); channel.queueDeclare(TEST_EXPIRE_QUEUE, false, false, false, args); Consumer consumer = new DefaultConsumer(channel); String consumerTag = channel.basicConsume(TEST_EXPIRE_QUEUE, consumer); Thread.sleep(SHOULD_EXPIRE_WITHIN); try { channel.queueDeclarePassive(TEST_EXPIRE_QUEUE); } catch (IOException e) { checkShutdownSignal(AMQP.NOT_FOUND, e); fail("Queue expired before before passive re-declaration."); } channel.basicCancel(consumerTag); Thread.sleep(SHOULD_EXPIRE_WITHIN); try { channel.queueDeclarePassive(TEST_EXPIRE_QUEUE); fail("Queue should have been expired by now."); } catch (IOException e) { checkShutdownSignal(AMQP.NOT_FOUND, e); } } void verifyQueueExpires(String name, boolean expire) throws IOException, InterruptedException { Map<String, Object> args = new HashMap<String, Object>(); if (expire) { args.put("x-expires", QUEUE_EXPIRES); } channel.queueDeclare(name, false, false, false, args); Thread.sleep(SHOULD_EXPIRE_WITHIN / 4); try { channel.queueDeclarePassive(name); } catch (IOException e) { checkShutdownSignal(AMQP.NOT_FOUND, e); fail("Queue expired before deadline."); } Thread.sleep(SHOULD_EXPIRE_WITHIN); // be on the safe side try { channel.queueDeclarePassive(name); if (expire) { fail("Queue should have been expired by now."); } } catch (IOException e) { if (expire) { checkShutdownSignal(AMQP.NOT_FOUND, e); } else { fail("Queue without expire flag deleted."); } } } protected void releaseResources() throws IOException { try { channel.queueDelete(TEST_NORMAL_QUEUE); channel.queueDelete(TEST_EXPIRE_QUEUE); channel.queueDelete(TEST_EXPIRE_REDECLARE_QUEUE); } catch (IOException e) { } super.releaseResources(); } }