github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/libgo/go/net/http/main_test.go (about) 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. 4 5 package http_test 6 7 import ( 8 "fmt" 9 "io/ioutil" 10 "log" 11 "net/http" 12 "os" 13 "runtime" 14 "sort" 15 "strings" 16 "testing" 17 "time" 18 ) 19 20 var quietLog = log.New(ioutil.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 // 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") { 51 continue 52 } 53 gs = append(gs, stack) 54 } 55 sort.Strings(gs) 56 return 57 } 58 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. 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 // Wait for goroutines to schedule and die off: 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 // 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) { 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 // Bad stuff found, but goroutines might just still be 140 // shutting down, so give it some time. 141 time.Sleep(250 * time.Millisecond) 142 } 143 t.Errorf("Test appears to have leaked %s:\n%s", bad, stacks) 144 } 145 146 // waitCondition reports whether fn eventually returned true, 147 // checking immediately and then every checkEvery amount, 148 // until waitFor has elapsed, at which point it returns false. 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 // waitErrCondition is like waitCondition but with errors instead of bools. 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 }