// 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.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import com.rabbitmq.client.*; import org.junit.Test; import com.rabbitmq.client.test.BrokerTestCase; public class DirectReplyTo extends BrokerTestCase { private static final String QUEUE = "amq.rabbitmq.reply-to"; @Test public void roundTrip() throws IOException, InterruptedException { QueueMessageConsumer c = new QueueMessageConsumer(channel); String replyTo = rpcFirstHalf(c); declare(connection, replyTo, true); channel.confirmSelect(); basicPublishVolatile("response".getBytes(), "", replyTo, MessageProperties.BASIC); channel.waitForConfirms(); byte[] body = c.nextDelivery(10000); assertEquals("response", new String(body)); } @Test public void hack() throws IOException, InterruptedException { QueueMessageConsumer c = new QueueMessageConsumer(channel); String replyTo = rpcFirstHalf(c); // 5 chars should overwrite part of the key but not the pid; aiming to prove // we can't publish using just the pid replyTo = replyTo.substring(0, replyTo.length() - 5) + "xxxxx"; declare(connection, replyTo, false); basicPublishVolatile("response".getBytes(), "", replyTo, MessageProperties.BASIC); byte[] body = c.nextDelivery(500); assertNull(body); } private void declare(Connection connection, String q, boolean expectedExists) throws IOException { Channel ch = connection.createChannel(); try { ch.queueDeclarePassive(q); assertTrue(expectedExists); } catch (IOException e) { assertFalse(expectedExists); checkShutdownSignal(AMQP.NOT_FOUND, e); // Hmmm... channel = connection.createChannel(); } } @Test public void consumeFail() throws IOException, InterruptedException { DefaultConsumer c = new DefaultConsumer(channel); Channel ch = connection.createChannel(); try { ch.basicConsume(QUEUE, false, c); } catch (IOException e) { // Can't have ack mode checkShutdownSignal(AMQP.PRECONDITION_FAILED, e); } ch = connection.createChannel(); ch.basicConsume(QUEUE, true, c); try { ch.basicConsume(QUEUE, true, c); } catch (IOException e) { // Can't have multiple consumers checkShutdownSignal(AMQP.PRECONDITION_FAILED, e); } } @Test public void consumeSuccess() throws IOException, InterruptedException { DefaultConsumer c = new DefaultConsumer(channel); String ctag = channel.basicConsume(QUEUE, true, c); channel.basicCancel(ctag); String ctag2 = channel.basicConsume(QUEUE, true, c); channel.basicCancel(ctag2); assertNotSame(ctag, ctag2); } private String rpcFirstHalf(Consumer c) throws IOException { channel.basicConsume(QUEUE, true, c); String serverQueue = channel.queueDeclare().getQueue(); basicPublishVolatile("request".getBytes(), "", serverQueue, props()); GetResponse req = channel.basicGet(serverQueue, true); return req.getProps().getReplyTo(); } private AMQP.BasicProperties props() { return MessageProperties.BASIC.builder().replyTo(QUEUE).build(); } class QueueMessageConsumer extends DefaultConsumer { BlockingQueue<byte[]> messages = new LinkedBlockingQueue<byte[]>(); public QueueMessageConsumer(Channel channel) { super(channel); } @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { messages.add(body); } byte[] nextDelivery() { return messages.poll(); } byte[] nextDelivery(long timeoutInMs) throws InterruptedException { return messages.poll(timeoutInMs, TimeUnit.MILLISECONDS); } } }