Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to run in strict mode. Fail if any exception is thrown while polling. #993

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion spock-core/src/main/java/spock/lang/Retry.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ enum Mode {
ITERATION,

/**
* Retry the the feature together with the setup and cleanup methods.
* Retry the feature together with the setup and cleanup methods.
*/
SETUP_FEATURE_CLEANUP
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.spockframework.lang.ConditionBlock;
import org.spockframework.runtime.GroovyRuntimeUtil;
import org.spockframework.runtime.SpockTimeoutError;
import org.spockframework.runtime.UnallowedExceptionThrownError;
import org.spockframework.util.Beta;

/**
Expand Down Expand Up @@ -53,6 +54,7 @@ public class PollingConditions {
private double initialDelay = 0;
private double delay = 0.1;
private double factor = 1.0;
private boolean strict = false;

/**
* Returns the timeout (in seconds) until which the conditions have to be satisfied.
Expand Down Expand Up @@ -128,11 +130,18 @@ public void setFactor(double factor) {
this.factor = factor;
}

/**
* Returns if is strict mode. If strict mode is enabled, will fail if any exception rather than {@link AssertionError} is thrown.
* Defaults to {@code false}
*/
public boolean isStrict() {
return strict;
}

/**
* Repeatedly evaluates the specified conditions until they are satisfied or the timeout has elapsed.
*
* @param conditions the conditions to evaluate
*
* @throws InterruptedException if evaluation is interrupted
*/
@ConditionBlock
Expand All @@ -144,11 +153,10 @@ public void eventually(Closure<?> conditions) throws InterruptedException {
* Repeatedly evaluates the specified conditions until they are satisfied or the specified timeout (in seconds) has elapsed.
*
* @param conditions the conditions to evaluate
*
* @throws InterruptedException if evaluation is interrupted
*/
@ConditionBlock
public void within(double seconds, Closure<?> conditions) throws InterruptedException {
public void within(double seconds, Closure<?> conditions) throws InterruptedException {
long timeoutMillis = toMillis(seconds);
long start = System.currentTimeMillis();
long lastAttempt = 0;
Expand All @@ -157,13 +165,16 @@ public void within(double seconds, Closure<?> conditions) throws InterruptedExce
long currDelay = toMillis(delay);
int attempts = 0;

while(true) {
while (true) {
try {
attempts++;
lastAttempt = System.currentTimeMillis();
GroovyRuntimeUtil.invokeClosure(conditions);
return;
} catch (Throwable e) {
if (strict && !(e instanceof AssertionError)) {
throw new UnallowedExceptionThrownError(e.getClass(), e);
}
long elapsedTime = lastAttempt - start;
if (elapsedTime >= timeoutMillis) {
String msg = String.format("Condition not satisfied after %1.2f seconds and %d attempts", elapsedTime / 1000d, attempts);
Expand Down
6 changes: 3 additions & 3 deletions spock-specs/specs.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ configurations {
}

dependencies {
testCompile project(":spock-core")
testCompile project(":spock-junit4")
testImplementation project(":spock-core")
testImplementation project(":spock-junit4")

testRuntime libs.asm
testRuntime libs.bytebuddy
Expand All @@ -27,7 +27,7 @@ targetCompatibility = javaVersion
// necessary to make @NotYetImplemented transform work (transform that ships
// with Groovy and statically references third-party class junit.framwork.AssertionFailedError)
tasks.withType(GroovyCompile) {
groovyClasspath += configurations.junit
groovyClasspath += configurations.junit
}

test {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package spock.util.concurrent

import org.spockframework.runtime.ConditionNotSatisfiedError
import org.spockframework.runtime.SpockTimeoutError
import org.spockframework.runtime.UnallowedExceptionThrownError
import spock.lang.Issue
import spock.lang.PendingFeature
import spock.lang.Specification
Expand Down Expand Up @@ -154,12 +155,49 @@ class PollingConditionsSpec extends Specification {
then:
condition.eventually {
try {
sleep 200;
assert secondAttempt;
sleep 200
assert secondAttempt
} finally {
secondAttempt = true
}
}
}

def "fails if an exception is thrown while polling"() {
given:
def iteration = 0

when:
new PollingConditions(strict: true).eventually {
try {
if (iteration < 2) {
throw new IllegalStateException("An exception is thrown")
}
assert true
} finally {
iteration++
}
}
then:
def ex = thrown(UnallowedExceptionThrownError)
ex.unallowed == IllegalStateException
}

def "swallow intermediate exceptions while polling"() {
given:
def iteration = 0

expect:
new PollingConditions(strict: false).eventually {
try {
if (iteration < 2) {
throw new IllegalStateException("An exception is thrown")
}
assert true
} finally {
iteration++
}
}
}
}