Added method-level timeouts to GWTTestCases, triggered by the need for
handling linker bugs (which otherwise stalled indefinitely, until killed
by the 2hr <limit> in the ant test target).
Review by: spoon (pair prog.)
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@4108 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/junit/JUnitMessageQueue.java b/user/src/com/google/gwt/junit/JUnitMessageQueue.java
index 373d004..e412721 100644
--- a/user/src/com/google/gwt/junit/JUnitMessageQueue.java
+++ b/user/src/com/google/gwt/junit/JUnitMessageQueue.java
@@ -88,6 +88,50 @@
}
/**
+ * Gets a human-readable string.
+ * @return Fetches a human-readable representation of the current test object
+ */
+ public String getCurrentTestName() {
+ if (currentTest == null) {
+ return "(no test)";
+ }
+ return currentTest.toString();
+ }
+
+ /**
+ * Returns a human-formatted message identifying what clients have connected
+ * but have not yet reported results for this test. It is used in a timeout
+ * condition, to identify what we're still waiting on.
+ *
+ * @return human readable message
+ */
+ public String getWorkingClients() {
+ synchronized (clientStatusesLock) {
+ StringBuilder buf = new StringBuilder();
+ int itemCount = 0;
+ for (ClientStatus clientStatus : clientStatuses.values()) {
+ if (clientStatus.hasRequestedCurrentTest
+ && clientStatus.currentTestResults == null) {
+ if (itemCount > 0) {
+ buf.append(", ");
+ }
+ buf.append(clientStatus.clientId);
+ ++itemCount;
+ }
+ }
+ int difference = numClients - itemCount;
+ if (difference > 0) {
+ if (itemCount > 0) {
+ buf.append('\n');
+ }
+ buf.append(difference +
+ " other client(s) haven't responded back to JUnitShell since the start of the test.");
+ }
+ return buf.toString();
+ }
+ }
+
+ /**
* Called by the servlet to query for for the next method to test.
*
* @param timeout how long to wait for an answer
diff --git a/user/src/com/google/gwt/junit/JUnitShell.java b/user/src/com/google/gwt/junit/JUnitShell.java
index cd21132..45eecf2 100644
--- a/user/src/com/google/gwt/junit/JUnitShell.java
+++ b/user/src/com/google/gwt/junit/JUnitShell.java
@@ -116,11 +116,19 @@
/**
* The amount of time to wait for all clients to have contacted the server and
- * begin running the test.
+ * begin running the test. "Contacted" does not necessarily mean "the test
+ * has begun," e.g. for linker errors stopping the test initialization.
*/
private static final int TEST_BEGIN_TIMEOUT_MILLIS = 60000;
/**
+ * The amount of time to wait for all clients to complete a single test
+ * method, in milliseconds, measured from when the <i>last</i> client
+ * connects (and thus starts the test). 5 minutes.
+ */
+ private static final long TEST_METHOD_TIMEOUT_MILLIS = 300000;
+
+ /**
* Singleton object for hosting unit tests. All test case instances executed
* by the TestRunner will use the single unitTestShell.
*/
@@ -270,6 +278,14 @@
private long testBeginTimeout;
/**
+ * Timeout for individual test method. If System.currentTimeMillis() is later
+ * than this timestamp, then we need to pack up and go home. Zero for "not
+ * yet set" (at the start of a test). This interval begins when the
+ * testBeginTimeout interval is done.
+ */
+ private long testMethodTimeout;
+
+ /**
* 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
@@ -545,6 +561,17 @@
* clients have transitioned to the current module.
*/
lastModule = currentModule;
+ if (testMethodTimeout == 0) {
+ testMethodTimeout = currentTimeMillis + TEST_METHOD_TIMEOUT_MILLIS;
+ } else if (testMethodTimeout < currentTimeMillis){
+ double elapsed = (currentTimeMillis - testBeginTime) / 1000.0;
+ throw new TimeoutException(
+ "The browser did not complete the test method "
+ + messageQueue.getCurrentTestName() + " in "
+ + TEST_METHOD_TIMEOUT_MILLIS + "ms.\n We have no results from: "
+ + messageQueue.getWorkingClients()
+ + "\n Actual time elapsed: " + elapsed + " seconds.\n");
+ }
} else if (testBeginTimeout < currentTimeMillis) {
double elapsed = (currentTimeMillis - testBeginTime) / 1000.0;
throw new TimeoutException(
@@ -650,6 +677,7 @@
// contacted; something probably went wrong (the module failed to load?)
testBeginTime = System.currentTimeMillis();
testBeginTimeout = testBeginTime + TEST_BEGIN_TIMEOUT_MILLIS;
+ testMethodTimeout = 0; // wait until test execution begins
pumpEventLoop();
} catch (TimeoutException e) {
lastLaunchFailed = true;