5
votes

I am trying to write a Camel test that checks to ensure a content based router is routing XML files correctly. Here are the enpoints and the route in my blueprint.xml:

<endpoint uri="activemq:queue:INPUTQUEUE" id="jms.queue.input" />
<endpoint uri="activemq:queue:QUEUE1" id="jms.queue.1" />
<endpoint uri="activemq:queue:QUEUE2" id="jms.queue.2" />

<route id="general-jms.to.specific-jms">
    <from ref="jms.queue.input" />
    <choice>
      <when>
        <xpath>//object-type = '1'</xpath>
        <log message="Sending message to queue: QUEUE1" />
        <to ref="jms.queue.1" />
      </when>
      <when>
        <xpath>//object-type = '2'</xpath>
        <log message="Sending message to queue: QUEUE2" />
        <to ref="jms.queue.2" />
      </when>
      <otherwise>
        <log message="No output was able to be determined based on the input." />
      </otherwise>
    </choice>
</route>

Right now, all I am trying to do is send in a sample source file that has an <object-type> of 1 and verify that is it routed to the correct queue (QUEUE1) and is the correct data (should just send the entire XML file to QUEUE1). Here is my test code:

public class RouteTest extends CamelBlueprintTestSupport {

    @Override
    protected String getBlueprintDescriptor() {
        return "/OSGI-INF/blueprint/blueprint.xml";
    }

    @Override
    public String isMockEndpointsAndSkip() {
        return "activemq:queue:QUEUE1";
    }

    @Test
    public void testQueue1Route() throws Exception {

        getMockEndpoint("mock:activemq:queue:QUEUE1").expectedBodiesReceived(context.getTypeConverter().convertTo(String.class, new File("src/test/resources/queue1-test.xml")));

        template.sendBody("activemq:queue:INPUTQUEUE", context.getTypeConverter().convertTo(String.class, new File("src/test/resources/queue1-test.xml")));

        assertMockEndpointsSatisfied();
    }
}

When I run this test, I see the log message that I put in the route definition that says it is sending it to QUEUE1, but the JUnit test fails with this error message: java.lang.AssertionError: mock://activemq:queue:QUEUE1 Received message count. Expected: <1> but was: <0>.

Can someone help me understand what I am doing wrong?

My understanding is that Camel will automatically mock the QUEUE1 endpoint since I overrode the isMockEndpointsAndSkip() and provided the QUEUE1 endpoint uri. I thought this meant I should be able to use that endpoint in the getMockEnpoint() method just by appending "mock:" to the beginning of the uri. Then I should have a mocked endpoint of which I can set expections on (i.e. that is has to have the input file).

If I am unclear on something please let me know and any help is greatly appreciated!

2
Jon, I made a file queue1-test.xml with contents <object-type>1</object-type> and this test test worked for me (in equivalent java dsl, instead of xml route configuration). How does your input file look? - vikingsteve
My XML just contains <object-type>1</object-type>. I think there is something odd going on if you have this defined as XML. It doesn't seem like the isMockEndpointsAndSkip() method works if your route is defined in XML. It may have something to do with mocking ActiveMQ endpoints. This article seems to have gotten it to work with XML: Testing (utest and itest) Apache Camel Blueprint route (look under the Camel route and utest heading). - jonjon1123
No worries, well that i guess is the main difference between your code and mine. I use the java DSL out of habit, it's nice to have compile-time syntax checking and auto-complete. Worth considering? - vikingsteve
Those are 2 good points about using the Java DSL. I will check it out. Thanks for your help! - jonjon1123

2 Answers

9
votes

The solution is to use CamelTestSupport.replaceRouteFromWith.

This method is completely lacking any documentation, but it works for me when invoking it like this:

public class FooTest extends CamelTestSupport {

    @Override
    public void setUp() throws Exception {
        replaceRouteFromWith("route-id", "direct:route-input-replaced");
        super.setUp();
    }

    // other stuff ...

}

This will also prevent the starting of the original consumer of the from destination of the route. For example that means it isn't necessary anymore to have a activemq instance running when a route with an activemq consumer is to be tested.

0
votes

After working on this for quite some time, the only solution I came up with that actaully worked for me was to use the createRouteBuilder() method in my test class to add a route to a mocked endpoint at the end of the route defined in my blueprint.xml file. Then I can check that mocked endpoint for my expectations. Below is my final code for the test class. The blueprint XML remained the same.

public class RouteTest extends CamelBlueprintTestSupport {

@Override
protected String getBlueprintDescriptor() {
    return "/OSGI-INF/blueprint/blueprint.xml";
}

@Test
public void testQueue1Route() throws Exception {

    getMockEndpoint("mock:QUEUE1").expectedBodiesReceived(context.getTypeConverter().convertTo(String.class, new File("src/test/resources/queue1-test.xml")));

    template.sendBody("activemq:queue:INPUTQUEUE", context.getTypeConverter().convertTo(String.class, new File("src/test/resources/queue1-test.xml")));

    assertMockEndpointsSatisfied();
}

@Test
public void testQueue2Route() throws Exception {

    getMockEndpoint("mock:QUEUE2").expectedBodiesReceived(context.getTypeConverter().convertTo(String.class, new File("src/test/resources/queue2-test.xml")));

    template.sendBody("activemq:queue:INPUTQUEUE", context.getTypeConverter().convertTo(String.class, new File("src/test/resources/queue2-test.xml")));

    assertMockEndpointsSatisfied();
}

@Override
protected RouteBuilder createRouteBuilder() throws Exception {
    return new RouteBuilder() {
        public void configure() throws Exception {
            from("activemq:queue:QUEUE1").to("mock:QUEUE1");
            from("activemq:queue:QUEUE2").to("mock:QUEUE2");
        }
    };
}

}

While this solution works, I don't fully understand why I can't just use isMockEndpointsAndSkip() instead of having to manually define a new route at the end of my existing blueprint.xml route. It is my understanding that defining isMockEndpointsAndSkip() with return "*"; will inject mocked endpoints for all of your endpoints defined in your blueprint.xml file. Then you can check for your expections on those mocked endpoints. But for some reason, this does not work for me.