Unit testing log nodes in Apache camel routes - apache-camel

Suppose I have the following camel route:
.from("direct:start")
.log("received ${body} message")
.to("mock:end");
How would you test that the message "received Camel rocks!" message is logged when you send a "Camel rocks!" message to the direct:start endpoint

I would read the written file. Or add a custom appender to the logging system and assert that it received the message.
Or check Camel's internal unit tests.
But what exactly are you trying to achieve?
You are supposed to test your application and not the frameworks you are using.

I would not test the actual logging part, but why not save the data you are interested in a property or header, and then in your unit test assert that the value of that property or header must be such and such?

Here is a way to test this which I admit is a bit too invasive. It would have been much easier if AdviceWithBuilder would have been added something like replaceWith(ProcessDefinition replacement).
Here is the working example:
package com.my.org.some.pkg;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.AdviceWithRouteBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.testng.CamelTestSupport;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.springframework.test.util.ReflectionTestUtils;
import org.testng.annotations.Test;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class CamelLoggingTest extends CamelTestSupport {
#Override
protected RoutesBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from("direct:start").id("abc")
.log("received ${body} message")
.to("mock:stop");
}
};
}
#Test
public void shouldLogExpectedMessage() throws Exception {
Logger logger = Mockito.mock(Logger.class);
context.getRouteDefinition("abc").adviceWith(context, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
ReflectionTestUtils.setField(context.getRouteDefinition("abc")
.getOutputs().get(0), "logger", logger);
}
});
when(logger.isInfoEnabled()).thenReturn(true);
sendBody("direct:start", "Camel rocks!");
verify(logger).info("received Camel rocks! message");
}
}

Related

apache camel JUnit5 test case for database operation

I am trying to write Junit5 test case for apache camel router which has the DB operations.
Use case : There is an API call which will give me the data and my router is inserting those data to local database.
I have to write the test case to check the count from the database and compare it with the api data count which should match.
And the Database connection as well
My test class needs to get the count from the database and api to compare if both matches the assert satisfied .
Please help me to write test case for the same , Please refer the below for junit test case code.
Thanks in advance.
import org.apache.camel.CamelContext;
import org.apache.camel.EndpointInject;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.AdviceWith;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.http.base.HttpOperationFailedException;
import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.BootstrapWith;
#CamelSpringBootTest
#ActiveProfiles("mock")
#BootstrapWith(SpringBootTestContextBootstrapper.class)
public class TestingPersonStoringDatabase {
#Autowired
protected CamelContext camelContext;
#Autowired
private ProducerTemplate template;
#EndpointInject("mock:purePersonsEndpoint")
private MockEndpoint personsMock;
#EndpointInject("mock:storePersons")
private MockEndpoint mock;
#BeforeEach
public void setup() throws Exception {
AdviceWith.adviceWith(camelContext, "storePersonsRoute",
a -> a.weaveAddLast().to("sql:select count(*) as results from persons").setBody()
.simple("${body[0][RESULTS]}").log("RESULTS: ${body}").to("mock:storePersons"));
camelContext.start();
}
#Test
public void testPersons() throws Exception {
personsMock.whenAnyExchangeReceived(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
throw new HttpOperationFailedException("", 400, "Simulated API error", null, null, null);
}
});
//MockEndpoint.assertIsSatisfied(camelContext);
mock.expectsMessageCount(142);
personsMock.expectsMessageCount(142);
mock.assertIsSatisfied();
}
}
storePersonsRoute this router has a inserting data in the database

How to throw exceptions from interceptSendToEndpoint handler in camel

I want to simulate HTTP exceptions for testing purposes in an integration test setting. I am using interceptSendToEndpoint. From the handler I can log, modify headers or body, but I can't throw any exception back into the intercepted route. They just get logged and that's it. They are not caught by an onException handler or doTry..doCatch block of the intercepted route where the code is that I actually want to test.
So my handler looks like
interceptSendToEndpoint("undertow:*").when(method("exTest", "enabled"))
.throwException(new Exception(("my Exception")))
Can somebody help me out here? I am still on camel 2.25? Is this different between 2.x and 3.x?
If you're talking about unit testing then you should use adviceWith with weaveByToUri or weaveById to replace the http-endpoint with your custom logic that you can then configure to throw the exception.
As far as I understand interceptSendToEndpoint isn't really intended to be used like this in unit testing.
Example:
package com.example;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.AdviceWithRouteBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Test;
public class ExampleTest extends CamelTestSupport {
#Test
public void testHttpErrorHandling() throws Exception {
context.getRouteDefinition("testRoute").adviceWith(context, new AdviceWithRouteBuilder(){
#Override
public void configure() throws Exception {
weaveByToUri("http*")
.replace()
.throwException(Exception.class, "Test Exception");
weaveById("logHttpExceptionEndpoint")
.after()
.to("mock:result");
}
});
MockEndpoint resultMockEndpoint = getMockEndpoint("mock:result");
resultMockEndpoint.expectedMessageCount(1);
resultMockEndpoint.message(0).exchangeProperty("CamelExceptionCaught")
.isInstanceOf(Exception.class);
startCamelContext();
template.sendBody("direct:test", "");
resultMockEndpoint.assertIsSatisfied();
}
#Override
protected RoutesBuilder createRouteBuilder() throws Exception {
return new RouteBuilder(){
#Override
public void configure() throws Exception {
from("direct:test")
.routeId(("testRoute"))
.onException(Exception.class)
.log("caught exception.").id("logHttpExceptionEndpoint")
.handled(true)
.end()
.to("http:somewebsite.com")
.log("Hello from test");
}
};
}
#Override
public boolean isUseAdviceWith() {
return true;
}
}
As for integration testing you can use a stub or something like mockoon to simulate the web-services to see how they handle different kinds of exceptions outside unit tests.

