golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/quic/main_test.go (about)

     1  // Copyright 2023 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  //go:build go1.21
     6  
     7  package quic
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    12  	"os"
    13  	"runtime"
    14  	"testing"
    15  	"time"
    16  )
    17  
    18  func TestMain(m *testing.M) {
    19  	// Add all goroutines running at the start of the test to the set
    20  	// of not-leaked goroutines. This includes TestMain, and anything else
    21  	// that might have been started by test infrastructure.
    22  	skip := [][]byte{
    23  		[]byte("created by os/signal.Notify"),
    24  		[]byte("gotraceback_test.go"),
    25  	}
    26  	buf := make([]byte, 2<<20)
    27  	buf = buf[:runtime.Stack(buf, true)]
    28  	for _, g := range bytes.Split(buf, []byte("\n\n")) {
    29  		id, _, _ := bytes.Cut(g, []byte("["))
    30  		skip = append(skip, id)
    31  	}
    32  
    33  	defer os.Exit(m.Run())
    34  
    35  	// Look for leaked goroutines.
    36  	//
    37  	// Checking after every test makes it easier to tell which test is the culprit,
    38  	// but checking once at the end is faster and less likely to miss something.
    39  	if runtime.GOOS == "js" {
    40  		// The js-wasm runtime creates an additional background goroutine.
    41  		// Just skip the leak check there.
    42  		return
    43  	}
    44  	start := time.Now()
    45  	warned := false
    46  	for {
    47  		buf := make([]byte, 2<<20)
    48  		buf = buf[:runtime.Stack(buf, true)]
    49  		leaked := false
    50  		for _, g := range bytes.Split(buf, []byte("\n\n")) {
    51  			leaked = true
    52  			for _, s := range skip {
    53  				if bytes.Contains(g, s) {
    54  					leaked = false
    55  					break
    56  				}
    57  			}
    58  		}
    59  		if !leaked {
    60  			break
    61  		}
    62  		if !warned && time.Since(start) > 1*time.Second {
    63  			// Print a warning quickly, in case this is an interactive session.
    64  			// Keep waiting until the test times out, in case this is a slow trybot.
    65  			fmt.Printf("Tests seem to have leaked some goroutines, still waiting.\n\n")
    66  			fmt.Print(string(buf))
    67  			warned = true
    68  		}
    69  		// Goroutines might still be shutting down.
    70  		time.Sleep(1 * time.Millisecond)
    71  	}
    72  }