Testing routes with fixed endpoints using AOP

When working with Camel you may at some point need to test a route that has endpoint URIs hardcoded into it. This tends to be more typical when testing Spring or Blueprint routes.

Consider the following route defined in /META-INF/spring/fixedEndpoints-context.xml:

<route id="modifyPayloadBetweenQueues">
  <from uri="activemq:in"/>
  <transform>
    <simple>Modified: ${body}</simple>
  </transform>
  <to uri="activemq:out"/>
</route>

The route endpoints here make use of the ActiveMQ Component to consume from one queue and publish to another. We would like to test this logic as described in the Testing routes defined in Spring recipe, in a pure unit test without making any changes to the route.

Camel provides you with a built-in form of Aspect-Oriented Programming (AOP) in the form of the adviceWith(..) Java DSL. This feature allows you to modify routing logic, once it has been loaded into the Camel context, to replace the route endpoints with direct: and mock: in order to make it easier to test. This recipe will show you how to use this approach to modify an existing route with fixed endpoints.

Getting ready

The Java code for this recipe is located in the org.camelcookbook.examples.testing.advicewith package.

How to do it...

In order to apply AOP to your tests, perform the following steps:

  1. In a test class that extends CamelSpringTestSupport, override the following method:
    @Override
    public boolean isUseAdviceWith() {
      return true;
    }

    This tells the base class to not start the Camel context before running each test method, as it would otherwise do.

  2. In your test method, fetch the route by its id (modifyPayloadBetweenQueues), and use the adviceWith(..) block to apply a new set of routing instructions over it using an AdviceWithRouteBuilder:
    context.getRouteDefinition("modifyPayloadBetweenQueues")
        .adviceWith(context, new AdviceWithRouteBuilder() () {
      @Override
      public void configure() throws Exception {
        replaceFromWith("direct:in");
    
        interceptSendToEndpoint("activemq:out")
          .skipSendToOriginalEndpoint()
          .to("mock:out");
      }
    });
  3. Start the Camel context manually, and proceed to test the route as you would otherwise do with direct: and mock: endpoints:
    context.start();
    
    MockEndpoint out = getMockEndpoint("mock:out");
    out.setExpectedMessageCount(1);
    out.message(0).body().isEqualTo("Modified: Cheese");
    
    template.sendBody("direct:in", "Cheese");
    
    assertMockEndpointsSatisfied();

How it works...

The adviceWith(..) statement allows us to provide a set of instructions to lay over the top of a route in order to modify its behavior. We define these instructions through a specialized DSL provided to us by overriding the AdviceWithRouteBuilder abstract class.

The isUseAdviceWith() method is defined in CamelTestSupport, which both CamelSpringTestSupport and CamelBlueprintTestSupport extend. This means that it can be used regardless of whether you are testing Java, Spring, or OSGi Blueprint routes. To achieve the same behavior in an Extended Spring Test, apply the org.apache.camel.test.spring.UseAdviceWith annotation to the test class to indicate the same thing.

There's more...

The adviceWith(..) mechanism can be used for a lot more than replacing the consumer and producer endpoints on a route. Using a technique called weaving , you can manipulate the route itself to remove or replace individual nodes. This can be handy if one step of your route is responsible for substantial processing that you want to skip for the purposes of testing, as in the following route:

from("direct:in").id("slowRoute")
  .process(new ReallySlowProcessor()).id("reallySlowProcessor")
  .to("mock:out");

To bypass the long-running process for testing, you can use the following to replace it with a much faster substitute:

context.getRouteDefinition("slowRoute")
  .adviceWith(context, new AdviceWithRouteBuilder() {
    @Override
    public void configure() throws Exception {
      weaveById("reallySlowProcessor").replace()
        .transform().simple("Fast reply to: ${body}");
    }
  });

In the preceding example, the node is fetched through weaveById(String), where the id attribute is one that you have assigned to the process DSL statement. You can also fetch nodes by a regular expression that matches the toString() representation of the node via weaveByToString(String), or by the internal Camel type of the node (for example, ToDefinition.class) through weaveByType(class).

Once a node has been selected via a weave..() method, the DSL gives you the following additional modification options:

  • before(): Add the nodes that follow immediately before the selected node
  • after(): Add the nodes that follow after the selected node, but before the next one in the original route
  • replace(): Replace the selected node with the following node(s)
  • remove(): Eliminate the selected node from the route
  • The methods weaveAddFirst() and weaveAddLast() can be used to add nodes to the start or end of a route that can be useful when you want to validate inputs or outputs, especially in routes used from other routes
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.143.255.36