You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jdo-dev@db.apache.org by Michael Watzek <mw...@spree.de> on 2005/05/25 19:49:07 UTC

Patch for JDO-48

Hi,

attached you find the patch for JDO-48.

In addition to the life cycle tests and class JDO_Test, I changed class
PersistenceManagerTest. There I removed methods tearDown(),
cleanupMylib(), and cleanupCompany(). I added method localTearDown()
which adds tear down classes, and I moved method
getAllObjects(PersistenceManager, Class) to class JDO_Test.

Furthermore, I changed a few tests in .../jdo/tck/extents because these
tests called cleanup() in methods testXXX. I removed those calls and
added methods localSetUp() adding tear down classes.

Also, the patch includes the changes to JDO_Test.runBare() which I have 
suggested in a previous mail.

You find the change log of my workspace below.

Regards,
Michael

M
test/java/org/apache/jdo/tck/lifecycle/ObjectIdNotModifiedWhenObjectIdInstanceModified.java
M
test/java/org/apache/jdo/tck/lifecycle/MultiplePMsReturnInstancesRepresentingSamePC.java
M
test/java/org/apache/jdo/tck/lifecycle/TransientTransactionalStateCommit.java
M
test/java/org/apache/jdo/tck/lifecycle/TransientTransactionalStateRollback.java
M      test/java/org/apache/jdo/tck/lifecycle/HollowInstanceMaintainsPK.java
M
test/java/org/apache/jdo/tck/lifecycle/PMsCanSharePCClassesButNotPCInstances.java
M      test/java/org/apache/jdo/tck/lifecycle/StateTransitions.java
M
test/java/org/apache/jdo/tck/lifecycle/PMReturnsIdenticalInstancesForEqualObjIds.java
M
test/java/org/apache/jdo/tck/api/persistencemanager/PersistenceManagerTest.java
M
test/java/org/apache/jdo/tck/api/persistencemanager/getobject/GetObjectByIdNoValidationInstanceNotInDatastore.jav
a
M
test/java/org/apache/jdo/tck/extents/IteratorHasNextFalseAfterExtentClose.java
M
test/java/org/apache/jdo/tck/extents/InstancesPersistedPriorToIterationReturned.java
M
test/java/org/apache/jdo/tck/extents/IteratorNextAfterExtentCloseAll.java
M      test/java/org/apache/jdo/tck/extents/IteratorMutatingMethods.java
M
test/java/org/apache/jdo/tck/extents/InstancesDeletedPriorToIterationNotReturned.java
M
test/java/org/apache/jdo/tck/extents/IteratorNextAfterExtentClose.java
M      test/java/org/apache/jdo/tck/extents/CloseAll.java
M      test/java/org/apache/jdo/tck/JDO_Test.java
-- 
-------------------------------------------------------------------
Michael Watzek                  Tech@Spree Engineering GmbH
mailto:mwa.tech@spree.de        Buelowstr. 66
Tel.:  ++49/30/235 520 36       10783 Berlin - Germany
Fax.:  ++49/30/217 520 12       http://www.spree.de/
-------------------------------------------------------------------


Re: Patch for JDO-48

Posted by Michelle Caisse <Mi...@Sun.COM>.
Hi Michael,

This is great!  I will add it.

To be able to edit Wiki pages you just have to register and log in.  
There's something at the top right of  the page that you click, maybe 
"User Preferences" or something next to that link.  After you log in, 
the page will have an Edit link instead of  "Immutable".

-- Michelle

Michael Watzek wrote:

> Hi Michelle,
>
> what do I have to do to edit that page. I can see the subsection 
> "Cleanup" but it seems I do not have permission to change it.



Re: Patch for JDO-48

Posted by Michael Watzek <mw...@spree.de>.
Hi Michelle,

what do I have to do to edit that page. I can see the subsection 
"Cleanup" but it seems I do not have permission to change it.

Below you find a proposal for "Cleanup" description:

The TCK uses the JUnit testing framework. JUnit encourages test classes 
to separate the real task to be tested from testing environment setup, 
relatively testing environment cleanup. TCK classes follow this 
implementation strategy.

For this reason, all TCK test classes extend abstract class 
"org.apache.jdo.tck.JDO_Test". This class provides two hooks that 
subclasses may override for test environment setup and test environment 
cleanup:

     protected void localSetUp()
     protected void localTearDown()

TCK classes usually set up persistent data in method "localSetUp" and 
they cleanup that that data in method "localTearDown". The real testing 
tasks are implemented in methods having the prefix "test".

Class JDO_Test implements a default strategy for "localTearDown": All 
persistent data that has been added for tear down is cleaned up 
automatically. Thus, TCK classes usually do not override "localTearDown".

JDO_Test defines three methods adding persistent data for tear down:

     protected void addTearDownObjectId(Object oid)
     protected void addTearDownInstance(Object pc)
     protected void addTearDownClass(Class pcClass)

The first two methods may be used to add single persistent instances for 
tear down. Method "addTearDownInstance" is convenience delegating to 
addTearDownObjectId. The last method may be used to add persistent 
classes for tear down. In the latter case, the extents of all added 
classes are deleted.

