You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@onami.apache.org by sc...@apache.org on 2014/04/07 16:12:21 UTC

svn commit: r1585487 [4/5] - in /onami/sandbox/persist: ./ src/main/java/org/apache/onami/persist/ src/sandbox/ src/test/java/org/apache/onami/persist/ src/test/java/org/apache/onami/persist/test/ src/test/java/org/apache/onami/persist/test/transaction...

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/TransactionalAnnotationReaderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/TransactionalAnnotationReaderTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/TransactionalAnnotationReaderTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/test/java/org/apache/onami/persist/TxnInterceptorTest.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/test/java/org/apache/onami/persist/TxnInterceptorTest.java?rev=1585487&view=auto
==============================================================================
--- onami/sandbox/persist/src/test/java/org/apache/onami/persist/TxnInterceptorTest.java (added)
+++ onami/sandbox/persist/src/test/java/org/apache/onami/persist/TxnInterceptorTest.java Mon Apr  7 14:12:18 2014
@@ -0,0 +1,360 @@
+package org.apache.onami.persist;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import de.bechte.junit.runners.context.HierarchicalContextRunner;
+import org.aopalliance.intercept.MethodInvocation;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.*;
+
+/**
+ * Test for {@link TxnInterceptor}
+ */
+@RunWith( HierarchicalContextRunner.class )
+public class TxnInterceptorTest
+{
+    private UnitOfWork unitOfWork;
+
+    private TransactionalAnnotationHelper txnAnnotationHelper;
+
+    private TransactionFacadeFactory tfProvider;
+
+    private TransactionFacade txnFacade;
+
+    private TxnInterceptor sut;
+
+    private MethodInvocation invocation;
+
+    @Before
+    public void setUp()
+        throws Exception
+    {
+        unitOfWork = mock( UnitOfWork.class );
+        tfProvider = mock( TransactionFacadeFactory.class );
+        txnAnnotationHelper = mock( TransactionalAnnotationHelper.class );
+
+        sut = new TxnInterceptor();
+        sut.unitOfWork = unitOfWork;
+        sut.tfProvider = tfProvider;
+        sut.txnAnnotationHelper = txnAnnotationHelper;
+
+        invocation = mock( MethodInvocation.class );
+    }
+
+    public class NotParticipatingInTransaction
+    {
+
+        @Before
+        public void setUp()
+            throws Exception
+        {
+            doReturn( false ).when( txnAnnotationHelper ).persistenceUnitParticipatesInTransactionFor( invocation );
+        }
+
+        @Test
+        public void invokesOriginalIfNotParticipatingInTransaction()
+            throws Throwable
+        {
+            sut.invoke( invocation );
+
+            verify( invocation ).proceed();
+        }
+    }
+
+    public class ParticipatingInTransaction
+    {
+
+        @Before
+        public void setUp()
+            throws Exception
+        {
+            doReturn( true ).when( txnAnnotationHelper ).persistenceUnitParticipatesInTransactionFor( invocation );
+
+            txnFacade = mock( TransactionFacade.class );
+            doReturn( txnFacade ).when( tfProvider ).createTransactionFacade();
+        }
+
+        public class UnitOfWorkInactive
+        {
+
+            private InOrder inOrder;
+
+            @Before
+            public void setup()
+            {
+                doReturn( false ).when( unitOfWork ).isActive();
+                inOrder = inOrder( unitOfWork, invocation );
+            }
+
+            @Test
+            public void processWithoutException()
+                throws Throwable
+            {
+                sut.invoke( invocation );
+
+                inOrder.verify( unitOfWork ).begin();
+                inOrder.verify( invocation ).proceed();
+                inOrder.verify( unitOfWork ).end();
+            }
+
+            @Test
+            public void processWithException()
+                throws Throwable
+            {
+                // given
+                final RuntimeException originalException = new RuntimeException();
+                doThrow( originalException ).when( invocation ).proceed();
+
+                // when
+                try
+                {
+                    sut.invoke( invocation );
+                }
+
+                // then
+                catch ( RuntimeException e )
+                {
+                    inOrder.verify( unitOfWork ).begin();
+                    inOrder.verify( invocation ).proceed();
+                    inOrder.verify( unitOfWork ).end();
+                    assertThat( e, sameInstance( originalException ) );
+                    return;
+                }
+                fail( "expected RuntimeException to be thrown" );
+            }
+
+            @Test
+            public void throwExceptionWhichOccurredInUnitOfWork()
+                throws Throwable
+            {
+                // given
+                final RuntimeException uowExec = new RuntimeException();
+                doThrow( uowExec ).when( unitOfWork ).end();
+
+                // when
+                try
+                {
+                    sut.invoke( invocation );
+                }
+
+                // then
+                catch ( RuntimeException e )
+                {
+                    inOrder.verify( unitOfWork ).begin();
+                    inOrder.verify( invocation ).proceed();
+                    inOrder.verify( unitOfWork ).end();
+                    assertThat( e, sameInstance( uowExec ) );
+                    return;
+                }
+                fail( "expected RuntimeException to be thrown" );
+            }
+
+            @Test
+            public void throwExceptionOfOriginalMethodIfExceptionOccurredInUnitOfWork()
+                throws Throwable
+            {
+                // given
+                final RuntimeException originalExc = new RuntimeException();
+                doThrow( originalExc ).when( invocation ).proceed();
+                doThrow( new RuntimeException() ).when( unitOfWork ).end();
+
+                // when
+                try
+                {
+                    sut.invoke( invocation );
+                }
+
+                // then
+                catch ( RuntimeException e )
+                {
+                    inOrder.verify( unitOfWork ).begin();
+                    inOrder.verify( invocation ).proceed();
+                    inOrder.verify( unitOfWork ).end();
+                    assertThat( e, sameInstance( originalExc ) );
+                    return;
+                }
+                fail( "expected RuntimeException to be thrown" );
+            }
+
+        }
+
+        public class UnitOfWorkActive
+        {
+
+            private InOrder inOrder;
+
+            @Before
+            public void setup()
+            {
+                doReturn( true ).when( unitOfWork ).isActive();
+                inOrder = inOrder( txnFacade, invocation );
+            }
+
+            @Test
+            public void processWithoutUnitOfWork()
+                throws Throwable
+            {
+                sut.invoke( invocation );
+
+                verify( unitOfWork, never() ).begin();
+                verify( invocation ).proceed();
+                verify( unitOfWork, never() ).end();
+            }
+
+
+            @Test
+            public void invokeStartsTransactionIfParticipatingInTransaction()
+                throws Throwable
+            {
+                // given
+                doReturn( true ).when( txnAnnotationHelper ).persistenceUnitParticipatesInTransactionFor( invocation );
+                // when
+                sut.invoke( invocation );
+                // then
+                inOrder.verify( txnFacade ).begin();
+                inOrder.verify( invocation ).proceed();
+                inOrder.verify( txnFacade ).commit();
+            }
+
+            @Test
+            public void rollbackIfExceptionThrownWhichRequiresRollback()
+                throws Throwable
+            {
+                // given
+                final RuntimeException exc = new RuntimeException();
+                doReturn( true ).when( txnAnnotationHelper ).persistenceUnitParticipatesInTransactionFor( invocation );
+                doThrow( exc ).when( invocation ).proceed();
+                doReturn( true ).when( txnAnnotationHelper ).isRollbackNecessaryFor( invocation, exc );
+
+                // when
+                try
+                {
+                    sut.invoke( invocation );
+                }
+
+                // then
+                catch ( RuntimeException e )
+                {
+                    inOrder.verify( txnFacade ).begin();
+                    inOrder.verify( invocation ).proceed();
+                    inOrder.verify( txnFacade ).rollback();
+                    assertThat( e, sameInstance( exc ) );
+                    return;
+                }
+                fail( "expected RuntimeException to be thrown" );
+            }
+
+            @Test
+            public void commitIfExceptionThrownWhichRequiresNoRollback()
+                throws Throwable
+            {
+                // given
+                final RuntimeException exc = new RuntimeException();
+                doReturn( true ).when( txnAnnotationHelper ).persistenceUnitParticipatesInTransactionFor( invocation );
+                doThrow( exc ).when( invocation ).proceed();
+                doReturn( false ).when( txnAnnotationHelper ).isRollbackNecessaryFor( invocation, exc );
+
+                // when
+                try
+                {
+                    sut.invoke( invocation );
+                }
+
+                // then
+                catch ( RuntimeException e )
+                {
+                    inOrder.verify( txnFacade ).begin();
+                    inOrder.verify( invocation ).proceed();
+                    inOrder.verify( txnFacade ).commit();
+                    assertThat( e, sameInstance( exc ) );
+                    return;
+                }
+                fail( "expected RuntimeException to be thrown" );
+            }
+
+            @Test
+            public void throwExceptionOfOriginalMethodIfExceptionOccurredInCommit()
+                throws Throwable
+            {
+                // given
+                final RuntimeException exc = new RuntimeException();
+                doReturn( true ).when( txnAnnotationHelper ).persistenceUnitParticipatesInTransactionFor( invocation );
+                doThrow( exc ).when( invocation ).proceed();
+                doReturn( false ).when( txnAnnotationHelper ).isRollbackNecessaryFor( invocation, exc );
+                doThrow( new RuntimeException() ).when( txnFacade ).commit();
+
+                // when
+                try
+                {
+                    sut.invoke( invocation );
+                }
+
+                // then
+                catch ( RuntimeException e )
+                {
+                    inOrder.verify( txnFacade ).begin();
+                    inOrder.verify( invocation ).proceed();
+                    inOrder.verify( txnFacade ).commit();
+                    assertThat( e, sameInstance( exc ) );
+                    return;
+                }
+                fail( "expected RuntimeException to be thrown" );
+            }
+
+            @Test
+            public void throwExceptionOfOriginalMethodIfExceptionOccurredInRollback()
+                throws Throwable
+            {
+                // given
+                final RuntimeException exc = new RuntimeException();
+                doReturn( true ).when( txnAnnotationHelper ).persistenceUnitParticipatesInTransactionFor( invocation );
+                doThrow( exc ).when( invocation ).proceed();
+                doReturn( true ).when( txnAnnotationHelper ).isRollbackNecessaryFor( invocation, exc );
+                doThrow( new RuntimeException() ).when( txnFacade ).rollback();
+
+                // when
+                try
+                {
+                    sut.invoke( invocation );
+                }
+
+                // then
+                catch ( RuntimeException e )
+                {
+                    inOrder.verify( txnFacade ).begin();
+                    inOrder.verify( invocation ).proceed();
+                    inOrder.verify( txnFacade ).rollback();
+                    assertThat( e, sameInstance( exc ) );
+                    return;
+                }
+                fail( "expected RuntimeException to be thrown" );
+            }
+
+
+        }
+    }
+}

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/TxnInterceptorTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/TxnInterceptorTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/TxnInterceptorTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/test/java/org/apache/onami/persist/UserTransactionFacadeTest.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/test/java/org/apache/onami/persist/UserTransactionFacadeTest.java?rev=1585487&view=auto
==============================================================================
--- onami/sandbox/persist/src/test/java/org/apache/onami/persist/UserTransactionFacadeTest.java (added)
+++ onami/sandbox/persist/src/test/java/org/apache/onami/persist/UserTransactionFacadeTest.java Mon Apr  7 14:12:18 2014
@@ -0,0 +1,290 @@
+package org.apache.onami.persist;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.hamcrest.Matcher;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.internal.matchers.GreaterThan;
+
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.SystemException;
+import javax.transaction.UserTransaction;
+
+import static java.lang.System.currentTimeMillis;
+import static javax.transaction.Status.*;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.*;
+
+/**
+ * Test for {@link UserTransactionFacade}.
+ */
+public class UserTransactionFacadeTest
+{
+
+    private UserTransactionFacade sut;
+
+    private UserTransaction txn;
+
+    @Before
+    public void setup()
+        throws Exception
+    {
+        txn = mock( UserTransaction.class );
+        sut = new UserTransactionFacade( txn );
+    }
+
+    @Test
+    public void beginOnTxn()
+        throws Exception
+    {
+        sut.begin();
+        verify( txn ).begin();
+    }
+
+    @Test( expected = RuntimeException.class )
+    public void beginWithNotSupportedException()
+        throws Exception
+    {
+        doThrow( new NotSupportedException() ).when( txn ).begin();
+        sut.begin();
+    }
+
+    @Test( expected = RuntimeException.class )
+    public void beginWithSystemException()
+        throws Exception
+    {
+        doThrow( new SystemException() ).when( txn ).begin();
+        sut.begin();
+    }
+
+    @Test
+    public void commitOnTxn()
+        throws Exception
+    {
+        sut.commit();
+        verify( txn ).commit();
+    }
+
+    @Test( expected = RuntimeException.class )
+    public void commitWithSecurityException()
+        throws Exception
+    {
+        doThrow( new SecurityException() ).when( txn ).commit();
+        sut.commit();
+    }
+
+    @Test( expected = RuntimeException.class )
+    public void commitWithIllegalStateException()
+        throws Exception
+    {
+        doThrow( new IllegalStateException() ).when( txn ).commit();
+        sut.commit();
+    }
+
+    @Test( expected = RuntimeException.class )
+    public void commitWithRollbackException()
+        throws Exception
+    {
+        doThrow( new RollbackException() ).when( txn ).commit();
+        sut.commit();
+    }
+
+    @Test( expected = RuntimeException.class )
+    public void commitWithHeuristicMixedException()
+        throws Exception
+    {
+        doThrow( new HeuristicMixedException() ).when( txn ).commit();
+        sut.commit();
+    }
+
+    @Test( expected = RuntimeException.class )
+    public void commitWithHeuristicRollbackException()
+        throws Exception
+    {
+        doThrow( new HeuristicRollbackException() ).when( txn ).commit();
+        sut.commit();
+    }
+
+    @Test( expected = RuntimeException.class )
+    public void commitWithSystemException()
+        throws Exception
+    {
+        doThrow( new SystemException() ).when( txn ).commit();
+        sut.commit();
+    }
+
+    @Test
+    public void rollbackOnTxn()
+        throws Exception
+    {
+        sut.rollback();
+        verify( txn ).rollback();
+    }
+
+    @Test( expected = RuntimeException.class )
+    public void rollbackWithIllegalStateException()
+        throws Exception
+    {
+        doThrow( new IllegalStateException() ).when( txn ).rollback();
+        sut.rollback();
+    }
+
+    @Test( expected = RuntimeException.class )
+    public void rollbackWithSecurityException()
+        throws Exception
+    {
+        doThrow( new SecurityException() ).when( txn ).rollback();
+        sut.rollback();
+    }
+
+    @Test( expected = RuntimeException.class )
+    public void rollbackWithSystemException()
+        throws Exception
+    {
+        doThrow( new SystemException() ).when( txn ).rollback();
+        sut.rollback();
+    }
+
+    @Test
+    public void setRollbackOnlyOnTxn()
+        throws Exception
+    {
+        sut.setRollbackOnly();
+        verify( txn ).setRollbackOnly();
+    }
+
+    @Test( expected = RuntimeException.class )
+    public void setRollbackOnlyWithIllegalStateException()
+        throws Exception
+    {
+        doThrow( new IllegalStateException() ).when( txn ).setRollbackOnly();
+        sut.setRollbackOnly();
+    }
+
+    @Test( expected = RuntimeException.class )
+    public void setRollbackOnlyWithSystemException()
+        throws Exception
+    {
+        doThrow( new SystemException() ).when( txn ).setRollbackOnly();
+        sut.setRollbackOnly();
+    }
+
+    @Test
+    public void getRollbackOnlyUsesStatusOfTransaction()
+        throws Exception
+    {
+        assertThatRollbackOnlyOf( STATUS_ACTIVE, is( false ) );
+        assertThatRollbackOnlyOf( STATUS_MARKED_ROLLBACK, is( true ) );
+        assertThatRollbackOnlyOf( STATUS_PREPARED, is( false ) );
+        assertThatRollbackOnlyOf( STATUS_COMMITTED, is( false ) );
+        assertThatRollbackOnlyOf( STATUS_ROLLEDBACK, is( true ) );
+        assertThatRollbackOnlyOf( STATUS_UNKNOWN, is( false ) );
+        assertThatRollbackOnlyOf( STATUS_NO_TRANSACTION, is( false ) );
+        assertThatRollbackOnlyOf( STATUS_PREPARING, is( false ) );
+        assertThatRollbackOnlyOf( STATUS_COMMITTING, is( false ) );
+        assertThatRollbackOnlyOf( STATUS_ROLLING_BACK, is( true ) );
+    }
+
+    @Test( expected = RuntimeException.class )
+    public void getRollbackOnlyWithSystemException()
+        throws Exception
+    {
+        doThrow( new SystemException() ).when( txn ).getStatus();
+        sut.getRollbackOnly();
+    }
+
+    @Test
+    public void getRollbackOnlyRetriesWhenStatusUnknown()
+        throws Exception
+    {
+        final long start = currentTimeMillis();
+        doReturn( STATUS_UNKNOWN ).when( txn ).getStatus();
+        sut.getRollbackOnly();
+        final long duration = currentTimeMillis() - start;
+
+        verify( txn, times( 9 ) ).getStatus();
+        assertThat( duration, is( greaterThan( 1000L ) ) );
+    }
+
+    @Test
+    public void isActiveUsesStatusOfTransaction()
+        throws Exception
+    {
+        assertThatIsActiveOf( STATUS_ACTIVE, is( true ) );
+        assertThatIsActiveOf( STATUS_MARKED_ROLLBACK, is( true ) );
+        assertThatIsActiveOf( STATUS_PREPARED, is( true ) );
+        assertThatIsActiveOf( STATUS_COMMITTED, is( true ) );
+        assertThatIsActiveOf( STATUS_ROLLEDBACK, is( true ) );
+        assertThatIsActiveOf( STATUS_UNKNOWN, is( true ) );
+        assertThatIsActiveOf( STATUS_NO_TRANSACTION, is( false ) );
+        assertThatIsActiveOf( STATUS_PREPARING, is( true ) );
+        assertThatIsActiveOf( STATUS_COMMITTING, is( true ) );
+        assertThatIsActiveOf( STATUS_ROLLING_BACK, is( true ) );
+    }
+
+    @Test( expected = RuntimeException.class )
+    public void isActiveWithSystemException()
+        throws Exception
+    {
+        doThrow( new SystemException() ).when( txn ).getStatus();
+        sut.isActive();
+    }
+
+    @Test
+    public void isActiveOnlyRetriesWhenStatusUnknown()
+        throws Exception
+    {
+        final long start = currentTimeMillis();
+        doReturn( STATUS_UNKNOWN ).when( txn ).getStatus();
+        sut.isActive();
+        final long duration = currentTimeMillis() - start;
+
+        verify( txn, times( 9 ) ).getStatus();
+        assertThat( duration, is( greaterThan( 1000L ) ) );
+    }
+
+    private void assertThatRollbackOnlyOf( int status, Matcher<Boolean> expected )
+        throws Exception
+    {
+        doReturn( status ).when( txn ).getStatus();
+        final boolean result = sut.getRollbackOnly();
+        assertThat( result, is( expected ) );
+    }
+
+    private void assertThatIsActiveOf( int status, Matcher<Boolean> expected )
+        throws Exception
+    {
+        doReturn( status ).when( txn ).getStatus();
+        final boolean result = sut.isActive();
+        assertThat( result, is( expected ) );
+    }
+
+    private Matcher<Long> greaterThan( long expected )
+    {
+        return new GreaterThan<Long>( expected );
+    }
+
+
+}

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/UserTransactionFacadeTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/UserTransactionFacadeTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/UserTransactionFacadeTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/NestedTransactionTest.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/NestedTransactionTest.java?rev=1585487&view=auto
==============================================================================
--- onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/NestedTransactionTest.java (added)
+++ onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/NestedTransactionTest.java Mon Apr  7 14:12:18 2014
@@ -0,0 +1,447 @@
+package org.apache.onami.persist.test.transaction;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.apache.onami.persist.PersistenceModule;
+import org.apache.onami.persist.PersistenceService;
+import org.apache.onami.persist.test.transaction.testframework.TransactionalTask;
+import org.apache.onami.persist.test.transaction.testframework.TransactionalWorker;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnAnyThrowingNone;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnAnyThrowingRuntimeTestException;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnAnyThrowingTestException;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnNoneThrowingNone;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnNoneThrowingRuntimeTestException;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnNoneThrowingTestException;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnRuntimeTestExceptionThrowingNone;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnRuntimeTestExceptionThrowingTestException;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnTestExceptionThrowingNone;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnTestExceptionThrowingRuntimeTestException;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnTestExceptionThrowingTestException;
+import org.junit.Test;
+
+import static org.junit.Assert.fail;
+
+/**
+ * Tests running nested transactions.
+ * The test make us of the testframework.
+ * Since the test is running a loop only the injector is created directly in the test to ensure
+ * that for every {@link TestVector} a new injector instance is used.
+ */
+public class NestedTransactionTest
+{
+
+    /**
+     * All possible combination of {@link org.apache.onami.persist.test.transaction.testframework.TransactionalTask}s
+     * and if they should have been rolled back.
+     */
+    private static final TestVector[] TEST_VECTORS =
+        { new TestVector( TaskRollingBackOnAnyThrowingNone.class, TaskRollingBackOnAnyThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnAnyThrowingNone.class,
+                            TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingNone.class, TaskRollingBackOnAnyThrowingTestException.class,
+                            true ),
+            new TestVector( TaskRollingBackOnAnyThrowingNone.class, TaskRollingBackOnNoneThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnAnyThrowingNone.class,
+                            TaskRollingBackOnNoneThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingNone.class, TaskRollingBackOnNoneThrowingTestException.class,
+                            true ), new TestVector( TaskRollingBackOnAnyThrowingNone.class,
+                                                    TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnAnyThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingNone.class, TaskRollingBackOnTestExceptionThrowingNone.class,
+                            false ), new TestVector( TaskRollingBackOnAnyThrowingNone.class,
+                                                     TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                                                     true ), new TestVector( TaskRollingBackOnAnyThrowingNone.class,
+                                                                             TaskRollingBackOnTestExceptionThrowingTestException.class,
+                                                                             true ),
+
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ),
+
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class, TaskRollingBackOnAnyThrowingNone.class,
+                            true ), new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                                                    TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class, TaskRollingBackOnNoneThrowingNone.class,
+                            true ), new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                                                    TaskRollingBackOnNoneThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnAnyThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ),
+
+            new TestVector( TaskRollingBackOnNoneThrowingNone.class, TaskRollingBackOnAnyThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingNone.class,
+                            TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnNoneThrowingNone.class, TaskRollingBackOnAnyThrowingTestException.class,
+                            true ),
+            new TestVector( TaskRollingBackOnNoneThrowingNone.class, TaskRollingBackOnNoneThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingNone.class,
+                            TaskRollingBackOnNoneThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingNone.class, TaskRollingBackOnNoneThrowingTestException.class,
+                            false ), new TestVector( TaskRollingBackOnNoneThrowingNone.class,
+                                                     TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnNoneThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingNone.class, TaskRollingBackOnTestExceptionThrowingNone.class,
+                            false ), new TestVector( TaskRollingBackOnNoneThrowingNone.class,
+                                                     TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                                                     false ), new TestVector( TaskRollingBackOnNoneThrowingNone.class,
+                                                                              TaskRollingBackOnTestExceptionThrowingTestException.class,
+                                                                              true ),
+
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ),
+
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class, TaskRollingBackOnAnyThrowingNone.class,
+                            false ), new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                                                     TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class, TaskRollingBackOnNoneThrowingNone.class,
+                            false ), new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                                                     TaskRollingBackOnNoneThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnNoneThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ),
+
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnAnyThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnNoneThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnNoneThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ),
+
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ),
+
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnAnyThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnNoneThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnNoneThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ),
+
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class, TaskRollingBackOnAnyThrowingNone.class,
+                            false ), new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                                                     TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class, TaskRollingBackOnNoneThrowingNone.class,
+                            false ), new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                                                     TaskRollingBackOnNoneThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingNone.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ),
+
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ),
+
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnAnyThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnAnyThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnAnyThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnNoneThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnNoneThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnNoneThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingNone.class, true ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class, false ),
+            new TestVector( TaskRollingBackOnTestExceptionThrowingTestException.class,
+                            TaskRollingBackOnTestExceptionThrowingTestException.class, true ), };
+
+    /**
+     * Test which iterates over ALL possible combinations of inner and outer tasks.
+     */
+    @Test
+    public void testNestedTransactions()
+    {
+        final StringBuilder msg = new StringBuilder();
+        for ( TestVector v : TEST_VECTORS )
+        {
+            try
+            {
+                doTestNestedTransaction( v );
+            }
+            catch ( AssertionError e )
+            {
+                msg.append( "\n" );
+                msg.append( e.getMessage() );
+            }
+        }
+        if ( msg.length() > 0 )
+        {
+            fail( msg.toString() );
+        }
+    }
+
+    private void doTestNestedTransaction( TestVector testVector )
+    {
+        final PersistenceModule pm = createPersistenceModuleForTest();
+        final Injector injector = Guice.createInjector( pm );
+        final PersistenceService persistService = injector.getInstance( PersistenceService.class );
+        persistService.start();
+        try
+        {
+            // given
+            final TransactionalWorker worker = injector.getInstance( TransactionalWorker.class );
+            worker.scheduleTask( testVector.getOuterTask() );
+            worker.scheduleTask( testVector.getInnerTask() );
+
+            // when
+            worker.doTasks();
+
+            // then
+            if ( testVector.shouldRollBack() )
+            {
+                worker.assertNoEntityHasBeenPersisted();
+            }
+            else
+            {
+                worker.assertAllEntitiesHaveBeenPersisted();
+            }
+        }
+        finally
+        {
+            persistService.stop();
+        }
+
+    }
+
+    private PersistenceModule createPersistenceModuleForTest()
+    {
+        return new PersistenceModule()
+        {
+            @Override
+            protected void configurePersistence()
+            {
+                addApplicationManagedPersistenceUnit( "testUnit" );
+            }
+        };
+    }
+
+    private static class TestVector
+    {
+        private final Class<? extends TransactionalTask> outerTask;
+
+        private final Class<? extends TransactionalTask> innerTask;
+
+        private final boolean shouldRollBack;
+
+        public TestVector( Class<? extends TransactionalTask> outerTask, Class<? extends TransactionalTask> innerTask,
+                           boolean shouldRollBack )
+        {
+            this.outerTask = outerTask;
+            this.innerTask = innerTask;
+            this.shouldRollBack = shouldRollBack;
+        }
+
+        public Class<? extends TransactionalTask> getOuterTask()
+        {
+            return outerTask;
+        }
+
+        public Class<? extends TransactionalTask> getInnerTask()
+        {
+            return innerTask;
+        }
+
+        public boolean shouldRollBack()
+        {
+            return shouldRollBack;
+        }
+    }
+}

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/NestedTransactionTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/NestedTransactionTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/NestedTransactionTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/SingleTransactionTest.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/SingleTransactionTest.java?rev=1585487&view=auto
==============================================================================
--- onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/SingleTransactionTest.java (added)
+++ onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/SingleTransactionTest.java Mon Apr  7 14:12:18 2014
@@ -0,0 +1,241 @@
+package org.apache.onami.persist.test.transaction;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.apache.onami.persist.PersistenceModule;
+import org.apache.onami.persist.PersistenceService;
+import org.apache.onami.persist.test.transaction.testframework.TransactionalWorker;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnAnyThrowingNone;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnAnyThrowingRuntimeTestException;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnAnyThrowingTestException;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnNoneThrowingNone;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnNoneThrowingRuntimeTestException;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnNoneThrowingTestException;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnRuntimeTestExceptionThrowingNone;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnRuntimeTestExceptionThrowingTestException;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnTestExceptionThrowingNone;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnTestExceptionThrowingRuntimeTestException;
+import org.apache.onami.persist.test.transaction.testframework.tasks.TaskRollingBackOnTestExceptionThrowingTestException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests running a single non nested transaction.
+ * The test make us of the testframework. For every test a new Injector is created.
+ */
+public class SingleTransactionTest
+{
+
+    private Injector injector;
+
+    private TransactionalWorker worker;
+
+    @Before
+    public void setUp()
+    {
+        final PersistenceModule pm = createPersistenceModuleForTest();
+        injector = Guice.createInjector( pm );
+
+        //startup persistence
+        injector.getInstance( PersistenceService.class ).start();
+        worker = injector.getInstance( TransactionalWorker.class );
+    }
+
+    private PersistenceModule createPersistenceModuleForTest()
+    {
+        return new PersistenceModule()
+        {
+
+            @Override
+            protected void configurePersistence()
+            {
+                addApplicationManagedPersistenceUnit( "testUnit" );
+            }
+        };
+    }
+
+    @After
+    public void tearDown()
+    {
+        injector.getInstance( PersistenceService.class ).stop();
+        injector = null;
+    }
+
+    @Test
+    public void testTaskRollingBackOnAnyThrowingNone()
+    {
+        // given
+        worker.scheduleTask( TaskRollingBackOnAnyThrowingNone.class );
+
+        // when
+        worker.doTasks();
+
+        // then
+        worker.assertAllEntitiesHaveBeenPersisted();
+    }
+
+    @Test
+    public void testTaskRollingBackOnAnyThrowingRuntimeTestException()
+    {
+        // given
+        worker.scheduleTask( TaskRollingBackOnAnyThrowingRuntimeTestException.class );
+
+        // when
+        worker.doTasks();
+
+        // then
+        worker.assertNoEntityHasBeenPersisted();
+    }
+
+    @Test
+    public void testTaskRollingBackOnAnyThrowingTestException()
+    {
+        // given
+        worker.scheduleTask( TaskRollingBackOnAnyThrowingTestException.class );
+
+        // when
+        worker.doTasks();
+
+        // then
+        worker.assertNoEntityHasBeenPersisted();
+    }
+
+    @Test
+    public void testTaskRollingBackOnNoneThrowingNone()
+    {
+        // given
+        worker.scheduleTask( TaskRollingBackOnNoneThrowingNone.class );
+
+        // when
+        worker.doTasks();
+
+        // then
+        worker.assertAllEntitiesHaveBeenPersisted();
+    }
+
+    @Test
+    public void testTaskRollingBackOnNoneThrowingRuntimeTestException()
+    {
+        // given
+        worker.scheduleTask( TaskRollingBackOnNoneThrowingRuntimeTestException.class );
+
+        // when
+        worker.doTasks();
+
+        // then
+        worker.assertAllEntitiesHaveBeenPersisted();
+    }
+
+    @Test
+    public void testTaskRollingBackOnNoneThrowingTestException()
+    {
+        // given
+        worker.scheduleTask( TaskRollingBackOnNoneThrowingTestException.class );
+
+        // when
+        worker.doTasks();
+
+        // then
+        worker.assertAllEntitiesHaveBeenPersisted();
+    }
+
+    @Test
+    public void testTaskRollingBackOnRuntimeTestExceptionThrowingNone()
+    {
+        // given
+        worker.scheduleTask( TaskRollingBackOnRuntimeTestExceptionThrowingNone.class );
+
+        // when
+        worker.doTasks();
+
+        // then
+        worker.assertAllEntitiesHaveBeenPersisted();
+    }
+
+    @Test
+    public void testTaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException()
+    {
+        // given
+        worker.scheduleTask( TaskRollingBackOnRuntimeTestExceptionThrowingRuntimeTestException.class );
+
+        // when
+        worker.doTasks();
+
+        // then
+        worker.assertNoEntityHasBeenPersisted();
+    }
+
+    @Test
+    public void testTaskRollingBackOnRuntimeTestExceptionThrowingTestException()
+    {
+        // given
+        worker.scheduleTask( TaskRollingBackOnRuntimeTestExceptionThrowingTestException.class );
+
+        // when
+        worker.doTasks();
+
+        // then
+        worker.assertAllEntitiesHaveBeenPersisted();
+    }
+
+    @Test
+    public void testTaskRollingBackOnTestExceptionThrowingNone()
+    {
+        // given
+        worker.scheduleTask( TaskRollingBackOnTestExceptionThrowingNone.class );
+
+        // when
+        worker.doTasks();
+
+        // then
+        worker.assertAllEntitiesHaveBeenPersisted();
+    }
+
+    @Test
+    public void testTaskRollingBackOnTestExceptionThrowingRuntimeTestException()
+    {
+        // given
+        worker.scheduleTask( TaskRollingBackOnTestExceptionThrowingRuntimeTestException.class );
+
+        // when
+        worker.doTasks();
+
+        // then
+        worker.assertAllEntitiesHaveBeenPersisted();
+    }
+
+    @Test
+    public void testTaskRollingBackOnTestExceptionThrowingTestException()
+    {
+        // given
+        worker.scheduleTask( TaskRollingBackOnTestExceptionThrowingTestException.class );
+
+        // when
+        worker.doTasks();
+
+        // then
+        worker.assertNoEntityHasBeenPersisted();
+    }
+
+}

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/SingleTransactionTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/SingleTransactionTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/SingleTransactionTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionTestEntity.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionTestEntity.java?rev=1585487&view=auto
==============================================================================
--- onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionTestEntity.java (added)
+++ onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionTestEntity.java Mon Apr  7 14:12:18 2014
@@ -0,0 +1,52 @@
+package org.apache.onami.persist.test.transaction.testframework;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import java.io.Serializable;
+import java.util.UUID;
+
+/**
+ * Entities which can be created during transaction tests.
+ * The ID will be unique in every run of a test.
+ */
+@Entity
+public final class TransactionTestEntity
+    implements Serializable
+{
+
+    private static final long serialVersionUID = 1L;
+
+    private UUID id = UUID.randomUUID();
+
+    @Id
+    public UUID getId()
+    {
+        return id;
+    }
+
+    @SuppressWarnings("unused")
+    // used by the persistence framework
+    private void setId( UUID id )
+    {
+        this.id = id;
+    }
+}

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionTestEntity.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionTestEntity.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionTestEntity.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionalTask.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionalTask.java?rev=1585487&view=auto
==============================================================================
--- onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionalTask.java (added)
+++ onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionalTask.java Mon Apr  7 14:12:18 2014
@@ -0,0 +1,98 @@
+package org.apache.onami.persist.test.transaction.testframework;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.inject.Inject;
+import org.apache.onami.persist.EntityManagerProvider;
+import org.apache.onami.persist.test.transaction.testframework.exceptions.RuntimeTestException;
+import org.apache.onami.persist.test.transaction.testframework.exceptions.TestException;
+
+import javax.persistence.EntityManager;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A {@link TransactionalTask} is a task which is executed during a transaction
+ * test. {@link TransactionalTask}s are passed to a {@link TransactionalWorker} which will call
+ * them one after another.
+ * The sub classes of {@link TransactionalTask} should create a {@link TransactionTestEntity} and
+ * use {@link #storeEntity(TransactionTestEntity)} to persist entities in the DB. They also must
+ * call {@link #doOtherTasks()} to allow the {@link TransactionalWorker} to call the other scheduled
+ * tasks.
+ */
+public abstract class TransactionalTask
+{
+
+    @Inject
+    private EntityManagerProvider emProvider;
+
+    private TransactionalWorker worker;
+
+    private final List<TransactionTestEntity> persistedEntities = new ArrayList<TransactionTestEntity>();
+
+    /**
+     * Should 'try to' create entities in the persistent storage (i.e. DB).
+     * Use {@link #storeEntity(TransactionTestEntity)} to persist entities.
+     *
+     * @throws TestException        may be thrown to test rollback.
+     * @throws RuntimeTestException may be thrown to test rollback.
+     */
+    public abstract void doTransactional()
+        throws TestException, RuntimeTestException;
+
+    /**
+     * Does other tasks.
+     *
+     * @throws TestException        may be thrown to test rollback.
+     * @throws RuntimeTestException may be thrown to test rollback.
+     */
+    protected final void doOtherTasks()
+        throws TestException, RuntimeTestException
+    {
+        worker.doNextTask();
+    }
+
+    /**
+     * Stores an entity.
+     *
+     * @param entity the entity to store.
+     */
+    protected final void storeEntity( TransactionTestEntity entity )
+    {
+        final EntityManager entityManager = emProvider.get();
+        entityManager.persist( entity );
+        entityManager.flush();
+        persistedEntities.add( entity );
+    }
+
+    @VisibleForTesting
+    void setWorker( TransactionalWorker transactionalWorker )
+    {
+        worker = transactionalWorker;
+    }
+
+    @VisibleForTesting
+    List<TransactionTestEntity> getPersistedEntities()
+    {
+        return persistedEntities;
+    }
+
+}

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionalTask.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionalTask.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionalTask.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionalWorker.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionalWorker.java?rev=1585487&view=auto
==============================================================================
--- onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionalWorker.java (added)
+++ onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionalWorker.java Mon Apr  7 14:12:18 2014
@@ -0,0 +1,232 @@
+package org.apache.onami.persist.test.transaction.testframework;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import org.apache.onami.persist.EntityManagerProvider;
+import org.apache.onami.persist.Transactional;
+import org.apache.onami.persist.UnitOfWork;
+import org.apache.onami.persist.test.transaction.testframework.exceptions.RuntimeTestException;
+import org.apache.onami.persist.test.transaction.testframework.exceptions.TestException;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Worker for transactional tests. The worker instantiates the {@link TransactionalTask} and
+ * executes them.
+ */
+public class TransactionalWorker
+{
+
+    private static final String DO_TRANSACTIONAL = "doTransactional";
+
+    private final TransactionalTasks tasks = new TransactionalTasks();
+
+    private final List<TransactionTestEntity> storedEntities = new ArrayList<TransactionTestEntity>();
+
+    @Inject
+    private Injector injector;
+
+    @Inject
+    private UnitOfWork unitOfWork;
+
+    @Inject
+    private EntityManagerProvider emProvider;
+
+    /**
+     * Schedules a task for execution by this worker.
+     * If more than one task are scheduled they will be called in the order they have been
+     * scheduled.
+     *
+     * @param taskType the task to schedule for execution.
+     */
+    public void scheduleTask( Class<? extends TransactionalTask> taskType )
+    {
+        checkTransactionalAnnotation( taskType );
+        final TransactionalTask task = injector.getInstance( taskType );
+        task.setWorker( this );
+        tasks.add( task );
+    }
+
+    private void checkTransactionalAnnotation( Class<? extends TransactionalTask> taskType )
+    {
+        try
+        {
+            final Method method = taskType.getMethod( DO_TRANSACTIONAL );
+            final Transactional annotation = method.getAnnotation( Transactional.class );
+            checkNotNull( annotation, "@Transactional annotation missing on %s.%s", taskType.getSimpleName(),
+                          method.getName() );
+        }
+        catch ( NoSuchMethodException e )
+        {
+            // should never occure.
+            throw new RuntimeException( e );
+        }
+    }
+
+    /**
+     * Executes the previously specified tasks. All entities which were stored using
+     * {@link TransactionalTask#storeEntity(TransactionTestEntity)} are collected by the worker.<p/>
+     */
+    public void doTasks()
+    {
+        checkState( tasks.hasTasks(), "no tasks have been added to the worker." );
+        checkState( tasks.hasNext(), "doTasks() has already been executed." );
+        checkState( !unitOfWork.isActive(), "Active UnitOfWork found." );
+
+        try
+        {
+            doNextTask();
+        }
+        catch ( TestException e )
+        {
+            // do nothing
+        }
+        catch ( RuntimeTestException e )
+        {
+            // do nothing
+        }
+
+        checkState( !tasks.hasNext(), "One of the tasks forgot to call doOtherTasks()." );
+        checkState( !unitOfWork.isActive(), "Active UnitOfWork after tasks found." );
+    }
+
+    /**
+     * Check all stored entities if they actually have been persisted in the DB.
+     */
+    @Transactional
+    public void assertAllEntitiesHaveBeenPersisted()
+    {
+        checkState( !storedEntities.isEmpty(), "no entities to check" );
+        for ( TransactionTestEntity storedEntity : storedEntities )
+        {
+            assertNotNull( "At least one entity which should have been persisted was NOT found in the DB. " + tasks,
+                           emProvider.get().find( TransactionTestEntity.class, storedEntity.getId() ) );
+        }
+    }
+
+    /**
+     * Check all stored entities if they actually have NOT been persisted in the DB.
+     */
+    @Transactional
+    public void assertNoEntityHasBeenPersisted()
+    {
+        checkState( !storedEntities.isEmpty(), "no entities to check" );
+        for ( TransactionTestEntity storedEntity : storedEntities )
+        {
+            assertNull( "At least one entity which should NOT have been persisted was found in the DB. " + tasks,
+                        emProvider.get().find( TransactionTestEntity.class, storedEntity.getId() ) );
+        }
+    }
+
+    @VisibleForTesting
+    void doNextTask()
+        throws TestException
+    {
+        if ( tasks.hasNext() )
+        {
+            final TransactionalTask task = tasks.next();
+            try
+            {
+                task.doTransactional();
+            }
+            finally
+            {
+                storedEntities.addAll( task.getPersistedEntities() );
+            }
+        }
+    }
+
+
+    /**
+     * Class holding the tasks of a worker.
+     */
+    private static class TransactionalTasks
+    {
+
+        private final List<TransactionalTask> tasks = new ArrayList<TransactionalTask>();
+
+        private int pos = 0;
+
+        /**
+         * @return {@code true} if there have already been tasks added.
+         */
+        public boolean hasTasks()
+        {
+            return !tasks.isEmpty();
+        }
+
+        /**
+         * Add a task.
+         *
+         * @param task the task to add.
+         * @throws IllegalStateException if {@link #next()} has already been called on this instance.
+         */
+        public void add( TransactionalTask task )
+        {
+            checkState( pos == 0 );
+            tasks.add( task );
+        }
+
+        /**
+         * @return {@code true} if there are more tasks.
+         */
+        public boolean hasNext()
+        {
+            return pos < tasks.size();
+        }
+
+        /**
+         * @return the next task.
+         * @throws IndexOutOfBoundsException if there are no more tasks.
+         */
+        public TransactionalTask next()
+        {
+            final TransactionalTask result = tasks.get( pos );
+            pos++;
+            return result;
+        }
+
+        @Override
+        public String toString()
+        {
+            final StringBuilder sb = new StringBuilder( "Tasks[" );
+            String separator = "";
+            for ( TransactionalTask t : tasks )
+            {
+                sb.append( separator );
+                final String taskType = t.getClass().getSimpleName();
+                sb.append( taskType.replaceAll( "\\$\\$EnhancerByGuice\\$\\$.*", "" ) );
+                separator = ", ";
+            }
+            sb.append( "]" );
+            return sb.toString();
+        }
+    }
+}

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionalWorker.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionalWorker.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/TransactionalWorker.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/exceptions/RuntimeTestException.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/exceptions/RuntimeTestException.java?rev=1585487&view=auto
==============================================================================
--- onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/exceptions/RuntimeTestException.java (added)
+++ onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/exceptions/RuntimeTestException.java Mon Apr  7 14:12:18 2014
@@ -0,0 +1,56 @@
+package org.apache.onami.persist.test.transaction.testframework.exceptions;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Exception which can be thrown by a {@link org.apache.onami.persist.test.transaction.testframework.TransactionalTask}.
+ */
+public class RuntimeTestException
+    extends RuntimeException
+{
+
+    private static final long serialVersionUID = 1L;
+
+    private final String message;
+
+    /**
+     * Constructor.
+     */
+    public RuntimeTestException()
+    {
+        this.message = RuntimeTestException.class.getSimpleName();
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param message the message of the exception.
+     */
+    public RuntimeTestException( String message )
+    {
+        this.message = message;
+    }
+
+    @Override
+    public String getMessage()
+    {
+        return message;
+    }
+}

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/exceptions/RuntimeTestException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/exceptions/RuntimeTestException.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/exceptions/RuntimeTestException.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/exceptions/TestException.java
URL: http://svn.apache.org/viewvc/onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/exceptions/TestException.java?rev=1585487&view=auto
==============================================================================
--- onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/exceptions/TestException.java (added)
+++ onami/sandbox/persist/src/test/java/org/apache/onami/persist/test/transaction/testframework/exceptions/TestException.java Mon Apr  7 14:12:18 2014
@@ -0,0 +1,56 @@
+package org.apache.onami.persist.test.transaction.testframework.exceptions;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Exception which can be thrown by a {@link org.apache.onami.persist.test.transaction.testframework.TransactionalTask}.
+ */
+public class TestException
+    extends Exception
+{
+
+    private static final long serialVersionUID = 1L;
+
+    private final String message;
+
+    /**
+     * Constructor.
+     */
+    public TestException()
+    {
+        message = TestException.class.getSimpleName();
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param message the message of the exception.
+     */
+    public TestException( String message )
+    {
+        this.message = message;
+    }
+
+    @Override
+    public String getMessage()
+    {
+        return message;
+    }
+}