mirror of
https://github.com/golang/go
synced 2024-11-14 06:40:22 -07:00
net/http: speed up and deflake TestCancelRequestWhenSharingConnection
This test made many requests over the same connection for 10 seconds, trusting that this will exercise the request cancelation race from #41600. Change the test to exhibit the specific race in a targeted fashion with only two requests. Updates #41600. Updates #47016. Change-Id: If99c9b9331ff645f6bb67fe9fb79b8aab8784710 Reviewed-on: https://go-review.googlesource.com/c/go/+/339594 Trust: Damien Neil <dneil@google.com> Run-TryBot: Damien Neil <dneil@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com>
This commit is contained in:
parent
8a7ee4c51e
commit
6e738868a7
@ -6441,10 +6441,11 @@ func TestErrorWriteLoopRace(t *testing.T) {
|
|||||||
// Test that a new request which uses the connection of an active request
|
// Test that a new request which uses the connection of an active request
|
||||||
// cannot cause it to be canceled as well.
|
// cannot cause it to be canceled as well.
|
||||||
func TestCancelRequestWhenSharingConnection(t *testing.T) {
|
func TestCancelRequestWhenSharingConnection(t *testing.T) {
|
||||||
if testing.Short() {
|
reqc := make(chan chan struct{}, 2)
|
||||||
t.Skip("skipping in short mode")
|
|
||||||
}
|
|
||||||
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, req *Request) {
|
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, req *Request) {
|
||||||
|
ch := make(chan struct{}, 1)
|
||||||
|
reqc <- ch
|
||||||
|
<-ch
|
||||||
w.Header().Add("Content-Length", "0")
|
w.Header().Add("Content-Length", "0")
|
||||||
}))
|
}))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
@ -6456,34 +6457,58 @@ func TestCancelRequestWhenSharingConnection(t *testing.T) {
|
|||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
||||||
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
putidlec := make(chan chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
for ctx.Err() == nil {
|
ctx := httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{
|
||||||
reqctx, reqcancel := context.WithCancel(ctx)
|
PutIdleConn: func(error) {
|
||||||
go reqcancel()
|
// Signal that the idle conn has been returned to the pool,
|
||||||
req, _ := NewRequestWithContext(reqctx, "GET", ts.URL, nil)
|
// and wait for the order to proceed.
|
||||||
|
ch := make(chan struct{})
|
||||||
|
putidlec <- ch
|
||||||
|
<-ch
|
||||||
|
},
|
||||||
|
})
|
||||||
|
req, _ := NewRequestWithContext(ctx, "GET", ts.URL, nil)
|
||||||
res, err := client.Do(req)
|
res, err := client.Do(req)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
res.Body.Close()
|
res.Body.Close()
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("request 1: got err %v, want nil", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
|
||||||
|
|
||||||
for ctx.Err() == nil {
|
// Wait for the first request to receive a response and return the
|
||||||
req, _ := NewRequest("GET", ts.URL, nil)
|
// connection to the idle pool.
|
||||||
if res, err := client.Do(req); err != nil {
|
r1c := <-reqc
|
||||||
t.Errorf("unexpected: %p %v", req, err)
|
close(r1c)
|
||||||
break
|
idlec := <-putidlec
|
||||||
} else {
|
|
||||||
|
wg.Add(1)
|
||||||
|
cancelctx, cancel := context.WithCancel(context.Background())
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
req, _ := NewRequestWithContext(cancelctx, "GET", ts.URL, nil)
|
||||||
|
res, err := client.Do(req)
|
||||||
|
if err == nil {
|
||||||
res.Body.Close()
|
res.Body.Close()
|
||||||
}
|
}
|
||||||
|
if !errors.Is(err, context.Canceled) {
|
||||||
|
t.Errorf("request 2: got err %v, want Canceled", err)
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Wait for the second request to arrive at the server, and then cancel
|
||||||
|
// the request context.
|
||||||
|
r2c := <-reqc
|
||||||
cancel()
|
cancel()
|
||||||
|
|
||||||
|
// Give the cancelation a moment to take effect, and then unblock the first request.
|
||||||
|
time.Sleep(1 * time.Millisecond)
|
||||||
|
close(idlec)
|
||||||
|
|
||||||
|
close(r2c)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user