396a978cec
This commit constructs a helper closure assertAmountSent that can be reused by other functions. The closure returns an error so that it can be used with wait.NoError or the new wait.InvariantNoError. The latter is added since the predicate could otherwise pass immediately for the sphinx_replay_persistence tests, but change shortly after. It also rounds out the wait package so that we offer all combinations of predicate and no-error style waits.
99 lines
2.5 KiB
Go
99 lines
2.5 KiB
Go
package wait
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// Predicate is a helper test function that will wait for a timeout period of
|
|
// time until the passed predicate returns true. This function is helpful as
|
|
// timing doesn't always line up well when running integration tests with
|
|
// several running lnd nodes. This function gives callers a way to assert that
|
|
// some property is upheld within a particular time frame.
|
|
func Predicate(pred func() bool, timeout time.Duration) error {
|
|
const pollInterval = 20 * time.Millisecond
|
|
|
|
exitTimer := time.After(timeout)
|
|
for {
|
|
<-time.After(pollInterval)
|
|
|
|
select {
|
|
case <-exitTimer:
|
|
return fmt.Errorf("predicate not satisfied after time out")
|
|
default:
|
|
}
|
|
|
|
if pred() {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
// NoError is a wrapper around Predicate that waits for the passed method f to
|
|
// execute without error, and returns the last error encountered if this doesn't
|
|
// happen within the timeout.
|
|
func NoError(f func() error, timeout time.Duration) error {
|
|
var predErr error
|
|
pred := func() bool {
|
|
if err := f(); err != nil {
|
|
predErr = err
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// If f() doesn't succeed within the timeout, return the last
|
|
// encountered error.
|
|
if err := Predicate(pred, timeout); err != nil {
|
|
return predErr
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Invariant is a helper test function that will wait for a timeout period of
|
|
// time, verifying that a statement remains true for the entire duration. This
|
|
// function is helpful as timing doesn't always line up well when running
|
|
// integration tests with several running lnd nodes. This function gives callers
|
|
// a way to assert that some property is maintained over a particular time
|
|
// frame.
|
|
func Invariant(statement func() bool, timeout time.Duration) error {
|
|
const pollInterval = 20 * time.Millisecond
|
|
|
|
exitTimer := time.After(timeout)
|
|
for {
|
|
<-time.After(pollInterval)
|
|
|
|
// Fail if the invariant is broken while polling.
|
|
if !statement() {
|
|
return fmt.Errorf("invariant broken before time out")
|
|
}
|
|
|
|
select {
|
|
case <-exitTimer:
|
|
return nil
|
|
default:
|
|
}
|
|
}
|
|
}
|
|
|
|
// InvariantNoError is a wrapper around Invariant that waits out the duration
|
|
// specified by timeout. It fails if the predicate ever returns an error during
|
|
// that time.
|
|
func InvariantNoError(f func() error, timeout time.Duration) error {
|
|
var predErr error
|
|
pred := func() bool {
|
|
if err := f(); err != nil {
|
|
predErr = err
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
if err := Invariant(pred, timeout); err != nil {
|
|
return predErr
|
|
}
|
|
|
|
return nil
|
|
}
|