[jboss-cvs] JBossAS SVN: r77962 - trunk/testsuite/src/main/org/jboss/test/jca/test.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Thu Sep 4 07:26:08 EDT 2008


Author: jesper.pedersen
Date: 2008-09-04 07:26:08 -0400 (Thu, 04 Sep 2008)
New Revision: 77962

Added:
   trunk/testsuite/src/main/org/jboss/test/jca/test/TxConnectionManagerStressTestCase.java
   trunk/testsuite/src/main/org/jboss/test/jca/test/TxConnectionManagerUnitTestCase.java
Log:
[JBAS-5095] Race condition between connection.close() and transaction.rollback()

Added: trunk/testsuite/src/main/org/jboss/test/jca/test/TxConnectionManagerStressTestCase.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/jca/test/TxConnectionManagerStressTestCase.java	                        (rev 0)
+++ trunk/testsuite/src/main/org/jboss/test/jca/test/TxConnectionManagerStressTestCase.java	2008-09-04 11:26:08 UTC (rev 77962)
@@ -0,0 +1,559 @@
+/*
+  * JBoss, Home of Professional Open Source
+  * Copyright 2005, JBoss Inc., and individual contributors as indicated
+  * by the @authors tag. See the copyright.txt in the distribution for a
+  * full listing of individual contributors.
+  *
+  * This is free software; you can redistribute it and/or modify it
+  * under the terms of the GNU Lesser General Public License as
+  * published by the Free Software Foundation; either version 2.1 of
+  * the License, or (at your option) any later version.
+  *
+  * This software is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  * Lesser General Public License for more details.
+  *
+  * You should have received a copy of the GNU Lesser General Public
+  * License along with this software; if not, write to the Free
+  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+  */
+package org.jboss.test.jca.test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.ManagedConnectionFactory;
+import javax.security.auth.Subject;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.SystemException;
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.jboss.logging.Logger;
+import org.jboss.resource.connectionmanager.CachedConnectionManager;
+import org.jboss.resource.connectionmanager.ConnectionListener;
+import org.jboss.resource.connectionmanager.InternalManagedConnectionPool;
+import org.jboss.resource.connectionmanager.JBossManagedConnectionPool;
+import org.jboss.resource.connectionmanager.ManagedConnectionPool;
+import org.jboss.resource.connectionmanager.TxConnectionManager;
+import org.jboss.test.JBossTestCase;
+import org.jboss.test.util.ejb.EJBTestCase;
+import org.jboss.test.jca.adapter.TestConnectionRequestInfo;
+import org.jboss.test.jca.adapter.TestManagedConnectionFactory;
+import org.jboss.tm.TransactionManagerLocator;
+import org.jboss.tm.TxUtils;
+
+/**
+ * Stress test case for TxConnectionManager.
+ *
+ * Based on BaseConnectionManagerStressTestCase by David Jencks.
+ * @author <a href="mailto:jesper.pedersen at jboss.org">Jesper Pedersen</a>
+ * @version $Revision: 1.1 $
+ */
+public class TxConnectionManagerStressTestCase extends EJBTestCase
+{
+   private static final Logger log = Logger.getLogger(TxConnectionManagerStressTestCase.class);
+
+   private boolean failed;
+   private Exception error;
+
+   private AtomicInteger startedThreadCount;
+   private CountDownLatch finishedThreadCount;
+
+   private AtomicLong elapsed = new AtomicLong(0);
+   private AtomicLong getConnection = new AtomicLong(0);
+   private AtomicLong returnConnection = new AtomicLong(0);
+   private AtomicLong held = new AtomicLong(0);
+
+   private AtomicInteger connectionCount;
+   private AtomicInteger errorCount;
+
+   private TransactionManager tm;
+   private Subject subject = new Subject();
+   private ConnectionRequestInfo cri = new TestConnectionRequestInfo();
+   private CachedConnectionManager ccm = new CachedConnectionManager();
+
+   /**
+    * Constructor
+    * @param name The test name
+    */
+   public TxConnectionManagerStressTestCase(String name)
+   {
+      super(name);
+   }
+
+   public static Test suite() throws Exception
+   {
+      TestSuite suite = new TestSuite();
+      suite.addTest(new TxConnectionManagerStressTestCase("testBlockingNoFill"));
+      suite.addTest(new TxConnectionManagerStressTestCase("testBlockingFill"));
+      suite.addTest(new TxConnectionManagerStressTestCase("testBlockingPartFill"));
+      suite.addTest(new TxConnectionManagerStressTestCase("testBlockingNearlyFill"));
+      suite.addTest(new TxConnectionManagerStressTestCase("testBlockingAggressiveRemoval"));
+      suite.addTest(new TxConnectionManagerStressTestCase("testBlockingAggressiveRemovalAndFill"));
+      suite.addTest(new TxConnectionManagerStressTestCase("testBlockingNoFillTrackByTx"));
+      suite.addTest(new TxConnectionManagerStressTestCase("testBlockingFillTrackByTx"));
+      suite.addTest(new TxConnectionManagerStressTestCase("testBlockingPartFillTrackByTx"));
+      suite.addTest(new TxConnectionManagerStressTestCase("testBlockingNearlyFillTrackByTx"));
+      suite.addTest(new TxConnectionManagerStressTestCase("testBlockingAggressiveRemovalTrackByTx"));
+      suite.addTest(new TxConnectionManagerStressTestCase("testBlockingAggressiveRemovalAndFillTrackByTx"));
+      suite.addTest(new TxConnectionManagerStressTestCase("testTimeoutNoFill"));
+      suite.addTest(new TxConnectionManagerStressTestCase("testTimeoutNoFillTrackByTx"));
+      suite.addTest(new TxConnectionManagerStressTestCase("testTimeoutFill"));
+      suite.addTest(new TxConnectionManagerStressTestCase("testTimeoutFillTrackByTx"));
+
+      return JBossTestCase.getDeploySetup(suite, "jca-tests.jar");
+   }
+
+   @Override
+   protected void setUp() throws Exception
+   {
+      super.setUp();
+
+      tm = TransactionManagerLocator.getInstance().locate();
+   }
+
+   @Override
+   protected void tearDown() throws Exception
+   {
+      tm = null;
+
+      super.tearDown();
+   }
+
+   private TxConnectionManager getCM(InternalManagedConnectionPool.PoolParams pp, boolean trackByTx) throws Exception
+   {
+      ManagedConnectionFactory mcf = new TestManagedConnectionFactory();
+      ManagedConnectionPool poolingStrategy = new TestPool(mcf, pp, false, log);
+
+      TxConnectionManager cm = new TxConnectionManager(ccm, poolingStrategy, tm);
+      cm.setTrackConnectionByTx(trackByTx);
+
+      poolingStrategy.setConnectionListenerFactory(cm);
+      return cm;
+   }
+
+   private void shutdown(TxConnectionManager cm)
+   {
+      TestPool pool = (TestPool) cm.getPoolingStrategy();
+      pool.shutdown();
+   }
+
+   public void testBlockingNoFill() throws Exception
+   {
+      doBlocking(20, 0, 5000, false);
+   }
+
+   public void testBlockingFill() throws Exception
+   {
+      doBlocking(20, getBeanCount(), 5000, false);
+   }
+
+   public void testBlockingPartFill() throws Exception
+   {
+      doBlocking(20, getBeanCount()/2, 5000, false);
+   }
+
+   public void testBlockingNearlyFill() throws Exception
+   {
+      doBlocking(20, getBeanCount() - 1, 5000, false);
+   }
+
+   public void testBlockingAggressiveRemoval() throws Exception
+   {
+      doBlocking(20, 0, 10, false);
+   }
+
+   public void testBlockingAggressiveRemovalAndFill() throws Exception
+   {
+      doBlocking(20, getBeanCount(), 10, false);
+   }
+
+   public void testBlockingNoFillTrackByTx() throws Exception
+   {
+      doBlocking(20, 0, 5000, true);
+   }
+
+   public void testBlockingFillTrackByTx() throws Exception
+   {
+      doBlocking(20, getBeanCount(), 5000, true);
+   }
+
+   public void testBlockingPartFillTrackByTx() throws Exception
+   {
+      doBlocking(20, getBeanCount()/2, 5000, true);
+   }
+
+   public void testBlockingNearlyFillTrackByTx() throws Exception
+   {
+      doBlocking(20, getBeanCount() - 1, 5000, true);
+   }
+
+   public void testBlockingAggressiveRemovalTrackByTx() throws Exception
+   {
+      doBlocking(20, 0, 10, true);
+   }
+
+   public void testBlockingAggressiveRemovalAndFillTrackByTx() throws Exception
+   {
+      doBlocking(20, getBeanCount(), 10, true);
+   }
+
+   public void testTimeoutNoFill() throws Exception
+   {
+      doTimeout(0, 5000, false);
+   }
+
+   public void testTimeoutNoFillTrackByTx() throws Exception
+   {
+      doTimeout(0, 5000, true);
+   }
+
+   public void testTimeoutFill() throws Exception
+   {
+      doTimeout(getBeanCount(), 5000, false);
+   }
+
+   public void testTimeoutFillTrackByTx() throws Exception
+   {
+      doTimeout(getBeanCount(), 5000, true);
+   }
+
+   /**
+    * The doBlocking method tries to simulate extremely high load on the pool.
+    * @exception Exception if an error occurs
+    */
+   public void doBlocking(long sleep, int min, long idle, final boolean trackByTx) throws Exception
+   {  
+      failed = false;
+
+      startedThreadCount = new AtomicInteger(0);
+      connectionCount = new AtomicInteger(0);
+      errorCount = new AtomicInteger(0);
+
+      final int reps = 5; //getIterationCount();
+      final int threadsPerConnection = 10; //getThreadCount();
+      final long sleepTime = sleep;
+
+      InternalManagedConnectionPool.PoolParams pp = new InternalManagedConnectionPool.PoolParams();
+      pp.minSize = min;
+      pp.maxSize = getBeanCount();
+      pp.blockingTimeout = 3000;
+      pp.idleTimeout = idle;
+
+      final TxConnectionManager cm = getCM(pp, trackByTx);
+
+      try
+      {
+         int totalThreads = pp.maxSize * threadsPerConnection;
+         finishedThreadCount = new CountDownLatch(totalThreads);
+
+         log.info("Blocking test with connections: " + pp.maxSize + " totalThreads: " + totalThreads + " reps: " + reps);
+         for (int i = 0; i < totalThreads; i++)
+         {
+            Runnable t = new Runnable()
+            {
+               int id;
+               public void run()
+               {
+                  id = startedThreadCount.getAndIncrement();
+
+                  long duration = 0;
+                  long getConnection = 0;
+                  long returnConnection = 0;
+                  long heldConnection = 0;
+                  for (int j = 0; j < reps; j++)
+                  {
+                     ConnectionListener cl = null;
+                     try
+                     {
+                        if (tm == null)
+                           throw new SystemException("TM is null");
+
+                        tm.begin();
+
+                        long startGetConnection = System.currentTimeMillis();
+                        cl = cm.getManagedConnection(subject, cri);
+                        cl.enlist();
+                        long endGetConnection = System.currentTimeMillis();
+
+                        TxConnectionManagerStressTestCase.this.connectionCount.incrementAndGet();
+
+                        Thread.sleep(sleepTime);
+
+                        if (tm == null)
+                           throw new SystemException("TM is null");
+
+                        tm.commit();
+
+                        long startReturnConnection = System.currentTimeMillis();
+                        if (!trackByTx)
+                        {
+                           cl.delist();
+                           cm.returnManagedConnection(cl, false);
+                        }
+                        cl = null;
+                        long endReturnConnection = System.currentTimeMillis();
+                        
+                        duration += (endReturnConnection - startGetConnection);
+                        getConnection += (endGetConnection - startGetConnection);
+                        returnConnection += (endReturnConnection - startReturnConnection);
+                        heldConnection += (startReturnConnection - endGetConnection);
+                      }
+                      catch (NotSupportedException nse)
+                      {
+                         TxConnectionManagerStressTestCase.this.log.info("error: iterationCount: " + j + ", connectionCount: " + TxConnectionManagerStressTestCase.this.connectionCount.get() + " " + nse.getMessage());
+                         TxConnectionManagerStressTestCase.this.errorCount.incrementAndGet();
+                         TxConnectionManagerStressTestCase.this.error = nse;
+                         TxConnectionManagerStressTestCase.this.failed = true;
+                      }
+                      catch (SystemException se)
+                      {
+                         TxConnectionManagerStressTestCase.this.log.info("error: iterationCount: " + j + ", connectionCount: " + TxConnectionManagerStressTestCase.this.connectionCount.get() + " " + se.getMessage());
+                         TxConnectionManagerStressTestCase.this.errorCount.incrementAndGet();
+                         TxConnectionManagerStressTestCase.this.error = se;
+                         TxConnectionManagerStressTestCase.this.failed = true;
+                      }
+                      catch (RollbackException rbe)
+                      {
+                         TxConnectionManagerStressTestCase.this.log.info("error: iterationCount: " + j + ", connectionCount: " + TxConnectionManagerStressTestCase.this.connectionCount.get() + " " + rbe.getMessage());
+                         TxConnectionManagerStressTestCase.this.errorCount.incrementAndGet();
+                         TxConnectionManagerStressTestCase.this.error = rbe;
+                         TxConnectionManagerStressTestCase.this.failed = true;
+                      }
+                      catch (HeuristicMixedException hme)
+                      {
+                         TxConnectionManagerStressTestCase.this.log.info("error: iterationCount: " + j + ", connectionCount: " + TxConnectionManagerStressTestCase.this.connectionCount.get() + " " + hme.getMessage());
+                         TxConnectionManagerStressTestCase.this.errorCount.incrementAndGet();
+                         TxConnectionManagerStressTestCase.this.error = hme;
+                         TxConnectionManagerStressTestCase.this.failed = true;
+                      }
+                      catch (HeuristicRollbackException hre)
+                      {
+                         TxConnectionManagerStressTestCase.this.log.info("error: iterationCount: " + j + ", connectionCount: " + TxConnectionManagerStressTestCase.this.connectionCount.get() + " " + hre.getMessage());
+                         TxConnectionManagerStressTestCase.this.errorCount.incrementAndGet();
+                         TxConnectionManagerStressTestCase.this.error = hre;
+                         TxConnectionManagerStressTestCase.this.failed = true;
+                      }
+                      catch (ResourceException re)
+                      {
+                         TxConnectionManagerStressTestCase.this.log.info("error: iterationCount: " + j + ", connectionCount: " + TxConnectionManagerStressTestCase.this.connectionCount.get() + " " + re.getMessage());
+                         TxConnectionManagerStressTestCase.this.errorCount.incrementAndGet();
+                         TxConnectionManagerStressTestCase.this.error = re;
+                         TxConnectionManagerStressTestCase.this.failed = true;
+                      }
+                      catch (InterruptedException ie)
+                      {
+                         break;
+                      }
+                      finally
+                      {
+                         if (cl != null)
+                            cm.returnManagedConnection(cl, true);
+
+                         try
+                         {
+                            if (tm == null)
+                               throw new SystemException("TM is null");
+
+                            Transaction tx = tm.getTransaction();
+                            if (tx != null)
+                               log.info("TX STATUS=" + TxUtils.getStatusAsString(tx.getStatus()));
+                            if (tx != null && TxUtils.isUncommitted(tx))
+                            {
+                               tm.rollback();
+                            }
+                         }
+                         catch (SystemException se)
+                         {
+                            TxConnectionManagerStressTestCase.this.log.info("error: iterationCount: " + j + ", connectionCount: " + TxConnectionManagerStressTestCase.this.connectionCount.get() + " " + se.getMessage());
+                            TxConnectionManagerStressTestCase.this.errorCount.incrementAndGet();
+                            TxConnectionManagerStressTestCase.this.error = se;
+                            TxConnectionManagerStressTestCase.this.failed = true;
+                         }
+                      }
+                  }
+
+                   TxConnectionManagerStressTestCase.this.elapsed.addAndGet(duration);
+                   TxConnectionManagerStressTestCase.this.getConnection.addAndGet(getConnection);
+                   TxConnectionManagerStressTestCase.this.returnConnection.addAndGet(returnConnection);
+                   TxConnectionManagerStressTestCase.this.held.addAndGet(heldConnection);
+
+                   finishedThreadCount.countDown();
+               }
+            };
+            new Thread(t).start();
+         }
+         finishedThreadCount.await();
+         
+         // Stop the pool/idle remover, otherwise the following checks will be random
+         TestPool pool = (TestPool) cm.getPoolingStrategy();
+         pool.shutdownWithoutClear();
+         
+         float expected = totalThreads * reps;
+         float lessWaiting = getConnection.get() - (threadsPerConnection - 1) * held.get();
+         log.info("completed " + getName() + " with connectionCount: " + connectionCount.get() + ", expected : " + expected);
+         log.info("errorCount: " + errorCount.get() + " %error=" + ((100 * errorCount.get()) / expected));
+         log.info("Total time elapsed: " + elapsed.get()  + ", perRequest: " + (elapsed.get() / (float)connectionCount.get()));
+         log.info("Total time held   : " + held.get()  + ", perRequest: " + (held.get() / (float)connectionCount.get()));
+         log.info("Time getConnection: " + getConnection.get()  + ", perRequest: " + (getConnection.get() / (float)connectionCount.get()));
+         log.info("     lessWaiting  : " + lessWaiting  + ", perRequest: " + (lessWaiting / connectionCount.get()));
+         log.info("Time retConnection: " + returnConnection.get()  + ", perRequest: " + (returnConnection.get() / (float)connectionCount.get()));
+         int available = (int) pool.getAvailableConnectionCount();
+         assertTrue("Wrong number of connections counted: " + available, available == pp.maxSize);
+         assertTrue("Blocking Timeout occurred in blocking test: " + error, !failed);
+      }
+      finally
+      {
+         if (cm != null)
+            shutdown(cm);
+      }
+   }
+   
+   /**
+    * The doTimeout method tries to simulate extremely high load on the pool.
+    * @exception Exception if an error occurs
+    */
+   public void doTimeout(int min, long idle, final boolean trackByTx) throws Exception
+   {  
+      failed = false;
+
+      startedThreadCount = new AtomicInteger(0);
+
+      final int reps = 1; //getIterationCount();
+      final int threadsPerConnection = 1; //getThreadCount();
+
+      InternalManagedConnectionPool.PoolParams pp = new InternalManagedConnectionPool.PoolParams();
+      pp.minSize = min;
+      pp.maxSize = getBeanCount();
+      pp.blockingTimeout = 30000;
+      pp.idleTimeout = idle;
+
+      final TxConnectionManager cm = getCM(pp, trackByTx);
+
+      try
+      {
+         int totalThreads = pp.maxSize * threadsPerConnection;
+         finishedThreadCount = new CountDownLatch(totalThreads);
+
+         log.info("Timeout test with connections: " + pp.maxSize + " totalThreads: " + totalThreads + " reps: " + reps);
+         for (int i = 0; i < totalThreads; i++)
+         {
+            Runnable t = new Runnable()
+            {
+               int id;
+               public void run()
+               {
+                  id = startedThreadCount.getAndIncrement();
+
+                  for (int j = 0; j < reps; j++)
+                  {
+                     ConnectionListener cl = null;
+                     try
+                     {
+                        assertNotNull(tm);
+
+                        tm.setTransactionTimeout(2);
+                        tm.begin();
+
+                        cl = cm.getManagedConnection(subject, cri);
+                        cl.enlist();
+
+                        // TX timeout
+                        Thread.sleep(2500L);
+
+                        assertNotNull(tm);
+
+                        Transaction tx = tm.getTransaction();
+                        if (tx != null && TxUtils.isActive(tx))
+                           failed = true;
+
+                        if (!trackByTx)
+                        {
+                           cl.delist();
+                           cm.returnManagedConnection(cl, false);
+                        }
+                        cl = null;
+
+                      }
+                      catch (NotSupportedException nse)
+                      {
+                         error = nse;
+                         log.info(nse.getMessage(), nse);
+                      }
+                      catch (SystemException se)
+                      {
+                         error = se;
+                         log.info(se.getMessage(), se);
+                      }
+                      catch (ResourceException re)
+                      {
+                         error = re;
+                         log.info(re.getMessage(), re);
+                      }
+                      catch (InterruptedException ie)
+                      {
+                         break;
+                      }
+                      finally
+                      {
+                         if (cl != null)
+                            cm.returnManagedConnection(cl, true);
+
+                         try
+                         {
+                            assertNotNull(tm);
+                            Transaction tx = tm.getTransaction();
+                            if (tx != null && TxUtils.isActive(tx))
+                               failed = true;
+                         }
+                         catch (SystemException se)
+                         {
+                         }
+                      }
+                  }
+
+                   finishedThreadCount.countDown();
+               }
+            };
+            new Thread(t).start();
+         }
+         finishedThreadCount.await();
+
+
+         assertTrue("Error in timeout test: " + error, !failed);
+      }
+      finally
+      {
+         if (cm != null)
+            shutdown(cm);
+      }
+   }
+   
+   public class TestPool extends JBossManagedConnectionPool.OnePool
+   {
+      public TestPool(final ManagedConnectionFactory mcf, 
+                      final InternalManagedConnectionPool.PoolParams poolParams,
+                      final boolean noTxSeparatePools, 
+                      final Logger log)
+      {
+         super(mcf, poolParams, noTxSeparatePools, log);
+      }
+
+      public void shutdownWithoutClear()
+      {
+         super.shutdownWithoutClear();
+      }
+   }
+}

