users@glassfish.java.net

Strange JPA cache leakage with embedded Glassfish?

From: Laird Nelson <ljnelson_at_gmail.com>
Date: Tue, 27 Sep 2011 20:58:58 -0400

File this one under working theory at the moment.

I have an embedded test framework that strives at the expense of performance
to achieve as much isolation as possible.

To that end, here is the workflow:

   1. Maven surefire forks a VM and instantiates a JUnit test class.
   Standard Maven stuff; I have <forkMode> set to "always", which does exactly
   this.
   2. For each method in the test class:
      1. I connect to a named H2 database in memory set to not shut down
      until the VM exits. The first such connection will create the (empty)
      database if it isn't there already.
      2. Liquibase (www.liquibase.org) creates the schemas and tables if
      they don't already exist. This will effectively only happen
once; Liquibase
      knows what it has run already.
      3. DbUnit (www.dbunit.org) issues a CLEAN_INSERT statement (
      http://www.dbunit.org/components.html#cleanInsert) and loads in test
      data into the tables. The "clean" part means that it
effectively truncates
      the test tables involved (DELETE FROM table). The "insert" part reads an
      XML file and inserts those rows into the relevant tables. The
net effect is
      that for each test method I have a clean, known, in-memory database
      containing only data that I put there--no more, no less. The
database looks
      exactly the same at the beginning of each test method. I can
prove that no
      test method impacts the data view of another test method.
      4. A new embedded Glassfish instance is created and started. A new
      one. Did I mention this is a new one?
      5. The EJB app under test is deployed. (There are many reasons why
      javax.ejb.EJBContainer doesn't work here.)
      6. The EJB under test is retrieved via a JNDI lookup in the
      java:global space.
      7. The EJB is installed into the test (during its setUp()) method. It
      usually has an EntityManager injected in it by Glassfish that it
makes heavy
      use of.
      8. The test does whatever the test does. Usually this involves
      updating and reading values in the H2 database.
      9. Glassfish is stopped and destroyed. Note: destroyed. Gone.
      Finis. Killed. Eliminated. Erased.
         1. (As a teaser, I assume this means that EclipseLink-as-bundled by
         Glassfish is destroyed as well.)
      3. After all methods in the test case have run like this, we're done.

What I am seeing is that the effects of one test method's operation on the
database are visible--through EclipseLink-supplied EntityManagers only, not
in the database--by other test methods. Specifically, if I ask H2 what the
version column values are at the beginning of a test method, H2 responds
"0", as I would expect (their initial value as set up by DbUnit). If I
find() the relevant entity and ask him about his @Version property, however,
his version is often 3 or 4, indicating that either I'm going mad (possible)
or that the entity in question is being sourced from a cache that should
have died with the destruction of Glassfish in step 9.

Again, there is a new Glassfish instance launched and destroyed for each
test method. And yet it appears that some values are still coming from the
EclipseLink session cache, even though Glassfish has died and risen again in
between test methods.

Something smells "static" here in a world of "instances".

Before I (lose money and :-)) spend time writing a test case for this, is
there something inherent (hi, Bhavani) in the embedded Glassfish design as
it interacts with EclipseLink that would result in the EclipseLink session
cache being leaked in this manner? Is this kind of method-by-method,
JUnit-based isolation impossible with embedded Glassfish?

See you all at JavaOne!

Best,
Laird

-- 
http://about.me/lairdnelson