[Releng] Detect leaked JDBC connections in H2 tests
diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/H2Config.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/H2Config.java
index 0aaf606..8fd5ec8 100644
--- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/H2Config.java
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/H2Config.java
@@ -10,6 +10,8 @@
  */
 package org.eclipse.emf.cdo.tests.db;
 
+import org.eclipse.emf.cdo.tests.db.bundle.OM;
+
 import org.eclipse.net4j.db.IDBAdapter;
 import org.eclipse.net4j.db.h2.H2Adapter;
 import org.eclipse.net4j.util.io.IOUtil;
@@ -20,6 +22,10 @@
 import javax.sql.DataSource;
 
 import java.io.File;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * @author Eike Stepper
@@ -30,10 +36,18 @@
 
   private static final long serialVersionUID = 1L;
 
+  private static final Boolean disableRepositoryRecreationOptimization = Boolean
+      .getBoolean("org.eclipse.emf.cdo.tests.db.H2Config.disableRepositoryRecreationOptimization");
+
   private static File reusableFolder;
 
   private static JdbcDataSource defaultDataSource;
 
+  /**
+   * @see #optimizeRepositoryRecreation(String, JdbcDataSource)
+   */
+  private final transient Map<String, Connection> leakyConnections = new HashMap<String, Connection>();
+
   public H2Config()
   {
     super(DB_ADAPTER_NAME);
@@ -51,6 +65,11 @@
     return new H2Adapter();
   }
 
+  protected File createDBFolder()
+  {
+    return TMPUtil.createTempFolder("h2_", "_test");
+  }
+
   @Override
   protected DataSource createDataSource(String repoName)
   {
@@ -72,17 +91,50 @@
 
     JdbcDataSource dataSource = new JdbcDataSource();
     dataSource.setURL(url + ";SCHEMA=" + repoName);
+
+    if (!disableRepositoryRecreationOptimization)
+    {
+      optimizeRepositoryRecreation(repoName, dataSource);
+    }
+
     return dataSource;
   }
 
