github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/util/testleak/leaktest.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 file.
     4  
     5  // Copyright 2016 PingCAP, Inc.
     6  //
     7  // Licensed under the Apache License, Version 2.0 (the "License");
     8  // you may not use this file except in compliance with the License.
     9  // You may obtain a copy of the License at
    10  //
    11  //     http://www.apache.org/licenses/LICENSE-2.0
    12  //
    13  // Unless required by applicable law or agreed to in writing, software
    14  // distributed under the License is distributed on an "AS IS" BASIS,
    15  // See the License for the specific language governing permissions and
    16  // limitations under the License.
    17  
    18  package testleak
    19  
    20  import (
    21  	"runtime"
    22  	"sort"
    23  	"strings"
    24  	"time"
    25  
    26  	"github.com/insionng/yougam/libraries/pingcap/check"
    27  )
    28  
    29  func interestingGoroutines() (gs []string) {
    30  	buf := make([]byte, 2<<20)
    31  	buf = buf[:runtime.Stack(buf, true)]
    32  	for _, g := range strings.Split(string(buf), "\n\n") {
    33  		sl := strings.SplitN(g, "\n", 2)
    34  		if len(sl) != 2 {
    35  			continue
    36  		}
    37  		stack := strings.TrimSpace(sl[1])
    38  		if stack == "" ||
    39  			strings.Contains(stack, "created by yougam/libraries/pingcap/tidb.init") ||
    40  			strings.Contains(stack, "testing.RunTests") ||
    41  			strings.Contains(stack, "check.(*resultTracker).start") ||
    42  			strings.Contains(stack, "localstore.(*dbStore).scheduler") ||
    43  			strings.Contains(stack, "ddl.(*ddl).start") ||
    44  			strings.Contains(stack, "domain.NewDomain") ||
    45  			strings.Contains(stack, "testing.Main(") ||
    46  			strings.Contains(stack, "runtime.goexit") ||
    47  			strings.Contains(stack, "created by runtime.gc") ||
    48  			strings.Contains(stack, "interestingGoroutines") ||
    49  			strings.Contains(stack, "runtime.MHeap_Scavenger") {
    50  			continue
    51  		}
    52  		gs = append(gs, stack)
    53  	}
    54  	sort.Strings(gs)
    55  	return
    56  }
    57  
    58  var beforeTestGorountines = map[string]bool{}
    59  
    60  // BeforeTest gets the current goroutines.
    61  // It's used for check.Suite.SetUpSuite() function.
    62  // Now it's only used in the tidb_test.go.
    63  func BeforeTest() {
    64  	for _, g := range interestingGoroutines() {
    65  		beforeTestGorountines[g] = true
    66  	}
    67  }
    68  
    69  // AfterTest gets the current goroutines and runs the returned function to
    70  // get the goroutines at that time to contrast wheter any goroutines leaked.
    71  // Usage: defer testleak.AfterTest(c)()
    72  // It can call with BeforeTest() at the beginning of check.Suite.TearDownSuite() or
    73  // call alone at the beginning of each test.
    74  func AfterTest(c *check.C) func() {
    75  	if len(beforeTestGorountines) == 0 {
    76  		for _, g := range interestingGoroutines() {
    77  			beforeTestGorountines[g] = true
    78  		}
    79  	}
    80  
    81  	return func() {
    82  		defer func() {
    83  			beforeTestGorountines = map[string]bool{}
    84  		}()
    85  
    86  		var leaked []string
    87  		for i := 0; i < 50; i++ {
    88  			for _, g := range interestingGoroutines() {
    89  				if !beforeTestGorountines[g] {
    90  					leaked = append(leaked, g)
    91  				}
    92  			}
    93  			// Bad stuff found, but goroutines might just still be
    94  			// shutting down, so give it some time.
    95  			if len(leaked) != 0 {
    96  				leaked = leaked[:0]
    97  				time.Sleep(50 * time.Millisecond)
    98  				continue
    99  			}
   100  
   101  			return
   102  		}
   103  		for _, g := range leaked {
   104  			c.Errorf("Test appears to have leaked: %v", g)
   105  		}
   106  	}
   107  }