*Note*: The order of adding tear down instances and classes is 
significant. The default implementation of "localTearDown" first deletes 
  all added instances in exactly that order they have been added. 
Afterwards it deletes the extents of all classes in exactly that order 
they have been added.

Regards,
Michael


> Hi, Michael,
> 
> When you get a chance, could you please add information on how to code 
> cleanup in a test to the TechnologyCompatibilityKit Wiki page 
> http://wiki.apache.org/jdo/TechnologyCompatibilityKit?  I added a 
> section called "Test Development Guidlines" and a subsection called 
> "Cleanup".
> 
> Thanks,
> Michelle
> 
> Michael Watzek wrote:
> 
>> Hi,
>>
>> attached you find the patch for JDO-48.
>>
> ...


-- 
-------------------------------------------------------------------
Michael Watzek                  Tech@Spree Engineering GmbH
mailto:mwa.tech@spree.de        Buelowstr. 66
Tel.:  ++49/30/235 520 36       10783 Berlin - Germany
Fax.:  ++49/30/217 520 12       http://www.spree.de/
-------------------------------------------------------------------

Re: Patch for JDO-48

Posted by Michelle Caisse <Mi...@Sun.COM>.
Hi, Michael,

When you get a chance, could you please add information on how to code 
cleanup in a test to the TechnologyCompatibilityKit Wiki page 
http://wiki.apache.org/jdo/TechnologyCompatibilityKit?  I added a 
section called "Test Development Guidlines" and a subsection called 
"Cleanup".

Thanks,
Michelle

Michael Watzek wrote:

> Hi,
>
> attached you find the patch for JDO-48.
>
...

Re: Patch for JDO-48

Posted by Michelle Caisse <Mi...@Sun.COM>.
Thank you, Michael!  I will check in the patch.

-- Michelle

Michael Watzek wrote:

