Skip to content

Commit 971448d

Browse files
ianlancetaylordr2chase
authored andcommitted
testing: support B.Context and F.Context
CL 603959 added T.Context for #36532. The discussion on the proposal only mentions t.Context. However, the implementation of CL 603959 also added B.Context and F.Context. They were added to the API listing, and B.Context was mentioned in the release notes. Unfortunately, the new B.Context and F.Context methods always returned nil, rather than a context.Context value. This change adds a working implementation of B.Context and F.Context. For #36532 Fixes #70866 Change-Id: I8a44e6649fb658e4f641ffb7efd08b4374f578ef Reviewed-on: https://go-review.googlesource.com/c/go/+/637236 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: David Chase <[email protected]> Reviewed-by: Damien Neil <[email protected]>
1 parent 95b433e commit 971448d

File tree

5 files changed

+113
-21
lines changed

5 files changed

+113
-21
lines changed

Diff for: src/cmd/go/testdata/script/test_fuzz_context.txt

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
[!fuzz] skip
2+
[short] skip
3+
env GOCACHE=$WORK/cache
4+
5+
# Test fuzz.Context.
6+
go test -vet=off context_fuzz_test.go
7+
stdout ^ok
8+
! stdout FAIL
9+
10+
go test -vet=off -fuzz=Fuzz -fuzztime=1x context_fuzz_test.go
11+
stdout ok
12+
! stdout FAIL
13+
14+
-- context_fuzz_test.go --
15+
package context_fuzz
16+
17+
import (
18+
"context"
19+
"errors"
20+
"testing"
21+
)
22+
23+
func Fuzz(f *testing.F) {
24+
ctx := f.Context()
25+
if err := ctx.Err(); err != nil {
26+
f.Fatalf("expected non-canceled context, got %v", err)
27+
}
28+
29+
f.Fuzz(func(t *testing.T, data []byte) {
30+
innerCtx := t.Context()
31+
if err := innerCtx.Err(); err != nil {
32+
t.Fatalf("expected inner test to not inherit canceled context, got %v", err)
33+
}
34+
35+
t.Cleanup(func() {
36+
if !errors.Is(innerCtx.Err(), context.Canceled) {
37+
t.Fatal("expected context of inner test to be canceled after its fuzz function finished")
38+
}
39+
})
40+
})
41+
42+
f.Cleanup(func() {
43+
if !errors.Is(ctx.Err(), context.Canceled) {
44+
f.Fatal("expected context canceled before cleanup")
45+
}
46+
})
47+
}

Diff for: src/testing/benchmark.go

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package testing
66

