Testing HTTP client timeout behaviour

1,103 views
Skip to first unread message

Amit Saha

unread,
Nov 14, 2020, 6:29:37 AM11/14/20
to golang-nuts
Hi all, I am attempting to write a test for http client timeout behaviour. Here’s my bad test server:

func startBadTestHTTPServer() *httptest.Server {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(60 * time.Second)
fmt.Fprint(w, "Hello World")
}))
return ts
}

func TestFetchBadRemoteResource(t *testing.T) {
ts := startBadTestHTTPServer()
defer ts.Close()

client := http.Client{Timeout: 15 * time.Second}
data, err := fetchRemoteResource(client, ts.URL)
if err != nil {
t.Fatal(err)
}

expected := "Hello World"
got := string(data)

if expected != got {
t.Errorf("Expected response to be: %s, Got: %s", expected, got)
}
}

When I run the test, I get:

RUN TestFetchBadRemoteResource
fetch_remote_resource_bad_server_test.go:27: Get "http://127.0.0.1:62721": context deadline exceeded (Client.Timeout exceeded while awaiting headers)


This is expected. But I also get:

2020/11/14 22:24:58 httptest.Server blocked in Close after 5 seconds, waiting for connections:
*net.TCPConn 0xc000124040 127.0.0.1:62722 in state active
--- FAIL: TestFetchBadRemoteResource (60.00s)


I understand why this is happening. But, my test still waits for 60 seconds for the server to shutdown.

Is there a way around this behaviour where the test server can be forcibly terminated and just carry on?

Thanks,
Amit


Amit Saha

unread,
Nov 14, 2020, 9:07:48 PM11/14/20
to golang-nuts
I didn’t succeed in finding a way for exactly what I wanted. However looking at https://golang.org/src/net/http/client_test.go I found a much better way to simulate a bad server. Instead a time.Sleep(), have it block on a channel and then write to the channel in the test. So my bad server now is:

func startBadTestHTTPServer(shutdownServer chan struct{}) *httptest.Server {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
<-shutdownServer
fmt.Fprint(w, "Hello World")
}))
return ts
}

In the test I then do:

data, err := fetchRemoteResource(client, ts.URL)
if err != nil {
shutdownServer <- struct{}{}
t.Fatal(err)
}



>
> Thanks,
> Amit
>
>

Reply all
Reply to author
Forward
0 new messages