Apache Camel - call simple language without side effect

Is it possible to call an object with the Simple language directly within the route and without side effects? The 2 approaches i've tried are;
.toD("${header.exchangeHelper.inc1()}") //works but fails if there is a return type from the called method
.bean(new Simple("${header.exchangeHelper.inc1()}")) //works but sets the body to false
Neither of which give the ideal solution.
You can store the result to exchange property or header instead. This way you'll keep the original body and get the result from your method in case you need it later. Alternatively you can just call the method using a processor.
These are generally better approaches with Java-DSL for something like this than using simple-language since they benefit from IDE's refactoring tools, error highlighting and many forms of linting.
package com.example;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.apache.camel.Exchange;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Test;
public class ExampleTest extends CamelTestSupport {
ExchangeHelper exchangeHelper = mock(ExchangeHelper.class);
#Test
public void useSetPropertyTest() throws Exception {
MockEndpoint resultMockEndpoint = getMockEndpoint("mock:result");
resultMockEndpoint.expectedMessageCount(1);
resultMockEndpoint.message(0).body().isEqualTo("Hello");
when(exchangeHelper.inc1()).thenReturn(true);
template.sendBodyAndHeader("direct:useSetProperty", "Hello",
"exchangeHelper", exchangeHelper);
verify(exchangeHelper, times(1)).inc1();
resultMockEndpoint.assertIsSatisfied();
}
#Test
public void justUseProcessorTest() throws Exception {
MockEndpoint resultMockEndpoint = getMockEndpoint("mock:result");
resultMockEndpoint.expectedMessageCount(1);
resultMockEndpoint.message(0).body().isEqualTo("Hello");
when(exchangeHelper.inc1()).thenReturn(true);
template.sendBody("direct:justUseProcessor", "Hello");
verify(exchangeHelper, times(1)).inc1();
resultMockEndpoint.assertIsSatisfied();
}
#Test
public void useHeaderFromProcessorTest() throws Exception {
MockEndpoint resultMockEndpoint = getMockEndpoint("mock:result");
resultMockEndpoint.expectedMessageCount(1);
resultMockEndpoint.message(0).body().isEqualTo("Hello");
when(exchangeHelper.inc1()).thenReturn(true);
template.sendBodyAndHeader("direct:useHeaderFromProcessor", "Hello",
"exchangeHelper", exchangeHelper);
verify(exchangeHelper, times(1)).inc1();
resultMockEndpoint.assertIsSatisfied();
}
#Override
protected RoutesBuilder createRouteBuilder() throws Exception {
return new RouteBuilder(){
#Override
public void configure() throws Exception {
from("direct:useSetProperty")
.setProperty("result")
.simple("${header.exchangeHelper.inc1()}")
.log("Body: ${body} Result header: ${exchangeProperty.result}")
.to("mock:result")
.removeProperty("result");
from("direct:justUseProcessor")
.process( ex -> { exchangeHelper.inc1(); })
.log("Body: ${body}")
.to("mock:result");
from("direct:useHeaderFromProcessor")
.process( ex -> {
ex.getMessage()
.getHeader("exchangeHelper", ExchangeHelper.class)
.inc1();
})
.log("Body: ${body}")
.to("mock:result");
}
};
}
interface ExchangeHelper {
public boolean inc1();
}
}
Not tried, but why not using the wiretap EIP to issue an extra (and separated!) request to your requestHelper method ?
Something like:
from("direct:demo")
.wireTap("bean:${header.exchangeHelper.inc1()}")
.to("direct:doSomething");
You can simply use Camel Script, something like that:
from("direct:exampleScript")
.script().simple("${header.exchangeHelper.inc1()}")
.log("End")
;

Apache-camel corda component connection error: Failed to create route route1

