-
-
Save decoomanj/c85e5f6540936b7c6b32ecc59a0c3e95 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package httpclient | |
| import ( | |
| "net" | |
| "net/http" | |
| "time" | |
| ) | |
| type Config struct { | |
| ConnectTimeout time.Duration | |
| ReadWriteTimeout time.Duration | |
| } | |
| func TimeoutDialer(config *Config) func(net, addr string) (c net.Conn, err error) { | |
| return func(netw, addr string) (net.Conn, error) { | |
| conn, err := net.DialTimeout(netw, addr, config.ConnectTimeout) | |
| if err != nil { | |
| return nil, err | |
| } | |
| conn.SetDeadline(time.Now().Add(config.ReadWriteTimeout)) | |
| return conn, nil | |
| } | |
| } | |
| func NewTimeoutClient(args ...interface{}) *http.Client { | |
| // Default configuration | |
| config := &Config{ | |
| ConnectTimeout: 1 * time.Second, | |
| ReadWriteTimeout: 1 * time.Second, | |
| } | |
| // merge the default with user input if there is one | |
| if len(args) == 1 { | |
| timeout := args[0].(time.Duration) | |
| config.ConnectTimeout = timeout | |
| config.ReadWriteTimeout = timeout | |
| } | |
| if len(args) == 2 { | |
| config.ConnectTimeout = args[0].(time.Duration) | |
| config.ReadWriteTimeout = args[1].(time.Duration) | |
| } | |
| return &http.Client{ | |
| Transport: &http.Transport{ | |
| Dial: TimeoutDialer(config), | |
| }, | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package httpclient | |
| import ( | |
| "io" | |
| "net" | |
| "net/http" | |
| "sync" | |
| "testing" | |
| "time" | |
| ) | |
| var starter sync.Once | |
| var addr net.Addr | |
| func testHandler(w http.ResponseWriter, req *http.Request) { | |
| time.Sleep(500 * time.Millisecond) | |
| io.WriteString(w, "hello, world!\n") | |
| } | |
| func testDelayedHandler(w http.ResponseWriter, req *http.Request) { | |
| time.Sleep(2100 * time.Millisecond) | |
| io.WriteString(w, "hello, world ... in a bit\n") | |
| } | |
| func setupMockServer(t *testing.T) { | |
| http.HandleFunc("/test", testHandler) | |
| http.HandleFunc("/test-delayed", testDelayedHandler) | |
| ln, err := net.Listen("tcp", ":0") | |
| if err != nil { | |
| t.Fatalf("failed to listen - %s", err.Error()) | |
| } | |
| go func() { | |
| err = http.Serve(ln, nil) | |
| if err != nil { | |
| t.Fatalf("failed to start HTTP server - %s", err.Error()) | |
| } | |
| }() | |
| addr = ln.Addr() | |
| } | |
| func TestDefaultConfig(t *testing.T) { | |
| starter.Do(func() { setupMockServer(t) }) | |
| httpClient := NewTimeoutClient() | |
| req, _ := http.NewRequest("GET", "http://"+addr.String()+"/test-delayed", nil) | |
| httpClient = NewTimeoutClient() | |
| _, err := httpClient.Do(req) | |
| if err == nil { | |
| t.Fatalf("request should have timed out") | |
| } | |
| } | |
| func TestHttpClient(t *testing.T) { | |
| starter.Do(func() { setupMockServer(t) }) | |
| httpClient := NewTimeoutClient() | |
| req, _ := http.NewRequest("GET", "http://"+addr.String()+"/test", nil) | |
| resp, err := httpClient.Do(req) | |
| if err != nil { | |
| t.Fatalf("1st request failed - %s", err.Error()) | |
| } | |
| defer resp.Body.Close() | |
| connectTimeout := (250 * time.Millisecond) | |
| readWriteTimeout := (50 * time.Millisecond) | |
| httpClient = NewTimeoutClient(connectTimeout, readWriteTimeout) | |
| resp, err = httpClient.Do(req) | |
| if err == nil { | |
| t.Fatalf("2nd request should have timed out") | |
| } | |
| resp, err = httpClient.Do(req) | |
| if resp != nil { | |
| t.Fatalf("3nd request should not have timed out") | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment