Coverage Report - org.mule.tck.AbstractTxThreadAssociationTestCase
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractTxThreadAssociationTestCase
0%
0/77
N/A
1.154
AbstractTxThreadAssociationTestCase$1
0%
0/6
N/A
1.154
AbstractTxThreadAssociationTestCase$1$1
0%
0/22
N/A
1.154
AbstractTxThreadAssociationTestCase$2
0%
0/3
N/A
1.154
AbstractTxThreadAssociationTestCase$2$1
0%
0/2
N/A
1.154
 
 1  
 /*
 2  
  * $Id: AbstractTxThreadAssociationTestCase.java 10468 2008-01-22 21:18:22Z aperepel $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 
 11  
 package org.mule.tck;
 12  
 
 13  
 import org.mule.MuleManager;
 14  
 import org.mule.impl.DefaultExceptionStrategy;
 15  
 import org.mule.impl.MuleTransactionConfig;
 16  
 import org.mule.transaction.TransactionCallback;
 17  
 import org.mule.transaction.TransactionTemplate;
 18  
 import org.mule.transaction.XaTransaction;
 19  
 import org.mule.transaction.XaTransactionFactory;
 20  
 import org.mule.umo.UMOTransactionConfig;
 21  
 import org.mule.umo.manager.UMOTransactionManagerFactory;
 22  
 
 23  
 import javax.transaction.Status;
 24  
 import javax.transaction.Transaction;
 25  
 import javax.transaction.TransactionManager;
 26  
 
 27  
 /**
 28  
  * Validate certain expectations when working with JTA API. It is called to catch discrepancies in TM implementations
 29  
  * and alert early. Subclasses are supposed to plug in specific transaction managers for tests.
 30  
  */
 31  0
 public abstract class AbstractTxThreadAssociationTestCase extends AbstractMuleTestCase
 32  
 {
 33  
     /* To allow access from the dead TX threads we spawn. */
 34  
     private TransactionManager tm;
 35  
     protected static final int TRANSACTION_TIMEOUT_SECONDS = 3;
 36  
 
 37  
     protected void doSetUp() throws Exception
 38  
     {
 39  0
         super.doSetUp();
 40  0
         UMOTransactionManagerFactory factory = getTransactionManagerFactory();
 41  0
         tm = factory.create();
 42  0
         assertNotNull("Transaction Manager should be available.", tm);
 43  0
         assertNull("There sould be no current transaction associated.", tm.getTransaction());
 44  0
     }
 45  
 
 46  
     public void testTxHandleCommitKeepsThreadAssociation() throws Exception
 47  
     {
 48  
         // don't wait for ages, has to be set before TX is begun
 49  0
         tm.setTransactionTimeout(TRANSACTION_TIMEOUT_SECONDS);
 50  0
         tm.begin();
 51  
 
 52  0
         Transaction tx = tm.getTransaction();
 53  0
         assertNotNull("Transaction should have started.", tx);
 54  0
         assertEquals("TX should have been active", Status.STATUS_ACTIVE, tx.getStatus());
 55  
 
 56  0
         tx.commit();
 57  
 
 58  0
         tx = tm.getTransaction();
 59  0
         assertNotNull("Committing via TX handle should NOT disassociated TX from the current thread.",
 60  
                       tx);
 61  0
         assertEquals("TX status should have been COMMITTED.", Status.STATUS_COMMITTED, tx.getStatus());
 62  
 
 63  
         // Remove the TX-thread association. The only public API to achieve it is suspend(),
 64  
         // technically we never resume the same transaction (TX forget).
 65  0
         Transaction suspended = tm.suspend();
 66  0
         assertTrue("Wrong TX suspended?.", suspended.equals(tx));
 67  0
         assertNull("TX should've been disassociated from the thread.", tm.getTransaction());
 68  
 
 69  
         // should be no-op and never fail
 70  0
         tm.resume(null);
 71  
 
 72  
         // ensure we don't have any TX-Thread association lurking around a main thread
 73  0
         assertNull(tm.getTransaction());
 74  0
     }
 75  
 
 76  
     public void testTxManagerCommitDissassociatesThread() throws Exception
 77  
     {
 78  
         // don't wait for ages, has to be set before TX is begun
 79  0
         tm.setTransactionTimeout(TRANSACTION_TIMEOUT_SECONDS);
 80  0
         tm.begin();
 81  
 
 82  0
         Transaction tx = tm.getTransaction();
 83  0
         assertNotNull("Transaction should have started.", tx);
 84  0
         assertEquals("TX should have been active", Status.STATUS_ACTIVE, tx.getStatus());
 85  
 
 86  0
         tm.commit();
 87  
 
 88  0
         assertNull("Committing via TX Manager should have disassociated TX from the current thread.",
 89  
                    tm.getTransaction());
 90  0
     }
 91  
 
 92  
     public void testTxManagerRollbackDissassociatesThread() throws Exception
 93  
     {
 94  
         // don't wait for ages, has to be set before TX is begun
 95  0
         tm.setTransactionTimeout(TRANSACTION_TIMEOUT_SECONDS);
 96  0
         tm.begin();
 97  
 
 98  0
         Transaction tx = tm.getTransaction();
 99  0
         assertNotNull("Transaction should have started.", tx);
 100  0
         assertEquals("TX should have been active", Status.STATUS_ACTIVE, tx.getStatus());
 101  
 
 102  0
         tm.rollback();
 103  
 
 104  0
         assertNull("Committing via TX Manager should have disassociated TX from the current thread.",
 105  
                    tm.getTransaction());
 106  0
     }
 107  
 
 108  
     /**
 109  
      * AlwaysBegin action suspends current transaction and begins a new one.
 110  
      *
 111  
      * @throws Exception if any error
 112  
      */
 113  
     public void testAlwaysBeginXaTransactionSuspendResume() throws Exception
 114  
     {
 115  0
         MuleManager.getInstance().setTransactionManager(tm);
 116  0
         assertNull("There sould be no current transaction associated.", tm.getTransaction());
 117  
 
 118  
         // don't wait for ages, has to be set before TX is begun
 119  0
         tm.setTransactionTimeout(TRANSACTION_TIMEOUT_SECONDS);
 120  
 
 121  
         // this is one component with a TX always begin
 122  0
         UMOTransactionConfig config = new MuleTransactionConfig();
 123  0
         config.setFactory(new XaTransactionFactory());
 124  0
         config.setAction(UMOTransactionConfig.ACTION_ALWAYS_BEGIN);
 125  0
         TransactionTemplate template = new TransactionTemplate(config, new DefaultExceptionStrategy());
 126  
 
 127  
         // and the callee component which should begin new transaction, current must be suspended
 128  0
         final UMOTransactionConfig nestedConfig = new MuleTransactionConfig();
 129  0
         nestedConfig.setFactory(new XaTransactionFactory());
 130  0
         nestedConfig.setAction(UMOTransactionConfig.ACTION_ALWAYS_BEGIN);
 131  
 
 132  
         // start the call chain
 133  0
         template.execute(new TransactionCallback()
 134  
         {
 135  0
             public Object doInTransaction() throws Exception
 136  
             {
 137  
                 // the callee executes within its own TX template, but uses the same global XA transaction,
 138  
                 // bound to the current thread of execution via a ThreadLocal
 139  0
                 TransactionTemplate nestedTemplate =
 140  
                         new TransactionTemplate(nestedConfig, new DefaultExceptionStrategy());
 141  0
                 final Transaction firstTx = tm.getTransaction();
 142  0
                 assertNotNull(firstTx);
 143  0
                 assertEquals(firstTx.getStatus(), Status.STATUS_ACTIVE);
 144  0
                 return nestedTemplate.execute(new TransactionCallback()
 145  
                 {
 146  0
                     public Object doInTransaction() throws Exception
 147  
                     {
 148  0
                         Transaction secondTx = tm.getTransaction();
 149  0
                         assertNotNull(secondTx);
 150  0
                         assertEquals(firstTx.getStatus(), Status.STATUS_ACTIVE);
 151  0
                         assertEquals(secondTx.getStatus(), Status.STATUS_ACTIVE);
 152  
                         try
 153  
                         {
 154  0
                             tm.resume(firstTx);
 155  0
                             fail("Second transaction must be active");
 156  
                         }
 157  0
                         catch (java.lang.IllegalStateException e)
 158  
                         {
 159  
                             // expected
 160  
 
 161  
                             //Thrown if the thread is already associated with another transaction.
 162  
                             //Second tx is associated with the current thread
 163  0
                         }
 164  
                         try
 165  
                         {
 166  0
                             Transaction currentTx = tm.suspend();
 167  0
                             assertTrue(currentTx.equals(secondTx));
 168  0
                             tm.resume(firstTx);
 169  0
                             assertEquals(firstTx, tm.getTransaction());
 170  0
                             assertEquals(firstTx.getStatus(), Status.STATUS_ACTIVE);
 171  0
                             assertEquals(secondTx.getStatus(), Status.STATUS_ACTIVE);
 172  0
                             Transaction a = tm.suspend();
 173  0
                             assertTrue(a.equals(firstTx));
 174  0
                             tm.resume(secondTx);
 175  
                         }
 176  0
                         catch (Exception e)
 177  
                         {
 178  0
                             fail("Error: " + e);
 179  0
                         }
 180  
 
 181  
                         // do not care about the return really
 182  0
                         return null;
 183  
                     }
 184  
                 });
 185  
             }
 186  
         });
 187  0
         assertNull("Committing via TX Manager should have disassociated TX from the current thread.",
 188  
                    tm.getTransaction());
 189  0
     }
 190  
 
 191  
     /**
 192  
      * This is a former XaTransactionTestCase.
 193  
      *
 194  
      * @throws Exception in case of any error
 195  
      */
 196  
     public void testXaTransactionTermination() throws Exception
 197  
     {
 198  0
         MuleManager.getInstance().setTransactionManager(tm);
 199  0
         assertNull("There sould be no current transaction associated.", tm.getTransaction());
 200  
 
 201  
         // don't wait for ages, has to be set before TX is begun
 202  0
         tm.setTransactionTimeout(TRANSACTION_TIMEOUT_SECONDS);
 203  
 
 204  0
         XaTransaction muleTx = new XaTransaction();
 205  0
         assertFalse(muleTx.isBegun());
 206  0
         assertEquals(Status.STATUS_NO_TRANSACTION, muleTx.getStatus());
 207  0
         muleTx.begin();
 208  
 
 209  0
         assertTrue(muleTx.isBegun());
 210  
 
 211  0
         muleTx.commit();
 212  
 
 213  0
         Transaction jtaTx = tm.getTransaction();
 214  0
         assertNull("Committing via TX Manager should have disassociated TX from the current thread.", jtaTx);
 215  0
         assertEquals(Status.STATUS_NO_TRANSACTION, muleTx.getStatus());
 216  0
     }
 217  
 
 218  
     /**
 219  
      * This is a former TransactionTemplateTestCase.
 220  
      * http://mule.mulesource.org/jira/browse/MULE-1494
 221  
      *
 222  
      * @throws Exception in case of any error
 223  
      */
 224  
     public void testNoNestedTxStarted() throws Exception
 225  
     {
 226  0
         MuleManager.getInstance().setTransactionManager(tm);
 227  0
         assertNull("There sould be no current transaction associated.", tm.getTransaction());
 228  
 
 229  
         // don't wait for ages, has to be set before TX is begun
 230  0
         tm.setTransactionTimeout(TRANSACTION_TIMEOUT_SECONDS);
 231  
 
 232  
         // this is one component with a TX always begin
 233  0
         UMOTransactionConfig config = new MuleTransactionConfig();
 234  0
         config.setFactory(new XaTransactionFactory());
 235  0
         config.setAction(UMOTransactionConfig.ACTION_ALWAYS_BEGIN);
 236  0
         TransactionTemplate template = new TransactionTemplate(config, new DefaultExceptionStrategy());
 237  
 
 238  
         // and the callee component which should join the current XA transaction, not begin a nested one
 239  0
         final UMOTransactionConfig nestedConfig = new MuleTransactionConfig();
 240  0
         nestedConfig.setFactory(new XaTransactionFactory());
 241  0
         nestedConfig.setAction(UMOTransactionConfig.ACTION_BEGIN_OR_JOIN);
 242  
 
 243  
         // start the call chain
 244  0
         template.execute(new TransactionCallback()
 245  
         {
 246  0
             public Object doInTransaction() throws Exception
 247  
             {
 248  
                 // the callee executes within its own TX template, but uses the same global XA transaction,
 249  
                 // bound to the current thread of execution via a ThreadLocal
 250  0
                 TransactionTemplate nestedTemplate =
 251  
                         new TransactionTemplate(nestedConfig, new DefaultExceptionStrategy());
 252  0
                 return nestedTemplate.execute(new TransactionCallback()
 253  
                 {
 254  0
                     public Object doInTransaction() throws Exception
 255  
                     {
 256  
                         // do not care about the return really
 257  0
                         return null;
 258  
                     }
 259  
                 });
 260  
             }
 261  
         });
 262  0
     }
 263  
 
 264  
 
 265  
     protected TransactionManager getTransactionManager()
 266  
     {
 267  0
         return tm;
 268  
     }
 269  
 
 270  
     protected abstract UMOTransactionManagerFactory getTransactionManagerFactory();
 271  
 
 272  
 }