1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
20 var quietLog
= log
.New(ioutil
.Discard
, "", 0)
22 func TestMain(m
*testing
.M
) {
24 if v
== 0 && goroutineLeaked() {
30 func interestingGoroutines() (gs
[]string) {
31 buf
:= make([]byte, 2<<20)
32 buf
= buf
[:runtime
.Stack(buf
, true)]
33 for _
, g
:= range strings
.Split(string(buf
), "\n\n") {
34 sl
:= strings
.SplitN(g
, "\n", 2)
38 stack
:= strings
.TrimSpace(sl
[1])
40 strings
.Contains(stack
, "testing.(*M).before.func1") ||
41 strings
.Contains(stack
, "os/signal.signal_recv") ||
42 strings
.Contains(stack
, "created by net.startServer") ||
43 strings
.Contains(stack
, "created by testing.RunTests") ||
44 strings
.Contains(stack
, "closeWriteAndWait") ||
45 strings
.Contains(stack
, "testing.Main(") ||
46 // These only show up with GOTRACEBACK=2; Issue 5005 (comment 28)
47 strings
.Contains(stack
, "runtime.goexit") ||
48 strings
.Contains(stack
, "created by runtime.gc") ||
49 strings
.Contains(stack
, "net/http_test.interestingGoroutines") ||
50 strings
.Contains(stack
, "runtime.MHeap_Scavenger") {
53 gs
= append(gs
, stack
)
59 // Verify the other tests didn't leave any goroutines running.
60 func goroutineLeaked() bool {
61 if testing
.Short() ||
runningBenchmarks() {
62 // Don't worry about goroutine leaks in -short mode or in
63 // benchmark mode. Too distracting when there are false positives.
67 var stackCount
map[string]int
68 for i
:= 0; i
< 5; i
++ {
70 stackCount
= make(map[string]int)
71 gs
:= interestingGoroutines()
72 for _
, g
:= range gs
{
79 // Wait for goroutines to schedule and die off:
80 time
.Sleep(100 * time
.Millisecond
)
82 fmt
.Fprintf(os
.Stderr
, "Too many goroutines running after net/http test(s).\n")
83 for stack
, count
:= range stackCount
{
84 fmt
.Fprintf(os
.Stderr
, "%d instances of:\n%s\n", count
, stack
)
89 // setParallel marks t as a parallel test if we're in short mode
90 // (all.bash), but as a serial test otherwise. Using t.Parallel isn't
91 // compatible with the afterTest func in non-short mode.
92 func setParallel(t
*testing
.T
) {
98 func runningBenchmarks() bool {
99 for i
, arg
:= range os
.Args
{
100 if strings
.HasPrefix(arg
, "-test.bench=") && !strings
.HasSuffix(arg
, "=") {
103 if arg
== "-test.bench" && i
< len(os
.Args
)-1 && os
.Args
[i
+1] != "" {
110 func afterTest(t testing
.TB
) {
111 http
.DefaultTransport
.(*http
.Transport
).CloseIdleConnections()
116 badSubstring
:= map[string]string{
117 ").readLoop(": "a Transport",
118 ").writeLoop(": "a Transport",
119 "created by net/http/httptest.(*Server).Start": "an httptest.Server",
120 "timeoutHandler": "a TimeoutHandler",
121 "net.(*netFD).connect(": "a timing out dial",
122 ").noteClientGone(": "a closenotifier sender",
125 for i
:= 0; i
< 4; i
++ {
127 stacks
= strings
.Join(interestingGoroutines(), "\n\n")
128 for substr
, what
:= range badSubstring
{
129 if strings
.Contains(stacks
, substr
) {
136 // Bad stuff found, but goroutines might just still be
137 // shutting down, so give it some time.
138 time
.Sleep(250 * time
.Millisecond
)
140 t
.Errorf("Test appears to have leaked %s:\n%s", bad
, stacks
)
143 // waitCondition reports whether fn eventually returned true,
144 // checking immediately and then every checkEvery amount,
145 // until waitFor has elapsed, at which point it returns false.
146 func waitCondition(waitFor
, checkEvery time
.Duration
, fn
func() bool) bool {
147 deadline
:= time
.Now().Add(waitFor
)
148 for time
.Now().Before(deadline
) {
152 time
.Sleep(checkEvery
)
157 // waitErrCondition is like waitCondition but with errors instead of bools.
158 func waitErrCondition(waitFor
, checkEvery time
.Duration
, fn
func() error
) error
{
159 deadline
:= time
.Now().Add(waitFor
)
161 for time
.Now().Before(deadline
) {
162 if err
= fn(); err
== nil {
165 time
.Sleep(checkEvery
)