github.com/zach-klippenstein/go@v0.0.0-20150108044943-fcfbeb3adf58/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 "net/http" 10 "os" 11 "runtime" 12 "sort" 13 "strings" 14 "testing" 15 "time" 16 ) 17 18 func TestMain(m *testing.M) { 19 v := m.Run() 20 if v == 0 && goroutineLeaked() { 21 os.Exit(1) 22 } 23 os.Exit(v) 24 } 25 26 func interestingGoroutines() (gs []string) { 27 buf := make([]byte, 2<<20) 28 buf = buf[:runtime.Stack(buf, true)] 29 for _, g := range strings.Split(string(buf), "\n\n") { 30 sl := strings.SplitN(g, "\n", 2) 31 if len(sl) != 2 { 32 continue 33 } 34 stack := strings.TrimSpace(sl[1]) 35 if stack == "" || 36 strings.Contains(stack, "created by net.startServer") || 37 strings.Contains(stack, "created by testing.RunTests") || 38 strings.Contains(stack, "closeWriteAndWait") || 39 strings.Contains(stack, "testing.Main(") || 40 // These only show up with GOTRACEBACK=2; Issue 5005 (comment 28) 41 strings.Contains(stack, "runtime.goexit") || 42 strings.Contains(stack, "created by runtime.gc") || 43 strings.Contains(stack, "net/http_test.interestingGoroutines") || 44 strings.Contains(stack, "runtime.MHeap_Scavenger") { 45 continue 46 } 47 gs = append(gs, stack) 48 } 49 sort.Strings(gs) 50 return 51 } 52 53 // Verify the other tests didn't leave any goroutines running. 54 func goroutineLeaked() bool { 55 if testing.Short() { 56 // not counting goroutines for leakage in -short mode 57 return false 58 } 59 gs := interestingGoroutines() 60 61 n := 0 62 stackCount := make(map[string]int) 63 for _, g := range gs { 64 stackCount[g]++ 65 n++ 66 } 67 68 if n == 0 { 69 return false 70 } 71 fmt.Fprintf(os.Stderr, "Too many goroutines running after net/http test(s).\n") 72 for stack, count := range stackCount { 73 fmt.Fprintf(os.Stderr, "%d instances of:\n%s\n", count, stack) 74 } 75 return true 76 } 77 78 func afterTest(t *testing.T) { 79 http.DefaultTransport.(*http.Transport).CloseIdleConnections() 80 if testing.Short() { 81 return 82 } 83 var bad string 84 badSubstring := map[string]string{ 85 ").readLoop(": "a Transport", 86 ").writeLoop(": "a Transport", 87 "created by net/http/httptest.(*Server).Start": "an httptest.Server", 88 "timeoutHandler": "a TimeoutHandler", 89 "net.(*netFD).connect(": "a timing out dial", 90 ").noteClientGone(": "a closenotifier sender", 91 } 92 var stacks string 93 for i := 0; i < 4; i++ { 94 bad = "" 95 stacks = strings.Join(interestingGoroutines(), "\n\n") 96 for substr, what := range badSubstring { 97 if strings.Contains(stacks, substr) { 98 bad = what 99 } 100 } 101 if bad == "" { 102 return 103 } 104 // Bad stuff found, but goroutines might just still be 105 // shutting down, so give it some time. 106 time.Sleep(250 * time.Millisecond) 107 } 108 t.Errorf("Test appears to have leaked %s:\n%s", bad, stacks) 109 }