/* * Copyright (c) 2011-2015 The original author or authors * ------------------------------------------------------ * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Apache License v2.0 which accompanies this distribution. * * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * * The Apache License v2.0 is available at * http://www.opensource.org/licenses/apache2.0.php * * You may elect to redistribute this code under either of these licenses. */ package io.vertx.camel; import com.jayway.awaitility.Duration; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.core.json.JsonObject; import io.vertx.ext.stomp.StompClient; import io.vertx.ext.stomp.StompClientConnection; import io.vertx.ext.stomp.StompServer; import io.vertx.ext.stomp.StompServerHandler; import io.vertx.ext.unit.Async; import io.vertx.ext.unit.TestContext; import io.vertx.ext.unit.junit.VertxUnitRunner; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.camel.ProducerTemplate; import org.apache.camel.impl.DefaultCamelContext; import org.apache.camel.spi.Synchronization; import org.apache.camel.support.SynchronizationAdapter; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import java.util.concurrent.atomic.AtomicReference; import static com.jayway.awaitility.Awaitility.await; import static io.vertx.camel.InboundMapping.fromCamel; /** * Tests that Camel exchanges are propagated to the event bus * * @author <a href="http://escoffier.me">Clement Escoffier</a> */ @RunWith(VertxUnitRunner.class) public class InboundEndpointTest { private static final Duration DEFAULT_TIMEOUT = Duration.TEN_SECONDS; private Vertx vertx; private DefaultCamelContext camel; private StompServer stomp; private CamelBridge bridge; @Before public void setUp() { vertx = Vertx.vertx(); camel = new DefaultCamelContext(); } @After public void tearDown(TestContext tc) throws Exception { if (bridge != null) { BridgeHelper.stopBlocking(bridge); } if (camel != null) { camel.stop(); } if (stomp != null) { stomp.close(null); } vertx.close(tc.asyncAssertSuccess()); } @Test public void testWithDirectEndpoint(TestContext context) throws Exception { Async async = context.async(); Endpoint endpoint = camel.getEndpoint("direct:foo"); bridge = CamelBridge.create(vertx, new CamelBridgeOptions(camel) .addInboundMapping(fromCamel("direct:foo").toVertx("test"))); vertx.eventBus().consumer("test", message -> { context.assertEquals("hello", message.body()); async.complete(); }); camel.start(); BridgeHelper.startBlocking(bridge); ProducerTemplate producer = camel.createProducerTemplate(); producer.asyncSendBody(endpoint, "hello"); } @Test public void testWithDirectEndpointAndCustomType(TestContext context) throws Exception { Async async = context.async(); Endpoint endpoint = camel.getEndpoint("direct:foo"); vertx.eventBus().registerDefaultCodec(Person.class, new PersonCodec()); bridge = CamelBridge.create(vertx, new CamelBridgeOptions(camel) .addInboundMapping(fromCamel("direct:foo").toVertx("test"))); vertx.eventBus().<Person>consumer("test", message -> { context.assertEquals("bob", message.body().getName()); async.complete(); }); camel.start(); BridgeHelper.startBlocking(bridge); ProducerTemplate producer = camel.createProducerTemplate(); producer.asyncSendBody(endpoint, new Person().setName("bob")); } @Test public void testWithDirectEndpointAndCustomTypeMissingCodec(TestContext context) throws Exception { Async async = context.async(); Endpoint endpoint = camel.getEndpoint("direct:foo"); bridge = CamelBridge.create(vertx, new CamelBridgeOptions(camel) .addInboundMapping(fromCamel("direct:foo").toVertx("test"))); camel.start(); BridgeHelper.startBlocking(bridge); ProducerTemplate producer = camel.createProducerTemplate(); producer.asyncSend(endpoint, exchange -> { Message message = exchange.getIn(); message.setBody(new Person().setName("bob")); exchange.addOnCompletion(new SynchronizationAdapter() { @Override public void onFailure(Exchange exchange) { context.assertTrue(exchange.getException().getMessage().contains("No message codec")); async.complete(); } }); }); } @Test public void testWithDirectEndpointWithHeaderCopy(TestContext context) throws Exception { Async async = context.async(); Endpoint endpoint = camel.getEndpoint("direct:foo"); bridge = CamelBridge.create(vertx, new CamelBridgeOptions(camel) .addInboundMapping(fromCamel("direct:foo").toVertx("test"))); vertx.eventBus().consumer("test", message -> { context.assertEquals("hello", message.body()); context.assertEquals(message.headers().get("key"), "value"); async.complete(); }); camel.start(); BridgeHelper.startBlocking(bridge); ProducerTemplate producer = camel.createProducerTemplate(); producer.asyncSend(endpoint, exchange -> { Message message = exchange.getIn(); message.setBody("hello"); message.setHeader("key", "value"); }); } @Test public void testWithDirectEndpointWithoutHeaderCopy(TestContext context) throws Exception { Async async = context.async(); Endpoint endpoint = camel.getEndpoint("direct:foo"); bridge = CamelBridge.create(vertx, new CamelBridgeOptions(camel) .addInboundMapping(fromCamel("direct:foo").toVertx("test").withoutHeadersCopy())); vertx.eventBus().consumer("test", message -> { context.assertEquals("hello", message.body()); context.assertNull(message.headers().get("key")); async.complete(); }); camel.start(); BridgeHelper.startBlocking(bridge); ProducerTemplate producer = camel.createProducerTemplate(); producer.asyncSend(endpoint, exchange -> { Message message = exchange.getIn(); message.setBody("hello"); message.setHeader("key", "value"); }); } @Test public void testWithDirectEndpoint2(TestContext context) throws Exception { Async async = context.async(); Endpoint endpoint = camel.getEndpoint("direct:foo"); bridge = CamelBridge.create(vertx, new CamelBridgeOptions(camel) .addInboundMapping(fromCamel(endpoint).toVertx("test"))); vertx.eventBus().consumer("test", message -> { context.assertEquals("hello", message.body()); async.complete(); }); camel.start(); BridgeHelper.startBlocking(bridge); ProducerTemplate producer = camel.createProducerTemplate(); producer.asyncSendBody(endpoint, "hello"); } @Test public void testWithDirectEndpointWithPublish(TestContext context) throws Exception { Async async = context.async(); Async async2 = context.async(); Endpoint endpoint = camel.getEndpoint("direct:foo"); bridge = CamelBridge.create(vertx, new CamelBridgeOptions(camel) .addInboundMapping(fromCamel(endpoint).toVertx("test").usePublish())); vertx.eventBus().consumer("test", message -> { context.assertEquals("hello", message.body()); async.complete(); }); vertx.eventBus().consumer("test", message -> { context.assertEquals("hello", message.body()); async2.complete(); }); camel.start(); BridgeHelper.startBlocking(bridge); ProducerTemplate producer = camel.createProducerTemplate(); producer.asyncSendBody(endpoint, "hello"); } @Test public void testWithDirectEndpointWithPublishAndCustomType(TestContext context) throws Exception { Async async = context.async(); Async async2 = context.async(); Endpoint endpoint = camel.getEndpoint("direct:foo"); vertx.eventBus().registerDefaultCodec(Person.class, new PersonCodec()); bridge = CamelBridge.create(vertx, new CamelBridgeOptions(camel) .addInboundMapping(fromCamel(endpoint).toVertx("test").usePublish())); vertx.eventBus().<Person>consumer("test", message -> { context.assertEquals("bob", message.body().getName()); async.complete(); }); vertx.eventBus().<Person>consumer("test", message -> { context.assertEquals("bob", message.body().getName()); async2.complete(); }); camel.start(); BridgeHelper.startBlocking(bridge); ProducerTemplate producer = camel.createProducerTemplate(); producer.asyncSendBody(endpoint, new Person().setName("bob")); } @Test public void testWithDirectEndpointWithPublishAndCustomTypeNoCodec(TestContext context) throws Exception { Async async = context.async(); Endpoint endpoint = camel.getEndpoint("direct:foo"); bridge = CamelBridge.create(vertx, new CamelBridgeOptions(camel) .addInboundMapping(fromCamel(endpoint).toVertx("test").usePublish())); camel.start(); BridgeHelper.startBlocking(bridge); ProducerTemplate producer = camel.createProducerTemplate(); producer.asyncSend(endpoint, exchange -> { Message message = exchange.getIn(); message.setBody(new Person().setName("bob")); exchange.addOnCompletion(new SynchronizationAdapter() { @Override public void onFailure(Exchange exchange) { context.assertTrue(exchange.getException().getMessage().contains("No message codec")); async.complete(); } }); }); } @Test public void testWithStomp(TestContext context) throws Exception { StompServerHandler serverHandler = StompServerHandler.create(vertx); StompServer.create(vertx).handler(serverHandler).listen(context.asyncAssertSuccess(s -> { stomp = s; })); await().atMost(DEFAULT_TIMEOUT).until(() -> stomp != null); Async async = context.async(); Endpoint endpoint = camel.getEndpoint("stomp:queue"); bridge = CamelBridge.create(vertx, new CamelBridgeOptions(camel) .addInboundMapping(fromCamel(endpoint).toVertx("test"))); vertx.eventBus().consumer("test", message -> { // We get a buffer. context.assertEquals("hello", message.body().toString()); async.complete(); }); camel.start(); Async a = context.async(); bridge.start(context.asyncAssertSuccess(v -> a.complete())); a.awaitSuccess(20000); AtomicReference<StompClientConnection> clientRef = new AtomicReference<>(); StompClient.create(vertx).connect(context.asyncAssertSuccess(client -> { clientRef.set(client); client.send("queue", Buffer.buffer("hello"), context.asyncAssertSuccess(receipt -> { })); })); try { async.awaitSuccess(20000); } finally { clientRef.get().close(); } } @Test @Ignore public void testWithStompAndJson(TestContext context) throws Exception { StompServerHandler serverHandler = StompServerHandler.create(vertx); StompServer.create(vertx).handler(serverHandler).listen(ar -> { stomp = ar.result(); }); await().atMost(DEFAULT_TIMEOUT).until(() -> stomp != null); Async async = context.async(); Endpoint endpoint = camel.getEndpoint("stomp:queue"); bridge = CamelBridge.create(vertx, new CamelBridgeOptions(camel) .addInboundMapping(fromCamel(endpoint).toVertx("test"))); vertx.eventBus().<Buffer>consumer("test", message -> { // We get a buffer. JsonObject json = message.body().toJsonObject(); context.assertEquals("bar", json.getString("foo")); async.complete(); }); camel.start(); BridgeHelper.startBlocking(bridge); StompClient.create(vertx).connect(connection -> { connection.result().send("queue", Buffer.buffer(new JsonObject().put("foo", "bar").encode())); connection.result().close(); }); } /** * Reproducer for https://github.com/vert-x3/vertx-camel-bridge/issues/27 */ @Test public void testReplyTimeout(TestContext tc) throws Exception { Async async = tc.async(); Endpoint endpoint = camel.getEndpoint("direct:foo"); bridge = CamelBridge.create(vertx, new CamelBridgeOptions(camel) .addInboundMapping(fromCamel(endpoint).toVertx("test").setTimeout(5000))); camel.start(); BridgeHelper.startBlocking(bridge); vertx.eventBus().consumer("test", message -> { // Simulate a timeout, so do not reply. }); ProducerTemplate producer = camel.createProducerTemplate(); long begin = System.currentTimeMillis(); producer.asyncCallbackRequestBody(endpoint, "ping", new Synchronization() { @Override public void onComplete(Exchange exchange) { tc.fail("The interaction should fail"); } @Override public void onFailure(Exchange exchange) { tc.assertTrue(exchange.getException().getMessage().contains("Timed out")); tc.assertTrue(exchange.getException().getMessage().contains("5000")); long end = System.currentTimeMillis(); tc.assertTrue((end - begin) < 20000); async.complete(); } }); } @Test public void testNoReceiver(TestContext tc) throws Exception { Async async = tc.async(); Endpoint endpoint = camel.getEndpoint("direct:foo"); bridge = CamelBridge.create(vertx, new CamelBridgeOptions(camel) .addInboundMapping(fromCamel(endpoint).toVertx("test").setTimeout(5000))); camel.start(); BridgeHelper.startBlocking(bridge); // Unlike the previous test, we don't register a consumer. ProducerTemplate producer = camel.createProducerTemplate(); producer.asyncCallbackRequestBody(endpoint, "ping", new Synchronization() { @Override public void onComplete(Exchange exchange) { tc.fail("The interaction should fail"); } @Override public void onFailure(Exchange exchange) { tc.assertTrue(exchange.getException().getMessage().contains("No handlers for address test")); async.complete(); } }); } }