@@ -97,63 +97,83 @@ func startH2cServer(t *testing.T) net.Listener {
97
97
98
98
func TestIdleConnTimeout (t * testing.T ) {
99
99
for _ , test := range []struct {
100
+ name string
100
101
idleConnTimeout time.Duration
101
102
wait time.Duration
102
103
baseTransport * http.Transport
103
- wantConns int32
104
+ wantNewConn bool
104
105
}{{
106
+ name : "NoExpiry" ,
105
107
idleConnTimeout : 2 * time .Second ,
106
108
wait : 1 * time .Second ,
107
109
baseTransport : nil ,
108
- wantConns : 1 ,
110
+ wantNewConn : false ,
109
111
}, {
112
+ name : "H2TransportTimeoutExpires" ,
110
113
idleConnTimeout : 1 * time .Second ,
111
114
wait : 2 * time .Second ,
112
115
baseTransport : nil ,
113
- wantConns : 5 ,
116
+ wantNewConn : true ,
114
117
}, {
118
+ name : "H1TransportTimeoutExpires" ,
115
119
idleConnTimeout : 0 * time .Second ,
116
120
wait : 1 * time .Second ,
117
121
baseTransport : & http.Transport {
118
122
IdleConnTimeout : 2 * time .Second ,
119
123
},
120
- wantConns : 1 ,
124
+ wantNewConn : false ,
121
125
}} {
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
+ }
128
153
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 )
134
165
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
+ }
145
170
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
+ }
149
175
}
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
+ })
157
177
}
158
178
}
159
179
0 commit comments