001 package org.junit.rules;
002
003 import org.junit.internal.runners.statements.FailOnTimeout;
004 import org.junit.runner.Description;
005 import org.junit.runners.model.Statement;
006
007 import java.util.concurrent.TimeUnit;
008
009 /**
010 * The Timeout Rule applies the same timeout to all test methods in a class:
011 * <pre>
012 * public static class HasGlobalLongTimeout {
013 *
014 * @Rule
015 * public Timeout globalTimeout = Timeout.millis(20);
016 *
017 * @Test
018 * public void run1() throws InterruptedException {
019 * Thread.sleep(100);
020 * }
021 *
022 * @Test
023 * public void infiniteLoop() {
024 * while (true) {}
025 * }
026 * }
027 * </pre>
028 * <p>
029 * Each test is run in a new thread. If the specified timeout elapses before
030 * the test completes, its execution is interrupted via {@link Thread#interrupt()}.
031 * This happens in interruptable I/O and locks, and methods in {@link Object}
032 * and {@link Thread} throwing {@link InterruptedException}.
033 * <p>
034 * A specified timeout of 0 will be interpreted as not set, however tests will
035 * still launch from separate threads. This can be useful for disabling timeouts
036 * in environments where they are dynamically set based on some property.
037 *
038 * @since 4.7
039 */
040 public class Timeout implements TestRule {
041 private final long timeout;
042 private final TimeUnit timeUnit;
043 private final boolean lookForStuckThread;
044
045 /**
046 * Returns a new builder for building an instance.
047 *
048 * @since 4.12
049 */
050 public static Builder builder() {
051 return new Builder();
052 }
053
054 /**
055 * Create a {@code Timeout} instance with the timeout specified
056 * in milliseconds.
057 * <p>
058 * This constructor is deprecated.
059 * <p>
060 * Instead use {@link #Timeout(long, java.util.concurrent.TimeUnit)},
061 * {@link Timeout#millis(long)}, or {@link Timeout#seconds(long)}.
062 *
063 * @param millis the maximum time in milliseconds to allow the
064 * test to run before it should timeout
065 */
066 @Deprecated
067 public Timeout(int millis) {
068 this(millis, TimeUnit.MILLISECONDS);
069 }
070
071 /**
072 * Create a {@code Timeout} instance with the timeout specified
073 * at the timeUnit of granularity of the provided {@code TimeUnit}.
074 *
075 * @param timeout the maximum time to allow the test to run
076 * before it should timeout
077 * @param timeUnit the time unit for the {@code timeout}
078 * @since 4.12
079 */
080 public Timeout(long timeout, TimeUnit timeUnit) {
081 this.timeout = timeout;
082 this.timeUnit = timeUnit;
083 lookForStuckThread = false;
084 }
085
086 /**
087 * Create a {@code Timeout} instance initialized with values from
088 * a builder.
089 *
090 * @since 4.12
091 */
092 protected Timeout(Builder builder) {
093 timeout = builder.getTimeout();
094 timeUnit = builder.getTimeUnit();
095 lookForStuckThread = builder.getLookingForStuckThread();
096 }
097
098 /**
099 * 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 }