Commit 54b4b946 authored by Ian Lance Taylor's avatar Ian Lance Taylor

net/http: deflake TestCloseNotifierPipelined

The test sends two HTTP/1.1 pipelined requests.  The first is
completedly by the second, and as such triggers an immediate call to the
CloseNotify channel.  The second calls the CloseNotify channel after the
overall connection is closed.

The test was passing fine on gc because the code would enter the select
loop before running the handler, so the send on gotReq would always be
seen first.  On gccgo the code would sometimes enter the select loop
after the handler had already finished, meaning that the select could
choose between gotReq and sawClose.  If it picked sawClose, it would
never close the overall connection, and the httptest server would hang.
The same hang could be induced with gc by adding a time.Sleep
immediately before the select loop.

Deflake the test by 1) don't close the overall connection until both
requests have been seen; 2) don't exit the loop until both closes have
been seen.

Fixes #14231.

Change-Id: I9d20c309125422ce60ac545f78bcfa337aec1c7d
Reviewed-on: https://go-review.googlesource.com/19281Reviewed-by: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent fd9fd4c3
...@@ -2416,7 +2416,7 @@ func TestCloseNotifierPipelined(t *testing.T) { ...@@ -2416,7 +2416,7 @@ func TestCloseNotifierPipelined(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("error dialing: %v", err) t.Fatalf("error dialing: %v", err)
} }
diec := make(chan bool, 2) diec := make(chan bool, 1)
go func() { go func() {
const req = "GET / HTTP/1.1\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n" const req = "GET / HTTP/1.1\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n"
_, err = io.WriteString(conn, req+req) // two requests _, err = io.WriteString(conn, req+req) // two requests
...@@ -2426,13 +2426,23 @@ func TestCloseNotifierPipelined(t *testing.T) { ...@@ -2426,13 +2426,23 @@ func TestCloseNotifierPipelined(t *testing.T) {
<-diec <-diec
conn.Close() conn.Close()
}() }()
reqs := 0
closes := 0
For: For:
for { for {
select { select {
case <-gotReq: case <-gotReq:
diec <- true reqs++
if reqs > 2 {
t.Fatal("too many requests")
} else if reqs > 1 {
diec <- true
}
case <-sawClose: case <-sawClose:
break For closes++
if closes > 1 {
break For
}
case <-time.After(5 * time.Second): case <-time.After(5 * time.Second):
ts.CloseClientConnections() ts.CloseClientConnections()
t.Fatal("timeout") t.Fatal("timeout")
......
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