Commit 0d87f6a6 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

net/http: deflake TestServerTimeouts

Retry the test several times with increasingly long timeouts.

Fixes #19538 (hopefully)

Change-Id: Ia3bf2b63b4298a6ee1e4082e14d9bfd5922c293a
Reviewed-on: https://go-review.googlesource.com/38154
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarJosh Bleecher Snyder <josharian@gmail.com>
parent 50520f15
...@@ -463,13 +463,29 @@ func TestMuxRedirectLeadingSlashes(t *testing.T) { ...@@ -463,13 +463,29 @@ func TestMuxRedirectLeadingSlashes(t *testing.T) {
func TestServerTimeouts(t *testing.T) { func TestServerTimeouts(t *testing.T) {
setParallel(t) setParallel(t)
defer afterTest(t) defer afterTest(t)
// Try three times, with increasing timeouts.
tries := []time.Duration{250 * time.Millisecond, 500 * time.Millisecond, 1 * time.Second}
for i, timeout := range tries {
err := testServerTimeouts(timeout)
if err == nil {
return
}
t.Logf("failed at %v: %v", timeout, err)
if i != len(tries)-1 {
t.Logf("retrying at %v ...", tries[i+1])
}
}
t.Fatal("all attempts failed")
}
func testServerTimeouts(timeout time.Duration) error {
reqNum := 0 reqNum := 0
ts := httptest.NewUnstartedServer(HandlerFunc(func(res ResponseWriter, req *Request) { ts := httptest.NewUnstartedServer(HandlerFunc(func(res ResponseWriter, req *Request) {
reqNum++ reqNum++
fmt.Fprintf(res, "req=%d", reqNum) fmt.Fprintf(res, "req=%d", reqNum)
})) }))
ts.Config.ReadTimeout = 250 * time.Millisecond ts.Config.ReadTimeout = timeout
ts.Config.WriteTimeout = 250 * time.Millisecond ts.Config.WriteTimeout = timeout
ts.Start() ts.Start()
defer ts.Close() defer ts.Close()
...@@ -477,12 +493,12 @@ func TestServerTimeouts(t *testing.T) { ...@@ -477,12 +493,12 @@ func TestServerTimeouts(t *testing.T) {
c := ts.Client() c := ts.Client()
r, err := c.Get(ts.URL) r, err := c.Get(ts.URL)
if err != nil { if err != nil {
t.Fatalf("http Get #1: %v", err) return fmt.Errorf("http Get #1: %v", err)
} }
got, err := ioutil.ReadAll(r.Body) got, err := ioutil.ReadAll(r.Body)
expected := "req=1" expected := "req=1"
if string(got) != expected || err != nil { if string(got) != expected || err != nil {
t.Errorf("Unexpected response for request #1; got %q ,%v; expected %q, nil", return fmt.Errorf("Unexpected response for request #1; got %q ,%v; expected %q, nil",
string(got), err, expected) string(got), err, expected)
} }
...@@ -490,17 +506,18 @@ func TestServerTimeouts(t *testing.T) { ...@@ -490,17 +506,18 @@ func TestServerTimeouts(t *testing.T) {
t1 := time.Now() t1 := time.Now()
conn, err := net.Dial("tcp", ts.Listener.Addr().String()) conn, err := net.Dial("tcp", ts.Listener.Addr().String())
if err != nil { if err != nil {
t.Fatalf("Dial: %v", err) return fmt.Errorf("Dial: %v", err)
} }
buf := make([]byte, 1) buf := make([]byte, 1)
n, err := conn.Read(buf) n, err := conn.Read(buf)
conn.Close() conn.Close()
latency := time.Since(t1) latency := time.Since(t1)
if n != 0 || err != io.EOF { if n != 0 || err != io.EOF {
t.Errorf("Read = %v, %v, wanted %v, %v", n, err, 0, io.EOF) return fmt.Errorf("Read = %v, %v, wanted %v, %v", n, err, 0, io.EOF)
} }
if latency < 200*time.Millisecond /* fudge from 250 ms above */ { minLatency := timeout / 5 * 4
t.Errorf("got EOF after %s, want >= %s", latency, 200*time.Millisecond) if latency < minLatency {
return fmt.Errorf("got EOF after %s, want >= %s", latency, minLatency)
} }
// Hit the HTTP server successfully again, verifying that the // Hit the HTTP server successfully again, verifying that the
...@@ -508,29 +525,31 @@ func TestServerTimeouts(t *testing.T) { ...@@ -508,29 +525,31 @@ func TestServerTimeouts(t *testing.T) {
// get "req=2", not "req=3") // get "req=2", not "req=3")
r, err = c.Get(ts.URL) r, err = c.Get(ts.URL)
if err != nil { if err != nil {
t.Fatalf("http Get #2: %v", err) return fmt.Errorf("http Get #2: %v", err)
} }
got, err = ioutil.ReadAll(r.Body) got, err = ioutil.ReadAll(r.Body)
r.Body.Close()
expected = "req=2" expected = "req=2"
if string(got) != expected || err != nil { if string(got) != expected || err != nil {
t.Errorf("Get #2 got %q, %v, want %q, nil", string(got), err, expected) return fmt.Errorf("Get #2 got %q, %v, want %q, nil", string(got), err, expected)
} }
if !testing.Short() { if !testing.Short() {
conn, err := net.Dial("tcp", ts.Listener.Addr().String()) conn, err := net.Dial("tcp", ts.Listener.Addr().String())
if err != nil { if err != nil {
t.Fatalf("Dial: %v", err) return fmt.Errorf("long Dial: %v", err)
} }
defer conn.Close() defer conn.Close()
go io.Copy(ioutil.Discard, conn) go io.Copy(ioutil.Discard, conn)
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
_, err := conn.Write([]byte("GET / HTTP/1.1\r\nHost: foo\r\n\r\n")) _, err := conn.Write([]byte("GET / HTTP/1.1\r\nHost: foo\r\n\r\n"))
if err != nil { if err != nil {
t.Fatalf("on write %d: %v", i, err) return fmt.Errorf("on write %d: %v", i, err)
} }
time.Sleep(ts.Config.ReadTimeout / 2) time.Sleep(timeout / 2)
} }
} }
return nil
} }
// Test that the HTTP/2 server handles Server.WriteTimeout (Issue 18437) // Test that the HTTP/2 server handles Server.WriteTimeout (Issue 18437)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment