implement http3.RoundTripper.CloseIdleConnections (#3820)

* implement CloseIdleConnections

* nit

Co-authored-by: Marten Seemann <martenseemann@gmail.com>

---------

Co-authored-by: Marten Seemann <martenseemann@gmail.com>
This commit is contained in:
Glonee 2023-05-15 15:12:00 +08:00 committed by GitHub
parent e9fea08613
commit cec79d338c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 74 additions and 6 deletions

View file

@ -8,6 +8,7 @@ import (
"io"
"net"
"net/http"
"sync/atomic"
"time"
"github.com/quic-go/quic-go"
@ -304,10 +305,10 @@ var _ = Describe("RoundTripper", func() {
Context("closing", func() {
It("closes", func() {
rt.clients = make(map[string]roundTripCloser)
rt.clients = make(map[string]*roundTripCloserWithCount)
cl := NewMockRoundTripCloser(mockCtrl)
cl.EXPECT().Close()
rt.clients["foo.bar"] = cl
rt.clients["foo.bar"] = &roundTripCloserWithCount{cl, atomic.Int64{}}
err := rt.Close()
Expect(err).ToNot(HaveOccurred())
Expect(len(rt.clients)).To(BeZero())
@ -319,6 +320,53 @@ var _ = Describe("RoundTripper", func() {
Expect(err).ToNot(HaveOccurred())
Expect(len(rt.clients)).To(BeZero())
})
It("closes idle connections", func() {
Expect(len(rt.clients)).To(Equal(0))
req1, err := http.NewRequest("GET", "https://site1.com", nil)
Expect(err).ToNot(HaveOccurred())
req2, err := http.NewRequest("GET", "https://site2.com", nil)
Expect(err).ToNot(HaveOccurred())
Expect(req1.Host).ToNot(Equal(req2.Host))
ctx1, cancel1 := context.WithCancel(context.Background())
ctx2, cancel2 := context.WithCancel(context.Background())
req1 = req1.WithContext(ctx1)
req2 = req2.WithContext(ctx2)
roundTripCalled := make(chan struct{})
reqFinished := make(chan struct{})
rt.newClient = func(hostname string, tlsConf *tls.Config, opts *roundTripperOpts, conf *quic.Config, dialer dialFunc) (roundTripCloser, error) {
cl := NewMockRoundTripCloser(mockCtrl)
cl.EXPECT().Close()
cl.EXPECT().RoundTripOpt(gomock.Any(), gomock.Any()).DoAndReturn(func(r *http.Request, _ RoundTripOpt) (*http.Response, error) {
roundTripCalled <- struct{}{}
<-r.Context().Done()
return nil, nil
})
return cl, nil
}
go func() {
rt.RoundTrip(req1)
reqFinished <- struct{}{}
}()
go func() {
rt.RoundTrip(req2)
reqFinished <- struct{}{}
}()
<-roundTripCalled
<-roundTripCalled
// Both two requests are started.
Expect(len(rt.clients)).To(Equal(2))
cancel1()
<-reqFinished
// req1 is finished
rt.CloseIdleConnections()
Expect(len(rt.clients)).To(Equal(1))
cancel2()
<-reqFinished
// all requests are finished
rt.CloseIdleConnections()
Expect(len(rt.clients)).To(Equal(0))
})
})
Context("reusing udpconn", func() {