From f17e06715488e2814b6f9b3b4e329961ce224f07 Mon Sep 17 00:00:00 2001 From: Chris Vest Date: Fri, 25 Jul 2014 08:09:29 +0200 Subject: [PATCH] Do not include thread start time in test timeout measurements. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The time it takes to start a thread can be surprisingly large. Especially in virtualized cloud environments where noisy neighbours. This change reduces the probability of non-deterministic failures of tests with timeouts (`@Test(timeout=…)`) by not beginning the timeout clock until we have observed the starting of the task thread – the thread that runs the actual test. This should make tests with small timeout values more reliable in general, and especially in cloud CI environments. No tests added for this because of the probabilistic nature of the problem, and the small scope of the change. --- .../internal/runners/statements/FailOnTimeout.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java b/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java index e92913374e28..93a5760326a3 100644 --- a/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java +++ b/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java @@ -4,6 +4,7 @@ import java.lang.management.ThreadMXBean; import java.util.Arrays; import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; @@ -37,11 +38,13 @@ public FailOnTimeout(Statement originalStatement, long timeout, TimeUnit unit, b @Override public void evaluate() throws Throwable { - FutureTask task = new FutureTask(new CallableStatement()); + CallableStatement callable = new CallableStatement(); + FutureTask task = new FutureTask(callable); threadGroup = new ThreadGroup("FailOnTimeoutGroup"); Thread thread = new Thread(threadGroup, task, "Time-limited test"); thread.setDaemon(true); thread.start(); + callable.awaitStarted(); Throwable throwable = getResult(task, thread); if (throwable != null) { throw throwable; @@ -204,8 +207,11 @@ private long cpuTime (Thread thr) { } private class CallableStatement implements Callable { + private final CountDownLatch startLatch = new CountDownLatch(1); + public Throwable call() throws Exception { try { + startLatch.countDown(); originalStatement.evaluate(); } catch (Exception e) { throw e; @@ -214,5 +220,9 @@ public Throwable call() throws Exception { } return null; } + + public void awaitStarted() throws InterruptedException { + startLatch.await(); + } } }