[dev.fuzz] testing: report T.Deadline when running seed values

T.Deadline should return the test deadline, set with -timeout. When
fuzz targets are run with seed values as unit tests, either with or
without -fuzz, T.Deadline should work inside the fuzz function.

There is no deadline when fuzzing, even if -fuzztime is set, since
workers may have much shorter deadlines, and fuzz function behavior
shouldn't be time-dependent anyway.

Fixes #46220

Change-Id: I84aaeb9d7bfdc12bdcb6f1ab3fe67b3067ad2dfe
Reviewed-on: https://go-review.googlesource.com/c/go/+/330509
Trust: Jay Conrod <jayconrod@google.com>
Trust: Katie Hockman <katie@golang.org>
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Katie Hockman <katie@golang.org>
diff --git a/src/cmd/go/testdata/script/test_fuzz_deadline.txt b/src/cmd/go/testdata/script/test_fuzz_deadline.txt
new file mode 100644
index 0000000..f082647
--- /dev/null
+++ b/src/cmd/go/testdata/script/test_fuzz_deadline.txt
@@ -0,0 +1,37 @@
+# TODO(jayconrod): support shared memory on more platforms.
+[!darwin] [!linux] [!windows] skip
+
+[short] skip
+
+# The fuzz function should be able to detect whether -timeout
+# was set with T.Deadline. Note there is no F.Deadline, and
+# there is no timeout while fuzzing, even if -fuzztime is set.
+go test -run=FuzzDeadline -wantdeadline=true # -timeout defaults to 10m
+go test -run=FuzzDeadline -timeout=0 -wantdeadline=false
+! go test -run=FuzzDeadline -timeout=1s -wantdeadline=false
+go test -run=FuzzDeadline -timeout=1s -wantdeadline=true
+go test -fuzz=FuzzDeadline -timeout=0 -fuzztime=1s -wantdeadline=false
+go test -fuzz=FuzzDeadline -timeout=0 -fuzztime=100x -wantdeadline=false
+
+-- go.mod --
+module fzz
+
+go 1.16
+-- fuzz_deadline_test.go --
+package fuzz_test
+
+import (
+	"flag"
+	"testing"
+)
+
+var wantDeadline = flag.Bool("wantdeadline", false, "whether the test should have a deadline")
+
+func FuzzDeadline(f *testing.F) {
+	f.Add("run once")
+	f.Fuzz(func (t *testing.T, _ string) {
+		if _, hasDeadline := t.Deadline(); hasDeadline != *wantDeadline {
+			t.Fatalf("function got %v; want %v", hasDeadline, *wantDeadline)
+		}
+	})
+}
diff --git a/src/testing/fuzz.go b/src/testing/fuzz.go
index fc1212b..55e5397 100644
--- a/src/testing/fuzz.go
+++ b/src/testing/fuzz.go
@@ -491,13 +491,14 @@
 // runFuzzTargets runs the fuzz targets matching the pattern for -run. This will
 // only run the f.Fuzz function for each seed corpus without using the fuzzing
 // engine to generate or mutate inputs.
-func runFuzzTargets(deps testDeps, fuzzTargets []InternalFuzzTarget) (ran, ok bool) {
+func runFuzzTargets(deps testDeps, fuzzTargets []InternalFuzzTarget, deadline time.Time) (ran, ok bool) {
 	ok = true
 	if len(fuzzTargets) == 0 || *isFuzzWorker {
 		return ran, ok
 	}
 	m := newMatcher(deps.MatchString, *match, "-test.run")
 	tctx := newTestContext(*parallel, m)
+	tctx.deadline = deadline
 	fctx := &fuzzContext{
 		importPath:       deps.ImportPath,
 		readCorpus:       deps.ReadCorpus,
diff --git a/src/testing/testing.go b/src/testing/testing.go
index fa92dbb..581271e 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -1595,7 +1595,7 @@
 		deadline := m.startAlarm()
 		haveExamples = len(m.examples) > 0
 		testRan, testOk := runTests(m.deps.MatchString, m.tests, deadline)
-		fuzzTargetsRan, fuzzTargetsOk := runFuzzTargets(m.deps, m.fuzzTargets)
+		fuzzTargetsRan, fuzzTargetsOk := runFuzzTargets(m.deps, m.fuzzTargets, deadline)
 		exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
 		m.stopAlarm()
 		if !testRan && !exampleRan && !fuzzTargetsRan && *matchBenchmarks == "" && *matchFuzz == "" {