Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
testtime: add mockable timers for use in tests (#14672)
* timeutil: add timer interface and fake timer Signed-off-by: Oliver Calder <[email protected]> * timeutil: fix timer stop/reset return values and add more methods Rather than returning whether the timer had fired, `Stop` and `Reset` should return whether the timer is currently active. If it has fired or been stopped manually, these should return false. Additionally, add the `Active` method to report whether the timer is currently active, and add the `FireCount` method to report the number of times that the timer has fired. This is useful to directly check whether a timer's callback has been called. Signed-off-by: Oliver Calder <[email protected]> * testtime,timeutil: move mockable timer to dedicated testtime package Signed-off-by: Oliver Calder <[email protected]> * testtime: create wrapper around time.Timer to include C in interface The `time.Timer` type uses an instance variable `C` for the channel over which the expiration time is sent when a timer which was created via `time.NewTimer` fires. Interfaces in Go cannot have instance variables, so we must use a `C()` method instead. However, this means `time.Timer` cannot implement our `testtime.Timer` interface fully. Thus, this commit adds `testtime.RealTimer` as a wrapper around `time.Timer` which exposes the latter's inner `C` variable as `C()`. Since we now need to construct `testtime.RealTimer` instances in place of `time.Timer` instances in production code, the `testtime.AfterFunc` and `testtime.NewTimer` functions now return `testtime.RealTimer`s by default, which are thin wrappers around `time.Timer`s. In test code, tests can call `testtime.MockTimers` to make all subsequent invocations of `testtime.AfterFunc` and `testtime.NewTimer` return `testtime.TestTimer`s instead of `testtime.RealTimer`s. It is important that `testtime.MockTimers` is never used in non-test code, so this commit adds a static check to ensure this is the case. Signed-off-by: Oliver Calder <[email protected]> * testtime,timeutil: move timer to timeutil and use testtime for mocked timer Signed-off-by: Oliver Calder <[email protected]> * testtime: panic if used in non-test code or fire called when inactive Signed-off-by: Oliver Calder <[email protected]> * testtime: add checks that firing inactive timer panics and remove leftover test Signed-off-by: Oliver Calder <[email protected]> * randutil: export Perm function from math/rand Signed-off-by: Oliver Calder <[email protected]> * testtime: add timer tests from the go standard library Signed-off-by: Oliver Calder <[email protected]> * testtime: prefer callback to expired channel and improve newTimerFunc test helper Signed-off-by: Oliver Calder <[email protected]> * testtime: rename internal lock to mu Signed-off-by: Oliver Calder <[email protected]> * testtime: replace internal expiration/currtime with duration/elapsed Since `TestTimer` is designed to allow the passage of time to be controlled manually, it makes sense to represent this internally using a duration and elapsed time, rather than storing the timestamp at the creation of the timer and advancing an internal "current time". This way, the time at which the timer was created has no effect on the expiration timestamp which may be sent over the C channel when it fires, and timers don't each have their own conflicting view of what time it is. When a timer expires, the current time is sent over the channel, or if `Fire` is called directly, then the given time is sent instead. Signed-off-by: Oliver Calder <[email protected]> * .golangci.yml: add lint to check for usage of testtime in non-test code Signed-off-by: Oliver Calder <[email protected]> * run-checks: remove manual check for testtime in favor of lint Signed-off-by: Oliver Calder <[email protected]> --------- Signed-off-by: Oliver Calder <[email protected]>
- Loading branch information