@@ -97,63 +97,83 @@ func startH2cServer(t *testing.T) net.Listener {
9797
9898func TestIdleConnTimeout (t * testing.T ) {
9999 for _ , test := range []struct {
100+ name string
100101 idleConnTimeout time.Duration
101102 wait time.Duration
102103 baseTransport * http.Transport
103- wantConns int32
104+ wantNewConn bool
104105 }{{
106+ name : "NoExpiry" ,
105107 idleConnTimeout : 2 * time .Second ,
106108 wait : 1 * time .Second ,
107109 baseTransport : nil ,
108- wantConns : 1 ,
110+ wantNewConn : false ,
109111 }, {
112+ name : "H2TransportTimeoutExpires" ,
110113 idleConnTimeout : 1 * time .Second ,
111114 wait : 2 * time .Second ,
112115 baseTransport : nil ,
113- wantConns : 5 ,
116+ wantNewConn : true ,
114117 }, {
118+ name : "H1TransportTimeoutExpires" ,
115119 idleConnTimeout : 0 * time .Second ,
116120 wait : 1 * time .Second ,
117121 baseTransport : & http.Transport {
118122 IdleConnTimeout : 2 * time .Second ,
119123 },
120- wantConns : 1 ,
124+ wantNewConn : false ,
121125 }} {
122- var gotConns int32
123-
124- st := newServerTester (t , func (w http.ResponseWriter , r * http.Request ) {
125- io .WriteString (w , r .RemoteAddr )
126- }, optOnlyServer )
127- defer st .Close ()
126+ t .Run (test .name , func (t * testing.T ) {
127+ tt := newTestTransport (t , func (tr * Transport ) {
128+ tr .IdleConnTimeout = test .idleConnTimeout
129+ })
130+ var tc * testClientConn
131+ for i := 0 ; i < 3 ; i ++ {
132+ req , _ := http .NewRequest ("GET" , "https://dummy.tld/" , nil )
133+ rt := tt .roundTrip (req )
134+
135+ // This request happens on a new conn if it's the first request
136+ // (and there is no cached conn), or if the test timeout is long
137+ // enough that old conns are being closed.
138+ wantConn := i == 0 || test .wantNewConn
139+ if has := tt .hasConn (); has != wantConn {
140+ t .Fatalf ("request %v: hasConn=%v, want %v" , i , has , wantConn )
141+ }
142+ if wantConn {
143+ tc = tt .getConn ()
144+ // Read client's SETTINGS and first WINDOW_UPDATE,
145+ // send our SETTINGS.
146+ tc .wantFrameType (FrameSettings )
147+ tc .wantFrameType (FrameWindowUpdate )
148+ tc .writeSettings ()
149+ }
150+ if tt .hasConn () {
151+ t .Fatalf ("request %v: Transport has more than one conn" , i )
152+ }
128153
129- tr := & Transport {
130- IdleConnTimeout : test .idleConnTimeout ,
131- TLSClientConfig : tlsConfigInsecure ,
132- }
133- defer tr .CloseIdleConnections ()
154+ // Respond to the client's request.
155+ hf := testClientConnReadFrame [* MetaHeadersFrame ](tc )
156+ tc .writeHeaders (HeadersFrameParam {
157+ StreamID : hf .StreamID ,
158+ EndHeaders : true ,
159+ EndStream : true ,
160+ BlockFragment : tc .makeHeaderBlockFragment (
161+ ":status" , "200" ,
162+ ),
163+ })
164+ rt .wantStatus (200 )
134165
135- for i := 0 ; i < 5 ; i ++ {
136- req , _ := http .NewRequest ("GET" , st .ts .URL , http .NoBody )
137- trace := & httptrace.ClientTrace {
138- GotConn : func (connInfo httptrace.GotConnInfo ) {
139- if ! connInfo .Reused {
140- atomic .AddInt32 (& gotConns , 1 )
141- }
142- },
143- }
144- req = req .WithContext (httptrace .WithClientTrace (req .Context (), trace ))
166+ // If this was a newly-accepted conn, read the SETTINGS ACK.
167+ if wantConn {
168+ tc .wantFrameType (FrameSettings ) // ACK to our settings
169+ }
145170
146- _ , err := tr .RoundTrip (req )
147- if err != nil {
148- t .Fatalf ("%v" , err )
171+ tt .advance (test .wait )
172+ if got , want := tc .netConnClosed , test .wantNewConn ; got != want {
173+ t .Fatalf ("after waiting %v, conn closed=%v; want %v" , test .wait , got , want )
174+ }
149175 }
150-
151- <- time .After (test .wait )
152- }
153-
154- if gotConns != test .wantConns {
155- t .Errorf ("incorrect gotConns: %d != %d" , gotConns , test .wantConns )
156- }
176+ })
157177 }
158178}
159179
0 commit comments