From abfeec5eb0356d1ac91a097d2124a6b7c8cfccd4 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Sun, 16 Aug 2020 21:58:40 +0000 Subject: testing/iotest: add ErrReader Adds an io.Reader that always returns 0 and a non-nil error. Fixes #38781 Change-Id: I56bd124de07bc8809e77c6cfaab33a1e32cfe2ee GitHub-Last-Rev: 4e232b17e9120405d4ea4743350ee361a3505043 GitHub-Pull-Request: golang/go#34741 Reviewed-on: https://go-review.googlesource.com/c/go/+/199501 Run-TryBot: Emmanuel Odeke TryBot-Result: Gobot Gobot Reviewed-by: Emmanuel Odeke --- src/testing/iotest/logger_test.go | 12 ++---------- src/testing/iotest/reader.go | 15 +++++++++++++++ src/testing/iotest/reader_test.go | 10 ++++++++++ 3 files changed, 27 insertions(+), 10 deletions(-) (limited to 'src/testing') diff --git a/src/testing/iotest/logger_test.go b/src/testing/iotest/logger_test.go index c121bf48f7..575f37e05c 100644 --- a/src/testing/iotest/logger_test.go +++ b/src/testing/iotest/logger_test.go @@ -81,14 +81,6 @@ func TestWriteLogger_errorOnWrite(t *testing.T) { } } -type errReader struct { - err error -} - -func (r errReader) Read([]byte) (int, error) { - return 0, r.err -} - func TestReadLogger(t *testing.T) { olw := log.Writer() olf := log.Flags() @@ -146,14 +138,14 @@ func TestReadLogger_errorOnRead(t *testing.T) { data := []byte("Hello, World!") p := make([]byte, len(data)) - lr := errReader{err: errors.New("Read Error!")} + lr := ErrReader() rl := NewReadLogger("read", lr) n, err := rl.Read(p) if err == nil { t.Fatalf("Unexpectedly succeeded to read: %v", err) } - wantLogWithHex := fmt.Sprintf("lr: read %x: %v\n", p[:n], "Read Error!") + wantLogWithHex := fmt.Sprintf("lr: read %x: %v\n", p[:n], "io") if g, w := lOut.String(), wantLogWithHex; g != w { t.Errorf("ReadLogger mismatch\n\tgot: %q\n\twant: %q", g, w) } diff --git a/src/testing/iotest/reader.go b/src/testing/iotest/reader.go index 8d82018fd6..b18e912f27 100644 --- a/src/testing/iotest/reader.go +++ b/src/testing/iotest/reader.go @@ -68,6 +68,7 @@ func (r *dataErrReader) Read(p []byte) (n int, err error) { return } +// ErrTimeout is a fake timeout error. var ErrTimeout = errors.New("timeout") // TimeoutReader returns ErrTimeout on the second read @@ -86,3 +87,17 @@ func (r *timeoutReader) Read(p []byte) (int, error) { } return r.r.Read(p) } + +// ErrIO is a fake IO error. +var ErrIO = errors.New("io") + +// ErrReader returns a fake error every time it is read from. +func ErrReader() io.Reader { + return errReader(0) +} + +type errReader int + +func (r errReader) Read(p []byte) (int, error) { + return 0, ErrIO +} diff --git a/src/testing/iotest/reader_test.go b/src/testing/iotest/reader_test.go index 9397837e08..ccba22ee29 100644 --- a/src/testing/iotest/reader_test.go +++ b/src/testing/iotest/reader_test.go @@ -224,3 +224,13 @@ func TestDataErrReader_emptyReader(t *testing.T) { t.Errorf("Unexpectedly read %d bytes, wanted %d", g, w) } } + +func TestErrReader(t *testing.T) { + n, err := ErrReader().Read([]byte{}) + if err != ErrIO { + t.Errorf("ErrReader.Read(any) should have returned ErrIO, returned %v", err) + } + if n != 0 { + t.Errorf("ErrReader.Read(any) should have read 0 bytes, read %v", n) + } +} -- cgit v1.3 From db4cda2ec0955854c8ff556ac19ec5e67d48d090 Mon Sep 17 00:00:00 2001 From: Emmanuel T Odeke Date: Mon, 17 Aug 2020 12:25:49 -0700 Subject: testing/iotest: correct ErrReader signature and remove exported error Corrects ErrReader's signature to what was accepted in the approved proposal, and also removes an exported ErrIO which wasn't part of the proposal and is unnecessary. The new signature allows users to customize their own errors. While here, started examples, with ErrReader leading the way. Updates #38781 Change-Id: Ia7f84721f11061343cfef8b1adc2b7b69bc3f43c Reviewed-on: https://go-review.googlesource.com/c/go/+/248898 Run-TryBot: Emmanuel Odeke Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/testing/iotest/example_test.go | 22 ++++++++++++++++++++++ src/testing/iotest/logger_test.go | 4 ++-- src/testing/iotest/reader.go | 17 ++++++++--------- src/testing/iotest/reader_test.go | 27 +++++++++++++++++++++------ 4 files changed, 53 insertions(+), 17 deletions(-) create mode 100644 src/testing/iotest/example_test.go (limited to 'src/testing') diff --git a/src/testing/iotest/example_test.go b/src/testing/iotest/example_test.go new file mode 100644 index 0000000000..10f6bd38f7 --- /dev/null +++ b/src/testing/iotest/example_test.go @@ -0,0 +1,22 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package iotest_test + +import ( + "errors" + "fmt" + "testing/iotest" +) + +func ExampleErrReader() { + // A reader that always returns a custom error. + r := iotest.ErrReader(errors.New("custom error")) + n, err := r.Read(nil) + fmt.Printf("n: %d\nerr: %q\n", n, err) + + // Output: + // n: 0 + // err: "custom error" +} diff --git a/src/testing/iotest/logger_test.go b/src/testing/iotest/logger_test.go index 575f37e05c..fec4467cc6 100644 --- a/src/testing/iotest/logger_test.go +++ b/src/testing/iotest/logger_test.go @@ -138,14 +138,14 @@ func TestReadLogger_errorOnRead(t *testing.T) { data := []byte("Hello, World!") p := make([]byte, len(data)) - lr := ErrReader() + lr := ErrReader(errors.New("io failure")) rl := NewReadLogger("read", lr) n, err := rl.Read(p) if err == nil { t.Fatalf("Unexpectedly succeeded to read: %v", err) } - wantLogWithHex := fmt.Sprintf("lr: read %x: %v\n", p[:n], "io") + wantLogWithHex := fmt.Sprintf("lr: read %x: io failure\n", p[:n]) if g, w := lOut.String(), wantLogWithHex; g != w { t.Errorf("ReadLogger mismatch\n\tgot: %q\n\twant: %q", g, w) } diff --git a/src/testing/iotest/reader.go b/src/testing/iotest/reader.go index b18e912f27..bc2f72a911 100644 --- a/src/testing/iotest/reader.go +++ b/src/testing/iotest/reader.go @@ -88,16 +88,15 @@ func (r *timeoutReader) Read(p []byte) (int, error) { return r.r.Read(p) } -// ErrIO is a fake IO error. -var ErrIO = errors.New("io") - -// ErrReader returns a fake error every time it is read from. -func ErrReader() io.Reader { - return errReader(0) +// ErrReader returns an io.Reader that returns 0, err from all Read calls. +func ErrReader(err error) io.Reader { + return &alwaysErrReader{err: err} } -type errReader int +type alwaysErrReader struct { + err error +} -func (r errReader) Read(p []byte) (int, error) { - return 0, ErrIO +func (aer *alwaysErrReader) Read(p []byte) (int, error) { + return 0, aer.err } diff --git a/src/testing/iotest/reader_test.go b/src/testing/iotest/reader_test.go index ccba22ee29..6004e841e5 100644 --- a/src/testing/iotest/reader_test.go +++ b/src/testing/iotest/reader_test.go @@ -6,6 +6,7 @@ package iotest import ( "bytes" + "errors" "io" "testing" ) @@ -226,11 +227,25 @@ func TestDataErrReader_emptyReader(t *testing.T) { } func TestErrReader(t *testing.T) { - n, err := ErrReader().Read([]byte{}) - if err != ErrIO { - t.Errorf("ErrReader.Read(any) should have returned ErrIO, returned %v", err) - } - if n != 0 { - t.Errorf("ErrReader.Read(any) should have read 0 bytes, read %v", n) + cases := []struct { + name string + err error + }{ + {"nil error", nil}, + {"non-nil error", errors.New("io failure")}, + {"io.EOF", io.EOF}, + } + + for _, tt := range cases { + tt := tt + t.Run(tt.name, func(t *testing.T) { + n, err := ErrReader(tt.err).Read(nil) + if err != tt.err { + t.Fatalf("Error mismatch\nGot: %v\nWant: %v", err, tt.err) + } + if n != 0 { + t.Fatalf("Byte count mismatch: got %d want 0", n) + } + }) } } -- cgit v1.3 From cdc77d34d7770ed02d84b9193380f9646017dce6 Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Mon, 17 Aug 2020 17:31:21 -0400 Subject: testing: treat PAUSE lines as changing the active test name We could instead fix cmd/test2json to treat PAUSE lines as *not* changing the active test name, but that seems like it would be more confusing to humans, and also wouldn't fix tools that parse output using existing builds of cmd/test2json. Fixes #40657 Change-Id: I937611778f5b1e7dd1d6e9f44424d7e725a589ed Reviewed-on: https://go-review.googlesource.com/c/go/+/248727 Run-TryBot: Bryan C. Mills Reviewed-by: Jean de Klerk --- .../go/testdata/script/test_json_interleaved.txt | 27 ++++++++++++++++++++++ src/testing/testing.go | 25 ++++++++++++++++---- 2 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 src/cmd/go/testdata/script/test_json_interleaved.txt (limited to 'src/testing') diff --git a/src/cmd/go/testdata/script/test_json_interleaved.txt b/src/cmd/go/testdata/script/test_json_interleaved.txt new file mode 100644 index 0000000000..e2d349e3fb --- /dev/null +++ b/src/cmd/go/testdata/script/test_json_interleaved.txt @@ -0,0 +1,27 @@ +# Regression test for https://golang.org/issue/40657: output from the main test +# function should be attributed correctly even if interleaved with the PAUSE +# line for a new parallel subtest. + +[short] skip + +go test -json +stdout '"Test":"TestWeirdTiming","Output":"[^"]* logging to outer again\\n"' + +-- go.mod -- +module example.com +go 1.15 +-- main_test.go -- +package main + +import ( + "testing" +) + +func TestWeirdTiming(outer *testing.T) { + outer.Run("pauser", func(pauser *testing.T) { + outer.Logf("logging to outer") + pauser.Parallel() + }) + + outer.Logf("logging to outer again") +} diff --git a/src/testing/testing.go b/src/testing/testing.go index 061142b9ab..6fc8c4fa9f 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -357,10 +357,19 @@ func (p *testPrinter) Fprint(w io.Writer, testName, out string) { defer p.lastNameMu.Unlock() if !p.chatty || - strings.HasPrefix(out, "--- PASS") || - strings.HasPrefix(out, "--- FAIL") || - strings.HasPrefix(out, "=== CONT") || - strings.HasPrefix(out, "=== RUN") { + strings.HasPrefix(out, "--- PASS: ") || + strings.HasPrefix(out, "--- FAIL: ") || + strings.HasPrefix(out, "--- SKIP: ") || + strings.HasPrefix(out, "=== RUN ") || + strings.HasPrefix(out, "=== CONT ") || + strings.HasPrefix(out, "=== PAUSE ") { + // If we're buffering test output (!p.chatty), we don't really care which + // test is emitting which line so long as they are serialized. + // + // If the message already implies an association with a specific new test, + // we don't need to check what the old test name was or log an extra CONT + // line for it. (We're updating it anyway, and the current message already + // includes the test name.) p.lastName = testName fmt.Fprint(w, out) return @@ -976,7 +985,13 @@ func (t *T) Parallel() { for ; root.parent != nil; root = root.parent { } root.mu.Lock() - fmt.Fprintf(root.w, "=== PAUSE %s\n", t.name) + // Unfortunately, even though PAUSE indicates that the named test is *no + // longer* running, cmd/test2json interprets it as changing the active test + // for the purpose of log parsing. We could fix cmd/test2json, but that + // won't fix existing deployments of third-party tools that already shell + // out to older builds of cmd/test2json — so merely fixing cmd/test2json + // isn't enough for now. + printer.Fprint(root.w, t.name, fmt.Sprintf("=== PAUSE %s\n", t.name)) root.mu.Unlock() } -- cgit v1.3