From 067d796549242bec2d33226c9da1e67f092a7be2 Mon Sep 17 00:00:00 2001 From: Katie Hockman Date: Thu, 14 Oct 2021 12:32:58 -0400 Subject: testing: write output to buffer when fuzzing Fixes #48709 Change-Id: Ia6376a2f792946498d6565a53605b3e6c985ea7c Reviewed-on: https://go-review.googlesource.com/c/go/+/355909 Trust: Katie Hockman Run-TryBot: Katie Hockman TryBot-Result: Go Bot Reviewed-by: Jay Conrod Reviewed-by: Roland Shoemaker Reviewed-by: Bryan C. Mills --- src/testing/fuzz.go | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'src/testing') diff --git a/src/testing/fuzz.go b/src/testing/fuzz.go index 0429f8243d..d5cb5e853f 100644 --- a/src/testing/fuzz.go +++ b/src/testing/fuzz.go @@ -5,6 +5,7 @@ package testing import ( + "bytes" "errors" "flag" "fmt" @@ -367,14 +368,14 @@ func (f *F) Fuzz(ff interface{}) { // run calls fn on a given input, as a subtest with its own T. // run is analogous to T.Run. The test filtering and cleanup works similarly. // fn is called in its own goroutine. - run := func(e corpusEntry) error { + run := func(captureOut io.Writer, e corpusEntry) (ok bool) { if e.Values == nil { // The corpusEntry must have non-nil Values in order to run the // test. If Values is nil, it is a bug in our code. panic(fmt.Sprintf("corpus file %q was not unmarshaled", e.Path)) } if shouldFailFast() { - return nil + return true } testName := f.name if e.Path != "" { @@ -405,6 +406,10 @@ func (f *F) Fuzz(ff interface{}) { }, context: f.testContext, } + if captureOut != nil { + // t.parent aliases f.common. + t.parent.w = captureOut + } t.w = indenter{&t.common} if t.chatty != nil { // TODO(#48132): adjust this to work with test2json. @@ -426,10 +431,7 @@ func (f *F) Fuzz(ff interface{}) { }) <-t.signal f.inFuzzFn = false - if t.Failed() { - return errors.New(string(f.output)) - } - return nil + return !t.Failed() } switch f.fuzzContext.mode { @@ -466,7 +468,17 @@ func (f *F) Fuzz(ff interface{}) { case fuzzWorker: // Fuzzing is enabled, and this is a worker process. Follow instructions // from the coordinator. - if err := f.fuzzContext.deps.RunFuzzWorker(run); err != nil { + if err := f.fuzzContext.deps.RunFuzzWorker(func(e corpusEntry) error { + // Don't write to f.w (which points to Stdout) if running from a + // fuzz worker. This would become very verbose, particularly during + // minimization. Return the error instead, and let the caller deal + // with the output. + var buf bytes.Buffer + if ok := run(&buf, e); !ok { + return errors.New(buf.String()) + } + return nil + }); err != nil { // Internal errors are marked with f.Fail; user code may call this too, before F.Fuzz. // The worker will exit with fuzzWorkerExitCode, indicating this is a failure // (and 'go test' should exit non-zero) but a crasher should not be recorded. @@ -479,7 +491,7 @@ func (f *F) Fuzz(ff interface{}) { for _, e := range f.corpus { name := fmt.Sprintf("%s/%s", f.name, filepath.Base(e.Path)) if _, ok, _ := f.testContext.match.fullName(nil, name); ok { - run(e) + run(f.w, e) } } } -- cgit v1.3-5-g9baa