I am writing test for an elasticsearch middleware, where I am using a function to build test servers in which I pass a slice of configuration structs for each tests and in a handler function they are iterated upon and the expected response is written to the response writer. This is my function.
func newMockClient(url string) (*elasticsearch, error) {
client, err := elastic.NewSimpleClient(elastic.SetURL(url))
if err != nil {
return nil, fmt.Errorf("error while initializing elastic client: %v", err)
}
es := &elasticsearch{
url: url,
client: client,
}
return es, nil
}
type ServerSetup struct {
Method, Path, Body, Response string
HTTPStatus int
}
func buildTestServer(t *testing.T, setups []*ServerSetup) *httptest.Server {
handlerFunc := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requestBytes, _ := ioutil.ReadAll(r.Body)
requestBody := string(requestBytes)
matched := false
for _, setup := range setups {
if r.Method == setup.Method && r.URL.EscapedPath() == setup.Path {
matched = true
if setup.HTTPStatus == 0 {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(setup.HTTPStatus)
}
_, err := w.Write([]byte(setup.Response))
if err != nil {
t.Fatalf("Unable to write test server response: %v", err)
}
}
}
if !matched {
t.Fatalf("No requests matched setup. Got method %s, Path %s, body %s", r.Method, r.URL.EscapedPath(), requestBody)
}
})
return httptest.NewServer(handlerFunc)
}
It is copied from github.com/github/vulcanizer
. When I run a single test using this, it works fine. For e.g. this test
func TestCreateIndex(t *testing.T) {
setup := &ServerSetup{
Method: "PUT",
Path: "/test",
Response: `{"acknowledged": true, "shards_acknowledged": true, "index": "test"}`,
}
ts := buildTestServer(t, []*ServerSetup{setup})
es, _ := newMockClient(ts.URL)
err := es.createIndex(context.Background(), "test", nil)
if err != nil {
t.Fatalf("Index creation failed with error: %v
", err)
}
}
But when I try to check different behaviours in a single test like this one I get an error http: multiple response.WriteHeader calls
func TestDeleteIndex(t *testing.T) {
setup := &ServerSetup{
Method: "DELETE",
Path: "/test",
Response: `{"acknowledged": true}`,
}
errSetup := &ServerSetup{
Method: "DELETE",
Path: "/test",
Response: `{"acknowledged": false}`,
}
ctx := context.Background()
ts := buildTestServer(t, []*ServerSetup{setup, errSetup})
defer ts.Close()
es, _ := newMockClient(ts.URL)
err := es.deleteIndex(ctx, "test")
if err != nil {
t.Fatalf("Index creation failed with error: %v
", err)
}
err = es.deleteIndex(ctx, "test")
if err == nil {
t.Fatal("Expected error but not found")
}
}
I am guessing that it is because of the fact that when I run deleteIndex for the second time it pings the server again but the response writer has already been written to so it can't write anything else to it.
Is there anyway I can have a check at the beginning of my handler func like
handlerFunc := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if w != nil{
// clear data in response writer
}
// .........
}