github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/net/http/z_last_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 file.
     4  
     5  package http_test
     6  
     7  import (
     8  	"net/http"
     9  	"runtime"
    10  	"sort"
    11  	"strings"
    12  	"testing"
    13  	"time"
    14  )
    15  
    16  func interestingGoroutines() (gs []string) {
    17  	buf := make([]byte, 2<<20)
    18  	buf = buf[:runtime.Stack(buf, true)]
    19  	for _, g := range strings.Split(string(buf), "\n\n") {
    20  		sl := strings.SplitN(g, "\n", 2)
    21  		if len(sl) != 2 {
    22  			continue
    23  		}
    24  		stack := strings.TrimSpace(sl[1])
    25  		if stack == "" ||
    26  			strings.Contains(stack, "created by net.newPollServer") ||
    27  			strings.Contains(stack, "created by net.startServer") ||
    28  			strings.Contains(stack, "created by testing.RunTests") ||
    29  			strings.Contains(stack, "closeWriteAndWait") ||
    30  			strings.Contains(stack, "testing.Main(") ||
    31  			// These only show up with GOTRACEBACK=2; Issue 5005 (comment 28)
    32  			strings.Contains(stack, "runtime.goexit") ||
    33  			strings.Contains(stack, "created by runtime.gc") ||
    34  			strings.Contains(stack, "runtime.MHeap_Scavenger") {
    35  			continue
    36  		}
    37  		gs = append(gs, stack)
    38  	}
    39  	sort.Strings(gs)
    40  	return
    41  }
    42  
    43  // Verify the other tests didn't leave any goroutines running.
    44  // This is in a file named z_last_test.go so it sorts at the end.
    45  func TestGoroutinesRunning(t *testing.T) {
    46  	if testing.Short() {
    47  		t.Skip("not counting goroutines for leakage in -short mode")
    48  	}
    49  	gs := interestingGoroutines()
    50  
    51  	n := 0
    52  	stackCount := make(map[string]int)
    53  	for _, g := range gs {
    54  		stackCount[g]++
    55  		n++
    56  	}
    57  
    58  	t.Logf("num goroutines = %d", n)
    59  	if n > 0 {
    60  		t.Error("Too many goroutines.")
    61  		for stack, count := range stackCount {
    62  			t.Logf("%d instances of:\n%s", count, stack)
    63  		}
    64  	}
    65  }
    66  
    67  func afterTest(t *testing.T) {
    68  	http.DefaultTransport.(*http.Transport).CloseIdleConnections()
    69  	if testing.Short() {
    70  		return
    71  	}
    72  	var bad string
    73  	badSubstring := map[string]string{
    74  		").readLoop(":                                  "a Transport",
    75  		").writeLoop(":                                 "a Transport",
    76  		"created by net/http/httptest.(*Server).Start": "an httptest.Server",
    77  		"timeoutHandler":                               "a TimeoutHandler",
    78  		"net.(*netFD).connect(":                        "a timing out dial",
    79  		").noteClientGone(":                            "a closenotifier sender",
    80  	}
    81  	var stacks string
    82  	for i := 0; i < 4; i++ {
    83  		bad = ""
    84  		stacks = strings.Join(interestingGoroutines(), "\n\n")
    85  		for substr, what := range badSubstring {
    86  			if strings.Contains(stacks, substr) {
    87  				bad = what
    88  			}
    89  		}
    90  		if bad == "" {
    91  			return
    92  		}
    93  		// Bad stuff found, but goroutines might just still be
    94  		// shutting down, so give it some time.
    95  		time.Sleep(250 * time.Millisecond)
    96  	}
    97  	t.Errorf("Test appears to have leaked %s:\n%s", bad, stacks)
    98  }