}
func TestClient(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(robotsTxtHandler)
defer ts.Close()
}
func TestClientHead(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(robotsTxtHandler)
defer ts.Close()
}
func TestGetRequestFormat(t *testing.T) {
+ defer checkLeakedTransports(t)
tr := &recordingTransport{}
client := &Client{Transport: tr}
url := "http://dummy.faketld/"
}
func TestPostRequestFormat(t *testing.T) {
+ defer checkLeakedTransports(t)
tr := &recordingTransport{}
client := &Client{Transport: tr}
}
func TestPostFormRequestFormat(t *testing.T) {
+ defer checkLeakedTransports(t)
tr := &recordingTransport{}
client := &Client{Transport: tr}
}
func TestRedirects(t *testing.T) {
+ defer checkLeakedTransports(t)
var ts *httptest.Server
ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
n, _ := strconv.Atoi(r.FormValue("n"))
if err != nil {
t.Fatalf("Get error: %v", err)
}
+ res.Body.Close()
finalUrl := res.Request.URL.String()
if e, g := "<nil>", fmt.Sprintf("%v", err); e != g {
t.Errorf("with custom client, expected error %q, got %q", e, g)
if res == nil {
t.Fatalf("Expected a non-nil Response on CheckRedirect failure (http://golang.org/issue/3795)")
}
+ res.Body.Close()
if res.Header.Get("Location") == "" {
t.Errorf("no Location header in Response")
}
}
func TestPostRedirects(t *testing.T) {
+ defer checkLeakedTransports(t)
var log struct {
sync.Mutex
bytes.Buffer
w.WriteHeader(code)
}
}))
+ defer ts.Close()
tests := []struct {
suffix string
want int // response code
}
func TestRedirectCookiesOnRequest(t *testing.T) {
+ defer checkLeakedTransports(t)
var ts *httptest.Server
ts = httptest.NewServer(echoCookiesRedirectHandler)
defer ts.Close()
}
func TestRedirectCookiesJar(t *testing.T) {
+ defer checkLeakedTransports(t)
var ts *httptest.Server
ts = httptest.NewServer(echoCookiesRedirectHandler)
defer ts.Close()
if err != nil {
t.Fatalf("Get: %v", err)
}
+ resp.Body.Close()
matchReturnedCookies(t, expectedCookies, resp.Cookies())
}
}
func TestJarCalls(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
pathSuffix := r.RequestURI[1:]
if r.RequestURI == "/nosetcookie" {
}
func TestStreamingGet(t *testing.T) {
+ defer checkLeakedTransports(t)
say := make(chan string)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.(Flusher).Flush()
// TestClientWrites verifies that client requests are buffered and we
// don't send a TCP packet per line of the http request + body.
func TestClientWrites(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
}))
defer ts.Close()
}
func TestClientInsecureTransport(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Write([]byte("Hello"))
}))
InsecureSkipVerify: insecure,
},
}
+ defer tr.CloseIdleConnections()
c := &Client{Transport: tr}
- _, err := c.Get(ts.URL)
+ res, err := c.Get(ts.URL)
if (err == nil) != insecure {
t.Errorf("insecure=%v: got unexpected err=%v", insecure, err)
}
+ if res != nil {
+ res.Body.Close()
+ }
}
}
func TestClientErrorWithRequestURI(t *testing.T) {
+ defer checkLeakedTransports(t)
req, _ := NewRequest("GET", "http://localhost:1234/", nil)
req.RequestURI = "/this/field/is/illegal/and/should/error/"
_, err := DefaultClient.Do(req)
}
func TestClientWithCorrectTLSServerName(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.TLS.ServerName != "127.0.0.1" {
t.Errorf("expected client to set ServerName 127.0.0.1, got: %q", r.TLS.ServerName)
}
func TestClientWithIncorrectTLSServerName(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
defer ts.Close()
// Verify Response.ContentLength is populated. http://golang.org/issue/4126
func TestClientHeadContentLength(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if v := r.FormValue("cl"); v != "" {
w.Header().Set("Content-Length", v)
if res.StatusCode != 404 {
t.Errorf("for %s, StatusCode = %d, want 404", badURL, res.StatusCode)
}
+ res.Body.Close()
}
}
func TestServeFile(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ServeFile(w, r, "testdata/file")
}))
}
func TestFSRedirect(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(StripPrefix("/test", FileServer(Dir("."))))
defer ts.Close()
}
func TestFileServerCleans(t *testing.T) {
+ defer checkLeakedTransports(t)
ch := make(chan string, 1)
fs := FileServer(&testFileSystem{func(name string) (File, error) {
ch <- name
}
func TestFileServerImplicitLeadingSlash(t *testing.T) {
+ defer checkLeakedTransports(t)
tempDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("TempDir: %v", err)
}
func TestServeFileContentType(t *testing.T) {
+ defer checkLeakedTransports(t)
const ctype = "icecream/chocolate"
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.FormValue("override") == "1" {
if h := resp.Header.Get("Content-Type"); h != want {
t.Errorf("Content-Type mismatch: got %q, want %q", h, want)
}
+ resp.Body.Close()
}
get("0", "text/plain; charset=utf-8")
get("1", ctype)
}
func TestServeFileMimeType(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ServeFile(w, r, "testdata/style.css")
}))
if err != nil {
t.Fatal(err)
}
+ resp.Body.Close()
want := "text/css; charset=utf-8"
if h := resp.Header.Get("Content-Type"); h != want {
t.Errorf("Content-Type mismatch: got %q, want %q", h, want)
}
func TestServeFileFromCWD(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ServeFile(w, r, "fs_test.go")
}))
}
func TestServeFileWithContentEncoding(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Content-Encoding", "foo")
ServeFile(w, r, "testdata/file")
if err != nil {
t.Fatal(err)
}
+ resp.Body.Close()
if g, e := resp.ContentLength, int64(-1); g != e {
t.Errorf("Content-Length mismatch: got %d, want %d", g, e)
}
}
func TestServeIndexHtml(t *testing.T) {
+ defer checkLeakedTransports(t)
const want = "index.html says hello\n"
ts := httptest.NewServer(FileServer(Dir(".")))
defer ts.Close()
}
func TestFileServerZeroByte(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(FileServer(Dir(".")))
defer ts.Close()
}
func TestDirectoryIfNotModified(t *testing.T) {
+ defer checkLeakedTransports(t)
const indexContents = "I am a fake index.html file"
fileMod := time.Unix(1000000000, 0).UTC()
fileModStr := fileMod.Format(TimeFormat)
}
func TestServeContent(t *testing.T) {
+ defer checkLeakedTransports(t)
type serveParam struct {
name string
modtime time.Time
// verifies that sendfile is being used on Linux
func TestLinuxSendfile(t *testing.T) {
+ defer checkLeakedTransports(t)
if runtime.GOOS != "linux" {
t.Skip("skipping; linux-only test")
}
}
func TestHostHandlers(t *testing.T) {
+ defer checkLeakedTransports(t)
mux := NewServeMux()
for _, h := range handlers {
mux.Handle(h.pattern, stringHandler(h.msg))
}
func TestServerTimeouts(t *testing.T) {
+ defer checkLeakedTransports(t)
reqNum := 0
ts := httptest.NewUnstartedServer(HandlerFunc(func(res ResponseWriter, req *Request) {
reqNum++
// Hit the HTTP server successfully.
tr := &Transport{DisableKeepAlives: true} // they interfere with this test
+ defer tr.CloseIdleConnections()
c := &Client{Transport: tr}
r, err := c.Get(ts.URL)
if err != nil {
// shouldn't cause a handler to block forever on reads (next HTTP
// request) that will never happen.
func TestOnlyWriteTimeout(t *testing.T) {
+ defer checkLeakedTransports(t)
var conn net.Conn
var afterTimeoutErrc = make(chan error, 1)
ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, req *Request) {
// TestIdentityResponse verifies that a handler can unset
func TestIdentityResponse(t *testing.T) {
+ defer checkLeakedTransports(t)
handler := HandlerFunc(func(rw ResponseWriter, req *Request) {
rw.Header().Set("Content-Length", "3")
rw.Header().Set("Transfer-Encoding", req.FormValue("te"))
// Verify that ErrContentLength is returned
url := ts.URL + "/?overwrite=1"
- _, err := Get(url)
+ res, err := Get(url)
if err != nil {
t.Fatalf("error with Get of %s: %v", url, err)
}
+ res.Body.Close()
+
// Verify that the connection is closed when the declared Content-Length
// is larger than what the handler wrote.
conn, err := net.Dial("tcp", ts.Listener.Addr().String())
}
func testTCPConnectionCloses(t *testing.T, req string, h Handler) {
+ defer checkLeakedTransports(t)
s := httptest.NewServer(h)
defer s.Close()
}
func TestSetsRemoteAddr(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "%s", r.RemoteAddr)
}))
}
func TestChunkedResponseHeaders(t *testing.T) {
+ defer checkLeakedTransports(t)
log.SetOutput(ioutil.Discard) // is noisy otherwise
defer log.SetOutput(os.Stderr)
if err != nil {
t.Fatalf("Get error: %v", err)
}
+ defer res.Body.Close()
if g, e := res.ContentLength, int64(-1); g != e {
t.Errorf("expected ContentLength of %d; got %d", e, g)
}
// chunking in their response headers and aren't allowed to produce
// output.
func Test304Responses(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.WriteHeader(StatusNotModified)
_, err := w.Write([]byte("illegal body"))
// allowed to produce output, and don't set a Content-Type since
// the real type of the body data cannot be inferred.
func TestHeadResponses(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
_, err := w.Write([]byte("Ignored body"))
if err != ErrBodyNotAllowed {
}
func TestTLSHandshakeTimeout(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
ts.Config.ReadTimeout = 250 * time.Millisecond
ts.StartTLS()
}
func TestTLSServer(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.TLS != nil {
w.Header().Set("X-TLS-Set", "true")
// Tests that the server responds to the "Expect" request header
// correctly.
func TestServerExpect(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
// Note using r.FormValue("readbody") because for POST
// requests that would read from r.Body, which we only
}
func TestTimeoutHandler(t *testing.T) {
+ defer checkLeakedTransports(t)
sendHi := make(chan bool, 1)
writeErrors := make(chan error, 1)
sayHi := HandlerFunc(func(w ResponseWriter, r *Request) {
// the previous request's body, which is not optimal for zero-lengthed bodies,
// as the client would then see http.ErrBodyReadAfterClose and not 0, io.EOF.
func TestZeroLengthPostAndResponse(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
all, err := ioutil.ReadAll(r.Body)
if err != nil {
}
func testHandlerPanic(t *testing.T, withHijack bool, panicValue interface{}) {
+ defer checkLeakedTransports(t)
// Unlike the other tests that set the log output to ioutil.Discard
// to quiet the output, this test uses a pipe. The pipe serves three
// purposes:
pr, pw := io.Pipe()
log.SetOutput(pw)
defer log.SetOutput(os.Stderr)
+ defer pw.Close()
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if withHijack {
buf := make([]byte, 4<<10)
_, err := pr.Read(buf)
pr.Close()
- if err != nil {
+ if err != nil && err != io.EOF {
t.Error(err)
}
done <- true
}
func TestNoDate(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header()["Date"] = nil
}))
}
func TestStripPrefix(t *testing.T) {
+ defer checkLeakedTransports(t)
h := HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("X-Path", r.URL.Path)
})
if g, e := res.Header.Get("X-Path"), "/bar"; g != e {
t.Errorf("test 1: got %s, want %s", g, e)
}
+ res.Body.Close()
res, err = Get(ts.URL + "/bar")
if err != nil {
if g, e := res.StatusCode, 404; g != e {
t.Errorf("test 2: got status %v, want %v", g, e)
}
+ res.Body.Close()
}
func TestRequestLimit(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
t.Fatalf("didn't expect to get request in Handler")
}))
// we do support it (at least currently), so we expect a response below.
t.Fatalf("Do: %v", err)
}
+ defer res.Body.Close()
if res.StatusCode != 413 {
t.Fatalf("expected 413 response status; got: %d %s", res.StatusCode, res.Status)
}
}
func TestRequestBodyLimit(t *testing.T) {
+ defer checkLeakedTransports(t)
const limit = 1 << 20
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
r.Body = MaxBytesReader(w, r.Body, limit)
// TestClientWriteShutdown tests that if the client shuts down the write
// side of their TCP connection, the server doesn't send a 400 Bad Request.
func TestClientWriteShutdown(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
defer ts.Close()
conn, err := net.Dial("tcp", ts.Listener.Addr().String())
// closing the TCP connection, causing the client to get a RST.
// See http://golang.org/issue/3595
func TestServerGracefulClose(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
Error(w, "bye", StatusUnauthorized)
}))
}
func TestCaseSensitiveMethod(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.Method != "get" {
t.Errorf(`Got method %q; want "get"`, r.Method)
}
func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) {
- done := make(chan bool)
+ done := make(chan bool, 1)
tw := &timeoutWriter{w: w}
go func() {
h.handler.ServeHTTP(tw, r)
if err == nil {
resp, err = ReadResponse(pc.br, rc.req)
}
+ hasBody := resp != nil && rc.req.Method != "HEAD" && resp.ContentLength != 0
if err != nil {
pc.close()
} else {
- hasBody := rc.req.Method != "HEAD" && resp.ContentLength != 0
if rc.addedGzip && hasBody && resp.Header.Get("Content-Encoding") == "gzip" {
resp.Header.Del("Content-Encoding")
resp.Header.Del("Content-Length")
alive = false
}
- hasBody := resp != nil && rc.req.Method != "HEAD" && resp.ContentLength != 0
var waitForBodyRead chan bool
if hasBody {
lastbody = resp.Body
// Two subsequent requests and verify their response is the same.
// The response from the server is our own IP:port
func TestTransportKeepAlives(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(hostPortHandler)
defer ts.Close()
for _, disableKeepAlive := range []bool{false, true} {
tr := &Transport{DisableKeepAlives: disableKeepAlive}
+ defer tr.CloseIdleConnections()
c := &Client{Transport: tr}
fetch := func(n int) string {
}
func TestTransportConnectionCloseOnResponse(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(hostPortHandler)
defer ts.Close()
}
func TestTransportConnectionCloseOnRequest(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(hostPortHandler)
defer ts.Close()
}
func TestTransportIdleCacheKeys(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(hostPortHandler)
defer ts.Close()
}
func TestTransportMaxPerHostIdleConns(t *testing.T) {
+ defer checkLeakedTransports(t)
resch := make(chan string)
gotReq := make(chan bool)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
}
func TestTransportServerClosingUnexpectedly(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(hostPortHandler)
defer ts.Close()
// Test for http://golang.org/issue/2616 (appropriate issue number)
// This fails pretty reliably with GOMAXPROCS=100 or something high.
func TestStressSurpriseServerCloses(t *testing.T) {
+ defer checkLeakedTransports(t)
if testing.Short() {
t.Skip("skipping test in short mode")
}
// TestTransportHeadResponses verifies that we deal with Content-Lengths
// with no bodies properly
func TestTransportHeadResponses(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.Method != "HEAD" {
panic("expected HEAD; got " + r.Method)
// TestTransportHeadChunkedResponse verifies that we ignore chunked transfer-encoding
// on responses to HEAD requests.
func TestTransportHeadChunkedResponse(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.Method != "HEAD" {
panic("expected HEAD; got " + r.Method)
// Test that the modification made to the Request by the RoundTripper is cleaned up
func TestRoundTripGzip(t *testing.T) {
+ defer checkLeakedTransports(t)
const responseBody = "test response body"
ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
accept := req.Header.Get("Accept-Encoding")
}
func TestTransportGzip(t *testing.T) {
+ defer checkLeakedTransports(t)
const testString = "The test string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
const nRandBytes = 1024 * 1024
ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
}
func TestTransportProxy(t *testing.T) {
+ defer checkLeakedTransports(t)
ch := make(chan string, 1)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ch <- "real server"
// but checks that we don't recurse forever, and checks that
// Content-Encoding is removed.
func TestTransportGzipRecursive(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Content-Encoding", "gzip")
w.Write(rgz)
// tests that persistent goroutine connections shut down when no longer desired.
func TestTransportPersistConnLeak(t *testing.T) {
+ defer checkLeakedTransports(t)
gotReqCh := make(chan bool)
unblockCh := make(chan bool)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
// golang.org/issue/4531: Transport leaks goroutines when
// request.ContentLength is explicitly short
func TestTransportPersistConnLeakShortBody(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
}))
defer ts.Close()
// This used to crash; http://golang.org/issue/3266
func TestTransportIdleConnCrash(t *testing.T) {
+ defer checkLeakedTransports(t)
tr := &Transport{}
c := &Client{Transport: tr}
// which sadly lacked a triggering test. The large response body made
// the old race easier to trigger.
func TestIssue3644(t *testing.T) {
+ defer checkLeakedTransports(t)
const numFoos = 5000
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Connection", "close")
// Test that a client receives a server's reply, even if the server doesn't read
// the entire request body.
func TestIssue3595(t *testing.T) {
+ defer checkLeakedTransports(t)
const deniedMsg = "sorry, denied."
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
Error(w, deniedMsg, StatusUnauthorized)
// From http://golang.org/issue/4454 ,
// "client fails to handle requests with no body and chunked encoding"
func TestChunkedNoContent(t *testing.T) {
+ defer checkLeakedTransports(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.WriteHeader(StatusNoContent)
}))
}
func TestTransportConcurrency(t *testing.T) {
+ defer checkLeakedTransports(t)
const maxProcs = 16
const numReqs = 500
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
}
func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
+ defer checkLeakedTransports(t)
const debug = false
mux := NewServeMux()
mux.HandleFunc("/get", func(w ResponseWriter, r *Request) {
}
func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) {
+ defer checkLeakedTransports(t)
const debug = false
mux := NewServeMux()
mux.HandleFunc("/get", func(w ResponseWriter, r *Request) {
}
func TestTransportAltProto(t *testing.T) {
+ defer checkLeakedTransports(t)
tr := &Transport{}
c := &Client{Transport: tr}
tr.RegisterProtocol("foo", fooProto{})
}
func TestTransportNoHost(t *testing.T) {
+ defer checkLeakedTransports(t)
tr := &Transport{}
_, err := tr.RoundTrip(&Request{
Header: make(Header),
--- /dev/null
+// 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 (
+ "net/http"
+ "runtime"
+ "strings"
+ "testing"
+ "time"
+)
+
+// Verify the other tests didn't leave any goroutines running.
+// This is in a file named z_last_test.go so it sorts at the end.
+func TestGoroutinesRunning(t *testing.T) {
+ n := runtime.NumGoroutine()
+ t.Logf("num goroutines = %d", n)
+ if n > 20 {
+ // Currently 14 on Linux (blocked in epoll_wait,
+ // waiting for on fds that are closed?), but give some
+ // slop for now.
+ buf := make([]byte, 1<<20)
+ buf = buf[:runtime.Stack(buf, true)]
+ t.Errorf("Too many goroutines:\n%s", buf)
+ }
+}
+
+func checkLeakedTransports(t *testing.T) {
+ http.DefaultTransport.(*http.Transport).CloseIdleConnections()
+ if testing.Short() {
+ return
+ }
+ buf := make([]byte, 1<<20)
+ var stacks string
+ 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",
+ }
+ for i := 0; i < 4; i++ {
+ bad = ""
+ stacks = string(buf[:runtime.Stack(buf, true)])
+ 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)
+}