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
44    /**
45     * Returns a new builder for building an instance.
46     *
47     * @since 4.12
48     */
49    public static Builder builder() {
50        return new Builder();
51    }
52
53    /**
54     * Create a {@code Timeout} instance with the timeout specified
55     * in milliseconds.
56     * <p>
57     * This constructor is deprecated.
58     * <p>
59     * Instead use {@link #Timeout(long, java.util.concurrent.TimeUnit)},
60     * {@link Timeout#millis(long)}, or {@link Timeout#seconds(long)}.
61     *
62     * @param millis the maximum time in milliseconds to allow the
63     * test to run before it should timeout
64     */
65    @Deprecated
66    public Timeout(int millis) {
67        this(millis, TimeUnit.MILLISECONDS);
68    }
69
70    /**
71     * Create a {@code Timeout} instance with the timeout specified
72     * at the timeUnit of granularity of the provided {@code TimeUnit}.
73     *
74     * @param timeout the maximum time to allow the test to run
75     * before it should timeout
76     * @param timeUnit the time unit for the {@code timeout}
77     * @since 4.12
78     */
79    public Timeout(long timeout, TimeUnit timeUnit) {
80        this.timeout = timeout;
81        this.timeUnit = timeUnit;
82    }
83
84    /**
85     * Create a {@code Timeout} instance initialized with values form
86     * a builder.
87     *
88     * @since 4.12
89     */
90    protected Timeout(Builder builder) {
91        timeout = builder.getTimeout();
92        timeUnit = builder.getTimeUnit();
93    }
94
95    /**
96     * Creates a {@link Timeout} that will timeout a test after the
97     * given duration, in milliseconds.
98     *
99     * @since 4.12
100     */
101    public static Timeout millis(long millis) {
102        return new Timeout(millis, TimeUnit.MILLISECONDS);
103    }
104
105    /**
106     * Creates a {@link Timeout} that will timeout a test after the
107     * given duration, in seconds.
108     *
109     * @since 4.12
110     */
111    public static Timeout seconds(long seconds) {
112        return new Timeout(seconds, TimeUnit.SECONDS);
113    }
114
115    /**
116     * Gets the timeout configured for this rule, in the given units.
117     *
118     * @since 4.12
119     */
120    protected final long getTimeout(TimeUnit unit) {
121        return unit.convert(timeout, timeUnit);
122    }
123
124    /**
125     * Creates a {@link Statement} that will run the given
126     * {@code statement}, and timeout the operation based
127     * on the values configured in this rule. Subclasses
128     * can override this method for different behavior.
129     *
130     * @since 4.12
131     */
132    protected Statement createFailOnTimeoutStatement(
133            Statement statement) throws Exception {
134        return FailOnTimeout.builder()
135            .withTimeout(timeout, timeUnit)
136            .build(statement);
137    }
138
139    public Statement apply(Statement base, Description description) {
140        try {
141            return createFailOnTimeoutStatement(base);
142        } catch (final Exception e) {
143            return new Statement() {
144                @Override public void evaluate() throws Throwable {
145                    throw new RuntimeException("Invalid parameters for Timeout", e);
146                }
147            };
148        }
149    }
150
151    /**
152     * Builder for {@link Timeout}.
153     *
154     * @since 4.12
155     */
156    public static class Builder {
157        private boolean lookForStuckThread = false;
158        private long timeout = 0;
159        private TimeUnit timeUnit = TimeUnit.SECONDS;
160
161        protected Builder() {
162        }
163
164        /**
165         * Specifies the time to wait before timing out the test.
166         *
167         * <p>If this is not called, or is called with a
168         * {@code timeout} of {@code 0}, the returned {@code Timeout}
169         * rule instance will cause the tests to wait forever to
170         * complete, however the tests will still launch from a
171         * separate thread. This can be useful for disabling timeouts
172         * in environments where they are dynamically set based on
173         * some property.
174         *
175         * @param timeout the maximum time to wait
176         * @param unit the time unit of the {@code timeout} argument
177         * @return {@code this} for method chaining.
178         */
179        public Builder withTimeout(long timeout, TimeUnit unit) {
180            this.timeout = timeout;
181            this.timeUnit = unit;
182            return this;
183        }
184
185        protected long getTimeout() {
186            return timeout;
187        }
188
189        protected TimeUnit getTimeUnit()  {
190            return timeUnit;
191        }
192
193        /**
194         * Builds a {@link Timeout} instance using the values in this builder.,
195         */
196        public Timeout build() {
197            return new Timeout(this);
198        }
199    }
200}
201