1
2
3
4
5 package http3_test
6
7 import (
8 "fmt"
9 "os"
10 "runtime"
11 "slices"
12 "strings"
13 "testing"
14 "time"
15 )
16
17 func TestMain(m *testing.M) {
18 v := m.Run()
19 if v == 0 && goroutineLeaked() {
20 os.Exit(1)
21 }
22 os.Exit(v)
23 }
24
25 func runningBenchmarks() bool {
26 for i, arg := range os.Args {
27 if strings.HasPrefix(arg, "-test.bench=") && !strings.HasSuffix(arg, "=") {
28 return true
29 }
30 if arg == "-test.bench" && i < len(os.Args)-1 && os.Args[i+1] != "" {
31 return true
32 }
33 }
34 return false
35 }
36
37 func interestingGoroutines() (gs []string) {
38 buf := make([]byte, 2<<20)
39 buf = buf[:runtime.Stack(buf, true)]
40 for g := range strings.SplitSeq(string(buf), "\n\n") {
41 _, stack, _ := strings.Cut(g, "\n")
42 stack = strings.TrimSpace(stack)
43 if stack == "" ||
44 strings.Contains(stack, "testing.(*M).before.func1") ||
45 strings.Contains(stack, "os/signal.signal_recv") ||
46 strings.Contains(stack, "created by net.startServer") ||
47 strings.Contains(stack, "created by testing.RunTests") ||
48 strings.Contains(stack, "closeWriteAndWait") ||
49 strings.Contains(stack, "testing.Main(") ||
50
51 strings.Contains(stack, "runtime.goexit") ||
52 strings.Contains(stack, "created by runtime.gc") ||
53 strings.Contains(stack, "interestingGoroutines") ||
54 strings.Contains(stack, "runtime.MHeap_Scavenger") {
55 continue
56 }
57 gs = append(gs, stack)
58 }
59 slices.Sort(gs)
60 return
61 }
62
63
64 func goroutineLeaked() bool {
65 if testing.Short() || runningBenchmarks() {
66
67
68 return false
69 }
70
71 var stackCount map[string]int
72 for range 5 {
73 n := 0
74 stackCount = make(map[string]int)
75 gs := interestingGoroutines()
76 for _, g := range gs {
77 stackCount[g]++
78 n++
79 }
80 if n == 0 {
81 return false
82 }
83
84 time.Sleep(100 * time.Millisecond)
85 }
86 fmt.Fprintf(os.Stderr, "Too many goroutines running after net/http test(s).\n")
87 for stack, count := range stackCount {
88 fmt.Fprintf(os.Stderr, "%d instances of:\n%s\n", count, stack)
89 }
90 return true
91 }
92
View as plain text