diff options
| author | Changkun Ou <hi@changkun.us> | 2020-09-14 10:24:59 +0200 |
|---|---|---|
| committer | Ian Lance Taylor <iant@golang.org> | 2020-09-14 20:27:49 +0000 |
| commit | a408139bb0166f6e0a5d9fd17fc934da960c354e (patch) | |
| tree | f5cade5946cab5b71a931a344a4a56143695b57d /src | |
| parent | 57646534297a9bd193e6aaa4239c98984f371b97 (diff) | |
| download | go-a408139bb0166f6e0a5d9fd17fc934da960c354e.tar.xz | |
testing: fix panicking tests hang if Cleanup calls FailNow
Previously, it was impossible to call FailNow in a Cleanup.
Because it can terminate a panicking goroutine and cause its
parent hangs on t.signal channel. This CL sends the signal
in a deferred call to prevent the hang.
Fixes #41355
Change-Id: I4552d3a7ea763ef86817bf9b50c0e37fb34bf20f
Reviewed-on: https://go-review.googlesource.com/c/go/+/254637
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Emmanuel Odeke <emm.odeke@gmail.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/cmd/go/testdata/script/test_cleanup_failnow.txt | 33 | ||||
| -rw-r--r-- | src/testing/testing.go | 12 |
2 files changed, 44 insertions, 1 deletions
diff --git a/src/cmd/go/testdata/script/test_cleanup_failnow.txt b/src/cmd/go/testdata/script/test_cleanup_failnow.txt new file mode 100644 index 0000000000..5ad4185fc1 --- /dev/null +++ b/src/cmd/go/testdata/script/test_cleanup_failnow.txt @@ -0,0 +1,33 @@ +# For issue 41355 +[short] skip + +! go test -v cleanup_failnow/panic_nocleanup_test.go +stdout '(?s)panic: die \[recovered\].*panic: die' +! stdout '(?s)panic: die \[recovered\].*panic: die.*panic: die' + +! go test -v cleanup_failnow/panic_withcleanup_test.go +stdout '(?s)panic: die \[recovered\].*panic: die' +! stdout '(?s)panic: die \[recovered\].*panic: die.*panic: die' + +-- cleanup_failnow/panic_nocleanup_test.go -- +package panic_nocleanup_test +import "testing" +func TestX(t *testing.T) { + t.Run("x", func(t *testing.T) { + panic("die") + }) +} + +-- cleanup_failnow/panic_withcleanup_test.go -- +package panic_withcleanup_test +import "testing" +func TestCleanupWithFailNow(t *testing.T) { + t.Cleanup(func() { + t.FailNow() + }) + t.Run("x", func(t *testing.T) { + t.Run("y", func(t *testing.T) { + panic("die") + }) + }) +}
\ No newline at end of file diff --git a/src/testing/testing.go b/src/testing/testing.go index 66f296234a..d86354093a 100644 --- a/src/testing/testing.go +++ b/src/testing/testing.go @@ -1075,6 +1075,7 @@ func tRunner(t *T, fn func(t *T)) { // If the test panicked, print any test output before dying. err := recover() signal := true + if !t.finished && err == nil { err = errNilPanicOrGoexit for p := t.parent; p != nil; p = p.parent { @@ -1086,6 +1087,15 @@ func tRunner(t *T, fn func(t *T)) { } } } + // Use a deferred call to ensure that we report that the test is + // complete even if a cleanup function calls t.FailNow. See issue 41355. + didPanic := false + defer func() { + t.signal <- signal + if err != nil && !didPanic { + panic(err) + } + }() doPanic := func(err interface{}) { t.Fail() @@ -1103,6 +1113,7 @@ func tRunner(t *T, fn func(t *T)) { fmt.Fprintf(root.parent.w, "cleanup panicked with %v", r) } } + didPanic = true panic(err) } if err != nil { @@ -1144,7 +1155,6 @@ func tRunner(t *T, fn func(t *T)) { if t.parent != nil && atomic.LoadInt32(&t.hasSub) == 0 { t.setRan() } - t.signal <- signal }() defer func() { if len(t.sub) == 0 { |
