Timeout.java revision aeb93fc33cae3aadbb9b46083350ad2dc9aea645
1package org.junit.rules;
2
3import org.junit.internal.runners.statements.FailOnTimeout;
4import org.junit.runner.Description;
5import org.junit.runners.model.Statement;
6
7import java.util.concurrent.TimeUnit;
8
9/**
10 * The Timeout Rule applies the same timeout to all test methods in a class:
11 * <pre>
12 * public static class HasGlobalLongTimeout {
13 *
14 *  &#064;Rule
15 *  public Timeout globalTimeout= new Timeout(20);
16 *
17 *  &#064;Test
18 *  public void run1() throws InterruptedException {
19 *      Thread.sleep(100);
20 *  }
21 *
22 *  &#064;Test
23 *  public void infiniteLoop() {
24 *      while (true) {}
25 *  }
26 * }
27 * </pre>
28 * <p>
29 * Each test is run in a new thread. If the specified timeout elapses before
30 * the test completes, its execution is interrupted via {@link Thread#interrupt()}.
31 * This happens in interruptable I/O and locks, and methods in {@link Object}
32 * and {@link Thread} throwing {@link InterruptedException}.
33 * <p>
34 * A specified timeout of 0 will be interpreted as not set, however tests will
35 * still launch from separate threads. This can be useful for disabling timeouts
36 * in environments where they are dynamically set based on some property.
37 *
38 * @since 4.7
39 */
40public class Timeout implements TestRule {
41    private final long timeout;
42    private final TimeUnit timeUnit;
43    private final boolean lookForStuckThread;
44
45    /**
46     * Returns a new builder for building an instance.
47     *
48     * @since 4.12
49     */
50    public static Builder builder() {
51        return new Builder();
52    }
53
54    /**
55     * Create a {@code Timeout} instance with the timeout specified
56     * in milliseconds.
57     * <p>
58     * This constructor is deprecated.
59     * <p>
60     * Instead use {@link #Timeout(long, java.util.concurrent.TimeUnit)},
61     * {@link Timeout#millis(long)}, or {@link Timeout#seconds(long)}.
62     *
63     * @param millis the maximum time in milliseconds to allow the
64     * test to run before it should timeout
65     */
66    @Deprecated
67    public Timeout(int millis) {
68        this(millis, TimeUnit.MILLISECONDS);
69    }
70
71    /**
72     * Create a {@code Timeout} instance with the timeout specified
73     * at the timeUnit of granularity of the provided {@code TimeUnit}.
74     *
75     * @param timeout the maximum time to allow the test to run
76     * before it should timeout
77     * @param timeUnit the time unit for the {@code timeout}
78     * @since 4.12
79     */
80    public Timeout(long timeout, TimeUnit timeUnit) {
81        this.timeout = timeout;
82        this.timeUnit = timeUnit;
83        lookForStuckThread = false;
84    }
85
86    /**
87     * Create a {@code Timeout} instance initialized with values form
88     * a builder.
89     *
90     * @since 4.12
91     */
92    protected Timeout(Builder builder) {
93        timeout = builder.getTimeout();
94        timeUnit = builder.getTimeUnit();
95        lookForStuckThread = builder.getLookingForStuckThread();
96    }
97
98    /**
99     * Creates a {@link Timeout} that will timeout a test after the
100     * given duration, in milliseconds.
101     *
102     * @since 4.12
103     */
104    public static Timeout millis(long millis) {
105        return new Timeout(millis, TimeUnit.MILLISECONDS);
106    }
107
108    /**
109     * Creates a {@link Timeout} that will timeout a test after the
110     * given duration, in seconds.
111     *
112     * @since 4.12
113     */
114    public static Timeout seconds(long seconds) {
115        return new Timeout(seconds, TimeUnit.SECONDS);
116    }
117
118    /**
119     * Gets the timeout configured for this rule, in the given units.
120     *
121     * @since 4.12
122     */
123    protected final long getTimeout(TimeUnit unit) {
124        return unit.convert(timeout, timeUnit);
125    }
126
127    /**
128     * Gets whether this {@code Timeout} will look for a stuck thread
129     * when the test times out.
130     *
131     * @since 4.12
132     */
133    protected final boolean getLookingForStuckThread() {
134        return lookForStuckThread;
135    }
136
137    /**
138     * Creates a {@link Statement} that will run the given
139     * {@code statement}, and timeout the operation based
140     * on the values configured in this rule. Subclasses
141     * can override this method for different behavior.
142     *
143     * @since 4.12
144     */
145    protected Statement createFailOnTimeoutStatement(
146            Statement statement) throws Exception {
147        return FailOnTimeout.builder()
148            .withTimeout(timeout, timeUnit)
149            .withLookingForStuckThread(lookForStuckThread)
150            .build(statement);
151    }
152
153    public Statement apply(Statement base, Description description) {
154        try {
155            return createFailOnTimeoutStatement(base);
156        } catch (final Exception e) {
157            return new Statement() {
158                @Override public void evaluate() throws Throwable {
159                    throw new RuntimeException("Invalid parameters for Timeout", e);
160                }
161            };
162        }
163    }
164
165    /**
166     * Builder for {@link Timeout}.
167     *
168     * @since 4.12
169     */
170    public static class Builder {
171        private boolean lookForStuckThread = false;
172        private long timeout = 0;
173        private TimeUnit timeUnit = TimeUnit.SECONDS;
174
175        protected Builder() {
176        }
177
178        /**
179         * Specifies the time to wait before timing out the test.
180         *
181         * <p>If this is not called, or is called with a
182         * {@code timeout} of {@code 0}, the returned {@code Timeout}
183         * rule instance will cause the tests to wait forever to
184         * complete, however the tests will still launch from a
185         * separate thread. This can be useful for disabling timeouts
186         * in environments where they are dynamically set based on
187         * some property.
188         *
189         * @param timeout the maximum time to wait
190         * @param unit the time unit of the {@code timeout} argument
191         * @return {@code this} for method chaining.
192         */
193        public Builder withTimeout(long timeout, TimeUnit unit) {
194            this.timeout = timeout;
195            this.timeUnit = unit;
196            return this;
197        }
198
199        protected long getTimeout() {
200            return timeout;
201        }
202
203        protected TimeUnit getTimeUnit()  {
204            return timeUnit;
205        }
206
207        /**
208         * Specifies whether to look for a stuck thread.  If a timeout occurs and this
209         * feature is enabled, the rule will look for a thread that appears to be stuck
210         * and dump its backtrace.  This feature is experimental.  Behavior may change
211         * after the 4.12 release in response to feedback.
212         *
213         * @param enable {@code true} to enable the feature
214         * @return {@code this} for method chaining.
215         */
216        public Builder withLookingForStuckThread(boolean enable) {
217            this.lookForStuckThread = enable;
218            return this;
219        }
220
221        protected boolean getLookingForStuckThread() {
222            return lookForStuckThread;
223        }
224
225
226        /**
227         * Builds a {@link Timeout} instance using the values in this builder.,
228         */
229        public Timeout build() {
230            return new Timeout(this);
231        }
232    }
233}
234