77
import (
8+
"context"
89
"flag"
910
"fmt"
1011
"internal/sysinfo"
@@ -181,6 +182,7 @@ func (b *B) ReportAllocs() {
181182
func (b *B) runN(n int) {
182183
benchmarkLock.Lock()
183184
defer benchmarkLock.Unlock()
185+
ctx, cancelCtx := context.WithCancel(context.Background())
184186
defer func() {
185187
b.runCleanup(normalPanic)
186188
b.checkRaces()
@@ -191,6 +193,8 @@ func (b *B) runN(n int) {
191193
b.resetRaces()
192194
b.N = n
193195
b.loopN = 0
196+
b.ctx = ctx
197+
b.cancelCtx = cancelCtx
194198

195199
b.parallelism = 1
196200
b.ResetTimer()

Diff for: src/testing/benchmark_test.go

+30
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ package testing_test
77
import (
88
"bytes"
99
"cmp"
10+
"context"
11+
"errors"
1012
"runtime"
1113
"slices"
1214
"strings"
@@ -127,6 +129,34 @@ func TestRunParallelSkipNow(t *testing.T) {
127129
})
128130
}
129131

132+
func TestBenchmarkContext(t *testing.T) {
133+
testing.Benchmark(func(b *testing.B) {
134+
ctx := b.Context()
135+
if err := ctx.Err(); err != nil {
136+
b.Fatalf("expected non-canceled context, got %v", err)
137+
}
138+
139+
var innerCtx context.Context
140+
b.Run("inner", func(b *testing.B) {
141+
innerCtx = b.Context()
142+
if err := innerCtx.Err(); err != nil {
143+
b.Fatalf("expected inner benchmark to not inherit canceled context, got %v", err)
144+
}
145+
})
146+
b.Run("inner2", func(b *testing.B) {
147+
if !errors.Is(innerCtx.Err(), context.Canceled) {
148+
t.Fatal("expected context of sibling benchmark to be canceled after its test function finished")
149+
}
150+
})
151+
152+
t.Cleanup(func() {
153+
if !errors.Is(ctx.Err(), context.Canceled) {
154+
t.Fatal("expected context canceled before cleanup")
155+
}
156+
})
157+
})
158+
}
159+
130160
func ExampleB_RunParallel() {
131161
// Parallel benchmark for text/template.Template.Execute on a single object.
132162
testing.Benchmark(func(b *testing.B) {

Diff for: src/testing/fuzz.go

+30-19
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package testing
66

77
import (
8+
"context"
89
"errors"
910
"flag"
1011
"fmt"
@@ -293,20 +294,24 @@ func (f *F) Fuzz(ff any) {
293294
f.tstate.match.clearSubNames()
294295
}
295296

297+
ctx, cancelCtx := context.WithCancel(f.ctx)
298+
296299
// Record the stack trace at the point of this call so that if the subtest
297300
// function - which runs in a separate stack - is marked as a helper, we can
298301
// continue walking the stack into the parent test.
299302
var pc [maxStackLen]uintptr
300303
n := runtime.Callers(2, pc[:])
301304
t := &T{
302305
common: common{
303-
barrier: make(chan bool),
304-
signal: make(chan bool),
305-
name: testName,
306-
parent: &f.common,
307-
level: f.level + 1,
308-
creator: pc[:n],
309-
chatty: f.chatty,
306+
barrier: make(chan bool),
307+
signal: make(chan bool),
308+
name: testName,
309+
parent: &f.common,
310+
level: f.level + 1,
311+
creator: pc[:n],
312+
chatty: f.chatty,
313+
ctx: ctx,
314+
cancelCtx: cancelCtx,
310315
},
311316
tstate: f.tstate,
312317
}
@@ -508,14 +513,17 @@ func runFuzzTests(deps testDeps, fuzzTests []InternalFuzzTarget, deadline time.T
508513
continue
509514
}
510515
}
516+
ctx, cancelCtx := context.WithCancel(context.Background())
511517
f := &F{
512518
common: common{
513-
signal: make(chan bool),
514-
barrier: make(chan bool),
515-
name: testName,
516-
parent: &root,
517-
level: root.level + 1,
518-
chatty: root.chatty,
519+
signal: make(chan bool),
520+
barrier: make(chan bool),
521+
name: testName,
522+
parent: &root,
523+
level: root.level + 1,
524+
chatty: root.chatty,
525+
ctx: ctx,
526+
cancelCtx: cancelCtx,
519527
},
520528
tstate: tstate,
521529
fstate: fstate,
@@ -590,14 +598,17 @@ func runFuzzing(deps testDeps, fuzzTests []InternalFuzzTarget) (ok bool) {
590598
return false
591599
}
592600

601+
ctx, cancelCtx := context.WithCancel(context.Background())
593602
f := &F{
594603
common: common{
595-
signal: make(chan bool),
596-
barrier: nil, // T.Parallel has no effect when fuzzing.
597-
name: testName,
598-
parent: &root,
599-
level: root.level + 1,
600-
chatty: root.chatty,
604+
signal: make(chan bool),
605+
barrier: nil, // T.Parallel has no effect when fuzzing.
606+
name: testName,
607+
parent: &root,
608+
level: root.level + 1,
609+
chatty: root.chatty,
610+
ctx: ctx,
611+
cancelCtx: cancelCtx,
601612
},
602613
fstate: fstate,
603614
tstate: tstate,

Diff for: src/testing/testing.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -1385,10 +1385,10 @@ func (c *common) Chdir(dir string) {
13851385
}
13861386

13871387
// Context returns a context that is canceled just before
1388-
// [T.Cleanup]-registered functions are called.
1388+
// Cleanup-registered functions are called.
13891389
//
13901390
// Cleanup functions can wait for any resources
1391-
// that shut down on Context.Done before the test completes.
1391+
// that shut down on Context.Done before the test or benchmark completes.
13921392
func (c *common) Context() context.Context {
13931393
c.checkFuzzFn("Context")
13941394
return c.ctx

0 commit comments

Comments
 (0)