Skip to content

Commit 33a6b0f

Browse files
jsalinaspolojordi9
andcommitted
Throw an exception when during polling conditions there is an exception invoking the closure.
Co-authored-by: jordi9 <[email protected]>
1 parent 3d79d9d commit 33a6b0f

File tree

4 files changed

+59
-10
lines changed

4 files changed

+59
-10
lines changed

Diff for: spock-core/src/main/java/spock/lang/Retry.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ enum Mode {
9999
ITERATION,
100100

101101
/**
102-
* Retry the the feature together with the setup and cleanup methods.
102+
* Retry the feature together with the setup and cleanup methods.
103103
*/
104104
SETUP_FEATURE_CLEANUP
105105
}

Diff for: spock-core/src/main/java/spock/util/concurrent/PollingConditions.java

+15-4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.spockframework.lang.ConditionBlock;
2020
import org.spockframework.runtime.GroovyRuntimeUtil;
2121
import org.spockframework.runtime.SpockTimeoutError;
22+
import org.spockframework.runtime.UnallowedExceptionThrownError;
2223
import org.spockframework.util.Beta;
2324

2425
/**
@@ -53,6 +54,7 @@ public class PollingConditions {
5354
private double initialDelay = 0;
5455
private double delay = 0.1;
5556
private double factor = 1.0;
57+
private boolean strict = false;
5658

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

133+
/**
134+
* Returns if is strict mode. If strict mode is enabled, will fail if any exception rather than {@link AssertionError} is thrown.
135+
* Defaults to {@code false}
136+
*/
137+
public boolean isStrict() {
138+
return strict;
139+
}
140+
131141
/**
132142
* Repeatedly evaluates the specified conditions until they are satisfied or the timeout has elapsed.
133143
*
134144
* @param conditions the conditions to evaluate
135-
*
136145
* @throws InterruptedException if evaluation is interrupted
137146
*/
138147
@ConditionBlock
@@ -144,11 +153,10 @@ public void eventually(Closure<?> conditions) throws InterruptedException {
144153
* Repeatedly evaluates the specified conditions until they are satisfied or the specified timeout (in seconds) has elapsed.
145154
*
146155
* @param conditions the conditions to evaluate
147-
*
148156
* @throws InterruptedException if evaluation is interrupted
149157
*/
150158
@ConditionBlock
151-
public void within(double seconds, Closure<?> conditions) throws InterruptedException {
159+
public void within(double seconds, Closure<?> conditions) throws InterruptedException {
152160
long timeoutMillis = toMillis(seconds);
153161
long start = System.currentTimeMillis();
154162
long lastAttempt = 0;
@@ -157,13 +165,16 @@ public void within(double seconds, Closure<?> conditions) throws InterruptedExce
157165
long currDelay = toMillis(delay);
158166
int attempts = 0;
159167

160-
while(true) {
168+
while (true) {
161169
try {
162170
attempts++;
163171
lastAttempt = System.currentTimeMillis();
164172
GroovyRuntimeUtil.invokeClosure(conditions);
165173
return;
166174
} catch (Throwable e) {
175+
if (strict && !(e instanceof AssertionError)) {
176+
throw new UnallowedExceptionThrownError(e.getClass(), e);
177+
}
167178
long elapsedTime = lastAttempt - start;
168179
if (elapsedTime >= timeoutMillis) {
169180
String msg = String.format("Condition not satisfied after %1.2f seconds and %d attempts", elapsedTime / 1000d, attempts);

Diff for: spock-specs/specs.gradle

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ configurations {
99
}
1010

1111
dependencies {
12-
testCompile project(":spock-core")
13-
testCompile project(":spock-junit4")
12+
testImplementation project(":spock-core")
13+
testImplementation project(":spock-junit4")
1414

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

3333
test {

Diff for: spock-specs/src/test/groovy/spock/util/concurrent/PollingConditionsSpec.groovy

+40-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package spock.util.concurrent
1616

1717
import org.spockframework.runtime.ConditionNotSatisfiedError
1818
import org.spockframework.runtime.SpockTimeoutError
19+
import org.spockframework.runtime.UnallowedExceptionThrownError
1920
import spock.lang.Issue
2021
import spock.lang.PendingFeature
2122
import spock.lang.Specification
@@ -154,12 +155,49 @@ class PollingConditionsSpec extends Specification {
154155
then:
155156
condition.eventually {
156157
try {
157-
sleep 200;
158-
assert secondAttempt;
158+
sleep 200
159+
assert secondAttempt
159160
} finally {
160161
secondAttempt = true
161162
}
162163
}
163164
}
165+
166+
def "fails if an exception is thrown while polling"() {
167+
given:
168+
def iteration = 0
169+
170+
when:
171+
new PollingConditions(strict: true).eventually {
172+
try {
173+
if (iteration < 2) {
174+
throw new IllegalStateException("An exception is thrown")
175+
}
176+
assert true
177+
} finally {
178+
iteration++
179+
}
180+
}
181+
then:
182+
def ex = thrown(UnallowedExceptionThrownError)
183+
ex.unallowed == IllegalStateException
184+
}
185+
186+
def "swallow intermediate exceptions while polling"() {
187+
given:
188+
def iteration = 0
189+
190+
expect:
191+
new PollingConditions(strict: false).eventually {
192+
try {
193+
if (iteration < 2) {
194+
throw new IllegalStateException("An exception is thrown")
195+
}
196+
assert true
197+
} finally {
198+
iteration++
199+
}
200+
}
201+
}
164202
}
165203

0 commit comments

Comments
 (0)