blob: 473d61880ed46730a02afce05ad465ac10d27121 [file] [edit]
// Copyright 2026 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package http3_test
import (
"fmt"
"os"
"runtime"
"slices"
"strings"
"testing"
"time"
)
func TestMain(m *testing.M) {
v := m.Run()
if v == 0 && goroutineLeaked() {
os.Exit(1)
}
os.Exit(v)
}
func runningBenchmarks() bool {
for i, arg := range os.Args {
if strings.HasPrefix(arg, "-test.bench=") && !strings.HasSuffix(arg, "=") {
return true
}
if arg == "-test.bench" && i < len(os.Args)-1 && os.Args[i+1] != "" {
return true
}
}
return false
}
func interestingGoroutines() (gs []string) {
buf := make([]byte, 2<<20)
buf = buf[:runtime.Stack(buf, true)]
for g := range strings.SplitSeq(string(buf), "\n\n") {
_, stack, _ := strings.Cut(g, "\n")
stack = strings.TrimSpace(stack)
if stack == "" ||
strings.Contains(stack, "testing.(*M).before.func1") ||
strings.Contains(stack, "os/signal.signal_recv") ||
strings.Contains(stack, "created by net.startServer") ||
strings.Contains(stack, "created by testing.RunTests") ||
strings.Contains(stack, "closeWriteAndWait") ||
strings.Contains(stack, "testing.Main(") ||
// These only show up with GOTRACEBACK=2; Issue 5005 (comment 28)
strings.Contains(stack, "runtime.goexit") ||
strings.Contains(stack, "created by runtime.gc") ||
strings.Contains(stack, "interestingGoroutines") ||
strings.Contains(stack, "runtime.MHeap_Scavenger") {
continue
}
gs = append(gs, stack)
}
slices.Sort(gs)
return
}
// Verify the other tests didn't leave any goroutines running.
func goroutineLeaked() bool {
if testing.Short() || runningBenchmarks() {
// Don't worry about goroutine leaks in -short mode or in
// benchmark mode. Too distracting when there are false positives.
return false
}
var stackCount map[string]int
for range 5 {
n := 0
stackCount = make(map[string]int)
gs := interestingGoroutines()
for _, g := range gs {
stackCount[g]++
n++
}
if n == 0 {
return false
}
// Wait for goroutines to schedule and die off:
time.Sleep(100 * time.Millisecond)
}
fmt.Fprintf(os.Stderr, "Too many goroutines running after net/http test(s).\n")
for stack, count := range stackCount {
fmt.Fprintf(os.Stderr, "%d instances of:\n%s\n", count, stack)
}
return true
}