package org.junit.rules;
import org.junit.internal.runners.statements.FailOnTimeout;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import java.util.concurrent.TimeUnit;
/**
* The Timeout Rule applies the same timeout to all test methods in a class:
* <pre>
* public static class HasGlobalLongTimeout {
*
* @Rule
* public Timeout globalTimeout= new Timeout(20);
*
* @Test
* public void run1() throws InterruptedException {
* Thread.sleep(100);
* }
*
* @Test
* public void infiniteLoop() {
* while (true) {}
* }
* }
* </pre>
* <p>
* Each test is run in a new thread. If the specified timeout elapses before
* the test completes, its execution is interrupted via {@link Thread#interrupt()}.
* This happens in interruptable I/O and locks, and methods in {@link Object}
* and {@link Thread} throwing {@link InterruptedException}.
* <p>
* A specified timeout of 0 will be interpreted as not set, however tests will
* still launch from separate threads. This can be useful for disabling timeouts
* in environments where they are dynamically set based on some property.
*
* @since 4.7
*/
public class Timeout implements TestRule {
private final long fTimeout;
private final TimeUnit fTimeUnit;
private final boolean fLookForStuckThread;
/**
* Create a {@code Timeout} instance with the timeout specified
* in milliseconds.
* <p>
* This constructor is deprecated.
* <p>
* Instead use {@link #Timeout(long, java.util.concurrent.TimeUnit)},
* {@link Timeout#millis(long)}, or {@link Timeout#seconds(long)}.
*
* @param millis the maximum time in milliseconds to allow the
* test to run before it should timeout
*/
@Deprecated
public Timeout(int millis) {
this(millis, TimeUnit.MILLISECONDS);
}
/**
* Create a {@code Timeout} instance with the timeout specified
* at the unit of granularity of the provided {@code TimeUnit}.
*
* @param timeout the maximum time to allow the test to run
* before it should timeout
* @param unit the time unit for the {@code timeout}
* @since 4.12
*/
public Timeout(long timeout, TimeUnit unit) {
fTimeout = timeout;
fTimeUnit = unit;
fLookForStuckThread = false;
}
/**
* Create a {@code Timeout} instance with the same fields as {@code t}
* except for {@code fLookForStuckThread}.
*
* @param t the {@code Timeout} instance to copy
* @param lookForStuckThread whether to look for a stuck thread
* @since 4.12
*/
protected Timeout(Timeout t, boolean lookForStuckThread) {
fTimeout = t.fTimeout;
fTimeUnit = t.fTimeUnit;
fLookForStuckThread = lookForStuckThread;
}
/**
* @param millis the timeout in milliseconds
* @since 4.12
*/
public static Timeout millis(long millis) {
return new Timeout(millis, TimeUnit.MILLISECONDS);
}
/**
* @param seconds the timeout in seconds
* @since 4.12
*/
public static Timeout seconds(long seconds) {
return new Timeout(seconds, TimeUnit.SECONDS);
}
/**
* Specifies whether to look for a stuck thread. If a timeout occurs and this
* feature is enabled, the test will look for a thread that appears to be stuck
* and dump its backtrace. This feature is experimental. Behavior may change
* after the 4.12 release in response to feedback.
* @param enable {@code true} to enable the feature
* @return This object
* @since 4.12
*/
public Timeout lookingForStuckThread(boolean enable) {
return new Timeout(this, enable);
}
public Statement apply(Statement base, Description description) {
return new FailOnTimeout(base, fTimeout, fTimeUnit, fLookForStuckThread);
}
}