Skip to content
Closed
Changes from 2 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
40 changes: 33 additions & 7 deletions assert/assertions.go
Original file line number Diff line number Diff line change
Expand Up @@ -2010,15 +2010,30 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t
h.Helper()
}

ch := make(chan bool, 1)
checkCond := func() { ch <- condition() }
const failed = 0
const stop = 1
const noStop = 2

resultCh := make(chan int, 1)
checkCond := func() {
result := failed
defer func() {
resultCh <- result
}()
if condition() {
result = stop
} else {
result = noStop
}
}

timer := time.NewTimer(waitFor)
defer timer.Stop()

ticker := time.NewTicker(tick)
defer ticker.Stop()

// Use a nillable channel to control ticks.
var tickC <-chan time.Time

// Check the condition once first on the initial call.
Expand All @@ -2029,13 +2044,24 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t
case <-timer.C:
return Fail(t, "Condition never satisfied", msgAndArgs...)
case <-tickC:
tickC = nil
go checkCond()
case v := <-ch:
if v {
tickC = nil // Do not check again until we get a result.
go checkCond() // Schedule the next check.
case v := <-resultCh:
switch v {
case failed:
// Condition panicked or test failed and finished.
// Cannot determine correct result.
// Cannot decide if we should continue gracefully or not.
// We can stop here and now, and mark test as failed with
// the same error message as the timeout case.
return Fail(t, "Condition never satisfied", msgAndArgs...)
case stop:
return true
case noStop:
fallthrough
default:
tickC = ticker.C // Enable ticks to check again.
}
tickC = ticker.C
}
}
}
Expand Down