h2non / gock

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

gock issue while mocking Prometheus with URL escaped query parameters #100

Open Ahmad-Faizan opened 2 years ago

Ahmad-Faizan commented 2 years ago

It seems there is an issue while mocking Prometheus URLs with gock. Prometheus URLs contain a query which is written in PromQL. The resulting URLs look similar to http://localhost:9090/api/v1/query?query=scalar(anyMetric)

This test fails as long as the MatchParam() is present in Line 18 in main_test.go

// file : main.go

package main

import (
    "log"
    "net/http"
    "net/url"
)

func main() {

    err := fetchMetrics()
    log.Println(err)
}

func fetchMetrics() error {
    promURL := &url.URL{
        Scheme: "http",
        Host:   "prometheus-k8s.monitoring:9090",
        Path:   "/api/v1/query",
    }
    q := promURL.Query()
    q.Set("query", "scalar(testMetric)")
    promURL.RawQuery = q.Encode()

    resp, err := http.Get(promURL.String())
    if err != nil || resp.StatusCode != http.StatusOK {
        return err
    }

    return nil
}
// file : main_test.go

package main

import (
    "log"
    "net/url"
    "testing"

    "gopkg.in/h2non/gock.v1"
)

func TestFetchMetrics(t *testing.T) {
    defer gock.Off()

    promQuery := "scalar(testMetric)"

    gock.New("http://prometheus-k8s.monitoring:9090").
        Get("/api/v1/query").
        MatchParam("query", url.QueryEscape(promQuery)).
        // MatchParam("query", promQuery).
        Reply(200)

    err := fetchMetrics()
    if err != nil {
        log.Println(err)
        t.Fail()
    }

}

I tried passing promQuery variable as a normal string as well as a URL encoded string but the test fails in both the scenarios. Test command -

go test -count 1 -v .

Is this a issue due to gock ?

denizgursoy commented 9 months ago

Same happened when I try to match param of date type. Encoded value: 2023-09-23T01%3A28%3A16%2B02%3A00 String value: 2023-09-23T01:28:16+02:00

wndhydrnt commented 4 months ago

Hello @Ahmad-Faizan @denizgursoy

gock uses regexp.MatchString() to match query parameters (code).

Any chars that have a special meaning in a regular expression, like (, ) or +, need to be escaped:

// ...
MatchParam("query", `scalar\(testMetric\)`)
// ...
denizgursoy commented 2 months ago

I just learnt that regexp.QuoteMeta method can be used escape special characters in a reqular expression