> Hi,
>
> attached you find the patch for JDO-48.
>
> In addition to the life cycle tests and class JDO_Test, I changed class
> PersistenceManagerTest. There I removed methods tearDown(),
> cleanupMylib(), and cleanupCompany(). I added method localTearDown()
> which adds tear down classes, and I moved method
> getAllObjects(PersistenceManager, Class) to class JDO_Test.
>
> Furthermore, I changed a few tests in .../jdo/tck/extents because these
> tests called cleanup() in methods testXXX. I removed those calls and
> added methods localSetUp() adding tear down classes.
>
> Also, the patch includes the changes to JDO_Test.runBare() which I 
> have suggested in a previous mail.
>
> You find the change log of my workspace below.
>
> Regards,
> Michael
>
> M
> test/java/org/apache/jdo/tck/lifecycle/ObjectIdNotModifiedWhenObjectIdInstanceModified.java 
>
> M
> test/java/org/apache/jdo/tck/lifecycle/MultiplePMsReturnInstancesRepresentingSamePC.java 
>
> M
> test/java/org/apache/jdo/tck/lifecycle/TransientTransactionalStateCommit.java 
>
> M
> test/java/org/apache/jdo/tck/lifecycle/TransientTransactionalStateRollback.java 
>
> M      
> test/java/org/apache/jdo/tck/lifecycle/HollowInstanceMaintainsPK.java
> M
> test/java/org/apache/jdo/tck/lifecycle/PMsCanSharePCClassesButNotPCInstances.java 
>
> M      test/java/org/apache/jdo/tck/lifecycle/StateTransitions.java
> M
> test/java/org/apache/jdo/tck/lifecycle/PMReturnsIdenticalInstancesForEqualObjIds.java 
>
> M
> test/java/org/apache/jdo/tck/api/persistencemanager/PersistenceManagerTest.java 
>
> M
> test/java/org/apache/jdo/tck/api/persistencemanager/getobject/GetObjectByIdNoValidationInstanceNotInDatastore.jav 
>
> a
> M
> test/java/org/apache/jdo/tck/extents/IteratorHasNextFalseAfterExtentClose.java 
>
> M
> test/java/org/apache/jdo/tck/extents/InstancesPersistedPriorToIterationReturned.java 
>
> M
> test/java/org/apache/jdo/tck/extents/IteratorNextAfterExtentCloseAll.java
> M      test/java/org/apache/jdo/tck/extents/IteratorMutatingMethods.java
> M
> test/java/org/apache/jdo/tck/extents/InstancesDeletedPriorToIterationNotReturned.java 
>
> M
> test/java/org/apache/jdo/tck/extents/IteratorNextAfterExtentClose.java
> M      test/java/org/apache/jdo/tck/extents/CloseAll.java
> M      test/java/org/apache/jdo/tck/JDO_Test.java
>
>------------------------------------------------------------------------
>
>Index: test/java/org/apache/jdo/tck/lifecycle/ObjectIdNotModifiedWhenObjectIdInstanceModified.java
>===================================================================
>--- test/java/org/apache/jdo/tck/lifecycle/ObjectIdNotModifiedWhenObjectIdInstanceModified.java	(revision 178413)
>+++ test/java/org/apache/jdo/tck/lifecycle/ObjectIdNotModifiedWhenObjectIdInstanceModified.java	(working copy)
>@@ -19,8 +19,6 @@
> import java.util.Iterator;
> 
> import javax.jdo.Extent;
>-import javax.jdo.PersistenceManager;
>-import javax.jdo.PersistenceManagerFactory;
> import javax.jdo.Transaction;
> 
> import org.apache.jdo.tck.JDO_Test;
>@@ -47,6 +45,9 @@
> 		
> 	private static final int NUM_OBJECTS = 50;
> 
>+    /** The persistent instances of this test. */
>+    private Object[] obj;
>+    
>     /**
>      * The <code>main</code> is called when the class
>      * is directly executed from the command line.
>@@ -56,15 +57,16 @@
> 		BatchTestRunner.run(ObjectIdNotModifiedWhenObjectIdInstanceModified.class);
>     }
> 
>-    public ObjectIdNotModifiedWhenObjectIdInstanceModified()
>-    {
>+    /**
>+     * @see JDO_Test#localSetUp()
>+     */
>+    protected void localSetUp() {
>+        pm = getPM();
>+        addTearDownClass(StateTransitionObj.class);
>+        obj = generatePersistentInstances();
>     }
>-
>+    
> 	public void test() throws Exception {
>-		pm = getPM();
>-		
>-		Object[] obj = generatePersistentInstances();
>-
> 		Extent extent = pm.getExtent(StateTransitionObj.class, false);
> 		Iterator iter = extent.iterator();
> 		if( !iter.hasNext() ){
>Index: test/java/org/apache/jdo/tck/lifecycle/MultiplePMsReturnInstancesRepresentingSamePC.java
>===================================================================
>--- test/java/org/apache/jdo/tck/lifecycle/MultiplePMsReturnInstancesRepresentingSamePC.java	(revision 178413)
>+++ test/java/org/apache/jdo/tck/lifecycle/MultiplePMsReturnInstancesRepresentingSamePC.java	(working copy)
>@@ -20,7 +20,6 @@
> 
> import javax.jdo.Extent;
> import javax.jdo.PersistenceManager;
>-import javax.jdo.PersistenceManagerFactory;
> import javax.jdo.Transaction;
> 
> import org.apache.jdo.tck.JDO_Test;
>@@ -49,6 +48,9 @@
> 
>    	private static final int NUM_OBJECTS = 50;
> 
>+    /** The persistent instances of this test. */
>+    private Object[] obj;
>+    
>     /**
>      * The <code>main</code> is called when the class
>      * is directly executed from the command line.
>@@ -58,22 +60,24 @@
> 		BatchTestRunner.run(MultiplePMsReturnInstancesRepresentingSamePC.class);
>     }
> 
>-    public MultiplePMsReturnInstancesRepresentingSamePC()
>-    {
>+    /**
>+     * @see JDO_Test#localSetUp()
>+     */
>+    protected void localSetUp() {
>+        pm = getPM();
>+        addTearDownClass(StateTransitionObj.class);
>+        obj = generatePersistentInstances();
>     }
>-
>+    
> 	public void test() {
> 		PersistenceManager pm2 = null;
> 		PersistenceManager pm3 = null;
> 	
> 	    try {
>-			pm = getPM();
> 			// Get two more PMs
> 			pm2 = pmf.getPersistenceManager();
> 			pm3 = pmf.getPersistenceManager();
> 
>-			Object[] obj = generatePersistentInstances();
>-
> 			Extent extent = pm.getExtent(StateTransitionObj.class, false);
> 			Iterator iter = extent.iterator();
> 			if( !iter.hasNext() ){
>Index: test/java/org/apache/jdo/tck/lifecycle/TransientTransactionalStateCommit.java
>===================================================================
>--- test/java/org/apache/jdo/tck/lifecycle/TransientTransactionalStateCommit.java	(revision 178413)
>+++ test/java/org/apache/jdo/tck/lifecycle/TransientTransactionalStateCommit.java	(working copy)
>@@ -16,13 +16,6 @@
>  
> package org.apache.jdo.tck.lifecycle;
> 
>-import java.util.Iterator;
>-
>-import javax.jdo.Extent;
>-import javax.jdo.PersistenceManager;
>-import javax.jdo.PersistenceManagerFactory;
>-import javax.jdo.Transaction;
>-
> import org.apache.jdo.tck.JDO_Test;
> import org.apache.jdo.tck.pc.lifecycle.StateTransitionObj;
> import org.apache.jdo.tck.util.BatchTestRunner;
>Index: test/java/org/apache/jdo/tck/lifecycle/TransientTransactionalStateRollback.java
>===================================================================
>--- test/java/org/apache/jdo/tck/lifecycle/TransientTransactionalStateRollback.java	(revision 178413)
>+++ test/java/org/apache/jdo/tck/lifecycle/TransientTransactionalStateRollback.java	(working copy)
>@@ -16,11 +16,6 @@
>  
> package org.apache.jdo.tck.lifecycle;
> 
>-import java.util.Iterator;
>-
>-import javax.jdo.Extent;
>-import javax.jdo.PersistenceManager;
>-import javax.jdo.PersistenceManagerFactory;
> import javax.jdo.Transaction;
> 
> import org.apache.jdo.tck.JDO_Test;
>Index: test/java/org/apache/jdo/tck/lifecycle/HollowInstanceMaintainsPK.java
>===================================================================
>--- test/java/org/apache/jdo/tck/lifecycle/HollowInstanceMaintainsPK.java	(revision 178413)
>+++ test/java/org/apache/jdo/tck/lifecycle/HollowInstanceMaintainsPK.java	(working copy)
>@@ -16,16 +16,9 @@
>  
> package org.apache.jdo.tck.lifecycle;
> 
>-import java.util.Iterator;
>-
>-import javax.jdo.Extent;
>-import javax.jdo.PersistenceManager;
>-import javax.jdo.PersistenceManagerFactory;
>-import javax.jdo.Transaction;
>-
> import org.apache.jdo.tck.JDO_Test;
>-import org.apache.jdo.tck.pc.mylib.PCRect;
> import org.apache.jdo.tck.pc.mylib.PCPoint;
>+import org.apache.jdo.tck.pc.mylib.PCRect;
> import org.apache.jdo.tck.util.BatchTestRunner;
> 
> /**
>@@ -64,7 +57,6 @@
>             pm.currentTransaction().begin();
> 
>             PCRect obj = getPersistentNewInstance();
>-
>             long beforeValue=obj.getId();
>             pm.currentTransaction().commit(); // obj should transition to HOLLOW
>             long afterValue=obj.getId();
>@@ -87,6 +79,8 @@
>                  "from transient instance via makePersistent(), state is " +
>                  states[curr]);
>         }
>+        addTearDownInstance(obj);
>         return obj;
>     }
>+
> }
>Index: test/java/org/apache/jdo/tck/lifecycle/PMsCanSharePCClassesButNotPCInstances.java
>===================================================================
>--- test/java/org/apache/jdo/tck/lifecycle/PMsCanSharePCClassesButNotPCInstances.java	(revision 178413)
>+++ test/java/org/apache/jdo/tck/lifecycle/PMsCanSharePCClassesButNotPCInstances.java	(working copy)
>@@ -67,10 +67,13 @@
>         BatchTestRunner.run(PMsCanSharePCClassesButNotPCInstances.class);
>     }
> 
>-    public PMsCanSharePCClassesButNotPCInstances()
>-    {
>+    /**
>+     * @see JDO_Test#localSetUp()
>+     */
>+    protected void localSetUp() {
>+        addTearDownClass(StateTransitionObj.class);
>     }
>-
>+    
>     public void test() {
>         // test shared PC - only one PM should succeed to insert the shared PC
>         threads = 0;
>@@ -105,11 +108,11 @@
>             t.start();
>         }
>         
>-        Thread.currentThread().yield();
>+        Thread.yield();
>         
>         while (! attemptsComplete()) { 
>             try  {
>-                Thread.currentThread().sleep(100);
>+                Thread.sleep(100);
>             } catch (InterruptedException ex) {
>                 logger.debug("interrupted while waiting for threads to insert");
>             }
>@@ -117,7 +120,7 @@
> 
>         while (threads > 0) {
>             try {
>-                Thread.currentThread().sleep(100);
>+                Thread.sleep(100);
>             } catch (InterruptedException ex) {
>                 logger.debug("interrupted while waiting for threads to finish");
>             }
>@@ -180,7 +183,7 @@
> 
>                 while (!attemptsComplete()) {
>                     try {
>-                        Thread.currentThread().sleep(100);
>+                        Thread.sleep(100);
>                     } catch (InterruptedException ex) {
>                         if (debug) logger.debug(" interrupted");
>                     }
>Index: test/java/org/apache/jdo/tck/lifecycle/StateTransitions.java
>===================================================================
>--- test/java/org/apache/jdo/tck/lifecycle/StateTransitions.java	(revision 178413)
>+++ test/java/org/apache/jdo/tck/lifecycle/StateTransitions.java	(working copy)
>@@ -19,8 +19,6 @@
> import java.util.Iterator;
> 
> import javax.jdo.Extent;
>-import javax.jdo.PersistenceManager;
>-import javax.jdo.PersistenceManagerFactory;
> import javax.jdo.Transaction;
> 
> import org.apache.jdo.tck.JDO_Test;
>@@ -230,14 +228,16 @@
>         {   true,          false,       false }   // retrieve with active datastore transaction
>     };
> 
>-    public StateTransitions()
>-    {
>+    /**
>+     * @see JDO_Test#localSetUp()
>+     */
>+    protected void localSetUp() {
>+        pm = getPM();
>+        generatePersistentInstances();
>+        addTearDownClass(StateTransitionObj.class);
>     }
>-
>+    
>     public void test() {
>-        pm = getPM();
>-        generatePersistentInstances();
>-
>         scenario = DATASTORE_TX;
>         checkTransitions();
> 
>Index: test/java/org/apache/jdo/tck/lifecycle/PMReturnsIdenticalInstancesForEqualObjIds.java
>===================================================================
>--- test/java/org/apache/jdo/tck/lifecycle/PMReturnsIdenticalInstancesForEqualObjIds.java	(revision 178413)
>+++ test/java/org/apache/jdo/tck/lifecycle/PMReturnsIdenticalInstancesForEqualObjIds.java	(working copy)
>@@ -19,8 +19,6 @@
> import java.util.Iterator;
> 
> import javax.jdo.Extent;
>-import javax.jdo.PersistenceManager;
>-import javax.jdo.PersistenceManagerFactory;
> import javax.jdo.Transaction;
> 
> import org.apache.jdo.tck.JDO_Test;
>@@ -47,6 +45,9 @@
>     
> 	private static final int NUM_OBJECTS = 50;
> 
>+    /** The persistent instances of this test. */
>+    private Object[] obj;
>+    
>     /**
>      * The <code>main</code> is called when the class
>      * is directly executed from the command line.
>@@ -56,15 +57,16 @@
> 		BatchTestRunner.run(PMReturnsIdenticalInstancesForEqualObjIds.class);
>     }
> 
>-    public PMReturnsIdenticalInstancesForEqualObjIds()
>-    {
>+    /**
>+     * @see JDO_Test#localSetUp()
>+     */
>+    protected void localSetUp() {
>+        pm = getPM();
>+        addTearDownClass(StateTransitionObj.class);
>+        obj = generatePersistentInstances();
>     }
>-
>+    
> 	public void test() {
>-	    pm = getPM();
>-
>-	    Object[] obj = generatePersistentInstances();
>-
>     	Extent extent = pm.getExtent(StateTransitionObj.class, false);
>     	Iterator iter = extent.iterator();
>     	if( !iter.hasNext() ){
>Index: test/java/org/apache/jdo/tck/api/persistencemanager/PersistenceManagerTest.java
>===================================================================
>--- test/java/org/apache/jdo/tck/api/persistencemanager/PersistenceManagerTest.java	(revision 178413)
>+++ test/java/org/apache/jdo/tck/api/persistencemanager/PersistenceManagerTest.java	(working copy)
>@@ -17,11 +17,7 @@
> package org.apache.jdo.tck.api.persistencemanager;
> 
> 
>-import java.util.Collection;
>-import java.util.Vector;
>-
> import javax.jdo.PersistenceManager;
>-import javax.jdo.Query;
> import javax.jdo.Transaction;
> 
> import org.apache.jdo.tck.JDO_Test;
>@@ -36,76 +32,19 @@
>     /** */
>     protected PersistenceManagerTest() { }
> 
>-    /** */
>-    protected void tearDown() {
>-        Throwable cleanupFailure = null;
>-        try {
>-            cleanup();
>-            cleanupMylib();
>-            cleanupCompany();
>-        }
>-        catch (Throwable ex) {
>-            cleanupFailure = ex;
>-            // set testSucceeded to false, otherwise a failure during
>-            // super.tearDown would swallow this exception
>-            testSucceeded = false;
>-        }
>-
>-        // cleanup pmf
>-        super.tearDown();
>-
>-        // fail if there was an exception during cleanup
>-        if (cleanupFailure != null) {
>-            fail("Exception during cleanupMylib: " + cleanupFailure);
>-        }
>+    /** 
>+     * @see JDO_Test#localSetUp()
>+     */
>+    protected void localSetUp() {
>+        // The order of addTearDownClass calls is significant
>+        // as it takes into account database FKs.
>+        addTearDownClass(PCRect.class);
>+        addTearDownClass(PCPoint.class);
>+        addTearDownClass(Department.class);
>+        addTearDownClass(Company.class);
>     }
>     
>     /** */
>-    protected void cleanupMylib() {
>-        PersistenceManager pm = getPM();
>-        Transaction tx = null;
>-        try {
>-            pm = pmf.getPersistenceManager();
>-            tx = pm.currentTransaction();
>-            tx.begin();
>-            // Note, remove PCRect instances first because of FK constraints
>-            Collection c = getAllObjects(pm, PCRect.class);
>-            pm.deletePersistentAll(c);
>-            c = getAllObjects(pm, PCPoint.class);
>-            pm.deletePersistentAll(c);
>-            tx.commit();
>-        }
>-        finally {
>-            if ((tx != null) && tx.isActive())
>-                tx.rollback();
>-            if ((pm != null) && pm.isClosed())
>-                pm.close();
>-        }
>-  }
>-
>-     /** */
>-    protected void cleanupCompany() {
>-        PersistenceManager pm = getPM();
>-        Transaction tx = null;
>-        try {
>-            pm = pmf.getPersistenceManager();
>-            tx = pm.currentTransaction();
>-            tx.begin();
>-            Collection c = getAllObjects(pm, Department.class);
>-            pm.deletePersistentAll(c);
>-            c = getAllObjects(pm, Company.class);
>-            pm.deletePersistentAll(c);
>-            tx.commit();
>-        }
>-        finally {
>-            if ((tx != null) && tx.isActive())
>-                tx.rollback();
>-            if ((pm != null) && pm.isClosed())
>-                pm.close();
>-        }
>-    }
>-  
>-    /** */
>     protected Object createPCPointInstance(PersistenceManager pm) {
>         PCPoint p1 = new PCPoint(8,8);
>         Transaction tx = pm.currentTransaction();
>@@ -113,6 +52,7 @@
>         pm.makePersistent(p1);
>         Object oid = pm.getObjectId(p1);
>         tx.commit();
>+        addTearDownInstance(p1);
>         return oid;
>     }
>   
>@@ -126,21 +66,6 @@
>     }
> 
>     /** */
>-    protected Collection getAllObjects(PersistenceManager pm, Class pcClass) {
>-        Collection col = new Vector() ;
>-        try {
>-            Query query = pm.newQuery();
>-            query.setClass(pcClass);
>-            query.setCandidates(pm.getExtent(pcClass, false));
>-            Object result = query.execute();
>-            col = (Collection)result;
>-        } catch (Exception e) {
>-            fail("Exception in getAllObjects()" + e);
>-        }
>-        return col ;
>-    }
>-
>-    /** */
>     public boolean testState(PCPoint obj, int expectState, String str) {
>         int actualState = currentState(obj);
>         if (actualState != expectState) {
>Index: test/java/org/apache/jdo/tck/api/persistencemanager/getobject/GetObjectByIdNoValidationInstanceNotInDatastore.java
>===================================================================
>--- test/java/org/apache/jdo/tck/api/persistencemanager/getobject/GetObjectByIdNoValidationInstanceNotInDatastore.java	(revision 178413)
>+++ test/java/org/apache/jdo/tck/api/persistencemanager/getobject/GetObjectByIdNoValidationInstanceNotInDatastore.java	(working copy)
>@@ -76,7 +76,6 @@
>         catch (JDOObjectNotFoundException ex) {
>             // expected exception
>         }
>-        cleanup();
>         if (debug)
>             logger.debug ("END GetObjectByIdNoValidationInstanceNotInDatastore");
>    }
>Index: test/java/org/apache/jdo/tck/extents/IteratorHasNextFalseAfterExtentClose.java
>===================================================================
>--- test/java/org/apache/jdo/tck/extents/IteratorHasNextFalseAfterExtentClose.java	(revision 178413)
>+++ test/java/org/apache/jdo/tck/extents/IteratorHasNextFalseAfterExtentClose.java	(working copy)
>@@ -91,7 +91,6 @@
>             }
>         } 
>         finally {
>-            cleanup();
>         }
>     }
> }
>Index: test/java/org/apache/jdo/tck/extents/InstancesPersistedPriorToIterationReturned.java
>===================================================================
>--- test/java/org/apache/jdo/tck/extents/InstancesPersistedPriorToIterationReturned.java	(revision 178413)
>+++ test/java/org/apache/jdo/tck/extents/InstancesPersistedPriorToIterationReturned.java	(working copy)
>@@ -78,7 +78,6 @@
>             }
>         } 
>         finally {
>-            cleanup();
>         }
>     }
> }
>Index: test/java/org/apache/jdo/tck/extents/IteratorNextAfterExtentCloseAll.java
>===================================================================
>--- test/java/org/apache/jdo/tck/extents/IteratorNextAfterExtentCloseAll.java	(revision 178413)
>+++ test/java/org/apache/jdo/tck/extents/IteratorNextAfterExtentCloseAll.java	(working copy)
>@@ -83,7 +83,6 @@
>         } 
>         finally  {
>             rollbackTransaction();
>-            cleanup();
>         }
>     }
>     
>Index: test/java/org/apache/jdo/tck/extents/IteratorMutatingMethods.java
>===================================================================
>--- test/java/org/apache/jdo/tck/extents/IteratorMutatingMethods.java	(revision 178413)
>+++ test/java/org/apache/jdo/tck/extents/IteratorMutatingMethods.java	(working copy)
>@@ -67,7 +67,6 @@
>             if (debug) logger.debug("expected exception " + ex);
>         } 
>         finally {
>-            cleanup();
>         }
>     }
> }
>Index: test/java/org/apache/jdo/tck/extents/InstancesDeletedPriorToIterationNotReturned.java
>===================================================================
>--- test/java/org/apache/jdo/tck/extents/InstancesDeletedPriorToIterationNotReturned.java	(revision 178413)
>+++ test/java/org/apache/jdo/tck/extents/InstancesDeletedPriorToIterationNotReturned.java	(working copy)
>@@ -78,7 +78,6 @@
>             }
>         } 
>         finally {
>-            cleanup();
>         }
>     }
> }
>Index: test/java/org/apache/jdo/tck/extents/IteratorNextAfterExtentClose.java
>===================================================================
>--- test/java/org/apache/jdo/tck/extents/IteratorNextAfterExtentClose.java	(revision 178413)
>+++ test/java/org/apache/jdo/tck/extents/IteratorNextAfterExtentClose.java	(working copy)
>@@ -85,7 +85,6 @@
>             } 
>             catch (Exception unexpected) {
>                 rollbackTransaction();
>-                cleanup();
>                 fail(ASSERTION_FAILED,
>                      "unexpected exception " + unexpected);
>             }
>@@ -94,9 +93,6 @@
>             fail(ASSERTION_FAILED,
>                  "unexpected exception " + unexpected);
>         } 
>-        finally  {
>-            cleanup();
>-        }
>     }
> 
>     /** */
>Index: test/java/org/apache/jdo/tck/extents/CloseAll.java
>===================================================================
>--- test/java/org/apache/jdo/tck/extents/CloseAll.java	(revision 178413)
>+++ test/java/org/apache/jdo/tck/extents/CloseAll.java	(working copy)
>@@ -79,7 +79,6 @@
>         } 
>         finally {
>             rollbackTransaction();
>-            cleanup();
>         }
>     }
> }
>Index: test/java/org/apache/jdo/tck/JDO_Test.java
>===================================================================
>--- test/java/org/apache/jdo/tck/JDO_Test.java	(revision 178413)
>+++ test/java/org/apache/jdo/tck/JDO_Test.java	(working copy)
>@@ -21,14 +21,21 @@
> import java.io.IOException;
> import java.io.InputStream;
> import java.lang.reflect.Field;
>-import java.lang.Runtime;
>+import java.util.Collection;
>+import java.util.Iterator;
>+import java.util.LinkedList;
> import java.util.Properties;
>+import java.util.Vector;
> 
>+import javax.jdo.JDOException;
>+import javax.jdo.JDOFatalException;
> import javax.jdo.JDOHelper;
>+import javax.jdo.JDOObjectNotFoundException;
> import javax.jdo.PersistenceManager;
> import javax.jdo.PersistenceManagerFactory;
>-import javax.jdo.JDOException;
>+import javax.jdo.Query;
> 
>+import junit.framework.AssertionFailedError;
> import junit.framework.TestCase;
> 
> import org.apache.commons.logging.Log;
>@@ -128,6 +135,24 @@
>     /** true if debug logging in enabled. */
>     protected boolean debug = logger.isDebugEnabled();
>     
>+    /** 
>+     * Indicates an exception thrown in method <code>tearDown</code>.
>+     * At the end of method <code>tearDown</code> this field is nullified. 
>+     */
>+    private Throwable tearDownThrowable;
>+    
>+    /** 
>+     * A list of registered oid instances. 
>+     * Corresponding pc instances are deleted in <code>localTearDown</code>.
>+     */
>+    private Collection oids = new LinkedList();
>+    
>+    /** 
>+     * A list of registered pc classes. 
>+     * Th extents of these classes are deleted in <code>localTearDown</code>.
>+     */
>+    private Collection pcClasses = new LinkedList();
>+    
>     /** */
>     protected JDO_Test() {
>         PMFProperties = System.getProperty("PMFProperties");
>@@ -136,49 +161,187 @@
>     /** */
>     protected void setUp() throws Exception {
>         pmf = getPMF();
>+        localSetUp();
>     }
>     
>     /**
>+     * Subclasses may override this method to allocate any data and resources
>+     * that they need in order to successfully execute this testcase.
>+     */
>+    protected void localSetUp() {}
>+    
>+    /**
>      * Runs the bare test sequence.
>      * @exception Throwable if any exception is thrown
>      */
>     public void runBare() throws Throwable {
>-        setUp();
>         try {
>             testSucceeded = false;
>+            setUp();
>             runTest();
>             testSucceeded = true;
>         }
>+        catch (AssertionFailedError e) {
>+            logger.error("Exception during setUp or runtest: ", e);
>+            throw e;
>+        }
>+        catch (Throwable t) {
>+            logger.fatal("Exception during setUp or runtest: ", t);
>+            throw t;
>+        }
>         finally {
>             tearDown();
>-            long freeMem = Runtime.getRuntime().freeMemory();
>-            if (debug) logger.debug("Free memory: " + freeMem);
>+            if (debug) {
>+                logger.debug("Free memory: " + Runtime.getRuntime().freeMemory());
>+            }
>         }
>     }
> 
>-    /** */
>+    /**
>+     * Sets field <code>tearDownThrowable</code> if it is <code>null</code>.
>+     * Else, the given throwable is logged using fatal log level. 
>+     * @param throwable the throwable
>+     */
>+    private void setTearDownThrowable(String context, Throwable throwable)
>+    {
>+        logger.fatal("Exception during "+context+": ", throwable);
>+        if (this.tearDownThrowable == null) {
>+            this.tearDownThrowable = throwable;
>+        }
>+    }
>+    
>+    /**
>+     * This method clears data and resources allocated by testcases.
>+     * It first closes the persistence manager of this testcase.
>+     * Then it calls method <code>localTearDown</code>. 
>+     * Subclasses may override that method to clear any data and resources
>+     * that they have allocated in method <code>localSetUp</code>.
>+     * Finally, this method closes the persistence manager factory.<p>
>+     * 
>+     * <b>Note:</b>These methods are called always, regardless of any exceptions.
>+     * The first caught exception is kept in field <code>tearDownThrowable</code>. 
>+     * That exception is thrown as a nested exception of <code>JDOFatalException</code>
>+     * if and only if the testcase executed successful.
>+     * Otherwise that exception is logged using fatal log level.
>+     * All other exceptions are logged using fatal log level, always.
>+     */
>     protected void tearDown() {
>         try {
>-            cleanup();
>+            cleanupPM();
>+        } 
>+        catch (Throwable t) {
>+            setTearDownThrowable("cleanupPM", t);
>+        }
>+        
>+        try {
>+            localTearDown();
>+        } 
>+        catch (Throwable t) {
>+            setTearDownThrowable("localTearDown", t);
>+        }
>+        
>+        try {
>             closePMF();
>         }
>-        catch (Throwable ex) {
>-            if (debug) ex.printStackTrace();
>+        catch (Throwable t) {
>+            setTearDownThrowable("closePMF", t);
>+        }
>+        
>+        if (this.tearDownThrowable != null) {
>+            Throwable t = this.tearDownThrowable;
>+            this.tearDownThrowable = null;
>             if (testSucceeded) {
>-                // runTest succeeded, but closePMF throws exception =>
>-                // failure
>-                fail("Exception during tearDown: " + ex);
>+                // runTest succeeded, but this method threw exception => error
>+                throw new JDOFatalException("Exception during tearDown", t);
>             }
>-            else {
>-                // runTest failed and closePMF throws exception =>
>-                // just print the closePMF exception, otherwise the
>-                // closePMF exception would swallow the test case failure
>-                if (debug) logger.debug("Exception during tearDown: " + ex);
>+        }
>+    }
>+
>+    /** 
>+     * Deletes all registered pc instances and extents of all registered pc classes. 
>+     * Subclasses may override this method to clear any data and resources
>+     * that they have allocated in method <code>localSetUp</code>.
>+     */
>+    protected void localTearDown() {
>+        deleteAndUnregisterPCInstances();
>+        deleteAndUnregisterPCClasses();
>+    }
>+
>+    protected void addTearDownObjectId(Object oid) {
>+        // ensure that oid is not a PC instance
>+        if (JDOHelper.getObjectId(oid) != null ||
>+            JDOHelper.isTransactional(oid))
>+            throw new IllegalArgumentException("oid");
>+        this.oids.add(oid);
>+    }
>+    
>+    protected void addTearDownInstance(Object pc) {
>+        Object oid = JDOHelper.getObjectId(pc);
>+        addTearDownObjectId(oid);
>+    }
>+    
>+    protected void addTearDownClass(Class pcClass) {
>+        this.pcClasses.add(pcClass);
>+    }
>+    
>+    /**
>+     * Deletes and unregistres all registered pc instances. 
>+     */
>+    protected void deleteAndUnregisterPCInstances() {
>+        getPM();
>+        try {
>+            this.pm.currentTransaction().begin();
>+            for (Iterator i = this.oids.iterator(); i.hasNext(); ) {
>+                Object pc;
>+                try {
>+                    pc = this.pm.getObjectById(i.next(), true);
>+                }
>+                catch (JDOObjectNotFoundException e) {
>+                    pc = null;
>+                }
>+                // we only delete those persistent instances
>+                // which have not been deleted by tests already.
>+                if (pc != null) {
>+                    this.pm.deletePersistent(pc);
>+                }
>             }
>+            this.pm.currentTransaction().commit();
>         }
>+        finally {
>+            this.oids.clear();
>+            cleanupPM();
>+        }
>     }
> 
>     /**
>+     * Deletes extents of all registered pc instances and unregisters all pc classes. 
>+     */
>+    protected void deleteAndUnregisterPCClasses() {
>+        getPM();
>+        try {
>+            this.pm.currentTransaction().begin();
>+            for (Iterator i = this.pcClasses.iterator(); i.hasNext(); ) {
>+                this.pm.deletePersistentAll(getAllObjects(this.pm, (Class)i.next()));
>+            }
>+            this.pm.currentTransaction().commit();
>+        }
>+        finally {
>+            this.pcClasses.clear();
>+            cleanupPM();
>+        }
>+    }
>+
>+    /** */
>+    protected Collection getAllObjects(PersistenceManager pm, Class pcClass) {
>+        Collection col = new Vector() ;
>+        Query query = pm.newQuery();
>+        query.setClass(pcClass);
>+        query.setCandidates(pm.getExtent(pcClass, false));
>+        Object result = query.execute();
>+        return (Collection)result;
>+    }
>+
>+    /**
>      * Get the <code>PersistenceManagerFactory</code> instance 
>      * for the implementation under test.
>      */
>@@ -209,7 +372,7 @@
>      * multiple PersistenceManager instances around, in case the
>      * PersistenceManagerFactory performs PersistenceManager pooling.  
>      */
>-    protected void cleanup() 
>+    protected void cleanupPM() 
>     {
>         cleanupPM(pm);
>         pm = null;
>@@ -220,7 +383,7 @@
>      * <code>PersistenceManager</code>. If the pm still has an open
>      * transaction, it will be rolled back, before closing the pm.
>      */
>-    protected void cleanupPM(PersistenceManager pm) 
>+    protected static void cleanupPM(PersistenceManager pm) 
>     {
>         if ((pm != null) && !pm.isClosed()) {
>             if (pm.currentTransaction().isActive()) {
>  
>