...
Source file
src/net/http/main_test.go
1
2
3
4
5 package http_test
6
7 import (
8 "fmt"
9 "io"
10 "log"
11 "net/http"
12 "os"
13 "runtime"
14 "sort"
15 "strings"
16 "testing"
17 "time"
18 )
19
20 var quietLog = log.New(io.Discard, "", 0)
21
22 func TestMain(m *testing.M) {
23 v := m.Run()
24 if v == 0 && goroutineLeaked() {
25 os.Exit(1)
26 }
27 os.Exit(v)
28 }
29
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)
35 if len(sl) != 2 {
36 continue
37 }
38 stack := strings.TrimSpace(sl[1])
39 if stack == "" ||
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
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") {
51 continue
52 }
53 gs = append(gs, stack)
54 }
55 sort.Strings(gs)
56 return
57 }
58
59
60 func goroutineLeaked() bool {
61 if testing.Short() || runningBenchmarks() {
62
63
64 return false
65 }
66
67 var stackCount map[string]int
68 for i := 0; i < 5; i++ {
69 n := 0
70 stackCount = make(map[string]int)
71 gs := interestingGoroutines()
72 for _, g := range gs {
73 stackCount[g]++
74 n++
75 }
76 if n == 0 {
77 return false
78 }
79
80 time.Sleep(100 * time.Millisecond)
81 }
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)
85 }
86 return true
87 }
88
89
90
91
92 func setParallel(t *testing.T) {
93 if strings.Contains(t.Name(), "HTTP2") {
94 http.CondSkipHTTP2(t)
95 }
96 if testing.Short() {
97 t.Parallel()
98 }
99 }
100
101 func runningBenchmarks() bool {
102 for i, arg := range os.Args {
103 if strings.HasPrefix(arg, "-test.bench=") && !strings.HasSuffix(arg, "=") {
104 return true
105 }
106 if arg == "-test.bench" && i < len(os.Args)-1 && os.Args[i+1] != "" {
107 return true
108 }
109 }
110 return false
111 }
112
113 func afterTest(t testing.TB) {
114 http.DefaultTransport.(*http.Transport).CloseIdleConnections()
115 if testing.Short() {
116 return
117 }
118 var bad string
119 badSubstring := map[string]string{
120 ").readLoop(": "a Transport",
121 ").writeLoop(": "a Transport",
122 "created by net/http/httptest.(*Server).Start": "an httptest.Server",
123 "timeoutHandler": "a TimeoutHandler",
124 "net.(*netFD).connect(": "a timing out dial",
125 ").noteClientGone(": "a closenotifier sender",
126 }
127 var stacks string
128 for i := 0; i < 10; i++ {
129 bad = ""
130 stacks = strings.Join(interestingGoroutines(), "\n\n")
131 for substr, what := range badSubstring {
132 if strings.Contains(stacks, substr) {
133 bad = what
134 }
135 }
136 if bad == "" {
137 return
138 }
139
140
141 time.Sleep(250 * time.Millisecond)
142 }
143 t.Errorf("Test appears to have leaked %s:\n%s", bad, stacks)
144 }
145
146
147
148
149 func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
150 deadline := time.Now().Add(waitFor)
151 for time.Now().Before(deadline) {
152 if fn() {
153 return true
154 }
155 time.Sleep(checkEvery)
156 }
157 return false
158 }
159
160
161 func waitErrCondition(waitFor, checkEvery time.Duration, fn func() error) error {
162 deadline := time.Now().Add(waitFor)
163 var err error
164 for time.Now().Before(deadline) {
165 if err = fn(); err == nil {
166 return nil
167 }
168 time.Sleep(checkEvery)
169 }
170 return err
171 }
172
View as plain text