1

I have the following route in my service:

public void configure() {

    /*
     * Scheduled Camel route to produce a monthly report from the audit table. 
     * This is scheduled to run the first day of every month.
     */

    // @formatter:off
    from(reportUri)
        .routeId("monthly-report-route")
        .log("Audit report processing started...")
        .to("mybatis:updateProcessControl?statementType=Update")
        .choice()
            /*
             * If the rows updated is 1, this service instance wins and can run the report.
             * If the rows updated is zero, go to sleep and wait for the next scheduled run.  
             */
            .when(header("CamelMyBatisResult").isEqualTo(1))
                .process(reportDateProcessor)
                .to("mybatis:selectReport?statementType=SelectList&consumer.routeEmptyResultSet=true")
                .process(new ReportProcessor())
                .to("smtp://smtpin.tilg.com?to=" 
                        + emailToAddr 
                        + "&from=" + emailFromAddr )
                .id("RecipientList_ReportEmail")
        .endChoice()
    .end();
    // @formatter:on
}

When i try to run a test on this it gives me an error stating camel cannot auto create component mybatis. I'm inexperienced with testing camel routes so im not entirely sure where to go with this. The first mybatis call updates a row in a table, which is not under test so i'd like to do something like when the endpoint is hit, return the CamelMyBatisResult header with a value of 1. The second mybatis endpoint should return a hashmap(empty for first test, populated for the second). How do i go about implementing a when/then kind of mechanism with camel testing? I've looked at the mock endpoint camel docs but i can't figure out how to apply that and have it return a value to the exchange, then continue with the route(the end result of the test is to check that an email with or without an attachment is sent)

EDIT: tried using both replace().set* methods and replacing the mybatis endpoints with a call to inline processors:

@Test
public void test_reportRoute_NoResultsFound_EmailSent() throws Exception {
    List<AuditLog> bodyList = new ArrayList<>();
    context.getRouteDefinition("monthly-report-route").adviceWith(context, 
            new AdviceWithRouteBuilder() {
                @Override
                public void configure() throws Exception {
                    replaceFromWith(TEST);
                    weaveById("updateProcControl").replace()
                        .process(new Processor() {
                            @Override
                            public void process(Exchange exchange) throws Exception {
                                exchange.getIn().setHeader("CamelMyBatisResult", 1);
                            }
                        });
                    weaveById("selectReport").replace()
                        .process(new Processor() {
                            @Override
                            public void process(Exchange exchange) throws Exception {
                                exchange.getIn().setBody(bodyList);
                            }
                        });
                    weaveById("RecipientList_reportEmail").replace()
                        .to("smtp://localhost:8083"
                                +"?to=" + "test@test.com"
                                +"&from=" + "test1@test1.com");
                }
    });
    ProducerTemplate prod = context.createProducerTemplate();
    prod.send(TEST, exch);

    assertThat(exch.getIn().getHeader("CamelMyBatisResult"), is(1));
    assertThat(exch.getIn().getBody(), is(""));
}

Thus far, the header is still null, as is the body(TEST variable is a direct component)

jbailie1991
  • 1,305
  • 2
  • 21
  • 42
  • Can you post the error you get? stacktrace? – Souciance Eqdam Rashti Nov 17 '16 at 14:18
  • The auto create stuff isnt really the issue; i want to mock those endpoints and return back a response, since its not those endpoints that are directly under test, so im not really concerned with getting the mybatis component created – jbailie1991 Nov 17 '16 at 14:22
  • In that case, set a .id() for each .to() and then you intercept, replace. and set hardcoded response values. See the advicewith for testing.. http://camel.apache.org/advicewith.html – Souciance Eqdam Rashti Nov 17 '16 at 14:23
  • @Souciance Eqdam Rashti ah ok thank you. On a semi related note, do you know what kind of expression i could use to send a hashMap or a list back via MockEndpoint.returnReplyBody? the Simple object doesnt seem to fit what im trying to do – jbailie1991 Nov 17 '16 at 14:29
  • It requires playing with the expressions but I would instead do an adviceWith and instead write like this: weaveById("yourid").replace().setBody(yourhashmap); – Souciance Eqdam Rashti Nov 17 '16 at 14:31
  • ah ok that looks reasonable, thank you. if you add that as an answer iull upvote etc – jbailie1991 Nov 17 '16 at 14:32

1 Answers1

5

If you want to put in hardcoded responses, it is easier to do an adviceWith on your routes. See here: http://camel.apache.org/advicewith.html

Basically, add an id to each endpoint or .to(). Then your test perform an adviceWith and then replace that .to() with some hardcoded response. It can be a map, string or anything else you want and it will be replaced. For example:

context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() {
    @Override
    public void configure() throws Exception {
        // weave the node in the route which has id = bar
        // and replace it with the following route path
        weaveById("bar").replace().multicast().to("mock:a").to("mock:b");
    }
});

Note, it says in the documentation that you need to override the isAdviceWith method and start and stop the camelContext manually.

Let us know if you run into issues with it. It can be a bit tricky to get started but once you get the hang of it it is actually very powerful to mock responses.

Here is an example that adds a body to simple expression when you do adviceWith..

context.getRouteDefinition("yourRouteId").adviceWith(context, new AdviceWithRouteBuilder() {
  @Override
  public void configure() throws Exception {
    weaveById("yourEndpointId").replace().setBody(new ConstantExpression("whateveryouwant"
     ));
  }

});
Miloš Milivojević
  • 5,219
  • 3
  • 26
  • 39
Souciance Eqdam Rashti
  • 3,143
  • 3
  • 15
  • 31
  • so I've been trying this for a while, the header isnt being set which is skipping the rest of the route, or at least each time i check the exchange in an assertion for the header it comes back as null, will update question with test – jbailie1991 Nov 17 '16 at 16:25
  • When you mentioned using setBody to insert the hashmap, how would I do that from an expression? the method takes an Expression argument and I cant find any resources on how to just insert a variable created before the setBody call – jbailie1991 Nov 17 '16 at 17:05
  • @jbailie1991, I have edited my answer with an example. – Souciance Eqdam Rashti Nov 17 '16 at 19:47