[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