I am trying the connect to Corda using that component and sending data to Apache ActiveMQ again using Apache Camel's Corda component.
Corda is running properly. Particularly, cardapp-example is running, and Notary- PartyA - PartyB and PartyC are alive. I can query using their terminal.
ActiveMQ is working properly, I test it with another input source.
I've also tried to connect difeerent localhost ports of all four nodes, and also the example one showed in the Camel's corda component webpage.
public class CordaConnector {
public void ConnectToCorda() throws Exception {
CamelContext context = new DefaultCamelContext();
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
context.addComponent("jms", JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));
context.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("corda://localhost:10004?username=user1&password=test&operation=VAULT_TRACK&contractStateClass=#contractStateClass").
}
});
while(true) {
context.start();
}
}
}
I got the following error message:
Exception in thread "main" org.apache.camel.FailedToCreateRouteException: Failed to create route route1: Route(route1)[From[corda://localhost:10004?username=user1&pa... because of Failed to resolve endpoint: corda://localhost:10004?contractStateClass=%23contractStateClass&operation=VAULT_TRACK&password=test&username=user1 due to: Error binding property (contractStateClass=#contractStateClass) with name: contractStateClass on bean: org.apache.camel.component.corda.CordaConfiguration#1de76cc7 with value: #contractStateClass
...
So when tested seperately, corda works properly, ActiveMQ works properly (with different output), and I ave tried different ports to query information. I have alos tried different commands to query, such as:
from("corda://localhost:10000?username=user1&password=test&operation=NETWORK_MAP_FEED").
to("activemq:queue:try");
I've checked this question Failed to create route route1, but was no help.
I would appreciate any help on what might be the reason.
In your route from uri, you are setting the contractStateClass property using value #contractStateClass : this references a bean named contractStateClass in the Camel registry. But since you did not bind any bean with this name in the context registry, Camel fail to resolve this value: Error binding property (contractStateClass=#contractStateClass) with name: contractStateClass on bean: org.apache.camel.component.corda.CordaConfiguration#1de76cc7 with value: #contractStateClass
You simply need to configure a bean of type Class and provide it to the camel registry. Something like that should work ( camel version 2.24.x )
import net.corda.core.contracts.OwnableState;
import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.impl.SimpleRegistry;
public class CordaConnector {
public static void main(String[] args) {
try {
SimpleRegistry registry = new SimpleRegistry();
registry.put("contractStateClass", OwnableState.class);
CamelContext camelContext = new DefaultCamelContext(registry);
camelContext.addRoutes(new RouteBuilder() {
#Override
public void configure() {
from("corda://localhost:10004?username=user1&password=test&operation=VAULT_TRACK&contractStateClass=#contractStateClass")
.log("got message");
}
});
camelContext.start();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
EDIT for Camel v3.x :
import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.support.SimpleRegistry;
public class CordaConnector {
public static void main(String[] args) {
try {
SimpleRegistry registry = new SimpleRegistry();
registry.bind("contractStateClass", MyContractClass.class);
CamelContext camelContext = new DefaultCamelContext(registry);
camelContext.addRoutes(new RouteBuilder() {
#Override
public void configure() {
from("corda://localhost:10004?username=user1&password=test&operation=VAULT_TRACK&contractStateClass=#contractStateClass")
.log("got message");
}
});
camelContext.start();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

Why isn't Camel route test resolving placeholder endpoint?

I have a simple Camel route test class that I have expanded to use a placeholder for an endpoint.
import org.apache.camel.CamelContext;
import org.apache.camel.EndpointInject;
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.properties.PropertiesComponent;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Test;
import java.util.Properties;
public class SimpleTestRoute extends CamelTestSupport {
#EndpointInject(uri = "{{test.route.out}}")
protected MockEndpoint resultEndpoint;
#Produce(uri = "direct:start")
protected ProducerTemplate template;
#Test
public void test() throws Exception {
}
#Override
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from("direct:start").to("{{test.route.out}}");
}
};
}
#Override
protected CamelContext createCamelContext() throws Exception {
Properties props = new Properties();
props.setProperty("test.route.out", "mock:result");
CamelContext context = super.createCamelContext();
PropertiesComponent pc = context.getComponent("properties", PropertiesComponent.class);
pc.setOverrideProperties(props);
return context;
}
}
However, when I run I get
org.apache.camel.ResolveEndpointFailedException: Failed to resolve endpoint: {{test.route.out}} due to: Property with key [test.route.out] not found in properties from text: {{test.route.out}}
at ...
Caused by: java.lang.IllegalArgumentException: Property with key [test.route.out] not found in properties from text: {{test.route.out}}
at ...
I have tried various combinations of brace locations without progress. Now I suspect the problem is that the override is not being set but I cannot see what I am doing wrong or how to resolve it.
FWIW, I am running camel 2.13.1

Resources