-
Notifications
You must be signed in to change notification settings - Fork 61
Open
Description
Hi All,
First of all thank you for a great package, that makes unit testing actually possible when dealing with time dependent code logic.
I've come across the issue in my unit tests which appears that fakeClock.After() time not reliably called when part of the for-select code. I've replicated the issue with the code below which I THINK should work, but it doesn't.
For the code below, I expect otherCount to be 3 (which it is), and then I expect timerFired to be true, which it's not.
This is on go 1.23.4 on MacOS 15.3.1
package main
import (
"context"
"fmt"
"time"
"github.com/jonboulle/clockwork"
)
func main() {
clock := clockwork.NewFakeClock()
timerFired := false
done := make(chan struct{})
otherChan := make(chan struct{})
otherCount := 0
fmt.Println(clock.Now().Format(time.StampMilli), "starting")
go func() {
for {
select {
case <-done:
fmt.Println(clock.Now().Format(time.StampMilli), "exiting")
case <-otherChan:
otherCount++
fmt.Println(clock.Now().Format(time.StampMilli), "received from otherChan")
clock.Sleep(1 * time.Second)
case <-clock.After(200 * time.Millisecond):
timerFired = true
fmt.Println(clock.Now().Format(time.StampMilli), "timer fired")
}
}
}()
ctx, cancelFn := context.WithTimeout(context.Background(), 3*time.Second)
defer cancelFn()
clock.BlockUntilContext(ctx, 1)
otherChan <- struct{}{}
time.Sleep(10 * time.Millisecond) // time for goroutine to read
clock.Advance(1 * time.Second) // advance to cover clock.Sleep()
otherChan <- struct{}{}
time.Sleep(10 * time.Millisecond) // time for goroutine to read
clock.Advance(1 * time.Second) // advance to cover clock.Sleep()
otherChan <- struct{}{}
time.Sleep(10 * time.Millisecond) // time for goroutine to read
clock.Advance(1 * time.Second) // advance to cover clock.Sleep()
clock.Advance(250 * time.Millisecond) // advance to cover clock.After()
time.Sleep(50 * time.Millisecond)
done <- struct{}{}
time.Sleep(100 * time.Millisecond)
fmt.Println("other count", otherCount, "timer fired", timerFired)
if timerFired && otherCount == 3 {
fmt.Println("PASSED")
} else {
fmt.Println("FAILED")
}
}
Output:
% go run main.go
Feb 20 21:02:00.917 starting
Feb 20 21:02:00.917 received from otherChan
Feb 20 21:02:01.917 received from otherChan
Feb 20 21:02:02.917 received from otherChan
Feb 20 21:02:04.117 exiting
other count 3 timer fired false
FAILED
Metadata
Metadata
Assignees
Labels
No labels