| // Copyright 2013 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. | 
 |  | 
 | package http_test | 
 |  | 
 | import ( | 
 | 	"fmt" | 
 | 	"io" | 
 | 	"log" | 
 | 	"net/http" | 
 | 	"os" | 
 | 	"runtime" | 
 | 	"sort" | 
 | 	"strings" | 
 | 	"testing" | 
 | 	"time" | 
 | ) | 
 |  | 
 | var quietLog = log.New(io.Discard, "", 0) | 
 |  | 
 | func TestMain(m *testing.M) { | 
 | 	v := m.Run() | 
 | 	if v == 0 && goroutineLeaked() { | 
 | 		os.Exit(1) | 
 | 	} | 
 | 	os.Exit(v) | 
 | } | 
 |  | 
 | func interestingGoroutines() (gs []string) { | 
 | 	buf := make([]byte, 2<<20) | 
 | 	buf = buf[:runtime.Stack(buf, true)] | 
 | 	for _, g := range strings.Split(string(buf), "\n\n") { | 
 | 		sl := strings.SplitN(g, "\n", 2) | 
 | 		if len(sl) != 2 { | 
 | 			continue | 
 | 		} | 
 | 		stack := strings.TrimSpace(sl[1]) | 
 | 		if stack == "" || | 
 | 			strings.Contains(stack, "testing.(*M).before.func1") || | 
 | 			strings.Contains(stack, "os/signal.signal_recv") || | 
 | 			strings.Contains(stack, "created by net.startServer") || | 
 | 			strings.Contains(stack, "created by testing.RunTests") || | 
 | 			strings.Contains(stack, "closeWriteAndWait") || | 
 | 			strings.Contains(stack, "testing.Main(") || | 
 | 			// These only show up with GOTRACEBACK=2; Issue 5005 (comment 28) | 
 | 			strings.Contains(stack, "runtime.goexit") || | 
 | 			strings.Contains(stack, "created by runtime.gc") || | 
 | 			strings.Contains(stack, "net/http_test.interestingGoroutines") || | 
 | 			strings.Contains(stack, "runtime.MHeap_Scavenger") { | 
 | 			continue | 
 | 		} | 
 | 		gs = append(gs, stack) | 
 | 	} | 
 | 	sort.Strings(gs) | 
 | 	return | 
 | } | 
 |  | 
 | // Verify the other tests didn't leave any goroutines running. | 
 | func goroutineLeaked() bool { | 
 | 	if testing.Short() || runningBenchmarks() { | 
 | 		// Don't worry about goroutine leaks in -short mode or in | 
 | 		// benchmark mode. Too distracting when there are false positives. | 
 | 		return false | 
 | 	} | 
 |  | 
 | 	var stackCount map[string]int | 
 | 	for i := 0; i < 5; i++ { | 
 | 		n := 0 | 
 | 		stackCount = make(map[string]int) | 
 | 		gs := interestingGoroutines() | 
 | 		for _, g := range gs { | 
 | 			stackCount[g]++ | 
 | 			n++ | 
 | 		} | 
 | 		if n == 0 { | 
 | 			return false | 
 | 		} | 
 | 		// Wait for goroutines to schedule and die off: | 
 | 		time.Sleep(100 * time.Millisecond) | 
 | 	} | 
 | 	fmt.Fprintf(os.Stderr, "Too many goroutines running after net/http test(s).\n") | 
 | 	for stack, count := range stackCount { | 
 | 		fmt.Fprintf(os.Stderr, "%d instances of:\n%s\n", count, stack) | 
 | 	} | 
 | 	return true | 
 | } | 
 |  | 
 | // setParallel marks t as a parallel test if we're in short mode | 
 | // (all.bash), but as a serial test otherwise. Using t.Parallel isn't | 
 | // compatible with the afterTest func in non-short mode. | 
 | func setParallel(t *testing.T) { | 
 | 	if strings.Contains(t.Name(), "HTTP2") { | 
 | 		http.CondSkipHTTP2(t) | 
 | 	} | 
 | 	if testing.Short() { | 
 | 		t.Parallel() | 
 | 	} | 
 | } | 
 |  | 
 | func runningBenchmarks() bool { | 
 | 	for i, arg := range os.Args { | 
 | 		if strings.HasPrefix(arg, "-test.bench=") && !strings.HasSuffix(arg, "=") { | 
 | 			return true | 
 | 		} | 
 | 		if arg == "-test.bench" && i < len(os.Args)-1 && os.Args[i+1] != "" { | 
 | 			return true | 
 | 		} | 
 | 	} | 
 | 	return false | 
 | } | 
 |  | 
 | func afterTest(t testing.TB) { | 
 | 	http.DefaultTransport.(*http.Transport).CloseIdleConnections() | 
 | 	if testing.Short() { | 
 | 		return | 
 | 	} | 
 | 	var bad string | 
 | 	badSubstring := map[string]string{ | 
 | 		").readLoop(":  "a Transport", | 
 | 		").writeLoop(": "a Transport", | 
 | 		"created by net/http/httptest.(*Server).Start": "an httptest.Server", | 
 | 		"timeoutHandler":        "a TimeoutHandler", | 
 | 		"net.(*netFD).connect(": "a timing out dial", | 
 | 		").noteClientGone(":     "a closenotifier sender", | 
 | 	} | 
 | 	var stacks string | 
 | 	for i := 0; i < 10; i++ { | 
 | 		bad = "" | 
 | 		stacks = strings.Join(interestingGoroutines(), "\n\n") | 
 | 		for substr, what := range badSubstring { | 
 | 			if strings.Contains(stacks, substr) { | 
 | 				bad = what | 
 | 			} | 
 | 		} | 
 | 		if bad == "" { | 
 | 			return | 
 | 		} | 
 | 		// Bad stuff found, but goroutines might just still be | 
 | 		// shutting down, so give it some time. | 
 | 		time.Sleep(250 * time.Millisecond) | 
 | 	} | 
 | 	t.Errorf("Test appears to have leaked %s:\n%s", bad, stacks) | 
 | } | 
 |  | 
 | // waitCondition reports whether fn eventually returned true, | 
 | // checking immediately and then every checkEvery amount, | 
 | // until waitFor has elapsed, at which point it returns false. | 
 | func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool { | 
 | 	deadline := time.Now().Add(waitFor) | 
 | 	for time.Now().Before(deadline) { | 
 | 		if fn() { | 
 | 			return true | 
 | 		} | 
 | 		time.Sleep(checkEvery) | 
 | 	} | 
 | 	return false | 
 | } | 
 |  | 
 | // waitErrCondition is like waitCondition but with errors instead of bools. | 
 | func waitErrCondition(waitFor, checkEvery time.Duration, fn func() error) error { | 
 | 	deadline := time.Now().Add(waitFor) | 
 | 	var err error | 
 | 	for time.Now().Before(deadline) { | 
 | 		if err = fn(); err == nil { | 
 | 			return nil | 
 | 		} | 
 | 		time.Sleep(checkEvery) | 
 | 	} | 
 | 	return err | 
 | } |