Fixes random JUnit timeouts that can occur while switching between modules in the same test suite.  The underlying problem is that module defs are held through soft references to allow memory to be freed.  That's great, except that sometimes the old module would be collected before client browsers could transition to the new module; this would cause the old servlet at the old path to die, and the clients would be left pinging a dead servlet and unable to transition to the new module.

TODO: this fix keeps a lot of memory tied up; another possible solution would be a change to GWTShellServlet to allow old servlets to hang around indefinitely.

Review by: knorton (desk)


git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/1.5@2941 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/junit/JUnitShell.java b/user/src/com/google/gwt/junit/JUnitShell.java
index 22bafdc..74d2837 100644
--- a/user/src/com/google/gwt/junit/JUnitShell.java
+++ b/user/src/com/google/gwt/junit/JUnitShell.java
@@ -231,6 +231,16 @@
   private long testBeginTimeout;
 
   /**
+   * We need to keep a hard reference to the last module that was launched until
+   * all client browsers have successfully transitioned to the current module.
+   * Failure to do so allows the last module to be GC'd, which transitively
+   * kills the {@link com.google.gwt.junit.server.JUnitHostImpl} servlet. If the
+   * servlet dies, the client browsers will be unable to transition.
+   */
+  @SuppressWarnings("unused")
+  private ModuleDef lastModule;
+
+  /**
    * Enforce the singleton pattern. The call to {@link GWTShell}'s ctor forces
    * server mode and disables processing extra arguments as URLs to be shown.
    */
@@ -463,6 +473,11 @@
     long currentTimeMillis = System.currentTimeMillis();
     if (activeClients == numClients) {
       firstLaunch = false;
+      /*
+       * It's now safe to release any reference to the last module since all
+       * clients have transitioned to the current module.
+       */
+      lastModule = currentModule;
     } else if (testBeginTimeout < currentTimeMillis) {
       double elapsed = (currentTimeMillis - testBeginTime) / 1000.0;
       throw new TimeoutException(