h2non / gock

HTTP traffic mocking and testing made easy in Go ༼ʘ̚ل͜ʘ̚༽
https://pkg.go.dev/github.com/h2non/gock
MIT License
2.09k stars 107 forks source link

*Request.HeaderPresent not working in v1.0.16 #77

Closed donirompang closed 3 years ago

donirompang commented 3 years ago

I have Test Code like this,

func TestHitHTTP(t *testing.T) {
    // create custom HTTP client
    httpClient := &http.Client{
        Transport: &http.Transport{
            TLSClientConfig: &tls.Config{
                InsecureSkipVerify: true,
            },
        },
    }

    // define URL
    URL := "https://ayssiz.com"

    // define mock
    gock.InterceptClient(httpClient)
    defer gock.Off()
    defer gock.RestoreClient(httpClient)

    // create mock response
    mockResponse := make(map[string]interface{})
    mockResponse["success"] = true

    gock.New(URL).
        HeaderPresent("KEY").
        Reply(200).
        JSON(mockResponse)

    // hit HTTP
    hitHttp(httpClient, URL)

    assert.Equal(t, true, gock.IsDone())
}

func hitHttp(httpClient *http.Client, URL string) (interface{}, error) {
    var jsonBody interface{}

    request, err := http.NewRequest("POST", URL, nil)
    request.Header.Set("KEY", "APIKEY")

    response, err := httpClient.Do(request)
    if err != nil {
        return jsonBody, err
    }

    defer response.Body.Close()
    json.NewDecoder(response.Body).Decode(&jsonBody)

    return jsonBody, nil
}

I use HeaderPresent to check wheter the header key is present or not. Previously it works fine in v1.0.15, but when I upgrade it to v1.0.16, it is not working. The value of gock.IsDone() is false, which mean the mock is not hit by the httpClient

--- FAIL: TestHitHTTP (0.00s) module_test.go:43: Error Trace: module_test.go:43 Error: Not equal: expected: true actual : false Test: TestHitHTTP FAIL

GrahamWalters commented 3 years ago

I just upgraded to v1.0.16 and I'm seeing the exact same issue. Looking at the diff it seems all calls to req.Header.Set and req.Header.Get have been replaced with directly modifying the header map

func (r *Request) MatchHeader(key, value string) *Request {
    r.Header[key] = []string{value}. // was r.Header.Set(key, value)
    return r
}

Unfortunately that doesn't match with what go is doing:

func (h Header) Set(key, value string) {
    textproto.MIMEHeader(h).Set(key, value)
}

The fix for me was to modify my application code to the following, but I'll be rolling back to v1.0.15.

// v1.0.15
req.Header.Add("content-type", "application/x-www-form-urlencoded")
req.Header.Add("content-length", strconv.Itoa(len(encoded)))
// v1.0.16
req.Header["content-type"] = []string{"application/x-www-form-urlencoded"}
req.Header["content-length"] = []string{strconv.Itoa(len(encoded))}
h2non commented 3 years ago

Yes, it should use the setter method instead. I will fix it asap, but if you can provide a PR, that will be possibly faster. Appreciated!