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 <m...@raibledesigns.com> 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 <claus.ib...@gmail.com> 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 <m...@raibledesigns.com> 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 <darth.minhs...@gmail.com> 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 <m...@raibledesigns.com> 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 <darth.minhs...@gmail.com> 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 <m...@raibledesigns.com> 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 <claus.ib...@gmail.com> 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 <m...@raibledesigns.com> >>>>>>>> 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: cib...@redhat.com >>>>>>>> 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: cib...@redhat.com >> 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: cib...@redhat.com Twitter: davsclaus Blog: http://davsclaus.com Author of Camel in Action: http://www.manning.com/ibsen hawtio: http://hawt.io/ fabric8: http://fabric8.io/