-  protected File createDBFolder()
+  /**
+   * This method implements kind of an evil performance optimization hack!
+   *
+   * As it turned out, a leaked JDBC connection leads to a cached H2 Database object
+   * in org.h2.engine.Engine.DATABASES, which, in turn, speeds up the recreation of
+   * CDO repositories as requested by RepositoryConfig.needsCleanRepos().
+   * A standard H2 test suite with 1555 test cases executes ~3.3 times faster then.
+   */
+  private void optimizeRepositoryRecreation(String repoName, JdbcDataSource dataSource)
   {
-    return TMPUtil.createTempFolder("h2_", "_test");
+    Connection leakyConnection = leakyConnections.get(repoName);
+    if (leakyConnection == null)
+    {
+      try
+      {
+        leakyConnection = dataSource.getConnection();
+        leakyConnections.put(repoName, leakyConnection);
+      }
+      catch (SQLException ex)
+      {
+        OM.LOG.info(ex);
+      }
+    }
   }
 
   @Override
   public void mainSuiteFinished() throws Exception
   {
+    for (Connection leakyConnection : leakyConnections.values())
+    {
+      leakyConnection.close();
+    }
+
+    leakyConnections.clear();
+
     deactivateRepositories();
 
     // if (defaultDataSource != null)
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CommitInfoTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CommitInfoTest.java
index c9dfdaf..b769149 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CommitInfoTest.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/CommitInfoTest.java
@@ -139,18 +139,25 @@
     InternalSession serverSession = getRepository().getSessionManager().getSession(session.getSessionID());
     StoreThreadLocal.setSession(serverSession);
 
-    CDOTransaction transaction = session.openTransaction();
-    CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
-    resource.getContents().add(getModel1Factory().createProduct1());
+    try
+    {
+      CDOTransaction transaction = session.openTransaction();
+      CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
+      resource.getContents().add(getModel1Factory().createProduct1());
 
-    CDOCommitInfo commitInfo = transaction.commit();
+      CDOCommitInfo commitInfo = transaction.commit();
 
-    Handler handler = new Handler();
-    getRepository().getCommitInfoManager().getCommitInfos(null, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
-    List<CDOCommitInfo> infos = handler.getInfos();
+      Handler handler = new Handler();
+      getRepository().getCommitInfoManager().getCommitInfos(null, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
+      List<CDOCommitInfo> infos = handler.getInfos();
 
-    assertEquals(2, infos.size()); // Initial root resource commit + 1
-    assertEquals(commitInfo.getTimeStamp(), infos.get(0).getTimeStamp());
+      assertEquals(2, infos.size()); // Initial root resource commit + 1
+      assertEquals(commitInfo.getTimeStamp(), infos.get(0).getTimeStamp());
+    }
+    finally
+    {
+      StoreThreadLocal.release();
+    }
   }
 
   @Skips("MongoDB")
@@ -160,19 +167,26 @@
     CDOSession session = openSession();
     StoreThreadLocal.setSession(getRepository().getSessionManager().getSession(session.getSessionID()));
 
-    CDOTransaction transaction = session.openTransaction();
-    CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
-    resource.getContents().add(getModel1Factory().createProduct1());
+    try
+    {
+      CDOTransaction transaction = session.openTransaction();
+      CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
+      resource.getContents().add(getModel1Factory().createProduct1());
 
-    CDOCommitInfo commitInfo = transaction.commit();
+      CDOCommitInfo commitInfo = transaction.commit();
 
-    Handler handler = new Handler();
-    getRepository().getCommitInfoManager().getCommitInfos(null, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
+      Handler handler = new Handler();
+      getRepository().getCommitInfoManager().getCommitInfos(null, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
 
-    List<CDOCommitInfo> infos = handler.getInfos();
+      List<CDOCommitInfo> infos = handler.getInfos();
 
-    assertEquals(2, infos.size()); // Initial root resource commit + 1
-    assertEquals(commitInfo.getBranch().getID(), infos.get(0).getBranch().getID());
+      assertEquals(2, infos.size()); // Initial root resource commit + 1
+      assertEquals(commitInfo.getBranch().getID(), infos.get(0).getBranch().getID());
+    }
+    finally
+    {
+      StoreThreadLocal.release();
+    }
   }
 
   @Requires(IRepositoryConfig.CAPABILITY_BRANCHING)
@@ -182,19 +196,26 @@
     CDOSession session = openSession();
     StoreThreadLocal.setSession(getRepository().getSessionManager().getSession(session.getSessionID()));
 
-    CDOBranch branch = session.getBranchManager().getMainBranch().createBranch("sub");
-    CDOTransaction transaction = session.openTransaction(branch);
-    CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
-    resource.getContents().add(getModel1Factory().createProduct1());
+    try
+    {
+      CDOBranch branch = session.getBranchManager().getMainBranch().createBranch("sub");
+      CDOTransaction transaction = session.openTransaction(branch);
+      CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
+      resource.getContents().add(getModel1Factory().createProduct1());
 
-    CDOCommitInfo commitInfo = transaction.commit();
+      CDOCommitInfo commitInfo = transaction.commit();
 
-    Handler handler = new Handler();
-    getRepository().getCommitInfoManager().getCommitInfos(null, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
-    List<CDOCommitInfo> infos = handler.getInfos();
+      Handler handler = new Handler();
+      getRepository().getCommitInfoManager().getCommitInfos(null, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
+      List<CDOCommitInfo> infos = handler.getInfos();
 
-    assertEquals(2, infos.size()); // Initial root resource commit + 1
-    assertEquals(commitInfo.getBranch().getID(), infos.get(0).getBranch().getID());
+      assertEquals(2, infos.size()); // Initial root resource commit + 1
+      assertEquals(commitInfo.getBranch().getID(), infos.get(0).getBranch().getID());
+    }
+    finally
+    {
+      StoreThreadLocal.release();
+    }
   }
 
   @Skips("MongoDB")
@@ -214,18 +235,25 @@
     CDOSession session = openSession(REPO_NAME);
     StoreThreadLocal.setSession(getRepository(REPO_NAME).getSessionManager().getSession(session.getSessionID()));
 
-    CDOTransaction transaction = session.openTransaction();
-    CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
-    resource.getContents().add(getModel1Factory().createProduct1());
+    try
+    {
+      CDOTransaction transaction = session.openTransaction();
+      CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
+      resource.getContents().add(getModel1Factory().createProduct1());
 
-    CDOCommitInfo commitInfo = transaction.commit();
+      CDOCommitInfo commitInfo = transaction.commit();
 
-    Handler handler = new Handler();
-    getRepository(REPO_NAME).getCommitInfoManager().getCommitInfos(null, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
-    List<CDOCommitInfo> infos = handler.getInfos();
+      Handler handler = new Handler();
+      getRepository(REPO_NAME).getCommitInfoManager().getCommitInfos(null, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
+      List<CDOCommitInfo> infos = handler.getInfos();
 
-    assertEquals(2, infos.size()); // Initial root resource commit + 1
-    assertEquals(commitInfo.getUserID(), infos.get(0).getUserID());
+      assertEquals(2, infos.size()); // Initial root resource commit + 1
+      assertEquals(commitInfo.getUserID(), infos.get(0).getUserID());
+    }
+    finally
+    {
+      StoreThreadLocal.release();
+    }
   }
 
   @Skips("MongoDB")
@@ -236,21 +264,28 @@
     CDOSession session = openSession();
     StoreThreadLocal.setSession(getRepository().getSessionManager().getSession(session.getSessionID()));
 
-    CDOTransaction transaction = session.openTransaction();
-    CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
-    resource.getContents().add(getModel1Factory().createProduct1());
+    try
+    {
+      CDOTransaction transaction = session.openTransaction();
+      CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
+      resource.getContents().add(getModel1Factory().createProduct1());
 
-    String comment = "Andre";
-    transaction.setCommitComment(comment);
+      String comment = "Andre";
+      transaction.setCommitComment(comment);
 
-    CDOCommitInfo commitInfo = transaction.commit();
+      CDOCommitInfo commitInfo = transaction.commit();
 
-    Handler handler = new Handler();
-    getRepository().getCommitInfoManager().getCommitInfos(null, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
-    List<CDOCommitInfo> infos = handler.getInfos();
+      Handler handler = new Handler();
+      getRepository().getCommitInfoManager().getCommitInfos(null, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
+      List<CDOCommitInfo> infos = handler.getInfos();
 
-    assertEquals(2, infos.size()); // Initial root resource commit + 1
-    assertEquals(commitInfo.getComment(), infos.get(0).getComment());
+      assertEquals(2, infos.size()); // Initial root resource commit + 1
+      assertEquals(commitInfo.getComment(), infos.get(0).getComment());
+    }
+    finally
+    {
+      StoreThreadLocal.release();
+    }
   }
 
   @Skips("MongoDB")
@@ -261,19 +296,26 @@
     CDOSession session = openSession();
     StoreThreadLocal.setSession(getRepository().getSessionManager().getSession(session.getSessionID()));
 
-    CDOTransaction transaction = session.openTransaction();
-    CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
-    resource.getContents().add(getModel1Factory().createProduct1());
+    try
+    {
+      CDOTransaction transaction = session.openTransaction();
+      CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
+      resource.getContents().add(getModel1Factory().createProduct1());
 
-    CDOCommitInfo commitInfo = transaction.commit();
+      CDOCommitInfo commitInfo = transaction.commit();
 
-    Handler handler = new Handler();
-    getRepository().getCommitInfoManager().getCommitInfos(getRepository().getBranchManager().getBranch(transaction.getBranch().getID()),
-        CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
-    List<CDOCommitInfo> infos = handler.getInfos();
+      Handler handler = new Handler();
+      getRepository().getCommitInfoManager().getCommitInfos(getRepository().getBranchManager().getBranch(transaction.getBranch().getID()),
+          CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
+      List<CDOCommitInfo> infos = handler.getInfos();
 
-    assertEquals(2, infos.size()); // Initial root resource commit + 1
-    assertEquals(commitInfo.getTimeStamp(), infos.get(0).getTimeStamp());
+      assertEquals(2, infos.size()); // Initial root resource commit + 1
+      assertEquals(commitInfo.getTimeStamp(), infos.get(0).getTimeStamp());
+    }
+    finally
+    {
+      StoreThreadLocal.release();
+    }
   }
 
   @Skips("MongoDB")
@@ -284,19 +326,26 @@
     CDOSession session = openSession();
     StoreThreadLocal.setSession(getRepository().getSessionManager().getSession(session.getSessionID()));
 
-    CDOTransaction transaction = session.openTransaction();
-    CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
-    resource.getContents().add(getModel1Factory().createProduct1());
+    try
+    {
+      CDOTransaction transaction = session.openTransaction();
+      CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
+      resource.getContents().add(getModel1Factory().createProduct1());
 
-    CDOCommitInfo commitInfo = transaction.commit();
+      CDOCommitInfo commitInfo = transaction.commit();
 
-    Handler handler = new Handler();
-    getRepository().getCommitInfoManager().getCommitInfos(getRepository().getBranchManager().getBranch(transaction.getBranch().getID()),
-        CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
-    List<CDOCommitInfo> infos = handler.getInfos();
+      Handler handler = new Handler();
+      getRepository().getCommitInfoManager().getCommitInfos(getRepository().getBranchManager().getBranch(transaction.getBranch().getID()),
+          CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
+      List<CDOCommitInfo> infos = handler.getInfos();
 
-    assertEquals(2, infos.size()); // Initial root resource commit + 1
-    assertEquals(commitInfo.getBranch().getID(), infos.get(0).getBranch().getID());
+      assertEquals(2, infos.size()); // Initial root resource commit + 1
+      assertEquals(commitInfo.getBranch().getID(), infos.get(0).getBranch().getID());
+    }
+    finally
+    {
+      StoreThreadLocal.release();
+    }
   }
 
   @Requires(IRepositoryConfig.CAPABILITY_BRANCHING)
@@ -305,20 +354,27 @@
     CDOSession session = openSession();
     StoreThreadLocal.setSession(getRepository().getSessionManager().getSession(session.getSessionID()));
 
-    CDOBranch branch = session.getBranchManager().getMainBranch().createBranch("sub");
-    CDOTransaction transaction = session.openTransaction(branch);
-    CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
-    resource.getContents().add(getModel1Factory().createProduct1());
+    try
+    {
+      CDOBranch branch = session.getBranchManager().getMainBranch().createBranch("sub");
+      CDOTransaction transaction = session.openTransaction(branch);
+      CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
+      resource.getContents().add(getModel1Factory().createProduct1());
 
-    CDOCommitInfo commitInfo = transaction.commit();
+      CDOCommitInfo commitInfo = transaction.commit();
 
-    Handler handler = new Handler();
-    getRepository().getCommitInfoManager().getCommitInfos(getRepository().getBranchManager().getBranch(transaction.getBranch().getID()),
-        CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
-    List<CDOCommitInfo> infos = handler.getInfos();
+      Handler handler = new Handler();
+      getRepository().getCommitInfoManager().getCommitInfos(getRepository().getBranchManager().getBranch(transaction.getBranch().getID()),
+          CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
+      List<CDOCommitInfo> infos = handler.getInfos();
 
-    assertEquals(1, infos.size());
-    assertEquals(commitInfo.getBranch().getID(), infos.get(0).getBranch().getID());
+      assertEquals(1, infos.size());
+      assertEquals(commitInfo.getBranch().getID(), infos.get(0).getBranch().getID());
+    }
+    finally
+    {
+      StoreThreadLocal.release();
+    }
   }
 
   @Skips("MongoDB")
@@ -338,19 +394,26 @@
     CDOSession session = openSession(REPO_NAME);
     StoreThreadLocal.setSession(getRepository(REPO_NAME).getSessionManager().getSession(session.getSessionID()));
 
-    CDOTransaction transaction = session.openTransaction();
-    CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
-    resource.getContents().add(getModel1Factory().createProduct1());
+    try
+    {
+      CDOTransaction transaction = session.openTransaction();
+      CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
+      resource.getContents().add(getModel1Factory().createProduct1());
 
-    CDOCommitInfo commitInfo = transaction.commit();
+      CDOCommitInfo commitInfo = transaction.commit();
 
-    Handler handler = new Handler();
-    getRepository(REPO_NAME).getCommitInfoManager().getCommitInfos(getRepository(REPO_NAME).getBranchManager().getBranch(transaction.getBranch().getID()),
-        CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
-    List<CDOCommitInfo> infos = handler.getInfos();
+      Handler handler = new Handler();
+      getRepository(REPO_NAME).getCommitInfoManager().getCommitInfos(getRepository(REPO_NAME).getBranchManager().getBranch(transaction.getBranch().getID()),
+          CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
+      List<CDOCommitInfo> infos = handler.getInfos();
 
-    assertEquals(2, infos.size()); // Initial root resource commit + 1
-    assertEquals(commitInfo.getUserID(), infos.get(0).getUserID());
+      assertEquals(2, infos.size()); // Initial root resource commit + 1
+      assertEquals(commitInfo.getUserID(), infos.get(0).getUserID());
+    }
+    finally
+    {
+      StoreThreadLocal.release();
+    }
   }
 
   @Skips("MongoDB")
@@ -361,22 +424,29 @@
     CDOSession session = openSession();
     StoreThreadLocal.setSession(getRepository().getSessionManager().getSession(session.getSessionID()));
 
-    CDOTransaction transaction = session.openTransaction();
-    CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
-    resource.getContents().add(getModel1Factory().createProduct1());
+    try
+    {
+      CDOTransaction transaction = session.openTransaction();
+      CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
+      resource.getContents().add(getModel1Factory().createProduct1());
 
-    String comment = "Andre";
-    transaction.setCommitComment(comment);
+      String comment = "Andre";
+      transaction.setCommitComment(comment);
 
-    CDOCommitInfo commitInfo = transaction.commit();
+      CDOCommitInfo commitInfo = transaction.commit();
 
-    Handler handler = new Handler();
-    getRepository().getCommitInfoManager().getCommitInfos(getRepository().getBranchManager().getBranch(transaction.getBranch().getID()),
-        CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
-    List<CDOCommitInfo> infos = handler.getInfos();
+      Handler handler = new Handler();
+      getRepository().getCommitInfoManager().getCommitInfos(getRepository().getBranchManager().getBranch(transaction.getBranch().getID()),
+          CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
+      List<CDOCommitInfo> infos = handler.getInfos();
 
-    assertEquals(2, infos.size()); // Initial root resource commit + 1
-    assertEquals(commitInfo.getComment(), infos.get(0).getComment());
+      assertEquals(2, infos.size()); // Initial root resource commit + 1
+      assertEquals(commitInfo.getComment(), infos.get(0).getComment());
+    }
+    finally
+    {
+      StoreThreadLocal.release();
+    }
   }
 
   @Requires(IRepositoryConfig.CAPABILITY_BRANCHING)
@@ -385,18 +455,25 @@
     CDOSession session = openSession();
     StoreThreadLocal.setSession(getRepository().getSessionManager().getSession(session.getSessionID()));
 
-    CDOBranch wrong = getRepository().getBranchManager().getMainBranch().createBranch("wrong");
-    CDOTransaction transaction = session.openTransaction();
-    CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
-    resource.getContents().add(getModel1Factory().createProduct1());
+    try
+    {
+      CDOBranch wrong = getRepository().getBranchManager().getMainBranch().createBranch("wrong");
+      CDOTransaction transaction = session.openTransaction();
+      CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
+      resource.getContents().add(getModel1Factory().createProduct1());
 
-    transaction.commit();
+      transaction.commit();
 
-    Handler handler = new Handler();
-    getRepository().getCommitInfoManager().getCommitInfos(wrong, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
-    List<CDOCommitInfo> infos = handler.getInfos();
+      Handler handler = new Handler();
+      getRepository().getCommitInfoManager().getCommitInfos(wrong, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
+      List<CDOCommitInfo> infos = handler.getInfos();
 
-    assertEquals(0, infos.size());
+      assertEquals(0, infos.size());
+    }
+    finally
+    {
+      StoreThreadLocal.release();
+    }
   }
 
   @Requires(IRepositoryConfig.CAPABILITY_BRANCHING)
@@ -405,18 +482,25 @@
     CDOSession session = openSession();
     StoreThreadLocal.setSession(getRepository().getSessionManager().getSession(session.getSessionID()));
 
-    CDOBranch wrong = getRepository().getBranchManager().getMainBranch().createBranch("wrong");
-    CDOTransaction transaction = session.openTransaction();
-    CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
-    resource.getContents().add(getModel1Factory().createProduct1());
+    try
+    {
+      CDOBranch wrong = getRepository().getBranchManager().getMainBranch().createBranch("wrong");
+      CDOTransaction transaction = session.openTransaction();
+      CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
+      resource.getContents().add(getModel1Factory().createProduct1());
 
-    transaction.commit();
+      transaction.commit();
 
-    Handler handler = new Handler();
-    getRepository().getCommitInfoManager().getCommitInfos(wrong, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
-    List<CDOCommitInfo> infos = handler.getInfos();
+      Handler handler = new Handler();
+      getRepository().getCommitInfoManager().getCommitInfos(wrong, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
+      List<CDOCommitInfo> infos = handler.getInfos();
 
-    assertEquals(0, infos.size());
+      assertEquals(0, infos.size());
+    }
+    finally
+    {
+      StoreThreadLocal.release();
+    }
   }
 
   @Requires(IRepositoryConfig.CAPABILITY_BRANCHING)
@@ -425,19 +509,26 @@
     CDOSession session = openSession();
     StoreThreadLocal.setSession(getRepository().getSessionManager().getSession(session.getSessionID()));
 
-    CDOBranch wrong = getRepository().getBranchManager().getMainBranch().createBranch("wrong");
-    CDOBranch branch = session.getBranchManager().getMainBranch().createBranch("sub");
-    CDOTransaction transaction = session.openTransaction(branch);
-    CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
-    resource.getContents().add(getModel1Factory().createProduct1());
+    try
+    {
+      CDOBranch wrong = getRepository().getBranchManager().getMainBranch().createBranch("wrong");
+      CDOBranch branch = session.getBranchManager().getMainBranch().createBranch("sub");
+      CDOTransaction transaction = session.openTransaction(branch);
+      CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
+      resource.getContents().add(getModel1Factory().createProduct1());
 
-    transaction.commit();
+      transaction.commit();
 
-    Handler handler = new Handler();
-    getRepository().getCommitInfoManager().getCommitInfos(wrong, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
-    List<CDOCommitInfo> infos = handler.getInfos();
+      Handler handler = new Handler();
+      getRepository().getCommitInfoManager().getCommitInfos(wrong, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
+      List<CDOCommitInfo> infos = handler.getInfos();
 
-    assertEquals(0, infos.size());
+      assertEquals(0, infos.size());
+    }
+    finally
+    {
+      StoreThreadLocal.release();
+    }
   }
 
   @Requires(IRepositoryConfig.CAPABILITY_BRANCHING)
@@ -455,18 +546,25 @@
     CDOSession session = openSession(REPO_NAME);
     StoreThreadLocal.setSession(getRepository(REPO_NAME).getSessionManager().getSession(session.getSessionID()));
 
-    CDOBranch wrong = getRepository(REPO_NAME).getBranchManager().getMainBranch().createBranch("wrong");
-    CDOTransaction transaction = session.openTransaction();
-    CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
-    resource.getContents().add(getModel1Factory().createProduct1());
+    try
+    {
+      CDOBranch wrong = getRepository(REPO_NAME).getBranchManager().getMainBranch().createBranch("wrong");
+      CDOTransaction transaction = session.openTransaction();
+      CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
+      resource.getContents().add(getModel1Factory().createProduct1());
 
-    transaction.commit();
+      transaction.commit();
 
-    Handler handler = new Handler();
-    getRepository(REPO_NAME).getCommitInfoManager().getCommitInfos(wrong, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
-    List<CDOCommitInfo> infos = handler.getInfos();
+      Handler handler = new Handler();
+      getRepository(REPO_NAME).getCommitInfoManager().getCommitInfos(wrong, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
+      List<CDOCommitInfo> infos = handler.getInfos();
 
-    assertEquals(0, infos.size());
+      assertEquals(0, infos.size());
+    }
+    finally
+    {
+      StoreThreadLocal.release();
+    }
   }
 
   @Requires(IRepositoryConfig.CAPABILITY_BRANCHING)
@@ -475,21 +573,28 @@
     CDOSession session = openSession();
     StoreThreadLocal.setSession(getRepository().getSessionManager().getSession(session.getSessionID()));
 
-    CDOBranch wrong = getRepository().getBranchManager().getMainBranch().createBranch("wrong");
-    CDOTransaction transaction = session.openTransaction();
-    CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
-    resource.getContents().add(getModel1Factory().createProduct1());
+    try
+    {
+      CDOBranch wrong = getRepository().getBranchManager().getMainBranch().createBranch("wrong");
+      CDOTransaction transaction = session.openTransaction();
+      CDOResource resource = transaction.createResource(getResourcePath(RESOURCE_PATH));
+      resource.getContents().add(getModel1Factory().createProduct1());
 
-    String comment = "Andre";
-    transaction.setCommitComment(comment);
+      String comment = "Andre";
+      transaction.setCommitComment(comment);
 
-    transaction.commit();
+      transaction.commit();
 
-    Handler handler = new Handler();
-    getRepository().getCommitInfoManager().getCommitInfos(wrong, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
-    List<CDOCommitInfo> infos = handler.getInfos();
+      Handler handler = new Handler();
+      getRepository().getCommitInfoManager().getCommitInfos(wrong, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, handler);
+      List<CDOCommitInfo> infos = handler.getInfos();
 
-    assertEquals(0, infos.size());
+      assertEquals(0, infos.size());
+    }
+    finally
+    {
+      StoreThreadLocal.release();
+    }
   }
 
   @CleanRepositoriesBefore(reason = "Commit info counting")
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/ConfigTestSuite.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/ConfigTestSuite.java
index dae2a55..05efd72 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/ConfigTestSuite.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/ConfigTestSuite.java
@@ -30,6 +30,7 @@
 import java.util.Set;
 
 import junit.framework.Test;
+import junit.framework.TestCase;
 import junit.framework.TestResult;
 import junit.framework.TestSuite;
 
@@ -177,7 +178,40 @@
     {
       // super(testClass, testClass.getName()); // Important for the UI to set the *qualified* class name!
       this.scenario = scenario;
-      addTestsFromTestCase(testClass, suite);
+
+      List<Test> tests = new ArrayList<Test>();
+      addTestsFromTestCase(testClass, suite, tests);
+
+      Collections.sort(tests, new Comparator<Test>()
+      {
+        public int compare(Test t1, Test t2)
+        {
+          String n1 = getName(t1);
+          String n2 = getName(t2);
+          return n1.compareTo(n2);
+        }
+
+        private String getName(Test test)
+        {
+          if (test instanceof TestCase)
+          {
+            return ((TestCase)test).getName();
+          }
+
+          if (test instanceof TestSuite)
+          {
+            return ((TestSuite)test).getName();
+          }
+
+          return "";
+        }
+      });
+
+      for (Test test : tests)
+      {
+        // System.err.println(test);
+        addTest(test);
+      }
     }
 
     @Override
@@ -201,7 +235,7 @@
       }
     }
 
-    private void addTestsFromTestCase(final Class<?> theClass, ConfigTestSuite suite) throws ConstraintsViolatedException
+    private void addTestsFromTestCase(final Class<?> theClass, ConfigTestSuite suite, List<Test> tests) throws ConstraintsViolatedException
     {
       setName(theClass.getName());
 
@@ -211,13 +245,13 @@
       }
       catch (NoSuchMethodException e)
       {
-        addTest(warning("Class " + theClass.getName() + " has no public constructor TestCase(String name) or TestCase()"));
+        tests.add(warning("Class " + theClass.getName() + " has no public constructor TestCase(String name) or TestCase()"));
         return;
       }
 
       if (!Modifier.isPublic(theClass.getModifiers()))
       {
-        addTest(warning("Class " + theClass.getName() + " is not public"));
+        tests.add(warning("Class " + theClass.getName() + " is not public"));
         return;
       }
 
@@ -243,7 +277,7 @@
         {
           if (validateConstraints(method, capabilities))
           {
-            addTestMethod(method, names, theClass, suite);
+            addTestMethod(method, names, theClass, suite, tests);
           }
         }
 
@@ -280,7 +314,7 @@
       return true;
     }
 
-    private void addTestMethod(Method m, List<String> names, Class<?> theClass, ConfigTestSuite suite)
+    private void addTestMethod(Method m, List<String> names, Class<?> theClass, ConfigTestSuite suite, List<Test> tests)
     {
       String name = m.getName();
       if (names.contains(name))
@@ -292,7 +326,7 @@
       {
         if (isTestMethod(m))
         {
-          addTest(warning("Test method isn't public: " + m.getName() + "(" + theClass.getCanonicalName() + ")"));
+          tests.add(warning("Test method isn't public: " + name + "(" + theClass.getCanonicalName() + ")"));
         }
 
         return;
@@ -306,7 +340,7 @@
         suite.prepareTest(configTest);
       }
 
-      addTest(test);
+      tests.add(test);
     }
 
     private boolean isPublicTestMethod(Method m)
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java
index 7931c9f..e3330a8 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java
@@ -90,6 +90,8 @@
 
 import org.eclipse.emf.spi.cdo.InternalCDOSession;
 
+import org.junit.Assert;
+
 import java.io.FileOutputStream;
 import java.io.PrintStream;
 import java.lang.annotation.Annotation;
@@ -529,6 +531,8 @@
   @Override
   public void setUp() throws Exception
   {
+    StoreThreadLocal.release();
+
     super.setUp();
 
     if (isOptimizing() && needsCleanRepos() && repositories != null && !repositories.isEmpty())
@@ -542,7 +546,6 @@
 
     if (repositories == null)
     {
-      StoreThreadLocal.release();
       repositories = new HashMap<String, InternalRepository>();
     }
 
@@ -567,7 +570,23 @@
   @Override
   public void tearDown() throws Exception
   {
+    if (StoreThreadLocal.hasSession())
+    {
+      Assert.fail("Test case has left a session in StoreThreadLocal: " + getCurrentTest());
+    }
+
+    if (StoreThreadLocal.hasAccessor())
+    {
+      Assert.fail("Test case has left an accessor in StoreThreadLocal: " + getCurrentTest());
+    }
+
+    if (StoreThreadLocal.hasCommitContext())
+    {
+      Assert.fail("Test case has left a commit context in StoreThreadLocal: " + getCurrentTest());
+    }
+
     deactivateServerBrowser();
+
     if (repositories != null)
     {
       if (!isOptimizing() || mustLeaveCleanRepos())
@@ -600,6 +619,8 @@
 
   protected void deactivateRepositories()
   {
+    StoreThreadLocal.release();
+
     for (InternalRepository repository : getRepositories())
     {
       LifecycleUtil.deactivate(repository);
@@ -611,8 +632,6 @@
       repositories = null;
     }
 
-    StoreThreadLocal.release();
-
     if (serverContainer != null)
     {
       LifecycleUtil.deactivate(serverContainer);
diff --git a/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/AbstractOMTest.java b/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/AbstractOMTest.java
index b056bee..162ea1c 100644
--- a/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/AbstractOMTest.java
+++ b/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/AbstractOMTest.java
@@ -330,7 +330,7 @@
         }
         catch (SkipTestException ex)
         {
-          OM.LOG.info("Skipped " + this); //$NON-NLS-1$
+          OM.LOG.info("Skipped " + this + "\n");
         }
         catch (Throwable t)
         {
@@ -348,6 +348,12 @@
           throw t;
         }
       }
+
+      @Override
+      public String toString()
+      {
+        return getCurrrentTest().toString();
+      }
     });
   }
 
@@ -360,7 +366,7 @@
     }
     catch (SkipTestException ex)
     {
-      OM.LOG.info("Skipped " + this); //$NON-NLS-1$
+      OM.LOG.info("Skipped " + this + "\n");
     }
     catch (RuntimeException ex)
     {
@@ -854,7 +860,7 @@
   /**
    * @author Eike Stepper
    */
-  private static final class SkipTestException extends RuntimeException
+  public static final class SkipTestException extends RuntimeException
   {
     private static final long serialVersionUID = 1L;
   }