Return-Path: X-Original-To: apmail-camel-users-archive@www.apache.org Delivered-To: apmail-camel-users-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 903C9116AF for ; Mon, 22 Sep 2014 23:23:50 +0000 (UTC) Received: (qmail 95934 invoked by uid 500); 22 Sep 2014 23:23:50 -0000 Delivered-To: apmail-camel-users-archive@camel.apache.org Received: (qmail 95885 invoked by uid 500); 22 Sep 2014 23:23:50 -0000 Mailing-List: contact users-help@camel.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: users@camel.apache.org Delivered-To: mailing list users@camel.apache.org Received: (qmail 95870 invoked by uid 99); 22 Sep 2014 23:23:49 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 22 Sep 2014 23:23:49 +0000 X-ASF-Spam-Status: No, hits=-0.7 required=5.0 tests=RCVD_IN_DNSWL_LOW,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (athena.apache.org: domain of darth.minhster@gmail.com designates 209.85.220.44 as permitted sender) Received: from [209.85.220.44] (HELO mail-pa0-f44.google.com) (209.85.220.44) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 22 Sep 2014 23:23:45 +0000 Received: by mail-pa0-f44.google.com with SMTP id eu11so4550263pac.31 for ; Mon, 22 Sep 2014 16:23:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=content-type:mime-version:subject:from:in-reply-to:date :content-transfer-encoding:message-id:references:to; bh=iEjBupm1h3KWe0kzZwkBUVc1sGmz6f5jsstxk/2cUjE=; b=v5zFWSCHY+hEpWDKZYoxZWQ/d4fgo8//cYUeOEt/tLzSxykwRZdIOpCtCXJIaA/4dX 09S8SzxoMNPSFCkyfQswMA9AAOfUKrt35pyfXuUL8YvDwRHIjnhzxcj/Qe55Le7xNyu2 FxnPseO+tQWoEINE4hdwFLqUuQz6XwBNUTB3+8pG1/RBdH1qy4jORM0RCbeJEdUa4jJ0 6o59cnLBZd+GGNXwqyezCfdmq/wRjl43F7y5PvCLYhJWoE+5vdCPa5bDySlwcw9qFRX5 fP3CTfiG/djEicu0Cm2f7C3EusjdYX1wtr4+I/9UOlvXtChtsIolfuvNaazHvwfI5ZdQ GmAQ== X-Received: by 10.68.217.33 with SMTP id ov1mr28493364pbc.50.1411428204759; Mon, 22 Sep 2014 16:23:24 -0700 (PDT) Received: from 2001-44b8-3104-c501-25d5-ab6e-8366-6c94.static.ipv6.internode.on.net (2001-44b8-3104-c501-25d5-ab6e-8366-6c94.static.ipv6.internode.on.net. [2001:44b8:3104:c501:25d5:ab6e:8366:6c94]) by mx.google.com with ESMTPSA id gr5sm10313614pbc.33.2014.09.22.16.23.22 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 22 Sep 2014 16:23:24 -0700 (PDT) Content-Type: text/plain; charset=windows-1252 Mime-Version: 1.0 (Mac OS X Mail 7.3 \(1878.6\)) Subject: Re: Can unit tests be @Transactional? From: Minh Tran In-Reply-To: Date: Tue, 23 Sep 2014 09:23:19 +1000 Content-Transfer-Encoding: quoted-printable Message-Id: <0B62D32D-9091-442D-9D01-5452655ED8A6@gmail.com> References: <96AD3E7D-D2B9-4479-9E9E-D718F88A2A27@gmail.com> To: users@camel.apache.org X-Mailer: Apple Mail (2.1878.6) X-Virus-Checked: Checked by ClamAV on apache.org I think it=92s important to understand the reason why your test fails, = it=92s not really camel=92s fault. It's because your camel route = executes your dao method on a separate thread. If you=92re using a JMS = consumer then this will definitely run under a separate thread. This is a spring transaction =93feature=94, 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=92d have = the same blocking issue. So the problem isn=92t explicitly camel, it=92s = spring=92s 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 = 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. >=20 > The crux is the source here: > = https://github.com/rajivj2/example2/blob/master/src/test/java/com/example/= NotificationRouterIT.java >=20 > 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. >=20 > 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. >=20 > 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. >=20 > Improvements and corrections welcome. >=20 >=20 > On 22 September 2014 15:17, Minh Tran = wrote: >=20 >> 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. >>=20 >> 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. >>=20 >> On 22 Sep 2014, at 11:51 pm, James Green = wrote: >>=20 >>> 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. >>>=20 >>> 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. >>>=20 >>> 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). >>>=20 >>> So we're clearly missing something here - how should we seed test = data if >>> @Transactional hangs and without it the data is not committed? >>>=20 >>> Thanks, >>>=20 >>> James >>=20 >>=20