I have PollingConditions
that probes system for some numerical value to have some exact value, e.g.:
def pollingConditions = new PollingConditions()
def status = 5;
..... //schedule change of status in some background task
pollingConditions.within(10,{
//when status is 20, test must fail right away as it will never become 10 by the business rules
assert status == 10;
})
Now it is OK to wait until status==10
unless status becomes e.g. 20
, in which case it is impossible for it to fulfill the assertion as defined by some status transition rules. In this case waiting for full period of 10 seconds makes no sense and I can fail the test right away.
How can I fail the test immediately in such case?
The PollingConditions
constructor without parameters sets a default delay of 0.1 s and a timeout of 1 s. I.e., your call will not wait the full 10 s but only 0.1 s in between iterations. That should be good enough for your purpose.
for more fine-grained control, you may use sometime like
PollingConditions pc = new PollingConditions(timeout : 3, delay : 0.2, factor : 1)
pc.eventually { /* ... */ }
or simply use the setters on the instance created without constructor parameters.
Here are the source code of
BTW, if you statically type your PollingConditions
instance, you no longer need to use assert
and can just use normal Spock conditions. So either, you directly use new PollingConditions().within(/* ... */)
or, like in my example above, declare the variable as PollingConditions pc
instead of def pc
.
Update after clarification in the comment: Just to show you how absolutely trivial it would have been for you to provide a full reproducer, I am going to provide one to prove that your "I cannot" is nonsense:
package de.scrum_master.stackoverflow.q76919522
import spock.lang.Specification
import spock.lang.Unroll
import spock.util.concurrent.PollingConditions
import static de.scrum_master.stackoverflow.q76919522.PollingConditionsWithExitConditionTest.StateMachine.State.*
class PollingConditionsWithExitConditionTest extends Specification {
static class StateMachine {
enum State { AWAKE, SLEEPING, DEAD }
State state
}
@Unroll("wake up from state #state")
def "state machine must wake up before timeout"() {
given:
def stateMachine = new StateMachine(state: state)
expect:
new PollingConditions().within 10, {
[AWAKE, DEAD].contains(stateMachine.state)
}
stateMachine.state == AWAKE
where:
state << [AWAKE, SLEEPING, DEAD]
}
}
As for the problem at hand, the workaround for bailing out from the polling condition is very simple: Just test for both conditions, the one you are actually waiting for (in my example AWAKE
) and the one that should bail out (in my example DEAD)
. Then simply add another condition to re-check the AWAKE
condition.
The effect is just what you want: The test terminates quickly for AWAKE
and DEAD
but waits the full 10 seconds for SLEEPING
:
Try it in the Groovy Web Console.