OK, I got that to work by using @UseAdviceWith. Here's my @Before method that
sets everything up and returns SQL results:
static List<Map> results = new ArrayList<Map>() {{
add(new HashMap<String, String>() {{
put("foo", "bar");
}});
}};
@Before
public void before() throws Exception {
camelContext.setTracing(true);
ModelCamelContext context = (ModelCamelContext) camelContext;
RouteDefinition route = context.getRouteDefinition("myRouteId");
route.adviceWith(context, new RouteBuilder() {
@Override
public void configure() throws Exception {
interceptSendToEndpoint("sql:*").skipSendToOriginalEndpoint().process(new
Processor() {
@Override
public void process(Exchange exchange)
throws Exception {
exchange.getOut().setBody(results);
}
});
}
});
camelContext.start();
}
Now in my route, I want to verify the final results. Since it's a .process()
call, there's no endpoint name to look for and mock.
.to("sql:select * ...")
.to("log:output")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
List<HashMap> data = (ArrayList<HashMap>)
exchange.getIn().getBody();
// create response from data
exchange.getOut().setBody(response);
}
});
Is it possible to add a "mock:result" at the end, after .process()?
I tried the following, but no messages are received.
@MockEndpoints // added to class
@EndpointInject(uri = "mock:result")
protected MockEndpoint result;
@Test
...
result.expectedMessageCount(1);
template.sendBody ...
MockEndpoint.assertIsSatisfied(camelContext);
On Jun 12, 2014, at 9:33 AM, Claus Ibsen <[email protected]> wrote:
> Hi
>
> @ EndpointInject does not match wildcards.
>
> Do this as I said before in my previous mail
>
> But as the SQL endpoint is dynamic calculated then its easier to use
> interceptSendToEndpoint and skip, as shown in the book on page 182
> with the advice with.
>
> On Thu, Jun 12, 2014 at 4:47 PM, Matt Raible <[email protected]> wrote:
>> Possibly. If I have the following annotations on my class:
>>
>> @MockEndpoints("sql:.*")
>> @UseAdviceWith
>>
>> And I mock the SQL endpoint:
>>
>> @EndpointInject(uri = "mock:sql:*")
>> MockEndpoint mockSql;
>>
>> Then I try to set the mocked endpoint's results:
>>
>> @Test
>> public void testMockSQLEndpoint() throws Exception {
>> mockSql.whenAnyExchangeReceived(new Processor() {
>> @Override
>> public void process(Exchange exchange) throws
>> Exception {
>> exchange.getIn().setBody("sql output");
>> }
>> });
>> camelContext.start();
>>
>> The mock SQL output is still not set.
>>
>> On Jun 12, 2014, at 8:40 AM, Claus Ibsen <[email protected]> wrote:
>>
>>> Hi
>>>
>>> Is it the @AdviceWith you are looking for ?
>>> http://camel.apache.org/spring-testing.html
>>>
>>> On Thu, Jun 12, 2014 at 4:30 PM, Matt Raible <[email protected]> wrote:
>>>> Is it possible to use adviceWith when using Spring/Camel's annotation
>>>> support? I was originally trying to use this method, but had to extend
>>>> CamelTestSupport and its context did not have my routes in it.
>>>>
>>>> On Jun 11, 2014, at 11:39 PM, Claus Ibsen <[email protected]> wrote:
>>>>
>>>>> Hi
>>>>>
>>>>> You may want to use @MockEndpointsAndSkip so you do not call the SQL
>>>>> component.
>>>>>
>>>>> The camel-spring-test with the annotations was added to Camel later,
>>>>> after the book was published.
>>>>>
>>>>> But you can find the annotations and more details here
>>>>> http://camel.apache.org/spring-testing.html
>>>>>
>>>>> But as the SQL endpoint is dynamic calculated then its easier to use
>>>>> interceptSendToEndpoint and skip, as shown in the book on page 182
>>>>> with the advice with.
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> On Thu, Jun 12, 2014 at 1:58 AM, Matt Raible <[email protected]>
>>>>> wrote:
>>>>>> Nope, my routes are defined using the Java DSL, not XML. Changing from:
>>>>>>
>>>>>> @ContextConfiguration(classes = CamelConfig.class)
>>>>>>
>>>>>> To:
>>>>>>
>>>>>> @ContextConfiguration(loader =
>>>>>> CamelSpringDelegatingTestContextLoader.class, classes =
>>>>>> CamelConfig.class)
>>>>>>
>>>>>> Solved my problem.
>>>>>>
>>>>>> I don't know if the regex needs to change. Using
>>>>>> @MockEndpoints("sql:*"), I see the following in my logs:
>>>>>>
>>>>>> 2014-06-11 17:53:35,388 [main ] INFO output
>>>>>> - Exchange[ExchangePattern: InOnly, BodyType: java.util.ArrayList,
>>>>>> Body: []]
>>>>>> 2014-06-11 17:53:35,389 [main ] INFO MockEndpoint
>>>>>> - Asserting: Endpoint[mock://sql:select...] is satisfied
>>>>>> 2014-06-11 17:53:35,390 [main ] INFO MockEndpoint
>>>>>> - Asserting: Endpoint[mock://sql:*] is satisfied
>>>>>>
>>>>>> It looks like it's working, but the test is failing:
>>>>>>
>>>>>> java.lang.AssertionError: mock://sql:* Received message count. Expected:
>>>>>> <1> but was: <0>
>>>>>>
>>>>>> So now I want to do two things: 1) understand why my mockSQL endpoint is
>>>>>> not receiving a message and 2) make the mock SQL endpoint return an
>>>>>> ArrayList of items so I can test my processing logic.
>>>>>>
>>>>>> On Jun 11, 2014, at 5:46 PM, Minh Tran <[email protected]> wrote:
>>>>>>
>>>>>>> It appears to me like you have your routes defined in xml and not
>>>>>>> actually in JavaConfig? In that case, you can simplify your
>>>>>>> configuration even further and not refer to your JavaConfig class like
>>>>>>> this
>>>>>>>
>>>>>>> @RunWith(CamelSpringJUnit4ClassRunner.class)
>>>>>>> @ContextConfiguration(loader =
>>>>>>> CamelSpringDelegatingTestContextLoader.class, locations = {
>>>>>>> "classpath:/path/to/xml" })
>>>>>>> @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
>>>>>>> @MockEndpointsAndSkip("sql:.*")
>>>>>>> public class FooRouteTests
>>>>>>>
>>>>>>> No need to extend any class.
>>>>>>> Also your regex has to be "sql:.*" and not "sql:*" They mean two
>>>>>>> different things in regex.
>>>>>>>
>>>>>>> On 12/06/2014, at 9:32 AM, Matt Raible <[email protected]> wrote:
>>>>>>>
>>>>>>>> Thanks for your advice. Here's my attempt to modify my test to use
>>>>>>>> CamelSpringJUnit4ClassRunner and annotations to mock my SQL endpoint.
>>>>>>>>
>>>>>>>> @RunWith(CamelSpringJUnit4ClassRunner.class)
>>>>>>>> @ContextConfiguration(classes = CamelConfig.class)
>>>>>>>> @DirtiesContext(classMode =
>>>>>>>> DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
>>>>>>>> @MockEndpoints("sql:*")
>>>>>>>> public class FooRouteTests {
>>>>>>>>
>>>>>>>> @Autowired
>>>>>>>> CamelContext camelContext;
>>>>>>>>
>>>>>>>> @Produce
>>>>>>>> ProducerTemplate template;
>>>>>>>>
>>>>>>>> @EndpointInject(uri = "mock:sql:*")
>>>>>>>> MockEndpoint mockSql;
>>>>>>>>
>>>>>>>> @Test
>>>>>>>> public void testMockSQLEndpoint() throws Exception {
>>>>>>>> template.sendBody("direct:foo", "bar");
>>>>>>>>
>>>>>>>> mockSql.expectedMessageCount(1);
>>>>>>>> // todo: take input message and return mock results
>>>>>>>> (ArrayList<HashMap>)
>>>>>>>> MockEndpoint.assertIsSatisfied(camelContext);
>>>>>>>> }
>>>>>>>> }
>>>>>>>>
>>>>>>>> For some reason, this results in an error, even though my CamelConfig
>>>>>>>> works for configuring other tests.
>>>>>>>>
>>>>>>>> Could not autowire field: org.apache.camel.CamelContext
>>>>>>>> com.company.app.foo.FooRouteTests.camelContext; nested exception is
>>>>>>>> org.springframework.beans.factory.NoSuchBeanDefinitionException: No
>>>>>>>> qualifying bean of type [org.apache.camel.CamelContext] found for
>>>>>>>> dependency: expected at least 1 bean which qualifies as autowire
>>>>>>>> candidate for this dependency.
>>>>>>>>
>>>>>>>> @Configuration
>>>>>>>> @ImportResource("classpath:META-INF/cxf/cxf.xml")
>>>>>>>> @ComponentScan("com.company.app")
>>>>>>>> public class CamelConfig extends CamelConfiguration {
>>>>>>>>
>>>>>>>> @Override
>>>>>>>> protected void setupCamelContext(CamelContext camelContext) throws
>>>>>>>> Exception {
>>>>>>>> PropertiesComponent pc = new PropertiesComponent();
>>>>>>>> pc.setLocation("classpath:application.properties");
>>>>>>>> camelContext.addComponent("properties", pc);
>>>>>>>> super.setupCamelContext(camelContext);
>>>>>>>> }
>>>>>>>> }
>>>>>>>>
>>>>>>>>
>>>>>>>> On Jun 11, 2014, at 5:08 PM, Minh Tran <[email protected]>
>>>>>>>> wrote:
>>>>>>>>
>>>>>>>>> If you're using Spring, I recommend not extending any of the Camel
>>>>>>>>> Test classes and using the Camel Enhanced Spring Test as described
>>>>>>>>> here
>>>>>>>>> http://camel.apache.org/spring-testing.html
>>>>>>>>>
>>>>>>>>> The docs take a bit of getting use to because it describes several
>>>>>>>>> different ways of testing via Spring but you just have to skip to the
>>>>>>>>> Camel Enhanced Spring Test bits. It also doesn't describe how to test
>>>>>>>>> using a JavaConfig class very well IMO. It only describes how to do
>>>>>>>>> this by extending AbstractJUnit4SpringContextTests which is a really
>>>>>>>>> old way of doing spring unit tests. I had to do a lot of
>>>>>>>>> experimenting to get it to work without extending this class.
>>>>>>>>>
>>>>>>>>> Here's an example I had, the only difference is my JavaConfig is
>>>>>>>>> embedded into my unit test class, but there's no reason you couldn't
>>>>>>>>> refer to an existing class. If you want to mock and skip your sql or
>>>>>>>>> soap calls, then instead of using @MockEndPoints, use
>>>>>>>>> @MockEndPointsAndSkip. Look further down to see some gotchas that I
>>>>>>>>> encountered in all of this.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> @RunWith(CamelSpringJUnit4ClassRunner.class)
>>>>>>>>> @ContextConfiguration(loader =
>>>>>>>>> CamelSpringDelegatingTestContextLoader.class, classes =
>>>>>>>>> RegexTest.JavaConfig.class)
>>>>>>>>> @MockEndpoints
>>>>>>>>> @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
>>>>>>>>> public class RegexTest {
>>>>>>>>>
>>>>>>>>> @Produce(uri = "direct:start")
>>>>>>>>> private ProducerTemplate producerTemplate;
>>>>>>>>>
>>>>>>>>> @EndpointInject(uri = "mock:direct:match")
>>>>>>>>> private MockEndpoint matchEndpoint;
>>>>>>>>>
>>>>>>>>> @EndpointInject(uri = "mock:direct:nomatch")
>>>>>>>>> private MockEndpoint noMatchEndpoint;
>>>>>>>>>
>>>>>>>>> @Configuration
>>>>>>>>> public static class JavaConfig extends SingleRouteCamelConfiguration
>>>>>>>>> {
>>>>>>>>>
>>>>>>>>> @Override
>>>>>>>>> public RouteBuilder route() {
>>>>>>>>> return new RouteBuilder() {
>>>>>>>>>
>>>>>>>>> @Override
>>>>>>>>> public void configure() throws Exception {
>>>>>>>>>
>>>>>>>>> from("direct:start").to("log:blah?showProperties=true").log("${property.scaleResponse.message}").choice().when()
>>>>>>>>>
>>>>>>>>> .simple("resource:classpath:simple/item_not_exists.txt").to("direct:match").otherwise().to("direct:nomatch").end();
>>>>>>>>> from("direct:match").log("matched");
>>>>>>>>> from("direct:nomatch").log("no
>>>>>>>>> match");
>>>>>>>>> this.getContext().setTracing(true);
>>>>>>>>> }
>>>>>>>>> };
>>>>>>>>> }
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> @After
>>>>>>>>> public void afterTest() throws InterruptedException {
>>>>>>>>> matchEndpoint.assertIsSatisfied();
>>>>>>>>> noMatchEndpoint.assertIsSatisfied();
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> @Test
>>>>>>>>> public void testMatch() {
>>>>>>>>> InterfaceResponse response = new InterfaceResponse();
>>>>>>>>> response.setMessage("ITEM XML Download ended. : Item
>>>>>>>>> \"blah\" does not exist. - ");
>>>>>>>>> matchEndpoint.expectedMessageCount(1);
>>>>>>>>>
>>>>>>>>> producerTemplate.sendBodyAndProperty(null, "scaleResponse",
>>>>>>>>> response);
>>>>>>>>>
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> The regex you provide to mockendpointandskip and mock endpoint is
>>>>>>>>> important to get right. I didn't add any regex to my example above
>>>>>>>>> because mocking all endpoints (the default) was ok in my example. if
>>>>>>>>> you get this regex wrong, camel doesn't warn you. You can turn on
>>>>>>>>> camel logging to see whether it has mocked your endpoint correctly or
>>>>>>>>> not. It should say something like the following. That's how you know
>>>>>>>>> it is working.
>>>>>>>>>
>>>>>>>>> INFO org.apache.camel.impl.InterceptSendToMockEndpointStrategy -
>>>>>>>>> Adviced endpoint [direct://start] with mock endpoint
>>>>>>>>> [mock:direct:start]
>>>>>>>>>
>>>>>>>>> The regex value matching is a bit strange, if it doesn't match your
>>>>>>>>> endpoint even though you are absolutely sure it is correct, try
>>>>>>>>> tacking on ".*" on the end of it, this fixed it up for me many times.
>>>>>>>>> IMO I think it's a bug in the camel regex matching somewhere.
>>>>>>>>>
>>>>>>>>> When you do the @EndpointInject uri, make sure you prepend with
>>>>>>>>> "mock" and don't include anything pass the "?" in your uri. This
>>>>>>>>> wasn't obvious to me. And again camel won't warn you if you get this
>>>>>>>>> wrong.
>>>>>>>>>
>>>>>>>>> @DirtiesContext is a must otherwise you get strange behaviour once
>>>>>>>>> one test starts failing.
>>>>>>>>>
>>>>>>>>> Hope that helps.
>>>>>>>>>
>>>>>>>>> On 12/06/2014, at 8:27 AM, Matt Raible <[email protected]> wrote:
>>>>>>>>>
>>>>>>>>>> Thanks for the advice. I bought the book, read chapter 6 and I'm
>>>>>>>>>> trying to use the advice builder. Chapter 6 talks about using mocks
>>>>>>>>>> quite a bit, which seems useful in building a route, but not when
>>>>>>>>>> it's already built.
>>>>>>>>>>
>>>>>>>>>> My routes are configured with Spring and JavaConfig in a CamelConfig
>>>>>>>>>> class. When I try to use CamelTestSupport as my parent class, the
>>>>>>>>>> context doesn't have any route definitions in it. In other words,
>>>>>>>>>> context.getRouteDefinitions() returns an empty list. How do I get
>>>>>>>>>> CamelTestSupport to recognize my routes configured in Spring? Or is
>>>>>>>>>> it possible to inject the context and template and use adviceWith
>>>>>>>>>> w/o extending CamelTestSupport?
>>>>>>>>>>
>>>>>>>>>> Thanks,
>>>>>>>>>>
>>>>>>>>>> Matt
>>>>>>>>>>
>>>>>>>>>> @RunWith(SpringJUnit4ClassRunner.class)
>>>>>>>>>> @ContextConfiguration(classes = CamelConfig.class)
>>>>>>>>>> public class FooRouteTests extends CamelTestSupport {
>>>>>>>>>>
>>>>>>>>>> @Test
>>>>>>>>>> public void testAdvised() throws Exception {
>>>>>>>>>> context.getRouteDefinition("routeId").adviceWith(context,
>>>>>>>>>> new RouteBuilder() {
>>>>>>>>>> @Override
>>>>>>>>>> public void configure() throws Exception {
>>>>>>>>>> // intercept sending to mock:foo and do
>>>>>>>>>> something else
>>>>>>>>>> interceptSendToEndpoint("sql:*")
>>>>>>>>>> .skipSendToOriginalEndpoint()
>>>>>>>>>> .to("log:foo")
>>>>>>>>>> .to("mock:advised");
>>>>>>>>>> }
>>>>>>>>>> });
>>>>>>>>>> // we must manually start when we are done with all the
>>>>>>>>>> advice with
>>>>>>>>>> context.start();
>>>>>>>>>>
>>>>>>>>>> template.sendBody("direct:foo", "bar");
>>>>>>>>>>
>>>>>>>>>> getMockEndpoint("mock:advised").expectedMessageCount(1);
>>>>>>>>>> assertMockEndpointsSatisfied();
>>>>>>>>>> }
>>>>>>>>>>
>>>>>>>>>> @Override
>>>>>>>>>> public boolean isUseAdviceWith() {
>>>>>>>>>> // tell we are using advice with, which allows us to advice
>>>>>>>>>> the route
>>>>>>>>>> // before Camel is being started, and thus can replace sql
>>>>>>>>>> with something else.
>>>>>>>>>> return true;
>>>>>>>>>> }
>>>>>>>>>>
>>>>>>>>>> On Jun 11, 2014, at 12:16 PM, Claus Ibsen <[email protected]>
>>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>>> Hi
>>>>>>>>>>>
>>>>>>>>>>> Yeah if you have Camel in Action book, read chapter 6.
>>>>>>>>>>>
>>>>>>>>>>> And see bottom of this page
>>>>>>>>>>> http://camel.apache.org/testing
>>>>>>>>>>>
>>>>>>>>>>> The advice builder is quite nifty and can "rework" the routes
>>>>>>>>>>> before testing.
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> On Wed, Jun 11, 2014 at 8:10 PM, Matt Raible
>>>>>>>>>>> <[email protected]> wrote:
>>>>>>>>>>>> Hello,
>>>>>>>>>>>>
>>>>>>>>>>>> I have a route that looks as follows:
>>>>>>>>>>>>
>>>>>>>>>>>> from(uri)
>>>>>>>>>>>> .to("log:input")
>>>>>>>>>>>>
>>>>>>>>>>>> .recipientList(simple("direct:${header.operationName}"));
>>>>>>>>>>>> from("direct:lookup")
>>>>>>>>>>>> .process(new Processor() {
>>>>>>>>>>>> public void process(Exchange
>>>>>>>>>>>> exchange) throws Exception {
>>>>>>>>>>>> // grab parameters from
>>>>>>>>>>>> request and set as headers for SQL statement
>>>>>>>>>>>> }
>>>>>>>>>>>> })
>>>>>>>>>>>>
>>>>>>>>>>>> .recipientList(simple("sql:{{sql.lookup}}")).delimiter("false")
>>>>>>>>>>>> .to("log:output")
>>>>>>>>>>>> .process(new Processor() {
>>>>>>>>>>>> public void process(Exchange
>>>>>>>>>>>> exchange) throws Exception {
>>>>>>>>>>>> List<HashMap> data =
>>>>>>>>>>>> (ArrayList<HashMap>) exchange.getIn().getBody();
>>>>>>>>>>>>
>>>>>>>>>>>> // convert data to response
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> exchange.getOut().setBody(response);
>>>>>>>>>>>> }
>>>>>>>>>>>> })
>>>>>>>>>>>>
>>>>>>>>>>>> Is it possible to unit test this route and mock the data returned
>>>>>>>>>>>> from the "sql" call? It'd love to be able to verify headers after
>>>>>>>>>>>> the first .process, mock the results from the SQL call and verify
>>>>>>>>>>>> the results from the 2nd .process method.
>>>>>>>>>>>>
>>>>>>>>>>>> All of the routes I've developed with Camel so far make SQL calls,
>>>>>>>>>>>> but I see SOAP calls in the future. I'll eventually need to mock
>>>>>>>>>>>> SOAP calls as well.
>>>>>>>>>>>>
>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>
>>>>>>>>>>>> Matt
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> --
>>>>>>>>>>> Claus Ibsen
>>>>>>>>>>> -----------------
>>>>>>>>>>> Red Hat, Inc.
>>>>>>>>>>> Email: [email protected]
>>>>>>>>>>> Twitter: davsclaus
>>>>>>>>>>> Blog: http://davsclaus.com
>>>>>>>>>>> Author of Camel in Action: http://www.manning.com/ibsen
>>>>>>>>>>> hawtio: http://hawt.io/
>>>>>>>>>>> fabric8: http://fabric8.io/
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Claus Ibsen
>>>>> -----------------
>>>>> Red Hat, Inc.
>>>>> Email: [email protected]
>>>>> Twitter: davsclaus
>>>>> Blog: http://davsclaus.com
>>>>> Author of Camel in Action: http://www.manning.com/ibsen
>>>>> hawtio: http://hawt.io/
>>>>> fabric8: http://fabric8.io/
>>>>
>>>
>>>
>>>
>>> --
>>> Claus Ibsen
>>> -----------------
>>> Red Hat, Inc.
>>> Email: [email protected]
>>> Twitter: davsclaus
>>> Blog: http://davsclaus.com
>>> Author of Camel in Action: http://www.manning.com/ibsen
>>> hawtio: http://hawt.io/
>>> fabric8: http://fabric8.io/
>>
>
>
>
> --
> Claus Ibsen
> -----------------
> Red Hat, Inc.
> Email: [email protected]
> Twitter: davsclaus
> Blog: http://davsclaus.com
> Author of Camel in Action: http://www.manning.com/ibsen
> hawtio: http://hawt.io/
> fabric8: http://fabric8.io/