0

I'm working with unit tests using Camel and, When I execute this test from Camel In Action repository it works perfectly but when I change the route type from SEDA to direct-vm it fails with the following message:

Caused by: org.apache.camel.component.directvm.DirectVmConsumerNotAvailableException: No consumers available on endpoint: direct-vm://camel. Exchange[ID....

The difference of these 2 types, SEDA and direct-vm, is that the first is asynchronous and the second is synchronous. Is that the reason why the test fails? How can I make the test work for direct-vm type of routes?

I'm using JDK 1.8 and Camel 2.25.2

UPDATE: I have found an issue with the mockEndpoints() method inside the adviceWith, the routes are not being mocked. This is what is printed in the logs when I launch the test:

2021-07-20 16:27:36.501  INFO 31220 --- [           main] org.apache.camel.model.RouteDefinition   : Adviced route before/after as XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<route xmlns="http://camel.apache.org/schema/spring" customId="true" id="basicRoute">
    <from uri="direct-vm:quotes"/>
    <choice id="choice2">
        <when id="when2">
            <simple>${body} contains 'Camel'</simple>
            <log id="log4" loggingLevel="INFO" message="camel route"/>
            <to id="to11" uri="direct-vm:camel"/>
        </when>
        <otherwise id="otherwise2">
            <log id="log5" loggingLevel="INFO" message="other route"/>
            <to id="to12" uri="direct-vm:other"/>
        </otherwise>
    </choice>
</route>

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<route xmlns="http://camel.apache.org/schema/spring" customId="true" id="basicRoute">
    <from uri="direct-vm:hitme"/>
    <choice id="choice2">
        <when id="when2">
            <simple>${body} contains 'Camel'</simple>
            <log id="log4" loggingLevel="INFO" message="camel route"/>
            <to id="to11" uri="direct-vm:camel"/>
        </when>
        <otherwise id="otherwise2">
            <log id="log5" loggingLevel="INFO" message="other route"/>
            <to id="to12" uri="direct-vm:other"/>
        </otherwise>
    </choice>
</route>

But if I use instead weaveByToUri to mock the routes:

weaveByToUri("direct-vm:camel").replace().to("mock:direct-vm:camel");
weaveByToUri("direct-vm:other").replace().to("mock:direct-vm:other");

The routes are mocked and the test works:

2021-07-20 16:30:42.409  INFO 9920 --- [           main] org.apache.camel.model.RouteDefinition   : Adviced route before/after as XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<route xmlns="http://camel.apache.org/schema/spring" customId="true" id="basicRoute">
    <from uri="direct-vm:quotes"/>
    <choice id="choice2">
        <when id="when2">
            <simple>${body} contains 'Camel'</simple>
            <log id="log4" loggingLevel="INFO" message="camel route"/>
            <to id="to11" uri="direct-vm:camel"/>
        </when>
        <otherwise id="otherwise2">
            <log id="log5" loggingLevel="INFO" message="other route"/>
            <to id="to12" uri="direct-vm:other"/>
        </otherwise>
    </choice>
</route>

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<route xmlns="http://camel.apache.org/schema/spring" customId="true" id="basicRoute">
    <from uri="direct-vm:hitme"/>
    <choice id="choice2">
        <when id="when2">
            <simple>${body} contains 'Camel'</simple>
            <log id="log4" loggingLevel="INFO" message="camel route"/>
            <pipeline>
                <to uri="mock:direct-vm:camel"/>
            </pipeline>
        </when>
        <otherwise id="otherwise2">
            <log id="log5" loggingLevel="INFO" message="other route"/>
            <pipeline>
                <to uri="mock:direct-vm:other"/>
            </pipeline>
        </otherwise>
    </choice>
</route>

Should It be a bug in the mockEndpoints method?

Joselo
  • 127
  • 1
  • 10

2 Answers2

1

If you want to use direct-vm in a test you'll have to run another CamelContext that contains consumer for the direct-vm endpoint you want to test. You can do this with Main class.

