/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.rabbitmq;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.camel.CamelExecutionException;
import org.apache.camel.Endpoint;
import org.apache.camel.EndpointInject;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.Produce;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.component.rabbitmq.testbeans.TestNonSerializableObject;
import org.apache.camel.component.rabbitmq.testbeans.TestPartiallySerializableObject;
import org.apache.camel.component.rabbitmq.testbeans.TestSerializableObject;
import org.apache.camel.impl.JndiRegistry;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Test;
public class RabbitMQInOutIntTest extends CamelTestSupport {
public static final String ROUTING_KEY = "rk5";
public static final long TIMEOUT_MS = 2000;
private static final String EXCHANGE = "ex5";
private static final String EXCHANGE_NO_ACK = "ex5.noAutoAck";
@Produce(uri = "direct:start")
protected ProducerTemplate template;
@Produce(uri = "direct:rabbitMQ")
protected ProducerTemplate directProducer;
@EndpointInject(uri = "rabbitmq:localhost:5672/" + EXCHANGE + "?threadPoolSize=1&exchangeType=direct&username=cameltest&password=cameltest"
+ "&autoAck=true&queue=q4&routingKey=" + ROUTING_KEY
+ "&transferException=true&requestTimeout=" + TIMEOUT_MS)
private Endpoint rabbitMQEndpoint;
@EndpointInject(uri = "rabbitmq:localhost:5672/" + EXCHANGE_NO_ACK + "?threadPoolSize=1&exchangeType=direct&username=cameltest&password=cameltest"
+ "&autoAck=false&autoDelete=false&durable=false&queue=q5&routingKey=" + ROUTING_KEY
+ "&transferException=true&requestTimeout=" + TIMEOUT_MS
+ "&queueArgs=#queueArgs")
private Endpoint noAutoAckEndpoint;
@EndpointInject(uri = "mock:result")
private MockEndpoint resultEndpoint;
@Override
protected JndiRegistry createRegistry() throws Exception {
JndiRegistry jndi = super.createRegistry();
HashMap<String, Object> queueArgs = new HashMap<>();
queueArgs.put("x-expires", 60000);
jndi.bind("queueArgs", queueArgs);
return jndi;
}
@Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
@Override
public void configure() throws Exception {
from("direct:rabbitMQ").id("producingRoute").setHeader("routeHeader", simple("routeHeader")).inOut(rabbitMQEndpoint);
from(rabbitMQEndpoint).id("consumingRoute").log("Receiving message").process(new Processor() {
public void process(Exchange exchange) throws Exception {
if (exchange.getIn().getBody(TestSerializableObject.class) != null) {
TestSerializableObject foo = exchange.getIn().getBody(TestSerializableObject.class);
foo.setDescription("foobar");
} else if (exchange.getIn().getBody(TestPartiallySerializableObject.class) != null) {
TestPartiallySerializableObject foo = exchange.getIn().getBody(TestPartiallySerializableObject.class);
foo.setNonSerializableObject(new TestNonSerializableObject());
foo.setDescription("foobar");
} else if (exchange.getIn().getBody(String.class) != null) {
if (exchange.getIn().getBody(String.class).contains("header")) {
assertEquals(exchange.getIn().getHeader("String"), "String");
assertEquals(exchange.getIn().getHeader("routeHeader"), "routeHeader");
}
if (exchange.getIn().getBody(String.class).contains("Exception")) {
throw new IllegalArgumentException("Boom");
}
if (exchange.getIn().getBody(String.class).contains("TimeOut")) {
Thread.sleep(TIMEOUT_MS * 2);
}
exchange.getIn().setBody(exchange.getIn().getBody(String.class) + " response");
}
}
});
from("direct:rabbitMQNoAutoAck").id("producingRouteNoAutoAck").setHeader("routeHeader", simple("routeHeader")).inOut(noAutoAckEndpoint);
from(noAutoAckEndpoint).id("consumingRouteNoAutoAck")
.to(resultEndpoint)
.throwException(new IllegalStateException("test exception"));
}
};
}
@Test
public void inOutRaceConditionTest1() throws InterruptedException, IOException {
String reply = template.requestBodyAndHeader("direct:rabbitMQ", "test1", RabbitMQConstants.EXCHANGE_NAME, EXCHANGE, String.class);
assertEquals("test1 response", reply);
}
@Test
public void inOutRaceConditionTest2() throws InterruptedException, IOException {
String reply = template.requestBodyAndHeader("direct:rabbitMQ", "test2", RabbitMQConstants.EXCHANGE_NAME, EXCHANGE, String.class);
assertEquals("test2 response", reply);
}
@Test
public void headerTest() throws InterruptedException, IOException {
Map<String, Object> headers = new HashMap<String, Object>();
TestSerializableObject testObject = new TestSerializableObject();
testObject.setName("header");
headers.put("String", "String");
headers.put("Boolean", new Boolean(false));
// This will blow up the connection if not removed before sending the message
headers.put("TestObject1", testObject);
// This will blow up the connection if not removed before sending the message
headers.put("class", testObject.getClass());
// This will mess up de-serialization if not removed before sending the message
headers.put("CamelSerialize", true);
// populate a map and an arrayList
Map<Object, Object> tmpMap = new HashMap<Object, Object>();
List<String> tmpList = new ArrayList<String>();
for (int i = 0; i < 3; i++) {
String name = "header" + i;
tmpList.add(name);
tmpMap.put(name, name);
}
// This will blow up the connection if not removed before sending the message
headers.put("arrayList", tmpList);
// This will blow up the connection if not removed before sending the message
headers.put("map", tmpMap);
String reply = template.requestBodyAndHeaders("direct:rabbitMQ", "header", headers, String.class);
assertEquals("header response", reply);
}
@Test
public void serializeTest() throws InterruptedException, IOException {
TestSerializableObject foo = new TestSerializableObject();
foo.setName("foobar");
TestSerializableObject reply = template.requestBodyAndHeader("direct:rabbitMQ", foo, RabbitMQConstants.EXCHANGE_NAME, EXCHANGE, TestSerializableObject.class);
assertEquals("foobar", reply.getName());
assertEquals("foobar", reply.getDescription());
}
@Test
public void partiallySerializeTest() throws InterruptedException, IOException {
TestPartiallySerializableObject foo = new TestPartiallySerializableObject();
foo.setName("foobar");
try {
TestPartiallySerializableObject reply = template.requestBodyAndHeader("direct:rabbitMQ", foo, RabbitMQConstants.EXCHANGE_NAME, EXCHANGE, TestPartiallySerializableObject.class);
} catch (CamelExecutionException e) {
// expected
}
// Make sure we didn't crash the one Consumer thread
String reply2 = template.requestBodyAndHeader("direct:rabbitMQ", "partiallySerializeTest1", RabbitMQConstants.EXCHANGE_NAME, EXCHANGE, String.class);
assertEquals("partiallySerializeTest1 response", reply2);
}
@Test
public void testSerializableObject() throws IOException {
TestSerializableObject foo = new TestSerializableObject();
foo.setName("foobar");
byte[] body = null;
try (ByteArrayOutputStream b = new ByteArrayOutputStream(); ObjectOutputStream o = new ObjectOutputStream(b);) {
o.writeObject(foo);
body = b.toByteArray();
}
TestSerializableObject newFoo = null;
try (InputStream b = new ByteArrayInputStream(body); ObjectInputStream o = new ObjectInputStream(b);) {
newFoo = (TestSerializableObject) o.readObject();
} catch (IOException | ClassNotFoundException e) {
}
assertEquals(foo.getName(), newFoo.getName());
}
@Test
public void inOutExceptionTest() {
try {
template.requestBodyAndHeader("direct:rabbitMQ", "Exception", RabbitMQConstants.EXCHANGE_NAME, EXCHANGE, String.class);
fail("This should have thrown an exception");
} catch (CamelExecutionException e) {
assertEquals(e.getCause().getClass(), IllegalArgumentException.class);
} catch (Exception e) {
fail("This should have caught CamelExecutionException");
}
}
@Test
public void inOutTimeOutTest() {
try {
template.requestBodyAndHeader("direct:rabbitMQ", "TimeOut", RabbitMQConstants.EXCHANGE_NAME, EXCHANGE, String.class);
fail("This should have thrown a timeOut exception");
} catch (CamelExecutionException e) {
// expected
} catch (Exception e) {
fail("This should have caught CamelExecutionException");
}
}
@Test
public void inOutNullTest() {
template.requestBodyAndHeader("direct:rabbitMQ", null, RabbitMQConstants.EXCHANGE_NAME, EXCHANGE, Object.class);
}
@Test
public void messageAckOnExceptionWhereNoAutoAckTest() throws Exception {
Map<String, Object> headers = new HashMap<>();
headers.put(RabbitMQConstants.EXCHANGE_NAME, EXCHANGE_NO_ACK);
headers.put(RabbitMQConstants.ROUTING_KEY, ROUTING_KEY);
resultEndpoint.expectedMessageCount(1);
try {
String reply = template.requestBodyAndHeaders("direct:rabbitMQNoAutoAck", "testMessage", headers, String.class);
fail("This should have thrown an exception");
} catch (CamelExecutionException e) {
if (!(e.getCause() instanceof IllegalStateException)) {
throw e;
}
}
resultEndpoint.assertIsSatisfied();
resultEndpoint.reset();
resultEndpoint.expectedMessageCount(0);
context.stop(); //On restarting the camel context, if the message was not acknowledged the message would be reprocessed
context.start();
resultEndpoint.assertIsSatisfied();
}
}