@@ -10,10 +10,13 @@ package http2
1010import (
1111 "bytes"
1212 "context"
13+ "crypto/tls"
1314 "fmt"
1415 "io"
16+ "net"
1517 "net/http"
1618 "reflect"
19+ "sync"
1720 "sync/atomic"
1821 "testing"
1922 "time"
@@ -79,6 +82,56 @@ func TestTestClientConn(t *testing.T) {
7982 rt .wantBody (nil )
8083}
8184
85+ // TestConnectTimeout tests that a request does not exceed request timeout + dial timeout
86+ func TestConnectTimeout (t * testing.T ) {
87+ tr := & Transport {
88+ DialTLSContext : func (ctx context.Context , network , addr string , cfg * tls.Config ) (net.Conn , error ) {
89+ // mock a net dialler with 1s timeout, encountering network issue
90+ // keeping dialing until timeout
91+ var dialer = net.Dialer {Timeout : time .Duration (- 1 )}
92+ select {
93+ case <- time .After (time .Second ):
94+ case <- ctx .Done ():
95+ }
96+ return dialer .DialContext (ctx , network , addr )
97+ },
98+ AllowHTTP : true ,
99+ }
100+
101+ var sg sync.WaitGroup
102+ parentCtx , cancel := context .WithCancel (context .Background ())
103+ defer cancel ()
104+
105+ for j := 0 ; j < 2 ; j ++ {
106+ sg .Add (1 )
107+ go func () {
108+ for i := 0 ; i < 10000 ; i ++ {
109+ sg .Add (1 )
110+ go func () {
111+ ctx , _ := context .WithTimeout (parentCtx , time .Second )
112+ req , err := http .NewRequestWithContext (ctx , "GET" , "http://127.0.0.1:80" , nil )
113+ if err != nil {
114+ t .Errorf ("NewRequest: %v" , err )
115+ }
116+
117+ start := time .Now ()
118+ tr .RoundTrip (req )
119+ duration := time .Since (start )
120+ // duration should not exceed request timeout + dial timeout
121+ if duration > 2 * time .Second {
122+ t .Errorf ("RoundTrip took %s; want <2s" , duration .String ())
123+ }
124+ sg .Done ()
125+ }()
126+ time .Sleep (1 * time .Millisecond )
127+ }
128+ sg .Done ()
129+ }()
130+ }
131+
132+ sg .Wait ()
133+ }
134+
82135// A testClientConn allows testing ClientConn.RoundTrip against a fake server.
83136//
84137// A test using testClientConn consists of:
0 commit comments