github.com/rkt/rkt@v1.30.1-0.20200224141603-171c416fac02/store/imagestore/main_test.go (about)

     1  // Copyright 2013 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.BSD file,
     4  // or at https://opensource.org/licenses/BSD-3-Clause
     5  
     6  package imagestore
     7  
     8  import (
     9  	"fmt"
    10  	"os"
    11  	"runtime"
    12  	"sort"
    13  	"strings"
    14  	"testing"
    15  	"time"
    16  )
    17  
    18  func interestingGoroutines() (gs []string) {
    19  	buf := make([]byte, 2<<20)
    20  	buf = buf[:runtime.Stack(buf, true)]
    21  	for _, g := range strings.Split(string(buf), "\n\n") {
    22  		sl := strings.SplitN(g, "\n", 2)
    23  		if len(sl) != 2 {
    24  			continue
    25  		}
    26  		stack := strings.TrimSpace(sl[1])
    27  		if stack == "" ||
    28  			strings.Contains(stack, "created by testing.RunTests") ||
    29  			strings.Contains(stack, "testing.Main(") ||
    30  			strings.Contains(stack, "runtime.goexit") ||
    31  			strings.Contains(stack, "github.com/rkt/rkt/store/imagestore.interestingGoroutines") ||
    32  			strings.Contains(stack, "created by runtime.gc") ||
    33  			strings.Contains(stack, "runtime.MHeap_Scavenger") {
    34  			continue
    35  		}
    36  		gs = append(gs, stack)
    37  	}
    38  	sort.Strings(gs)
    39  	return
    40  }
    41  
    42  // Verify the other tests didn't leave any goroutines running.
    43  func TestMain(m *testing.M) {
    44  	v := m.Run()
    45  	if v == 0 && goroutineLeaked() {
    46  		os.Exit(254)
    47  	}
    48  	os.Exit(v)
    49  }
    50  
    51  func goroutineLeaked() bool {
    52  	if testing.Short() {
    53  		// not counting goroutines for leakage in -short mode
    54  		return false
    55  	}
    56  
    57  	var stackCount map[string]int
    58  	for i := 0; i < 5; i++ {
    59  		n := 0
    60  		stackCount = make(map[string]int)
    61  		gs := interestingGoroutines()
    62  		for _, g := range gs {
    63  			stackCount[g]++
    64  			n++
    65  		}
    66  		if n == 0 {
    67  			return false
    68  		}
    69  		// Wait for goroutines to schedule and die off:
    70  		time.Sleep(100 * time.Millisecond)
    71  	}
    72  	fmt.Fprintf(os.Stderr, "Too many goroutines running after integration test(s).\n")
    73  	for stack, count := range stackCount {
    74  		fmt.Fprintf(os.Stderr, "%d instances of:\n%s\n", count, stack)
    75  	}
    76  	return true
    77  }