| // Copyright 2023 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. |
| |
| //go:build go1.21 |
| |
| package quic |
| |
| import ( |
| "bytes" |
| "fmt" |
| "os" |
| "runtime" |
| "testing" |
| "time" |
| ) |
| |
| func TestMain(m *testing.M) { |
| defer os.Exit(m.Run()) |
| |
| // Look for leaked goroutines. |
| // |
| // Checking after every test makes it easier to tell which test is the culprit, |
| // but checking once at the end is faster and less likely to miss something. |
| if runtime.GOOS == "js" { |
| // The js-wasm runtime creates an additional background goroutine. |
| // Just skip the leak check there. |
| return |
| } |
| start := time.Now() |
| warned := false |
| for { |
| buf := make([]byte, 2<<20) |
| buf = buf[:runtime.Stack(buf, true)] |
| leaked := false |
| for _, g := range bytes.Split(buf, []byte("\n\n")) { |
| if bytes.Contains(g, []byte("quic.TestMain")) || |
| bytes.Contains(g, []byte("created by os/signal.Notify")) || |
| bytes.Contains(g, []byte("gotraceback_test.go")) { |
| continue |
| } |
| leaked = true |
| } |
| if !leaked { |
| break |
| } |
| if !warned && time.Since(start) > 1*time.Second { |
| // Print a warning quickly, in case this is an interactive session. |
| // Keep waiting until the test times out, in case this is a slow trybot. |
| fmt.Printf("Tests seem to have leaked some goroutines, still waiting.\n\n") |
| fmt.Print(string(buf)) |
| warned = true |
| } |
| // Goroutines might still be shutting down. |
| time.Sleep(1 * time.Millisecond) |
| } |
| } |