Skip to content

Commit 1444c0b

Browse files
committed
net/http: wait forever for write results in tests
After performing a round trip on a connection, the connection is usually returned to the idle connection pool. If the write of the request did not complete successfully, the connection is not returned. It is possible for the response to be read before the write goroutine has finished signalling that its write has completed. To allow for this, the check to see if the write completed successfully waits for 50ms for the write goroutine to report the result of the write. See comments in persistConn.wroteRequest for more details. On a slow builder, it is possible for the write goroutine to take longer than 50ms to report the status of its write, leading to test flakiness when successive requests unexpectedly use different connections. Set the timeout for waiting for the writer to an effectively infinite duration in tests. Fixes #51147 Fixes #56275 Fixes #56419 Fixes #56577 Fixes #57375 Fixes #57417 Fixes #57476 Fixes #57604 Fixes #57605 Change-Id: I5e92ffd66b676f3f976d8832c0910f27456a6991 Reviewed-on: https://go-review.googlesource.com/c/go/+/483116 TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Bryan Mills <[email protected]> Run-TryBot: Bryan Mills <[email protected]>
1 parent 38dadcc commit 1444c0b

File tree

4 files changed

+13
-5
lines changed

4 files changed

+13
-5
lines changed

src/net/http/export_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ var (
3636
Export_is408Message = is408Message
3737
)
3838

39-
const MaxWriteWaitBeforeConnReuse = maxWriteWaitBeforeConnReuse
39+
var MaxWriteWaitBeforeConnReuse = &maxWriteWaitBeforeConnReuse
4040

4141
func init() {
4242
// We only want to pay for this cost during testing.

src/net/http/main_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
var quietLog = log.New(io.Discard, "", 0)
2121

2222
func TestMain(m *testing.M) {
23+
*http.MaxWriteWaitBeforeConnReuse = 60 * time.Minute
2324
v := m.Run()
2425
if v == 0 && goroutineLeaked() {
2526
os.Exit(1)

src/net/http/transport.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -2452,7 +2452,10 @@ func (pc *persistConn) writeLoop() {
24522452
// maxWriteWaitBeforeConnReuse is how long the a Transport RoundTrip
24532453
// will wait to see the Request's Body.Write result after getting a
24542454
// response from the server. See comments in (*persistConn).wroteRequest.
2455-
const maxWriteWaitBeforeConnReuse = 50 * time.Millisecond
2455+
//
2456+
// In tests, we set this to a large value to avoid flakiness from inconsistent
2457+
// recycling of connections.
2458+
var maxWriteWaitBeforeConnReuse = 50 * time.Millisecond
24562459

24572460
// wroteRequest is a check before recycling a connection that the previous write
24582461
// (from writeLoop above) happened and was successful.

src/net/http/transport_test.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -3402,9 +3402,13 @@ func (c byteFromChanReader) Read(p []byte) (n int, err error) {
34023402
// questionable state.
34033403
// golang.org/issue/7569
34043404
func TestTransportNoReuseAfterEarlyResponse(t *testing.T) {
3405-
run(t, testTransportNoReuseAfterEarlyResponse, []testMode{http1Mode})
3405+
run(t, testTransportNoReuseAfterEarlyResponse, []testMode{http1Mode}, testNotParallel)
34063406
}
34073407
func testTransportNoReuseAfterEarlyResponse(t *testing.T, mode testMode) {
3408+
defer func(d time.Duration) {
3409+
*MaxWriteWaitBeforeConnReuse = d
3410+
}(*MaxWriteWaitBeforeConnReuse)
3411+
*MaxWriteWaitBeforeConnReuse = 10 * time.Millisecond
34083412
var sconn struct {
34093413
sync.Mutex
34103414
c net.Conn
@@ -3631,13 +3635,13 @@ func testRetryRequestsOnError(t *testing.T, mode testMode) {
36313635
req := tc.req()
36323636
res, err := c.Do(req)
36333637
if err != nil {
3634-
if time.Since(t0) < MaxWriteWaitBeforeConnReuse/2 {
3638+
if time.Since(t0) < *MaxWriteWaitBeforeConnReuse/2 {
36353639
mu.Lock()
36363640
got := logbuf.String()
36373641
mu.Unlock()
36383642
t.Fatalf("i=%d: Do = %v; log:\n%s", i, err, got)
36393643
}
3640-
t.Skipf("connection likely wasn't recycled within %d, interfering with actual test; skipping", MaxWriteWaitBeforeConnReuse)
3644+
t.Skipf("connection likely wasn't recycled within %d, interfering with actual test; skipping", *MaxWriteWaitBeforeConnReuse)
36413645
}
36423646
res.Body.Close()
36433647
if res.Request != req {

0 commit comments

Comments
 (0)