001package org.junit.rules; 002 003import org.junit.internal.runners.statements.FailOnTimeout; 004import org.junit.runner.Description; 005import org.junit.runners.model.Statement; 006 007import 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 */ 040public 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}