diff options
| author | Damien Neil <dneil@google.com> | 2022-10-03 16:07:48 -0700 |
|---|---|---|
| committer | Damien Neil <dneil@google.com> | 2022-10-07 16:53:14 +0000 |
| commit | 747e1961e95c2eb3df62e045b90b111c2ceea337 (patch) | |
| tree | 59a7c933ffe695cac3c9c48e8c8e8afa068b0985 /src/net/http/client_test.go | |
| parent | 5ca0cd3f1824f189b6c5edf59b669f22a393e2e1 (diff) | |
| download | go-747e1961e95c2eb3df62e045b90b111c2ceea337.tar.xz | |
net/http: refactor tests to run most in HTTP/1 and HTTP/2 modes
Replace the ad-hoc approach to running tests in HTTP/1 and HTTP/2
modes with a 'run' function that executes a test in various modes.
By default, these modes are HTTP/1 and HTTP/2, but tests can
opt-in to HTTPS/1 as well.
The 'run' function also takes care of post-test cleanup (running the
afterTest function).
The 'run' function runs tests in parallel by default. Tests which
can't run in parallel (generally because they use global test hooks)
pass a testNotParallel option to disable parallelism.
Update clientServerTest to use t.Cleanup to clean up after itself,
rather than leaving this up to tests to handle.
Drop an unnecessary mutex in SetReadLoopBeforeNextReadHook.
Test hooks can't be set in parallel, and we want the race detector
to notify us if two simultaneous tests try to set a hook.
Fixes #56032
Change-Id: I16be64913c426fc93d84abc6ad85dbd3bc191224
Reviewed-on: https://go-review.googlesource.com/c/go/+/438137
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Damien Neil <dneil@google.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Diffstat (limited to 'src/net/http/client_test.go')
| -rw-r--r-- | src/net/http/client_test.go | 337 |
1 files changed, 134 insertions, 203 deletions
diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go index 44b532ae1f..8b53c41687 100644 --- a/src/net/http/client_test.go +++ b/src/net/http/client_test.go @@ -67,11 +67,9 @@ func (w chanWriter) Write(p []byte) (n int, err error) { return len(p), nil } -func TestClient(t *testing.T) { - setParallel(t) - defer afterTest(t) - ts := httptest.NewServer(robotsTxtHandler) - defer ts.Close() +func TestClient(t *testing.T) { run(t, testClient) } +func testClient(t *testing.T, mode testMode) { + ts := newClientServerTest(t, mode, robotsTxtHandler).ts c := ts.Client() r, err := c.Get(ts.URL) @@ -87,14 +85,9 @@ func TestClient(t *testing.T) { } } -func TestClientHead_h1(t *testing.T) { testClientHead(t, h1Mode) } -func TestClientHead_h2(t *testing.T) { testClientHead(t, h2Mode) } - -func testClientHead(t *testing.T, h2 bool) { - defer afterTest(t) - cst := newClientServerTest(t, h2, robotsTxtHandler) - defer cst.close() - +func TestClientHead(t *testing.T) { run(t, testClientHead) } +func testClientHead(t *testing.T, mode testMode) { + cst := newClientServerTest(t, mode, robotsTxtHandler) r, err := cst.c.Head(cst.ts.URL) if err != nil { t.Fatal(err) @@ -200,11 +193,10 @@ func TestPostFormRequestFormat(t *testing.T) { } } -func TestClientRedirects(t *testing.T) { - setParallel(t) - defer afterTest(t) +func TestClientRedirects(t *testing.T) { run(t, testClientRedirects) } +func testClientRedirects(t *testing.T, mode testMode) { var ts *httptest.Server - ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + ts = newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { n, _ := strconv.Atoi(r.FormValue("n")) // Test Referer header. (7 is arbitrary position to test at) if n == 7 { @@ -217,8 +209,7 @@ func TestClientRedirects(t *testing.T) { return } fmt.Fprintf(w, "n=%d", n) - })) - defer ts.Close() + })).ts c := ts.Client() _, err := c.Get(ts.URL) @@ -299,13 +290,11 @@ func TestClientRedirects(t *testing.T) { } // Tests that Client redirects' contexts are derived from the original request's context. -func TestClientRedirectContext(t *testing.T) { - setParallel(t) - defer afterTest(t) - ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { +func TestClientRedirectsContext(t *testing.T) { run(t, testClientRedirectsContext) } +func testClientRedirectsContext(t *testing.T, mode testMode) { + ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { Redirect(w, r, "/", StatusTemporaryRedirect) - })) - defer ts.Close() + })).ts ctx, cancel := context.WithCancel(context.Background()) c := ts.Client() @@ -373,7 +362,9 @@ func TestPostRedirects(t *testing.T) { `POST /?code=404 "c404"`, } want := strings.Join(wantSegments, "\n") - testRedirectsByMethod(t, "POST", postRedirectTests, want) + run(t, func(t *testing.T, mode testMode) { + testRedirectsByMethod(t, mode, "POST", postRedirectTests, want) + }) } func TestDeleteRedirects(t *testing.T) { @@ -410,17 +401,18 @@ func TestDeleteRedirects(t *testing.T) { `DELETE /?code=404 "c404"`, } want := strings.Join(wantSegments, "\n") - testRedirectsByMethod(t, "DELETE", deleteRedirectTests, want) + run(t, func(t *testing.T, mode testMode) { + testRedirectsByMethod(t, mode, "DELETE", deleteRedirectTests, want) + }) } -func testRedirectsByMethod(t *testing.T, method string, table []redirectTest, want string) { - defer afterTest(t) +func testRedirectsByMethod(t *testing.T, mode testMode, method string, table []redirectTest, want string) { var log struct { sync.Mutex bytes.Buffer } var ts *httptest.Server - ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + ts = newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { log.Lock() slurp, _ := io.ReadAll(r.Body) fmt.Fprintf(&log.Buffer, "%s %s %q", r.Method, r.RequestURI, slurp) @@ -445,8 +437,7 @@ func testRedirectsByMethod(t *testing.T, method string, table []redirectTest, wa } w.WriteHeader(code) } - })) - defer ts.Close() + })).ts c := ts.Client() for _, tt := range table { @@ -491,12 +482,11 @@ func removeCommonLines(a, b string) (asuffix, bsuffix string, commonLines int) { } } -func TestClientRedirectUseResponse(t *testing.T) { - setParallel(t) - defer afterTest(t) +func TestClientRedirectUseResponse(t *testing.T) { run(t, testClientRedirectUseResponse) } +func testClientRedirectUseResponse(t *testing.T, mode testMode) { const body = "Hello, world." var ts *httptest.Server - ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + ts = newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { if strings.Contains(r.URL.Path, "/other") { io.WriteString(w, "wrong body") } else { @@ -504,8 +494,7 @@ func TestClientRedirectUseResponse(t *testing.T) { w.WriteHeader(StatusFound) io.WriteString(w, body) } - })) - defer ts.Close() + })).ts c := ts.Client() c.CheckRedirect = func(req *Request, via []*Request) error { @@ -533,18 +522,16 @@ func TestClientRedirectUseResponse(t *testing.T) { // Issues 17773 and 49281: don't follow a 3xx if the response doesn't // have a Location header. -func TestClientRedirectNoLocation(t *testing.T) { +func TestClientRedirectNoLocation(t *testing.T) { run(t, testClientRedirectNoLocation) } +func testClientRedirectNoLocation(t *testing.T, mode testMode) { for _, code := range []int{301, 308} { t.Run(fmt.Sprint(code), func(t *testing.T) { setParallel(t) - defer afterTest(t) - ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { w.Header().Set("Foo", "Bar") w.WriteHeader(code) })) - defer ts.Close() - c := ts.Client() - res, err := c.Get(ts.URL) + res, err := cst.c.Get(cst.ts.URL) if err != nil { t.Fatal(err) } @@ -560,15 +547,13 @@ func TestClientRedirectNoLocation(t *testing.T) { } // Don't follow a 307/308 if we can't resent the request body. -func TestClientRedirect308NoGetBody(t *testing.T) { - setParallel(t) - defer afterTest(t) +func TestClientRedirect308NoGetBody(t *testing.T) { run(t, testClientRedirect308NoGetBody) } +func testClientRedirect308NoGetBody(t *testing.T, mode testMode) { const fakeURL = "https://localhost:1234/" // won't be hit - ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { w.Header().Set("Location", fakeURL) w.WriteHeader(308) - })) - defer ts.Close() + })).ts req, err := NewRequest("POST", ts.URL, strings.NewReader("some body")) if err != nil { t.Fatal(err) @@ -659,12 +644,10 @@ func (j *TestJar) Cookies(u *url.URL) []*Cookie { return j.perURL[u.Host] } -func TestRedirectCookiesJar(t *testing.T) { - setParallel(t) - defer afterTest(t) +func TestRedirectCookiesJar(t *testing.T) { run(t, testRedirectCookiesJar) } +func testRedirectCookiesJar(t *testing.T, mode testMode) { var ts *httptest.Server - ts = httptest.NewServer(echoCookiesRedirectHandler) - defer ts.Close() + ts = newClientServerTest(t, mode, echoCookiesRedirectHandler).ts c := ts.Client() c.Jar = new(TestJar) u, _ := url.Parse(ts.URL) @@ -696,9 +679,9 @@ func matchReturnedCookies(t *testing.T, expected, given []*Cookie) { } } -func TestJarCalls(t *testing.T) { - defer afterTest(t) - ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { +func TestJarCalls(t *testing.T) { run(t, testJarCalls, []testMode{http1Mode}) } +func testJarCalls(t *testing.T, mode testMode) { + ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { pathSuffix := r.RequestURI[1:] if r.RequestURI == "/nosetcookie" { return // don't set cookies for this path @@ -707,8 +690,7 @@ func TestJarCalls(t *testing.T) { if r.RequestURI == "/" { Redirect(w, r, "http://secondhost.fake/secondpath", 302) } - })) - defer ts.Close() + })).ts jar := new(RecordingJar) c := ts.Client() c.Jar = jar @@ -757,20 +739,16 @@ func (j *RecordingJar) logf(format string, args ...any) { fmt.Fprintf(&j.log, format, args...) } -func TestStreamingGet_h1(t *testing.T) { testStreamingGet(t, h1Mode) } -func TestStreamingGet_h2(t *testing.T) { testStreamingGet(t, h2Mode) } - -func testStreamingGet(t *testing.T, h2 bool) { - defer afterTest(t) +func TestStreamingGet(t *testing.T) { run(t, testStreamingGet) } +func testStreamingGet(t *testing.T, mode testMode) { say := make(chan string) - cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { + cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { w.(Flusher).Flush() for str := range say { w.Write([]byte(str)) w.(Flusher).Flush() } })) - defer cst.close() c := cst.c res, err := c.Get(cst.ts.URL) @@ -811,11 +789,10 @@ func (c *writeCountingConn) Write(p []byte) (int, error) { // 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 afterTest(t) - ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { - })) - defer ts.Close() +func TestClientWrites(t *testing.T) { run(t, testClientWrites, []testMode{http1Mode}) } +func testClientWrites(t *testing.T, mode testMode) { + ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { + })).ts writes := 0 dialer := func(netz string, addr string) (net.Conn, error) { @@ -847,11 +824,12 @@ func TestClientWrites(t *testing.T) { } func TestClientInsecureTransport(t *testing.T) { - setParallel(t) - defer afterTest(t) - ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { + run(t, testClientInsecureTransport, []testMode{https1Mode, http2Mode}) +} +func testClientInsecureTransport(t *testing.T, mode testMode) { + ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { w.Write([]byte("Hello")) - })) + })).ts errc := make(chanWriter, 10) // but only expecting 1 ts.Config.ErrorLog = log.New(errc, "", 0) defer ts.Close() @@ -898,15 +876,15 @@ func TestClientErrorWithRequestURI(t *testing.T) { } func TestClientWithCorrectTLSServerName(t *testing.T) { - defer afterTest(t) - + run(t, testClientWithCorrectTLSServerName, []testMode{https1Mode, http2Mode}) +} +func testClientWithCorrectTLSServerName(t *testing.T, mode testMode) { const serverName = "example.com" - ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { + ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { if r.TLS.ServerName != serverName { t.Errorf("expected client to set ServerName %q, got: %q", serverName, r.TLS.ServerName) } - })) - defer ts.Close() + })).ts c := ts.Client() c.Transport.(*Transport).TLSClientConfig.ServerName = serverName @@ -916,9 +894,10 @@ func TestClientWithCorrectTLSServerName(t *testing.T) { } func TestClientWithIncorrectTLSServerName(t *testing.T) { - defer afterTest(t) - ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) - defer ts.Close() + run(t, testClientWithIncorrectTLSServerName, []testMode{https1Mode, http2Mode}) +} +func testClientWithIncorrectTLSServerName(t *testing.T, mode testMode) { + ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {})).ts errc := make(chanWriter, 10) // but only expecting 1 ts.Config.ErrorLog = log.New(errc, "", 0) @@ -951,11 +930,12 @@ func TestClientWithIncorrectTLSServerName(t *testing.T) { // // The httptest.Server has a cert with "example.com" as its name. func TestTransportUsesTLSConfigServerName(t *testing.T) { - defer afterTest(t) - ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { + run(t, testTransportUsesTLSConfigServerName, []testMode{https1Mode, http2Mode}) +} +func testTransportUsesTLSConfigServerName(t *testing.T, mode testMode) { + ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { w.Write([]byte("Hello")) - })) - defer ts.Close() + })).ts c := ts.Client() tr := c.Transport.(*Transport) @@ -971,11 +951,12 @@ func TestTransportUsesTLSConfigServerName(t *testing.T) { } func TestResponseSetsTLSConnectionState(t *testing.T) { - defer afterTest(t) - ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { + run(t, testResponseSetsTLSConnectionState, []testMode{https1Mode}) +} +func testResponseSetsTLSConnectionState(t *testing.T, mode testMode) { + ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { w.Write([]byte("Hello")) - })) - defer ts.Close() + })).ts c := ts.Client() tr := c.Transport.(*Transport) @@ -1001,10 +982,11 @@ func TestResponseSetsTLSConnectionState(t *testing.T) { // to determine that the server is speaking HTTP. // See golang.org/issue/11111. func TestHTTPSClientDetectsHTTPServer(t *testing.T) { - defer afterTest(t) - ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) + run(t, testHTTPSClientDetectsHTTPServer, []testMode{http1Mode}) +} +func testHTTPSClientDetectsHTTPServer(t *testing.T, mode testMode) { + ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {})).ts ts.Config.ErrorLog = quietLog - defer ts.Close() _, err := Get(strings.Replace(ts.URL, "http", "https", 1)) if got := err.Error(); !strings.Contains(got, "HTTP response to HTTPS client") { @@ -1013,22 +995,13 @@ func TestHTTPSClientDetectsHTTPServer(t *testing.T) { } // Verify Response.ContentLength is populated. https://golang.org/issue/4126 -func TestClientHeadContentLength_h1(t *testing.T) { - testClientHeadContentLength(t, h1Mode) -} - -func TestClientHeadContentLength_h2(t *testing.T) { - testClientHeadContentLength(t, h2Mode) -} - -func testClientHeadContentLength(t *testing.T, h2 bool) { - defer afterTest(t) - cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { +func TestClientHeadContentLength(t *testing.T) { run(t, testClientHeadContentLength) } +func testClientHeadContentLength(t *testing.T, mode testMode) { + cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { if v := r.FormValue("cl"); v != "" { w.Header().Set("Content-Length", v) } })) - defer cst.close() tests := []struct { suffix string want int64 @@ -1056,11 +1029,10 @@ func testClientHeadContentLength(t *testing.T, h2 bool) { } } -func TestEmptyPasswordAuth(t *testing.T) { - setParallel(t) - defer afterTest(t) +func TestEmptyPasswordAuth(t *testing.T) { run(t, testEmptyPasswordAuth) } +func testEmptyPasswordAuth(t *testing.T, mode testMode) { gopher := "gopher" - ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { auth := r.Header.Get("Authorization") if strings.HasPrefix(auth, "Basic ") { encoded := auth[6:] @@ -1076,7 +1048,7 @@ func TestEmptyPasswordAuth(t *testing.T) { } else { t.Errorf("Invalid auth %q", auth) } - })) + })).ts defer ts.Close() req, err := NewRequest("GET", ts.URL, nil) if err != nil { @@ -1205,19 +1177,14 @@ func TestStripPasswordFromError(t *testing.T) { } } -func TestClientTimeout_h1(t *testing.T) { testClientTimeout(t, h1Mode) } -func TestClientTimeout_h2(t *testing.T) { testClientTimeout(t, h2Mode) } - -func testClientTimeout(t *testing.T, h2 bool) { - setParallel(t) - defer afterTest(t) - +func TestClientTimeout(t *testing.T) { run(t, testClientTimeout) } +func testClientTimeout(t *testing.T, mode testMode) { var ( mu sync.Mutex nonce string // a unique per-request string sawSlowNonce bool // true if the handler saw /slow?nonce=<nonce> ) - cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { + cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { _ = r.ParseForm() if r.URL.Path == "/" { Redirect(w, r, "/slow?nonce="+r.Form.Get("nonce"), StatusFound) @@ -1238,7 +1205,6 @@ func testClientTimeout(t *testing.T, h2 bool) { return } })) - defer cst.close() // Try to trigger a timeout after reading part of the response body. // The initial timeout is emprically usually long enough on a decently fast @@ -1308,18 +1274,13 @@ func testClientTimeout(t *testing.T, h2 bool) { } } -func TestClientTimeout_Headers_h1(t *testing.T) { testClientTimeout_Headers(t, h1Mode) } -func TestClientTimeout_Headers_h2(t *testing.T) { testClientTimeout_Headers(t, h2Mode) } - // Client.Timeout firing before getting to the body -func testClientTimeout_Headers(t *testing.T, h2 bool) { - setParallel(t) - defer afterTest(t) +func TestClientTimeout_Headers(t *testing.T) { run(t, testClientTimeout_Headers) } +func testClientTimeout_Headers(t *testing.T, mode testMode) { donec := make(chan bool, 1) - cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { + cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { <-donec }), optQuietLog) - defer cst.close() // Note that we use a channel send here and not a close. // The race detector doesn't know that we're waiting for a timeout // and thinks that the waitgroup inside httptest.Server is added to concurrently @@ -1355,18 +1316,15 @@ func testClientTimeout_Headers(t *testing.T, h2 bool) { // Issue 16094: if Client.Timeout is set but not hit, a Timeout error shouldn't be // returned. -func TestClientTimeoutCancel(t *testing.T) { - setParallel(t) - defer afterTest(t) - +func TestClientTimeoutCancel(t *testing.T) { run(t, testClientTimeoutCancel) } +func testClientTimeoutCancel(t *testing.T, mode testMode) { testDone := make(chan struct{}) ctx, cancel := context.WithCancel(context.Background()) - cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { + cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { w.(Flusher).Flush() <-testDone })) - defer cst.close() defer close(testDone) cst.c.Timeout = 1 * time.Hour @@ -1383,18 +1341,12 @@ func TestClientTimeoutCancel(t *testing.T) { } } -func TestClientTimeoutDoesNotExpire_h1(t *testing.T) { testClientTimeoutDoesNotExpire(t, h1Mode) } -func TestClientTimeoutDoesNotExpire_h2(t *testing.T) { testClientTimeoutDoesNotExpire(t, h2Mode) } - // Issue 49366: if Client.Timeout is set but not hit, no error should be returned. -func testClientTimeoutDoesNotExpire(t *testing.T, h2 bool) { - setParallel(t) - defer afterTest(t) - - cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { +func TestClientTimeoutDoesNotExpire(t *testing.T) { run(t, testClientTimeoutDoesNotExpire) } +func testClientTimeoutDoesNotExpire(t *testing.T, mode testMode) { + cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { w.Write([]byte("body")) })) - defer cst.close() cst.c.Timeout = 1 * time.Hour req, _ := NewRequest("GET", cst.ts.URL, nil) @@ -1410,19 +1362,15 @@ func testClientTimeoutDoesNotExpire(t *testing.T, h2 bool) { } } -func TestClientRedirectEatsBody_h1(t *testing.T) { testClientRedirectEatsBody(t, h1Mode) } -func TestClientRedirectEatsBody_h2(t *testing.T) { testClientRedirectEatsBody(t, h2Mode) } -func testClientRedirectEatsBody(t *testing.T, h2 bool) { - setParallel(t) - defer afterTest(t) +func TestClientRedirectEatsBody_h1(t *testing.T) { run(t, testClientRedirectEatsBody) } +func testClientRedirectEatsBody(t *testing.T, mode testMode) { saw := make(chan string, 2) - cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { + cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { saw <- r.RemoteAddr if r.URL.Path == "/" { Redirect(w, r, "/foo", StatusFound) // which includes a body } })) - defer cst.close() res, err := cst.c.Get(cst.ts.URL) if err != nil { @@ -1522,13 +1470,14 @@ func TestClientRedirectResponseWithoutRequest(t *testing.T) { } // Issue 4800: copy (some) headers when Client follows a redirect. -func TestClientCopyHeadersOnRedirect(t *testing.T) { +func TestClientCopyHeadersOnRedirect(t *testing.T) { run(t, testClientCopyHeadersOnRedirect) } +func testClientCopyHeadersOnRedirect(t *testing.T, mode testMode) { const ( ua = "some-agent/1.2" xfoo = "foo-val" ) var ts2URL string - ts1 := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + ts1 := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { want := Header{ "User-Agent": []string{ua}, "X-Foo": []string{xfoo}, @@ -1543,12 +1492,10 @@ func TestClientCopyHeadersOnRedirect(t *testing.T) { } else { w.Header().Set("Result", "ok") } - })) - defer ts1.Close() - ts2 := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + })).ts + ts2 := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { Redirect(w, r, ts1.URL, StatusFound) - })) - defer ts2.Close() + })).ts ts2URL = ts2.URL c := ts1.Client() @@ -1583,22 +1530,24 @@ func TestClientCopyHeadersOnRedirect(t *testing.T) { } // Issue 22233: copy host when Client follows a relative redirect. -func TestClientCopyHostOnRedirect(t *testing.T) { +func TestClientCopyHostOnRedirect(t *testing.T) { run(t, testClientCopyHostOnRedirect) } +func testClientCopyHostOnRedirect(t *testing.T, mode testMode) { // Virtual hostname: should not receive any request. - virtual := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + virtual := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { t.Errorf("Virtual host received request %v", r.URL) w.WriteHeader(403) io.WriteString(w, "should not see this response") - })) + })).ts defer virtual.Close() virtualHost := strings.TrimPrefix(virtual.URL, "http://") + virtualHost = strings.TrimPrefix(virtualHost, "https://") t.Logf("Virtual host is %v", virtualHost) // Actual hostname: should not receive any request. const wantBody = "response body" var tsURL string var tsHost string - ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { switch r.URL.Path { case "/": // Relative redirect. @@ -1630,10 +1579,10 @@ func TestClientCopyHostOnRedirect(t *testing.T) { t.Errorf("Serving unexpected path %q", r.URL.Path) w.WriteHeader(404) } - })) - defer ts.Close() + })).ts tsURL = ts.URL tsHost = strings.TrimPrefix(ts.URL, "http://") + tsHost = strings.TrimPrefix(tsHost, "https://") t.Logf("Server host is %v", tsHost) c := ts.Client() @@ -1653,7 +1602,8 @@ func TestClientCopyHostOnRedirect(t *testing.T) { } // Issue 17494: cookies should be altered when Client follows redirects. -func TestClientAltersCookiesOnRedirect(t *testing.T) { +func TestClientAltersCookiesOnRedirect(t *testing.T) { run(t, testClientAltersCookiesOnRedirect) } +func testClientAltersCookiesOnRedirect(t *testing.T, mode testMode) { cookieMap := func(cs []*Cookie) map[string][]string { m := make(map[string][]string) for _, c := range cs { @@ -1662,7 +1612,7 @@ func TestClientAltersCookiesOnRedirect(t *testing.T) { return m } - ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { var want map[string][]string got := cookieMap(r.Cookies()) @@ -1717,8 +1667,7 @@ func TestClientAltersCookiesOnRedirect(t *testing.T) { if !reflect.DeepEqual(got, want) { t.Errorf("redirect %s, Cookie = %v, want %v", c.Value, got, want) } - })) - defer ts.Close() + })).ts jar, _ := cookiejar.New(nil) c := ts.Client() @@ -1790,10 +1739,8 @@ func TestShouldCopyHeaderOnRedirect(t *testing.T) { } } -func TestClientRedirectTypes(t *testing.T) { - setParallel(t) - defer afterTest(t) - +func TestClientRedirectTypes(t *testing.T) { run(t, testClientRedirectTypes) } +func testClientRedirectTypes(t *testing.T, mode testMode) { tests := [...]struct { method string serverStatus int @@ -1838,11 +1785,10 @@ func TestClientRedirectTypes(t *testing.T) { handlerc := make(chan HandlerFunc, 1) - ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { + ts := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) { h := <-handlerc h(rw, req) - })) - defer ts.Close() + })).ts c := ts.Client() for i, tt := range tests { @@ -1898,18 +1844,16 @@ func (b issue18239Body) Close() error { // Issue 18239: make sure the Transport doesn't retry requests with bodies // if Request.GetBody is not defined. -func TestTransportBodyReadError(t *testing.T) { - setParallel(t) - defer afterTest(t) - ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { +func TestTransportBodyReadError(t *testing.T) { run(t, testTransportBodyReadError) } +func testTransportBodyReadError(t *testing.T, mode testMode) { + ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { if r.URL.Path == "/ping" { return } buf := make([]byte, 1) n, err := r.Body.Read(buf) w.Header().Set("X-Body-Read", fmt.Sprintf("%v, %v", n, err)) - })) - defer ts.Close() + })).ts c := ts.Client() tr := c.Transport.(*Transport) @@ -1993,22 +1937,13 @@ func TestClientPropagatesTimeoutToContext(t *testing.T) { c.Get("https://example.tld/") } -func TestClientDoCanceledVsTimeout_h1(t *testing.T) { - testClientDoCanceledVsTimeout(t, h1Mode) -} - -func TestClientDoCanceledVsTimeout_h2(t *testing.T) { - testClientDoCanceledVsTimeout(t, h2Mode) -} - // Issue 33545: lock-in the behavior promised by Client.Do's // docs about request cancellation vs timing out. -func testClientDoCanceledVsTimeout(t *testing.T, h2 bool) { - defer afterTest(t) - cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { +func TestClientDoCanceledVsTimeout(t *testing.T) { run(t, testClientDoCanceledVsTimeout) } +func testClientDoCanceledVsTimeout(t *testing.T, mode testMode) { + cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { w.Write([]byte("Hello, World!")) })) - defer cst.close() cases := []string{"timeout", "canceled"} @@ -2084,13 +2019,11 @@ func TestClientPopulatesNilResponseBody(t *testing.T) { } // Issue 40382: Client calls Close multiple times on Request.Body. -func TestClientCallsCloseOnlyOnce(t *testing.T) { - setParallel(t) - defer afterTest(t) - cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { +func TestClientCallsCloseOnlyOnce(t *testing.T) { run(t, testClientCallsCloseOnlyOnce) } +func testClientCallsCloseOnlyOnce(t *testing.T, mode testMode) { + cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { w.WriteHeader(StatusNoContent) })) - defer cst.close() // Issue occurred non-deterministically: needed to occur after a successful // write (into TCP buffer) but before end of body. @@ -2140,17 +2073,15 @@ func (b *issue40382Body) Close() error { return nil } -func TestProbeZeroLengthBody(t *testing.T) { - setParallel(t) - defer afterTest(t) +func TestProbeZeroLengthBody(t *testing.T) { run(t, testProbeZeroLengthBody) } +func testProbeZeroLengthBody(t *testing.T, mode testMode) { reqc := make(chan struct{}) - cst := newClientServerTest(t, false, HandlerFunc(func(w ResponseWriter, r *Request) { + cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) { close(reqc) if _, err := io.Copy(w, r.Body); err != nil { t.Errorf("error copying request body: %v", err) } })) - defer cst.close() bodyr, bodyw := io.Pipe() var gotBody string |
