Understood. I am trying to summarise for those of us trying to get an
initial project "up and running" as too often deep technical text can put
off the reader.

I have added the following: "Spring's transactional model ensures each
transaction is bound to one thread. A Camel route may invoke additional
threads which is where the blockage may occur. This is not a fault of Camel
but as the programmer you must be aware of the consequences of beginning a
transaction in a test thread and expecting a separate thread created by
your Camel route to be participate, which it cannot. You can, in your test,
mock the parts that cause separate threads to avoid this issue."

Hopefully this addresses your core point.


On 23 September 2014 00:23, Minh Tran <darth.minhs...@gmail.com> wrote:

> I think it’s important to understand the reason why your test fails, it’s
> not really camel’s fault. It's because your camel route executes your dao
> method on a separate thread. If you’re using a JMS consumer then this will
> definitely run under a separate thread.
>
> This is a spring transaction “feature”, transactions are bound to the
> current thread and if you have multiple threads then it will create
> separate transactions. Lets say you had a spring unit test purely testing
> your dao method(minus all the camel stuff) and you put @Transactional on
> the unit test. Then you did the same thing and seed the data, your test
> would run just fine because your dao would participate in the same
> transaction as your unit test. But if you change your dao to thread off and
> then execute a transaction then you’d have the same blocking issue. So the
> problem isn’t explicitly camel, it’s spring’s rule of one transaction per
> thread.
>
> Alternatively think about using a mocked dao instead and not worry about
> these transactional issues. Either by using @MockEndpointsAndSkip or inject
> via a third party mocking library like mockito. The real dao method can be
> unit tested separately.
>
> Or in your unit test, you can remove the jms component out using
> @UseAdviceWith and replace with a direct component. This will ensure no
> threading will occur due to the jms consumer when you execute the route in
> your unit test.
>
> On 23 Sep 2014, at 1:41 am, James Green <james.mk.gr...@gmail.com> wrote:
>
> > OK - we have a working solution. Someone should document this at
> > http://camel.apache.org/transactional-client.html and
> > http://camel.apache.org/spring-testing.html since we have had many days
> of
> > trouble.
> >
> > The crux is the source here:
> >
> https://github.com/rajivj2/example2/blob/master/src/test/java/com/example/NotificationRouterIT.java
> >
> > Essentially in our case the test runner is a Spring integration test that
> > seeds data then tests a route that consumes a JMS message and processes
> it
> > in a database.
> >
> > First problem is that database access requires a transaction. We annotate
> > our Processor classes @Transactional (remembering not to do so within the
> > DAO, a common error) and crucially avoid annotating our test method
> > @Transactional. Instead, the test method creates a TransactionTemplate
> from
> > Spring, handing it the injected TransactionManager and execute the data
> > seeding operation. Finally, send a test message and assert that the sun
> > still shines.
> >
> > If the test method itself is annotated @Transactional, as Minh infers,
> the
> > seed data is held in memory until the test method completes. We were
> > expecting Camel, using the shared TransactionManager, to see this data
> but
> > instead is either hangs because of a separate transaction context, or
> just
> > doesn't see anything if no transaction is used. Programming the
> transaction
> > using the TransactionTemplate lets us commit the seed data before the end
> > of the test, allowing Camel's transaction context to see database data
> > written already.
> >
> > Improvements and corrections welcome.
> >
> >
> > On 22 September 2014 15:17, Minh Tran <darth.minhs...@gmail.com> wrote:
> >
> >> The reason for the hang is because Spring unit test transaction is
> >> separate to the camel transaction. The camel transaction is blocked
> waiting
> >> because the spring has uncommitted changes to the same table it is
> trying
> >> to read from.
> >>
> >> Either
> >> 1. commit the spring transaction first, drop the @Transactional and use
> a
> >> TransactionTemplate to do this OR
> >> 2. Somehow get the spring and camel to participate in the same
> transaction
> >> during the unit test. If they share the same transaction manager and
> camel
> >> transaction is set to PROPAGATION_REQUIRED which is the default, this
> >> should just work. This assumes your unit test and camel execution is
> >> running under the same thread though. If not then stick to the first
> method.
> >>
> >> On 22 Sep 2014, at 11:51 pm, James Green <james.mk.gr...@gmail.com>
> wrote:
> >>
> >>> We have a Spring project that has a unit test annotated @Transactional.
> >>> This uses a DAO to save a sample Entity before invoking a Camel route
> >> that
> >>> accepts a JMS message and sends it to some Processors.
> >>>
> >>> The problem we have is when the test itself is annotated
> @Transactional.
> >>> The route stops having received the message and begin performing a
> >> database
> >>> query - it literally hangs performing the SELECT. Naturally after 20s
> the
> >>> time-out is hit.
> >>>
> >>> If we remove @Transactional from the test the route continues but finds
> >>> nothing in the database as the initial Entity save had no effect (it
> >>> appears).
> >>>
> >>> So we're clearly missing something here - how should we seed test data
> if
> >>> @Transactional hangs and without it the data is not committed?
> >>>
> >>> Thanks,
> >>>
> >>> James
> >>
> >>
>
>

Reply via email to