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;