-
Couldn't load subscription status.
- Fork 206
Description
What happened:
Consider the following code (playground):
package main
import (
"time"
"k8s.io/utils/clock"
clocktesting "k8s.io/utils/clock/testing"
)
func main() {
clk := clocktesting.NewFakeClock(time.Now())
go func(clk clock.Clock) {
clk.Sleep(time.Second * 2)
println("after 2 fakeclock seconds")
}(clk)
time.Sleep(time.Millisecond) // used to emulate race condition
clk.Sleep(time.Second)
println("after 1 fakeclock second")
}The code above prints
after 2 fakeclock seconds
after 1 fakeclock second
When clk is changed to clock.RealClock{} (playground), the println lines are in correct order (1 -> 2).
What you expected to happen:
Intuitively, one would expect clk.Sleep(duration) to be identical to <-clk.After(duration). However, (*FakeClock).Sleep actually calls clk.Step instead, which immediately modifies the clock.
Suggested fix:
It would be a huge BC break to many testing packages if (*FakeClock).Sleep is changed to be passive. Documentation improvement would suffice, although deprecating Sleep would be great since Sleep doesn't always do what users intend. (imo, clk.Step is usually only intended in the main control flow of the unit test rather than other goroutines, so calling clk.Sleep from non-testing code is often unintended).
Alternatively, consider adding a ref-counted clock, where Sleep and After have identical behavior and the clock is only stepped when all refs are sleeping.
Environment:
k8s.io/utils: fe8a2dd