context.Context cancellation behavior.
- Go 100%
| canceltest.go | ||
| go.mod | ||
| README.md | ||
canceltest
Go helper module to test context.Context cancellation behavior.
go get grub4k.dev/canceltest
Usage
Inside of a test, use canceltest.Run to run a test function inside a synctest bubble.
It takes a subtest name and a function which must produce a canceltest.Func.
As an example of a simple passing test:
canceltest.Run(t, "valid", func() canceltest.Func {
return func(ctx context.Context) {
<-ctx.Done()
}
})
If the context.Context is not yet cancelled, the test must block; otherwise the prerequisite check will fail:
canceltest.Run(t, "not-blocked", func() canceltest.Func {
return func(ctx context.Context) {
}
})
A failing test is indicative of suboptimal cancellation behavior, in contrast to perfect behavior:
unblocking when ctx.Done() is closed while avoiding leaked goroutines.
Below are some examples of failing tests.
Blocks infinitely
canceltest.Run(t, "blocked", func() canceltest.Func {
return func(ctx context.Context) {
select {}
}
})
Cancellable only before I/O
This test checks if the context is cancelled only before performing IO, but then blocks forever during I/O.
canceltest.Run(t, "preempt", func() canceltest.Func {
return func(ctx context.Context) {
select {
case <-ctx.Done():
return
default:
}
select {}
}
})
Leaked goroutine
Here the cancellation behaves as expected, however a goroutine is leaked, so the test also fails:
canceltest.Run(t, "leaky", func() canceltest.Func {
return func(ctx context.Context) {
go func() {
select {}
}()
<-ctx.Done()
}
})