1package dns 2 3import ( 4 "fmt" 5 "os" 6 "runtime" 7 "sort" 8 "strings" 9 "testing" 10 "time" 11) 12 13// copied from net/http/main_test.go 14 15func interestingGoroutines() (gs []string) { 16 buf := make([]byte, 2<<20) 17 buf = buf[:runtime.Stack(buf, true)] 18 for _, g := range strings.Split(string(buf), "\n\n") { 19 sl := strings.SplitN(g, "\n", 2) 20 if len(sl) != 2 { 21 continue 22 } 23 stack := strings.TrimSpace(sl[1]) 24 if stack == "" || 25 strings.Contains(stack, "testing.(*M).before.func1") || 26 strings.Contains(stack, "os/signal.signal_recv") || 27 strings.Contains(stack, "created by net.startServer") || 28 strings.Contains(stack, "created by testing.RunTests") || 29 strings.Contains(stack, "closeWriteAndWait") || 30 strings.Contains(stack, "testing.Main(") || 31 strings.Contains(stack, "testing.(*T).Run(") || 32 // These only show up with GOTRACEBACK=2; Issue 5005 (comment 28) 33 strings.Contains(stack, "runtime.goexit") || 34 strings.Contains(stack, "created by runtime.gc") || 35 strings.Contains(stack, "dns.interestingGoroutines") || 36 strings.Contains(stack, "runtime.MHeap_Scavenger") { 37 continue 38 } 39 gs = append(gs, stack) 40 } 41 sort.Strings(gs) 42 return 43} 44 45func goroutineLeaked() error { 46 if testing.Short() { 47 // Don't worry about goroutine leaks in -short mode or in 48 // benchmark mode. Too distracting when there are false positives. 49 return nil 50 } 51 52 var stackCount map[string]int 53 for i := 0; i < 5; i++ { 54 n := 0 55 stackCount = make(map[string]int) 56 gs := interestingGoroutines() 57 for _, g := range gs { 58 stackCount[g]++ 59 n++ 60 } 61 if n == 0 { 62 return nil 63 } 64 // Wait for goroutines to schedule and die off: 65 time.Sleep(100 * time.Millisecond) 66 } 67 for stack, count := range stackCount { 68 fmt.Fprintf(os.Stderr, "%d instances of:\n%s\n", count, stack) 69 } 70 return fmt.Errorf("too many goroutines running after dns test(s)") 71} 72