Added: trunk/testsuite/src/main/org/jboss/test/jca/test/TxConnectionManagerUnitTestCase.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/jca/test/TxConnectionManagerUnitTestCase.java	                        (rev 0)
+++ trunk/testsuite/src/main/org/jboss/test/jca/test/TxConnectionManagerUnitTestCase.java	2008-09-04 11:26:08 UTC (rev 77962)
@@ -0,0 +1,663 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.test.jca.test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.Attribute;
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.ManagedConnection;
+import javax.resource.spi.ManagedConnectionFactory;
+import javax.security.auth.Subject;
+import javax.transaction.RollbackException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.jboss.mx.util.MBeanServerLocator;
+import org.jboss.logging.Logger;
+import org.jboss.resource.connectionmanager.CachedConnectionManager;
+import org.jboss.resource.connectionmanager.ConnectionListener;
+import org.jboss.resource.connectionmanager.InternalManagedConnectionPool;
+import org.jboss.resource.connectionmanager.JBossManagedConnectionPool.BasePool;
+import org.jboss.resource.connectionmanager.JBossManagedConnectionPool;
+import org.jboss.resource.connectionmanager.ManagedConnectionPool;
+import org.jboss.resource.connectionmanager.TxConnectionManager;
+import org.jboss.test.JBossTestCase;
+import org.jboss.test.util.ejb.EJBTestCase;
+import org.jboss.tm.TransactionManagerLocator;
+import org.jboss.tm.TxUtils;
+
+import org.jboss.test.jca.adapter.TestConnection;
+import org.jboss.test.jca.adapter.TestConnectionRequestInfo;
+import org.jboss.test.jca.adapter.TestManagedConnection;
+import org.jboss.test.jca.adapter.TestManagedConnectionFactory;
+
+/**
+ * Unit test for class TxConnectionManager
+ *
+ * @author <a href="mailto:jesper.pedersen at jboss.org">Jesper Pedersen</a>
+ * @version $Revision: 1.1 $
+ */
+public class TxConnectionManagerUnitTestCase extends EJBTestCase
+{
+   private static final Logger log = Logger.getLogger(TxConnectionManagerUnitTestCase.class);
+   private Subject subject = new Subject();
+   private ConnectionRequestInfo cri = new TestConnectionRequestInfo();
+   private CachedConnectionManager ccm = new CachedConnectionManager();
+   private TestManagedConnectionFactory mcf;
+   private TxConnectionManager cm;
+   private TransactionManager tm;
+   private int txTimeout;
+
+   /**
+    * Creates a new <code>TxConnectionManagerUnitTestCase</code> instance.
+    * @param name test name
+    */
+   public TxConnectionManagerUnitTestCase(String name)
+   {
+      super(name);
+   }
+
+   public static Test suite() throws Exception
+   {
+      TestSuite suite = new TestSuite();
+      suite.addTest(new TxConnectionManagerUnitTestCase("testAllocateConnection"));
+      suite.addTest(new TxConnectionManagerUnitTestCase("testConnectionEventListenerConnectionClosed"));
+      suite.addTest(new TxConnectionManagerUnitTestCase("testSynchronizationAfterCompletion"));
+      suite.addTest(new TxConnectionManagerUnitTestCase("testSynchronizationAfterCompletionTxTimeout"));
+      suite.addTest(new TxConnectionManagerUnitTestCase("testGetManagedConnection"));
+      suite.addTest(new TxConnectionManagerUnitTestCase("testGetManagedConnectionTimeout"));
+      suite.addTest(new TxConnectionManagerUnitTestCase("testGetManagedConnectionTrackByTx"));
+      suite.addTest(new TxConnectionManagerUnitTestCase("testGetManagedConnectionTimeoutTrackByTx"));
+      suite.addTest(new TxConnectionManagerUnitTestCase("testConnectionError"));
+      suite.addTest(new TxConnectionManagerUnitTestCase("testConnectionErrorTrackByTx"));
+      suite.addTest(new TxConnectionManagerUnitTestCase("testSimulateConnectionError"));
+      suite.addTest(new TxConnectionManagerUnitTestCase("testSimulateConnectionErrorTrackByTx"));
+
+      return JBossTestCase.getDeploySetup(suite, "jca-tests.jar");
+   }
+
+   @Override
+   protected void setUp() throws Exception
+   {
+      super.setUp();
+
+      tm = TransactionManagerLocator.getInstance().locate();
+
+      mcf = new TestManagedConnectionFactory();
+
+      InternalManagedConnectionPool.PoolParams pp = new InternalManagedConnectionPool.PoolParams();
+
+      ManagedConnectionPool poolingStrategy = new JBossManagedConnectionPool.OnePool(mcf, pp, false, log);
+
+      cm = new TxConnectionManager(ccm, poolingStrategy, tm);
+
+      poolingStrategy.setConnectionListenerFactory(cm);
+
+      MBeanServer server = MBeanServerLocator.locateJBoss();
+      ObjectName onTM = new ObjectName("jboss:service=TransactionManager");
+
+      txTimeout = ((Integer)server.getAttribute(onTM, "TransactionTimeout")).intValue();
+   }
+
+   @Override
+   protected void tearDown() throws Exception
+   {
+      JBossManagedConnectionPool.OnePool pool = (JBossManagedConnectionPool.OnePool)cm.getPoolingStrategy();
+      pool.shutdown();
+
+      tm.setTransactionTimeout(txTimeout);
+      tm = null;
+      cm = null;
+      mcf = null;
+
+      super.tearDown();
+   }
+
+   /**
+    * Test that a connection can be allocated
+    * @exception Exception If an error occurs
+    */
+   public void testAllocateConnection() throws Exception
+   {
+      log.info("----------------------");
+      log.info("testAllocateConnection");
+      log.info("----------------------");
+
+      tm.begin();
+      TestConnection c = null;
+      try
+      {
+         c = (TestConnection)cm.allocateConnection(mcf, cri);
+         try
+         {
+            assertTrue("Connection not enlisted in tx!", c.isInTx());
+         }
+         finally
+         {
+            c.close();
+         }
+      }
+      finally
+      {
+         Transaction tx = tm.getTransaction();
+         if (tx != null)
+         {
+            if (TxUtils.isActive(tx))
+               tm.commit();
+            else
+               tm.rollback();
+         }
+         else
+            fail("Transaction is null");
+      }
+      assertTrue("Connection still enlisted in tx!", !c.isInTx());
+   }
+
+   /**
+    * Test
+    * @exception Exception If an error occurs
+    */
+   public void testConnectionEventListenerConnectionClosed() throws Exception
+   {
+      log.info("-------------------------------------------");
+      log.info("testConnectionEventListenerConnectionClosed");
+      log.info("-------------------------------------------");
+
+      tm.begin();
+      try
+      {
+         TestConnection c = (TestConnection)cm.allocateConnection(mcf, cri);
+         c.close();
+      }
+      finally
+      {
+         Transaction tx = tm.getTransaction();
+         if (tx != null)
+         {
+            if (TxUtils.isActive(tx))
+               tm.commit();
+            else
+               tm.rollback();
+         }
+         else
+            fail("Transaction is null");
+      }
+   }
+
+   /**
+    * Test
+    * @exception Exception If an error occurs
+    */
+   public void testSynchronizationAfterCompletion() throws Exception
+   {
+      log.info("----------------------------------");
+      log.info("testSynchronizationAfterCompletion");
+      log.info("----------------------------------");
+
+      // track-by-tx = true
+      cm.setTrackConnectionByTx(true);
+
+      tm.begin();
+      try
+      {
+         TestConnection c = (TestConnection)cm.allocateConnection(mcf, cri);
+         c.close();
+      }
+      finally
+      {
+         Transaction tx = tm.getTransaction();
+         if (tx != null)
+         {
+            if (TxUtils.isActive(tx))
+               tm.commit();
+            else
+               tm.rollback();
+         }
+         else
+            fail("Transaction is null");
+      }
+   }
+
+   /**
+    * Test
+    * @exception Exception If an error occurs
+    */
+   public void testSynchronizationAfterCompletionTxTimeout() throws Exception
+   {
+      log.info("-------------------------------------------");
+      log.info("testSynchronizationAfterCompletionTxTimeout");
+      log.info("-------------------------------------------");
+
+      // track-by-tx = true
+      cm.setTrackConnectionByTx(true);
+
+      tm.setTransactionTimeout(2);
+
+      TestConnection c = null;
+      try
+      {
+         tm.begin();
+
+         assertEquals("1", 0, cm.getPoolingStrategy().getInUseConnectionCount());
+
+         c = (TestConnection)cm.allocateConnection(mcf, cri);
+         
+         assertEquals("2", 1, cm.getPoolingStrategy().getInUseConnectionCount());
+         
+         Thread.sleep(2500L);
+         
+         Transaction tx = tm.getTransaction();
+         if (tx != null && TxUtils.isActive(tx))
+            fail("TX is still active");
+         
+         c.close();
+         c = null;
+         
+         assertEquals("3", 0, cm.getPoolingStrategy().getInUseConnectionCount());
+      }
+      finally
+      {
+         if (c != null)
+         {
+            c.close();
+            fail("Connection wasnt closed");
+         }
+         
+         assertNotNull(tm);
+            
+         if (!TxUtils.isCompleted(tm))
+         {
+            tm.rollback();
+            fail("Tx was still active");
+         }
+      }
+   }
+
+   /**
+    * Test that a connection can be obtained from getManagedConnection
+    * and enlisted/delisted in a transaction
+    * @exception Exception If an error occurs
+    */
+   public void testGetManagedConnection() throws Exception
+   {
+      log.info("------------------------");
+      log.info("testGetManagedConnection");
+      log.info("------------------------");
+
+
+      ConnectionListener cl = null;
+      try
+      {
+         assertNotNull(tm);
+         tm.begin();
+
+         assertEquals(0, cm.getPoolingStrategy().getInUseConnectionCount());
+
+         cl = cm.getManagedConnection(subject, cri);
+
+         assertEquals(1, cm.getPoolingStrategy().getInUseConnectionCount());
+         
+         assertNotNull(cl);
+         cl.enlist();
+         
+         assertNotNull(tm);
+         tm.commit();
+         
+         cl.delist();
+         cm.returnManagedConnection(cl, false);
+         cl = null;
+
+         assertEquals(0, cm.getPoolingStrategy().getInUseConnectionCount());
+      }
+      finally
+      {
+         if (cl != null)
+         {
+            cm.returnManagedConnection(cl, true);
+            fail("ConnectionListener wasnt returned to the pool");
+         }
+         
+         assertNotNull(tm);
+            
+         if (TxUtils.isUncommitted(tm))
+         {
+            tm.rollback();
+         }
+      }
+   }
+
+   /**
+    * Test that a connection can be obtained from getManagedConnection
+    * and enlisted in a transaction that suffer timeout
+    * @exception Exception If an error occurs
+    */
+   public void testGetManagedConnectionTimeout() throws Exception
+   {
+      log.info("-------------------------------");
+      log.info("testGetManagedConnectionTimeout");
+      log.info("-------------------------------");
+
+
+      ConnectionListener cl = null;
+      try
+      {
+         assertNotNull(tm);
+         tm.setTransactionTimeout(2);
+         tm.begin();
+
+         assertEquals(0, cm.getPoolingStrategy().getInUseConnectionCount());
+
+         cl = cm.getManagedConnection(subject, cri);
+
+         assertEquals(1, cm.getPoolingStrategy().getInUseConnectionCount());
+         
+         assertNotNull(cl);
+         cl.enlist();
+         
+         Thread.sleep(2500L);
+
+         cl.delist();
+         cm.returnManagedConnection(cl, false);
+
+         cl = null;
+
+         assertEquals(0, cm.getPoolingStrategy().getInUseConnectionCount());
+      }
+      finally
+      {
+         if (cl != null)
+         {
+            cm.returnManagedConnection(cl, true);
+            fail("ConnectionListener wasnt returned to the pool");
+         }
+         
+         assertNotNull(tm);
+            
+         if (!TxUtils.isCompleted(tm))
+         {
+            tm.rollback();
+            fail("Tx was still active");
+         }
+      }
+   }
+
+   /**
+    * Test that a connection can be obtained from getManagedConnection
+    * and enlisted/delisted in a transaction with track-by-tx enabled
+    * @exception Exception If an error occurs
+    */
+   public void testGetManagedConnectionTrackByTx() throws Exception
+   {
+      log.info("---------------------------------");
+      log.info("testGetManagedConnectionTrackByTx");
+      log.info("---------------------------------");
+
+      // track-by-tx = true
+      cm.setTrackConnectionByTx(true);
+
+      ConnectionListener cl = null;
+      try
+      {
+         assertNotNull(tm);
+         tm.begin();
+
+         assertEquals(0, cm.getPoolingStrategy().getInUseConnectionCount());
+
+         cl = cm.getManagedConnection(subject, cri);
+
+         assertEquals(1, cm.getPoolingStrategy().getInUseConnectionCount());
+
+         assertNotNull(cl);
+         cl.enlist();
+         
+         assertNotNull(tm);
+         tm.commit();
+         
+         assertEquals(0, cm.getPoolingStrategy().getInUseConnectionCount());
+         
+         cl = null;
+      }
+      finally
+      {
+         if (cl != null)
+         {
+            cm.returnManagedConnection(cl, true);
+            fail("ConnectionListener wasnt returned to the pool");
+         }
+         
+         assertNotNull(tm);
+            
+         if (TxUtils.isUncommitted(tm))
+         {
+            tm.rollback();
+         }
+      }
+   }
+
+   /**
+    * Test that a connection can be obtained from getManagedConnection
+    * and enlisted in a transaction that suffer timeout with track-by-tx enabled
+    * @exception Exception If an error occurs
+    */
+   public void testGetManagedConnectionTimeoutTrackByTx() throws Exception
+   {
+      log.info("----------------------------------------");
+      log.info("testGetManagedConnectionTimeoutTrackByTx");
+      log.info("----------------------------------------");
+
+      // track-by-tx = true
+      cm.setTrackConnectionByTx(true);
+
+      ConnectionListener cl = null;
+      try
+      {
+         assertNotNull(tm);
+         tm.setTransactionTimeout(2);
+         tm.begin();
+
+         assertEquals(0, cm.getPoolingStrategy().getInUseConnectionCount());
+
+         cl = cm.getManagedConnection(subject, cri);
+
+         assertEquals(1, cm.getPoolingStrategy().getInUseConnectionCount());
+
+         assertNotNull(cl);
+         cl.enlist();
+
+         Thread.sleep(2500L);
+
+         assertEquals(0, cm.getPoolingStrategy().getInUseConnectionCount());
+         
+         cl = null;
+      }
+      finally
+      {
+         if (cl != null)
+         {
+            cm.returnManagedConnection(cl, true);
+            fail("ConnectionListener wasnt returned to the pool");
+         }
+         
+         assertNotNull(tm);
+            
+         if (!TxUtils.isCompleted(tm))
+         {
+            tm.rollback();
+            fail("Tx was still active");
+         }
+      }
+   }
+
+   /**
+    * Test a connection error
+    * @exception Exception If an error occurs
+    */
+   public void testConnectionError() throws Exception
+   {
+      log.info("-------------------");
+      log.info("testConnectionError");
+      log.info("-------------------");
+
+      tm.begin();
+      TestConnection c = (TestConnection)cm.allocateConnection(mcf, cri);
+      c.fireConnectionError();
+      try
+      {
+         c.close();
+      }
+      catch (Exception ignored)
+      {
+      }
+
+      try
+      {
+         tm.commit();
+         fail("Should not be here");
+      }
+      catch (RollbackException expected)
+      {
+      }
+
+      assertTrue("Connection still enlisted in tx!", !c.isInTx());
+   }
+
+   /**
+    * Test a connection error with track-by-tx enabled
+    * @exception Exception If an error occurs
+    */
+   public void testConnectionErrorTrackByTx() throws Exception
+   {
+      log.info("----------------------------");
+      log.info("testConnectionErrorTrackByTx");
+      log.info("----------------------------");
+
+      // track-by-tx = true
+      cm.setTrackConnectionByTx(true);
+
+      tm.begin();
+      TestConnection c = (TestConnection)cm.allocateConnection(mcf, cri);
+      c.fireConnectionError();
+      try
+      {
+         c.close();
+      }
+      catch (Exception ignored)
+      {
+      }
+
+      try
+      {
+         tm.commit();
+         fail("Should not be here");
+      }
+      catch (RollbackException expected)
+      {
+      }
+
+      assertTrue("Connection still enlisted in tx!", !c.isInTx());
+   }
+
+   /**
+    * Test a connection error
+    * @exception Exception If an error occurs
+    */
+   public void testSimulateConnectionError() throws Exception
+   {
+      log.info("---------------------------");
+      log.info("testSimulateConnectionError");
+      log.info("---------------------------");
+
+      tm.begin();
+      TestConnection c = (TestConnection)cm.allocateConnection(mcf, cri);
+
+      try
+      {
+         c.simulateConnectionError();
+         fail("No exception thrown");
+      }
+      catch (Exception expected)
+      {
+      }
+
+      c.close();
+
+      try
+      {
+         tm.commit();
+         fail("Should not be here");
+      }
+      catch (RollbackException expected)
+      {
+      }
+
+      assertTrue("Connection still enlisted in tx!", !c.isInTx());
+   }
+
+   /**
+    * Test a connection error with track-by-tx enabled
+    * @exception Exception If an error occurs
+    */
+   public void testSimulateConnectionErrorTrackByTx() throws Exception
+   {
+      log.info("------------------------------------");
+      log.info("testSimulateConnectionErrorTrackByTx");
+      log.info("------------------------------------");
+
+      // track-by-tx = true
+      cm.setTrackConnectionByTx(true);
+
+      tm.begin();
+      TestConnection c = (TestConnection)cm.allocateConnection(mcf, cri);
+
+      try
+      {
+         c.simulateConnectionError();
+         fail("No exception thrown");
+      }
+      catch (Exception expected)
+      {
+      }
+
+      c.close();
+
+      try
+      {
+         tm.commit();
+         fail("Should not be here");
+      }
+      catch (RollbackException expected)
+      {
+      }
+
+      assertTrue("Connection still enlisted in tx!", !c.isInTx());
+   }
+}




More information about the jboss-cvs-commits mailing list