#httptest.Server incorrectly responds with same file contents from two separate endpoints

8 messages · Page 1 of 1 (latest)

compact mist
#

I'm setting up some http tests and I need a server to respond on /cookies and /release with unique contents that I load from files containing test data.

I have the below function to set up the endpoint paths, and a couple of extra endpoints for debugging this issue:

func HTTPServer(t *testing.T, endpoints []Endpoint) *httptest.Server {
    mux := http.NewServeMux()
    for _, e := range endpoints {
        mux.HandleFunc(e.Path, func(res http.ResponseWriter, req *http.Request) {
            _, err := res.Write(e.Response)
            assert.NoError(t, err)
        })
    }

    mux.HandleFunc("/one", func(res http.ResponseWriter, req *http.Request) {
        _, err := res.Write([]byte("one"))
        assert.NoError(t, err)
    })

    mux.HandleFunc("/two", func(res http.ResponseWriter, req *http.Request) {
        _, err := res.Write([]byte("two"))
        assert.NoError(t, err)
    })

    return httptest.NewServer(mux)
}

I have verified several times that I have unique endpoint data coming into this function, but when I start the test server and try curl to the endpoints I get correct responses from /one and /two, but /cookies and /release are both responding with the data I expect only from the /release endpoint.

The test setup has these input values:

endpoints: map[string]string{
    "/cookies": "../internal/testing/scraper/testdata/cookie_selection.html",
    "/release": "../internal/testing/scraper/testdata/release.html",
},

the values are then read and passed on like this:

for path, file := range tt.endpoints {
    f, err := os.ReadFile(file)
    assert.NoError(t, err)
    endpoints = append(endpoints, mock.Endpoint{Path: path, Response: f})
}
ts := mock.HTTPServer(t, endpoints)

What is causing the http test server to serve the same data on both /cookie and /release?

vague flame
#

put e := e before mux.HandleFunc in the loop and it will work

#

as it is, you're using the same e variable for all endpoints, the loop just changes the data in it

compact mist
#

Yeah, I had a feeling that it was something like that, I couldn't figure out what search terms to use.
I also didn't really catch that I had a goroutine involved in this case

#

Thanks for the answer though, adding e := e did indeed fix the endpoints

vague flame
#

it isn't about goroutines per se, it's about closures that escape

#

goroutines are just the most common way to encounter this, which is why the faq is written that way