diff --git a/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java b/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java index 93a5760326a3..6ce7bebe38fe 100644 --- a/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java +++ b/src/main/java/org/junit/internal/runners/statements/FailOnTimeout.java @@ -21,19 +21,94 @@ public class FailOnTimeout extends Statement { private final boolean lookForStuckThread; private volatile ThreadGroup threadGroup = null; - public FailOnTimeout(Statement originalStatement, long millis) { - this(originalStatement, millis, TimeUnit.MILLISECONDS); + /** + * Returns a new builder for building an instance. + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Creates an instance wrapping the given statement with the given timeout in milliseconds. + * + * @param statement the statement to wrap + * @param timeoutMillis the timeout in milliseconds + * @deprecated use {@link #builder()} instead. + */ + @Deprecated + public FailOnTimeout(Statement statement, long timeoutMillis) { + this(builder().withTimeout(timeoutMillis, TimeUnit.MILLISECONDS), statement); } - public FailOnTimeout(Statement originalStatement, long timeout, TimeUnit unit) { - this(originalStatement, timeout, unit, false); + private FailOnTimeout(Builder builder, Statement statement) { + originalStatement = statement; + timeout = builder.timeout; + timeUnit = builder.unit; + lookForStuckThread = builder.lookForStuckThread; } - public FailOnTimeout(Statement originalStatement, long timeout, TimeUnit unit, boolean lookForStuckThread) { - this.originalStatement = originalStatement; - this.timeout = timeout; - timeUnit = unit; - this.lookForStuckThread = lookForStuckThread; + /** + * Builder for {@link FailOnTimeout}. + */ + public static class Builder { + private boolean lookForStuckThread = false; + private long timeout = 0; + private TimeUnit unit = TimeUnit.SECONDS; + + private Builder() { + } + + /** + * Specifies the time to wait before timing out the test. + * + *
If this is not called, or is called with a {@code timeout} of
+ * {@code 0}, the returned {@code Statement} will wait forever for the
+ * test to complete, however the test will still launch from a separate
+ * thread. This can be useful for disabling timeouts in environments
+ * where they are dynamically set based on some property.
+ *
+ * @param timeout the maximum time to wait
+ * @param unit the time unit of the {@code timeout} argument
+ * @return {@code this} for method chaining.
+ */
+ public Builder withTimeout(long timeout, TimeUnit unit) {
+ if (timeout < 0) {
+ throw new IllegalArgumentException("timeout must be non-negative");
+ }
+ if (unit == null) {
+ throw new NullPointerException("TimeUnit cannot be null");
+ }
+ this.timeout = timeout;
+ this.unit = unit;
+ return this;
+ }
+
+ /**
+ * 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 {@code this} for method chaining.
+ */
+ public Builder withLookingForStuckThread(boolean enable) {
+ this.lookForStuckThread = enable;
+ return this;
+ }
+
+ /**
+ * Builds a {@link FailOnTimeout} instance using the values in this builder,
+ * wrapping the given statement.
+ *
+ * @param statement
+ */
+ public FailOnTimeout build(Statement statement) {
+ if (statement == null) {
+ throw new NullPointerException("statement cannot be null");
+ }
+ return new FailOnTimeout(this, statement);
+ }
}
@Override
@@ -86,8 +161,8 @@ private Exception createTimeoutException(Thread thread) {
new Exception ("Appears to be stuck in thread " +
stuckThread.getName());
stuckThreadException.setStackTrace(getStackTrace(stuckThread));
- return new MultipleFailureException
- (Arrays.