github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/src/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, "created by net.startServer") || 41 strings.Contains(stack, "created by testing.RunTests") || 42 strings.Contains(stack, "closeWriteAndWait") || 43 strings.Contains(stack, "testing.Main(") || 44 // These only show up with GOTRACEBACK=2; Issue 5005 (comment 28) 45 strings.Contains(stack, "runtime.goexit") || 46 strings.Contains(stack, "created by runtime.gc") || 47 strings.Contains(stack, "net/http_test.interestingGoroutines") || 48 strings.Contains(stack, "runtime.MHeap_Scavenger") { 49 continue 50 } 51 gs = append(gs, stack) 52 } 53 sort.Strings(gs) 54 return 55 } 56 57 // Verify the other tests didn't leave any goroutines running. 58 func goroutineLeaked() bool { 59 if testing.Short() { 60 // not counting goroutines for leakage in -short mode 61 return false 62 } 63 64 var stackCount map[string]int 65 for i := 0; i < 5; i++ { 66 n := 0 67 stackCount = make(map[string]int) 68 gs := interestingGoroutines() 69 for _, g := range gs { 70 stackCount[g]++ 71 n++ 72 } 73 if n == 0 { 74 return false 75 } 76 // Wait for goroutines to schedule and die off: 77 time.Sleep(100 * time.Millisecond) 78 } 79 fmt.Fprintf(os.Stderr, "Too many goroutines running after net/http test(s).\n") 80 for stack, count := range stackCount { 81 fmt.Fprintf(os.Stderr, "%d instances of:\n%s\n", count, stack) 82 } 83 return true 84 } 85 86 // setParallel marks t as a parallel test if we're in short mode 87 // (all.bash), but as a serial test otherwise. Using t.Parallel isn't 88 // compatible with the afterTest func in non-short mode. 89 func setParallel(t *testing.T) { 90 if testing.Short() { 91 t.Parallel() 92 } 93 } 94 95 func afterTest(t testing.TB) { 96 http.DefaultTransport.(*http.Transport).CloseIdleConnections() 97 if testing.Short() { 98 return 99 } 100 var bad string 101 badSubstring := map[string]string{ 102 ").readLoop(": "a Transport", 103 ").writeLoop(": "a Transport", 104 "created by net/http/httptest.(*Server).Start": "an httptest.Server", 105 "timeoutHandler": "a TimeoutHandler", 106 "net.(*netFD).connect(": "a timing out dial", 107 ").noteClientGone(": "a closenotifier sender", 108 } 109 var stacks string 110 for i := 0; i < 4; i++ { 111 bad = "" 112 stacks = strings.Join(interestingGoroutines(), "\n\n") 113 for substr, what := range badSubstring { 114 if strings.Contains(stacks, substr) { 115 bad = what 116 } 117 } 118 if bad == "" { 119 return 120 } 121 // Bad stuff found, but goroutines might just still be 122 // shutting down, so give it some time. 123 time.Sleep(250 * time.Millisecond) 124 } 125 t.Errorf("Test appears to have leaked %s:\n%s", bad, stacks) 126 } 127 128 // waitCondition reports whether fn eventually returned true, 129 // checking immediately and then every checkEvery amount, 130 // until waitFor has elapsed, at which point it returns false. 131 func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool { 132 deadline := time.Now().Add(waitFor) 133 for time.Now().Before(deadline) { 134 if fn() { 135 return true 136 } 137 time.Sleep(checkEvery) 138 } 139 return false 140 } 141 142 // waitErrCondition is like waitCondition but with errors instead of bools. 143 func waitErrCondition(waitFor, checkEvery time.Duration, fn func() error) error { 144 deadline := time.Now().Add(waitFor) 145 var err error 146 for time.Now().Before(deadline) { 147 if err = fn(); err == nil { 148 return nil 149 } 150 time.Sleep(checkEvery) 151 } 152 return err 153 } 154 155 func closeClient(c *http.Client) { 156 c.Transport.(*http.Transport).CloseIdleConnections() 157 }