Simple Camel test fails with no messages recieved - apache-camel

Am using Spring Boot and I have just added camel to it.
I have a simple camel route setup :
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;
#Component
public class MyRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("file://in").to("file://out");
}
}
When I try to create simple test for this route with :
#RunWith(CamelSpringBootRunner.class)
#SpringBootTest
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class MyRouteTest extends CamelTestSupport {
#Autowired
private CamelContext camelContext;
#Produce(uri = "file://in")
private ProducerTemplate producerTemplate;
#EndpointInject(uri = "mock:file://out")
private MockEndpoint mockEndpoint;
#Test
public void routeTest() throws Exception {
mockEndpoint.expectedMessageCount(1);
producerTemplate.sendBody("Test");
mockEndpoint.assertIsSatisfied();
}
}
It fails with
mock://file://out Received message count. Expected: <1> but was: <0>
Not sure what could be a problem here. I have producer template that has uri as my route from point and am mocking to endpoint with EndpointInject and the the mock uri?

Fixed but not 100%
If I change route from real one
from("file://in").to("file://out");
to
from("file://in").to("mock:out");
And in my test override
#Override
protected RoutesBuilder createRouteBuilder() throws Exception {
return new MyRoute();
}
to create specific route
and strangest of all ! Had to remove :
#SpringBootTest
and after that
private CamelContext camelContext;
And then it started working !
But unfortunately not what I need, still there are things that need to be fixed, I would like to use my real prod route !
from("file://in").to("file://out");
And if possible not use advise on route , but just mock it , tried with
mock:file://out in test, but it didnt work :(
and also , it does not work with #SpringBootTest ??? very strange ?!

You need to add
#Override
public String isMockEndpoints() {
return "*";
}
This should mock all the enpoints and then you can use mock:file:out for example

If I am not misstaken you are mocking your output endpoint yet your endpoint endpoint is a file endpoint. When you send a message you need to drop a message to whereever the file endpoint is polling. Otherwise you need to mock that as well.

Related

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.

Working with apache camel Bean in Quarkus framework

I am trying to use apache camel with Quarkus. Previously I was using the spring-boot framework to develop camel integration. So there are lots of questions that I am still trying to figure out w.r.t. Quarkus framework.
Regarding: Bean
In spring-boot I could do something like this
#Configuration
public class JABXContextConfig {
#Bean
Unmarshaller jaxbUnmarshaller() throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(MyPOJO.class );
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
return jaxbUnmarshaller;
}
}
and then I could inject it into the class using DI
#Component
public class MyRestServiceRoute extends RouteBuilder {
private final JaxbDataFormat jaxb;
#Autowired
public MyRestServiceRoute(JaxbDataFormat jaxb) throws Exception{
this.jaxb = jaxb;
}
....
}
QUESTION:
How can I do the same in the Quarkus framework?
P.S> I tried replacing #Configuration with #ApplicationScoped and #Bean with #Dependent but it's not working.
Thanks,
I recommend taking a read through the Quarkus CDI documentation:
https://quarkus.io/guides/cdi
https://quarkus.io/guides/cdi-reference
There's also a basic overview of using CDI to configure Camel:
https://camel.apache.org/camel-quarkus/latest/user-guide/bootstrap.html#_cdi
https://camel.apache.org/camel-quarkus/latest/user-guide/cdi.html
In your examples, #Bean could be replaced by a producer method like:
public class JaxbDataFormatProducer {
#ApplicationScoped
JaxbDataFormat jaxbDataFormat() {
return new JaxbDataFormat();
}
}
And the #Autowired constructor argument might look like this (If there’s only one constructor then there's actually no need for #Inject):
#ApplicationScoped
public class MyRestServiceRoute extends BaseRouteBuilder {
private final JaxbDataFormat jaxb;
#Inject
public MyRestServiceRoute(JaxbDataFormat jaxb) throws Exception{
super(properties);
this.jaxb = jaxb;
}
}

Unit testing log nodes in Apache camel routes

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");
}
}

camel return value from external Web Service

I need to invoke an external Web service running on WildFly from camel.
I managed to invoke it using the following route:
public class CamelRoute extends RouteBuilder {
final String cxfUri =
"cxf:http://localhost:8080/DemoWS/HelloWorld?" +
"serviceClass=" + HelloWorld.class.getName();
#Override
public void configure() throws Exception {
from("direct:start")
.id("wsClient")
.log("${body}")
.to(cxfUri + "&defaultOperationName=greet");
}
}
My question is how to get the return value from the Web service invocation ? The method used returns a String :
#WebService
public class HelloWorld implements Hello{
#Override
public String greet(String s) {
// TODO Auto-generated method stub
return "Hello "+s;
}
}
If the service in the Wild Fly returns the value then to see the values you can do the below
public class CamelRoute extends RouteBuilder {
final String cxfUri =
"cxf:http://localhost:8080/DemoWS/HelloWorld?" +
"serviceClass=" + HelloWorld.class.getName();
#Override
public void configure() throws Exception {
from("direct:start")
.id("wsClient")
.log("${body}")
.to(cxfUri + "&defaultOperationName=greet").log("${body}");
//beyond this to endpoint you can as many number of componenets to manipulate the response data.
}
}
The second log will log the response from the web service that you are returning. If you need to manipulate or do some routing and transformation with the response then you should look at the type of the response and accordingly you should use appropriate transformer.
Hope this helps.

Migrating from CamelTestSupport to AbstractCamelTestNGSpringContextTests

I've been using Apache Camel since 3-4 months on Spring 4.0.7.RELEASE
I have several Camel 2.14.0 TestNG tests based on extending CamelTestSupport, in which I use some MockEndpoints.
I configured my routes by overriding the createRouteBuilder() method.
Now I would need also to inject some Spring beans in one of them, by #Autowired annotation.
By reading what is said at http://camel.apache.org/spring-testing.html, I understood that I've to extend AbstractCamelTestNGSpringContextTests now, which supports #Autowired, #DirtiesContext, and #ContextConfiguration.
While I understood that all MockEndpoints are no more accessible by getMockEndpoint() method, but by using #EndpointInject annotation, it is not clear to me is how I can express my routes, because createRouteBuilder() is not more available.
I saw that is possible to define producers and consumers by using annotations, but I cannot manage to understand how routes can be designed.
Many thanks to the community.
Alternatively to the solution given here, you may use the TestNG helper CamelSpringTestSupport in combination with AnnotationConfigApplicationContextif you want to initialize an annotated based Spring configuration context without the need of an additional XML Spring configuration file.
Camel configuration bean class using Spring annotations:
#Configuration
public class MyConfig extends SingleRouteCamelConfiguration {
#Bean
#Override
public RouteBuilder route() {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from("direct:test").to("mock:direct:end");
}
};
}
}
The TestNG test class extends CamelSpringTestSupport and the Spring configuration MyConfig is initialized with AnnotationConfigApplicationContext:
public class TestNGTest extends org.apache.camel.testng.CamelSpringTestSupport {
#EndpointInject(uri = "mock:direct:end")
protected MockEndpoint errorEndpoint;
#Produce(uri = "direct:test")
protected ProducerTemplate testProducer;
#Override
protected AbstractApplicationContext createApplicationContext() {
return new AnnotationConfigApplicationContext(MyConfig.class);
}
#DirtiesContext
#Test
public void testRoute() throws InterruptedException {
// use templates and endpoints
}
}

Resources