public class Example extends CamelTestSupport {
    
    @Override
    protected CamelContext createCamelContext() throws Exception {
        return new DefaultCamelContext();
    }

    @Override
    protected RoutesBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder(){

            @Override
            public void configure() throws Exception {
              
                from("direct-vm:helloReceiver")
                    .routeId("helloReceiver")
                    .log("Message received: ${body}")
                    .to("mock:result");
            }
        };
    }

    @Test
    public void testDirectVM() throws Exception{

        RouteBuilder builder = new RouteBuilder(){

            @Override
            public void configure() throws Exception {
              
                from("direct:helloSender")
                    .routeId("helloSender")
                    .to("direct-vm:helloReceiver");
            }
        };
        
        MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
        mockEndpoint.expectedMessageCount(1);
        mockEndpoint.message(0).body().isEqualTo("hello");

        Main camelMain = new Main();
        camelMain.addRouteBuilder(builder);
        camelMain.start();

        camelMain.getCamelTemplate()
            .sendBody("direct:helloSender", "hello");

        mockEndpoint.assertIsSatisfied();
    }
}

However it would be better to just to use string variable with setter for the direct-vm endpoint that you can easily change to mock endpoint during testing. Give it id and you can use weaveById to make it return whatever you need for the tests.

Pasi Österman
  • 2,002
  • 1
  • 6
  • 13
  • Hi Pasi. Thanks for your reply. The thing is, the test should work without having the need to create a new camel context, I mean, if it works correctly for SEDA routes should work as well for DIRECT-VM routes. And I think I found the issue: The _mockEndpoints()_ command inside the _adviceWith_ method is not mocking the endpoints in the route. But by using **weaveByToUri("direct-vm:camel").replace().to("mock:direct-vm:camel");** and **weaveByToUri("direct-vm:other").replace().to("mock:direct-vm:other");** instead the test works. I guess there's a bug in mockEndpoints command for direct-vm routs – Joselo Jul 20 '21 at 14:24
  • SEDA and direct-vm endpoints differ in visibility. SEDA consumer endpoints are visible in the same camel-context where as direct-vm endpoints are visible inside same JVM. When you call direct-vm producer endpoint I am guessing that camel just assumes that the endpoint lies in another CamelContext that is running in the same JVM since otherwise you'd be calling direct or seda endpoint. – Pasi Österman Jul 20 '21 at 14:57
  • Yeah that could be the cause. In my project we have more than one camel context so we need to use direct-vm routes and we are implementing unit tests for those. But perhaps the __mockEndpoints()__ function should contemplate this situation, perhaps could be useful not only for direct or seda but for direct-vm and vm – Joselo Jul 20 '21 at 15:13
  • Instead of testing these 2 routes on 2 different camel contexts in single test you should test the route that produces the message to direct-vm and the route that consumes the direct-vm message **individually**. Testing both in the same test kinda goes against the best practices when it comes to unit tests. – Pasi Österman Jul 20 '21 at 15:24
  • Yes you're right about that. I won't test more that one route in a unit test in our project, this was only for testing direct-vm routes only – Joselo Jul 20 '21 at 15:41
0

The error message No consumers available on endpoint: ... typically means you have a producer that sends messages to a synchronous endpoint but no consumer that listens to this endpoint.

Is it possible that you just changed the producer to direct-vm?

By the way: direct-vm is typically used to connect Camel routes inside the same JVM but from different Camel contexts. One example for this is between OSGi bundles. If you only have 1 Camel context, just use direct.

burki
  • 6,741
  • 1
  • 15
  • 31
  • Hi Burki. In the project that i work we have more than once camel context, that's why I need to use direct-vm routes. I haven't changed only the producer but all the routes in the test and the route configuration, from seda to direct-vm and I get the error. I'm testing with the latest camel 2: 2.25.4 – Joselo Jul 19 '21 at 16:36