h2non / gock Goto Github PK
View Code? Open in Web Editor NEWHTTP traffic mocking and testing made easy in Go ༼ʘ̚ل͜ʘ̚༽
Home Page: https://pkg.go.dev/github.com/h2non/gock
License: MIT License
HTTP traffic mocking and testing made easy in Go ༼ʘ̚ل͜ʘ̚༽
Home Page: https://pkg.go.dev/github.com/h2non/gock
License: MIT License
Hello,
Great lib!
I'm trying to test retries with a specific http.Client.Timeout
value. Response.Delay
does not seem to work as expected. I set it to 60 and I set my http.Client.Timeout
to 5. My retries are also set to retry after Client.Timeout. When I do this and run the following test it does not seem to timeout as expected. What I expect to happen is to retry twice after a maximum of 5 seconds per request. What happens instead is the test takes much longer to run. Any idea of a workaround or area of the gock code that might change to make this work? Happy to submit a PR for this with your guidance. Thanks.
gock.New(url).
Post("/endpoint").
Response.
Delay(60 * time.Second)
gock.New(url).
Post("/endpoint").
Response.
Delay(60 * time.Second)
gock.New(url).
Post("/endpoint").
MatchHeaders(expectedRequestHeaders).
Reply(http.StatusCreated)
client := CreateHTTClientAdapter()
gock.InterceptClient(client.GetHTTPClient())
resp,err := client.Post(generateBody(), test.CreateStandardHeaders())
assert.Nil(suite.T(), err, "err should be nil and should handle error through response")
assert.Equal(suite.T(), http.StatusCreated, resp.Status, "status should be 201/Created")
When using this gock:
gock.New("http://www.google.com"). Get("/").Reply(500).SetError(errors.New("Internal Server Error"))
The following line is printed:
2016/04/18 12:14:03 RoundTripper returned a response & error; ignoring response
I'm guessing the RoundTripper is supposed to return a nil response when the error is set? Or I am supposed to set it to nil somehow?
context.WithTimeout()
http.DefaultClient.Do(taskReq.WithContext(cxt))
not working when mocking with gock.
Any idea to test the timeout?
my func is
{
defer gock.Off()
gock.New("https//url.com").Get("path").Reply(200)
gock.New("https//url.com").Get("path").Reply(200)
gock.Observe(gock.DumpRequest)
// some test in the func maybe access url twice or more
}
if i use once, other access got Matches: false
why
Hi, I was wondering how does gock intercepts an outgoing HTTP.
We use API client generated by swagger-codegen to access our other services, so any HTTP traffic are handled inside the said library, not in our packages. And it seems that gock were unable to intercepts any outgoing HTTP request originating from this API client. There's no issue if the HTTP request coming from the code residing in the same package as when gock is invoked.
gock.New(baseUrl).Get(path).Reply(404)
// this will produces the expected result
resp, _ := http.Get(url)
// this will not, the handler type is from another package (the API Client)
result, _ := handler.GetData(param1, param2, param3)
I suggest gork random return to success and failed data, thank u.
I'm trying to match the body of a request as shown below using BodyString
on Request
. However I am receiving gock: cannot match any request
. When I use it without BodyString
it is fine. gock.Observe(gock.DumpRequest)
confirms the value is indeed in the request. Any help much appreciated.
func TestContentClient_UpdateNode(t *testing.T) {
dummy := struct {
ServerUrl string
Token string
NodeId string
Body string
}{
ServerUrl: "http://test.server",
Token: "TOKEN",
NodeId: "100",
Body: "Hello",
}
defer gock.Off()
gock.Observe(gock.DumpRequest)
gock.New(dummy.ServerUrl).
Put("/nodes/"+dummy.NodeId+"/content").
MatchHeader("Content-Type", "application/octet-stream").
BodyString(dummy.Body).
Reply(http.StatusOK).
JSON(NodeEntry{
Node{
ID: dummy.NodeId,
},
})
client := NewContentClient(dummy.ServerUrl, dummy.Token)
node, err := client.UpdateNode(dummy.NodeId, dummy.Body)
assert.NoError(t, err)
assert.Equal(t, dummy.NodeId, node.ID)
}
I have a code. It can work before 1.0.14. but in 1.0.14. It can't work
package main
import (
"fmt"
"io/ioutil"
"net/http"
"gopkg.in/h2non/gock.v1"
)
func main() {
data := `{"code":0,"msg":"ok"}`
gock.New("http://big.tree.com").
MatchParams(map[string]string{
"moduleName": "MySQL",
}).
Reply(200).
BodyString(data)
defer gock.Off()
resp, err := http.Get("http://big.tree.com?moduleName=MySQL")
defer resp.Body.Close()
if err != nil {
panic(err)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Println(string(body))
resp2, err := http.Get("http://big.tree.com?moduleName=MySQL")
if err != nil {
panic(err)
}
body, err = ioutil.ReadAll(resp2.Body)
if err != nil {
panic(err)
}
fmt.Println(string(body))
}
the result is
{"code":0,"msg":"ok"}
panic: Get http://big.tree.com?moduleName=MySQL: gock: cannot match any request
goroutine 1 [running]:
main.main()
F:/newbr/t1/main.go:32 +0x502
I am trying to set multiple cookies with the same name on the gock response, but it always seems to only set the first cookie on the response object.
Am I doing something wrong - is there a better way to set cookies?
The mergeHeaders function appears to be the culprit. I have a solution and test here: steinfletcher@75ea39d
Thanks
I'm doing tests with Consul lib, and I'm trying to intercept the requests to Consul but I'm receiving the following error:
Expected nil, but got: &url.Error{Op:"Get", URL:"http://127.0.0.1:8500/v1/kv/bots/my-bot/?recurse=", Err:(*net.OpError)(0xc0000ba3c0)}
that means that I'm not intercepting the requests to Consul, and this is my code:
func TestGetBotById(t *testing.T) {
consulURL := fmt.Sprintf("/v1/kv/bots/%s/", fakeBotID)
consulData := helperLoadBytes(t, "consul/bots.json")
defer gock.Off()
gock.New("http://127.0.0.1:8500").
Get(consulURL).
MatchParams(map[string]string{
"recurse": "",
}).
Persist().
Reply(http.StatusOK).
BodyString(string(consulData))
botInfo, err := helpers.GetBotByID(fakeBotID)
expectedValue := map[string]string{
"host": "my-host",
"port": "3000",
}
assert.Nil(t, err)
assert.NotNil(t, botInfo)
assert.Equal(t, expectedValue, botInfo, "should be equals to")
assert.True(t, gock.IsDone(), true)
}
the function helpers.GetBotById
is making the requests to Consul but grock can't intercept it
does someone has seen the same error?
The following test passes: even though "/b" is the expected path and "/bar" is the actual path:
func TestA(t *testing.T) {
// Passes -- but shouldn't
defer gock.Off()
gock.New("http://foo").
Get("/b").
Reply(http.StatusOK).
BodyString("Some text")
c := &http.Client{}
c.Get("http://foo/bar")
assert.Equal(t, true, gock.IsDone())
}
Is this expected behaviour?
Using a regex ($) seems to give the behaviour I'd expect (for matching and non-matching cases):
func TestB(t *testing.T) {
// Fails -- correctly
defer gock.Off()
gock.New("http://foo").
Get("/b($)").
Reply(http.StatusOK).
BodyString("Some text")
c := &http.Client{}
c.Get("http://foo/bar")
assert.Equal(t, true, gock.IsDone())
}
Thanks.
I'd like to assert that a mocked call occurs once. What is the best way to do this with the Gock library?
For example, with the following mock:
defer gock.Off()
gock.New("http://example.com").
Get("/oauth2/abcd/v1/keys").
Reply(http.StatusOK).
JSON("{\"foo\":\"bar\")
I want to make sure that endpoint is only called once.
I installed gock using the specified gopkg.in url:
go get -u gopkg.in/h2non/gock.v0
And I'm pretty sure it installed a really old version, because .Get() did not exist. Are we supposed to specify the version ourselves? If so, maybe add a hint about that (for the people like me that have not come across a gopkg url before)?
Hey
Here's my code:
defer gock.Off()
gock.New("https://foo.com").
Post("/bar").
MatchHeader("Authorization", "12345").
MatchHeader("Accept", "^"+regexp.QuoteMeta("application/vnd.api+json")+"$").
MatchHeader("Content-Type", "^"+regexp.QuoteMeta("application/vnd.api+json")+"$").
// MatchType("json").
// JSON(map[string]string{"foo": "bar"}).
Reply(201).
JSON(map[string]string{"bar": "foo"})
var reqBody io.Reader
body:=`{"foo": "bar"}`
fmt.Println(body)
bodied := json.RawMessage(body)
jsonDocument, err1 = json.Marshal(bodied)
reqBody = bytes.NewReader(jsonDocument)
statusCode, resBody, err = request("https://foo.com/bar", "POST", "12345", reqBody)
And the request function:
func request(url string, method string, authorization string, body io.Reader) (int, interface{}, error)
{
req, _ := http.NewRequest(method, url, body)
req.Header.Add("Content-Type", applicationType)
req.Header.Add("Authorization","Bearer "+authorization)
req.Header.Add("Accept", applicationType)
client := &http.Client{}
res, err := client.Do(req)
....
}
Works fine without the MatchType("json")
and JSON(json.RawMessage(
{"foo": "bar"}))
. When I comment either of them, the request fails and prints
gock: cannot match any request
I've tried changing many things. Including: removing the RawMessage transformation, changing the body definition e,g. body:=map[string]string{"foo": "bar"}
.
Not sure what I am doing wrong, can you recommend something?
Edit: Using the request function in an actual deployment does work with {"foo": "bar"}, but not in Gock.
Hi,
I test my application A using it's HTTP API. During the test my application calls application B using HTTP API. I would like to mock application B response using gock. I've learned that I have to use networking mode, otherwise my calls to A would fail.
However, even though I created a mock that matches the request issued by application A towards application B, it is not used because of code lines below with my comments added (link to the code in github):
if networking { // true
res, err = m.Transport.RoundTrip(req) // res == nil, err != nil
// In no mock matched, continue with the response
if err != nil || mock == nil { // as err from native transport is not nil, because app B host cannot be reached, native transport res is returned
return res, err // line reached and nil res returned with non-nil err
}
}
return Responder(req, mock.Response(), res)
From the gock's readme I understood that mock takes precedence over NativeTransport in networking mode. The comment from this line additionally enforces me in such understanding. What's your view?
Daniel
I copied the example from the README
and tried to run golangci-lint
on it. This is what I got:
√ ; lsd -l ook.go
.rw-rw-r-- yann yann 294 B Fri Sep 18 12:06:18 2020 ook.go
√ ; bat ook.go
File: ook.go
1 package main
2
3 import (
4 "testing"
5
6 "gopkg.in/h2non/gock.v1"
7 )
8
9 func TestFoo(t *testing.T) {
10 defer gock.Off() // Flush pending mocks after test execution
11
12 gock.New("http://server.com").
13 Get("/bar").
14 Reply(200).
15 JSON(map[string]string{"foo": "bar"})
16
17 // Your test code starts here...
18 }
√ ; golangci-lint run ook.go
WARN [runner] Can't run linter goanalysis_metalinter: S1033: failed prerequisites: [(inspect@command-line-arguments, isgenerated@command-line-arguments): analysis skipped: errors in package: [/home/yann/tmp/ook.go:6:2: could not import gopkg.in/h2non/gock.v1 (ook.go:6:2: cannot find module providing package gopkg.in/h2non/gock.v1: working directory is not part of a module) /home/yann/tmp/ook.go:10:8: undeclared name: gock /home/yann/tmp/ook.go:12:2: undeclared name: gock /home/yann/tmp/ook.go:6:2: "gopkg.in/h2non/gock.v1" imported but not used]]
WARN [runner] Can't run linter unused: buildir: failed to load package : could not load export data: no export data for "gopkg.in/h2non/gock.v1"
ERRO Running error: buildir: failed to load package : could not load export data: no export data for "gopkg.in/h2non/gock.v1"
✗ 3 ;
Am I doing something wrong? If so, what? If not, is that a bug? …
Hi,
thanks for this amazing project!
I've a function like this
func MakeRequest() {
query := url.Values{}
query.Add("key1", "value1")
query.Add("key2", "value2")
queryString := query.Encode()
requestURL := fmt.SPrintf("%s?%s, "http://foo.com/bar", queryString)
res, err := http.Get(requestURL)
....
}
I would like to test it. The simplest way to to that is
func Test(t *testing.T) {
gock.New("http://foo.com").
Get("/bar").
MatchParam("key1", "value1").
MatchParam("key2", "value2").
Reply(200).
JSON(map[string]string{"foo": "bar"})
}
Anyway:
I would like to write something like that:
func Test(t *testing.T) {
query, err := url.ParseQuery("key1=value1&key2=value2")
gock.New("http://foo.com").
Get("/bar").
MatchExactParamValue(query).
Reply(200).
JSON(map[string]string{"foo": "bar"})
}
The check is made exactly using url.Values
struct.
Another proposal can be
func Test(t *testing.T) {
gock.New("http://foo.com").
Get("/bar").
MatchParam("key1", "value1").
MatchParam("key2", "value2").
MatchParamExactly().
Reply(200).
JSON(map[string]string{"foo": "bar"})
}
If you are interested in, I'll send a PR for that implementation or a similar one
Is it possible to access the request body in the ReplyFunc ?
gock.New(myEndpoint).
Post("/scim/v2/Groups").
Persist().
ReplyFunc(func(response *gock.Response) {
response.???
})
I keep getting this error no matter what I do with this mock.
This is the mock:
gock.New("http://www.espn.com").
Get("/nfl/player/gamelog/_/id/16733/year/2015/").
Reply(200).
File("testdata/espn_gamelog_2015.html")
And this is the error I get:
Failed to query ESPN: Get http://espn.go.com/nfl/player/gamelog/_/id/16733/year/2015/: gock: cannot match any request"
As you can see it's the exact same URL. What's wrong?
Right now you can only flush all of the mocks, right? What if I want to flush only certain mocks because I want some mocks to remain?
The case: I've started my service before running any tests, my service fetching some URLs during tests (just by timer), so I want some mocks to remain during all tests run, but at the same time I want to flush test-mocks after each test run.
Is there a way to simulate a http client timeout?
I am struggling to find a way how to implement that.
It would be nice to have an example of that on the docs.
I am planning to open a PR with that, if I find a solution in the the meanwhile.
Thanks
Hello,
I had an issue regarding trying to match JSON payloads with a mocked response even though the keys/values matched exactly. In my search for figuring out why it wasn't working, I noticed that the section in which a check for equality is sensitive to the order by which keys and values are present in the casted string.
My approach to solving this is (at least for JSON) is to convert the byte bodies into a map[string]interface{}
and check equality using reflect.DeepEqual(x,y)
.
I will open a PR shortly with my suggested fixes. I'd like to merge this into master if possible, please let me know if you have any suggestions on how to implement this better.
PR: #16
Thank you 👍
I run into an error trying to run go mod vendor
(we sadly are using Go11Modules + Vendoring at the moment):
$ go mod vendor
go: github.com/h2non/[email protected]: parsing go.mod: unexpected module path "gopkg.in/h2non/gock.v1"
go: error loading module requirements
Any ideas why go mod
is complaining here?
It'd be nice to have a way to specify a compression type, for testing clients that gzip their body contents. For example:
gock.New(url).
Post("/path").
MatchCompression("gzip").
JSON(map[string]interface{}{
"foo": "bar",
}).
Reply(200)
To accomplish this now requires a custom matcher, since the JSON
matcher assumes the request body is unencoded.
I can write a PR if you're interested in including this.
Thanks!
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
Great package @h2non. Thanks for making it.
Question: Is it possible to mock custom SSL Certs in the mocked responses?
package main
import (
"fmt"
"gopkg.in/h2non/gock.v1"
"net/http"
)
func main() {
defer gock.Off()
gock.New("https://blah.com").Path("/path").
AddMatcher(func(request *http.Request, request2 *gock.Request) (b bool, e error) {
fmt.Println("Matcher001")
return false, nil
}).
Reply(200)
gock.New("https://blah.com").Path("/path").
AddMatcher(func(request *http.Request, request2 *gock.Request) (b bool, e error) {
fmt.Println("Matcher002")
return false, nil
}).
Reply(200)
gock.New("https://blah.com").Path("/path").
AddMatcher(func(request *http.Request, request2 *gock.Request) (b bool, e error) {
fmt.Println("FinalMatcher")
return true, nil
}).
Reply(200)
http.Get("https://blah.com/path")
}
Expected Output:
Matcher001
Matcher002
FinalMatcher
Actual Output:
Matcher001
Matcher001
Matcher001
Request.XML() implemented in a way it matches Content-Type of "application/xml". I encountered a third-party API where I need to send "text/xml". I tried to use MatchType
later in a chain, but it seems counter-intuitive (and didn't match in my case, but may be it's due another cause).
I think, it's, probably, more clear to have separate calls to API, like: gock.Post(...).MatchType(...).XML(...)
. Another option is to add optional parameter to XML()
(or add a new method with parameter).
Hello.
Can support import request and response from JSON file configuration?
For example:
{
"request": {
"method": "GET",
"url": "/test"
},
"response": {
"status": 200,
"body": "test 200 OK\n"
}
}
Examples run
curl http://localhost/test
test 200 OK
gock.MatchHeader
accepts two strings (key, value), but the underlying function that matches the mock request Headers against the real request headers is regexp.MatchString
. (File: matchers.go)
The issue is that regexp.MatchString
takes a regex pattern expression and a string.
That causes the problem of matching headers that have parentheses or other special characters.
Example:
// main.go
req, err := http.NewRequest("GET", "http://example.com", nil)
req.Header.Add("User-Agent", "Agent (version1.0)")
// main_test.go
gock.New("http://example.com").
MatchHeader("User-Agent", "Agent (version1.0)"). // Will never match the request
Get("/").
Reply(200).
BodyString("Success")
A way of fixing the issue is that the key and value are escaped first using regexp.QuoteMeta(key) & regexp.QuoteMeta(value)
, before being passed to the regexp.MatchString function.
for _, field := range req.Header[key] {
escapedValue := regexp.QuoteMeta(value[0]) // Something like this
escapedField := regexp.QuoteMeta(field)
match, err = regexp.MatchString(escapedValue, escapedField)
if err != nil {
return false, err
}
if match {
break
}
}
gock v1.0.13 appears to depend on the parth
repository. Using normal go get -u gopkg.in/h2non/gock.v1
in a go modules environment results in the following error:
../../go/pkg/mod/gopkg.in/h2non/[email protected]/matchers.go:123:13: undefined: parth.Sequent
This appears to be caused by the go modules version resolver which somehow imports perth v.1.1.3 as a transitive dependency, instead of the v.2.0.0.
Currently this can be fixed by pinning gock to version v.1.0.12 in the go.mod
file of the project using gock
.
OS version: Ubuntu 18.04
Go version: 1.11.1 linux/amd64
$GOPATH
, using go mod init
go get -u gopkg.in/h2non/gock.v1
to add gock
as a module dependency.Hi,
I'm finding gock extremely useful, however I have a test where I need to make a real call to an httptest Server which will then spawn a couple of requests which gock should intercept.
However, I can't seem to find a way to do it. I tried enabling networking and filtering, which makes it work, but it won't call the actual server, it just mocks that call, too.
It("receives a complete trigger [DOC]", func() {
defer gock.DisableNetworking()
defer gock.DisableNetworkingFilters()
gock.EnableNetworking()
var a args
a.Host = docServer.URL
a.Path = "/triggers"
a.Body = completeTrigger
a.Method = "POST"
a.Headers = map[string]string{
"Authorization": "Token token=" + configuration.Config.AppToken,
"Content-Type": middleware.MimeType,
"Accept": middleware.MimeType,
}
gock.NetworkingFilter(func(req *http.Request) bool {
return req.URL.String() == docServer.URL
})
gock.New(docServer.URL).
Post("/triggers").
Reply(201)
// here are the actual mocks I need
resp, err := a.run()
Expect(err).ToNot(HaveOccurred())
Expect(resp.StatusCode).To(Equal(201))
Expect(gock.IsDone())
})
The first Expect will generate this error:
Expected error:
<*url.Error | 0xc4204040f0>: {
Op: "Post",
URL: "http://127.0.0.1:59186/triggers",
Err: {
s: "gock: cannot match any request",
},
}
Post http://127.0.0.1:59186/triggers: gock: cannot match any request
not to have occurred
Am I missing something?
Thanks a lot for your help!
So I was writing some tests for my code.
In one of my functions I was calling two APIs (for different purposes). So I needed to have two mockers. one of them(route2) should have had a matcher for the request body while the other (route1) did not. (For this, I had make two mockers with gock.New)
Then I traced an unexpected behavior. When I was calling the API to route2, the matcher registered on route1 mocker was being called.
Therefore, I looked up in the code to see the reason and I found out that there was a global variable named "Matchers" in "matcher.go". And this causes all the mockers to have the same matchers which I believe is a bug.
My test code:
//route1
gock.New("http://emad.host").
Get("/notifications/bucketname").
Reply(200).
JSON(map[string]interface{}{
"ok": "ok",
})
//route2
gock.New("http://emad.host").
Put("/notifications/bucketname").
AddMatcher(func(r *http.Request, request *gock.Request) (bool, error) {
fmt.Println("matcher called")
return true, nil
}).Reply(400)
client := &http.Client{}
//this request would call matcher of route2 (unexpected behaviour)
request1, _ := http.NewRequest("GET", "http://emad.host/notifications/bucketname", nil)
fmt.Println(client.Do(request1))
request2, _ := http.NewRequest("PUT", "http://emad.host/notifications/bucketname", bytes.NewReader([]byte(`hello world`)))
fmt.Println(client.Do(request2))
Hi,
is possible to enable verbose mode to see all requests which cross Gock?
If not, I suggest to add it, it is very useful to debug.
Best regards,
Stéphane
Hi,
In my code I do a POST request to a service but before the request is executed I add a http.RoundTripper to add a header to my request. When I comment this code out gock intercepts the request but with the RoundTripper added gock does not seem to intercept the request. Any idea on how to fix it?
Thanks in advance!
I got these two gocks in a test suite:
gock.New("http://www.url.com").
Get("/path/page.php").
MatchParam("site", "yahoo").
Persist().
Reply(200).
File("testdata/yahoo.html")
gock.New("http://www.url.com").
Get("/path/page.php").
MatchParam("site", "google").
Persist().
Reply(200).
File("testdata/google.html")
However, it's always the first gock that takes the requests. What is wrong?
I think, it could be nice to reset unmatchedRequests during Off() so that unit tests will be more independent of each other.
Instead of Reply(code), use:
gock.New("https://google.com").
Get("/foo").
ReplyFunc(func (r *gock.Response) {
r.StatusCode = 200
r.Header.Set("foo", "bar")
})
Are there any plans to support http2 transport mocking?
I am trying to test the following line of code:
func ook() error {
[…]
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return errors.Wrap(err, "cannot read body, trying again")
}
This is my test:
func (errReader) Read(p []byte) (int, error) {
return 1, errors.New("Computer says NON!")
}
// Wait for vault to unseal: body error.
func TestWaitForVaultToUnsealBodyError(t *testing.T) {
defer gock.Off() // Flush pending mocks after test execution
gock.New(URL).
Get("v1/seal-status").
Reply(200).
Body(errReader{})
ook()
}
I removed the URL and other extra stuff, the code is a little (but not much) more complex than that. However, the ioutil.ReadAll
refuses to spew an error. What am I doing wrong?
Setting BodyString
to anything causes the test to crash.
gock.New(skynet.DefaultDownloadOptions.PortalURL).
Get(urlpath).
BodyString("form-data").
Reply(200).
BodyString("test\n")
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x10d3070]
goroutine 7 [running]:
testing.tRunner.func1(0xc000104100)
/usr/local/Cellar/go/1.13.6/libexec/src/testing/testing.go:874 +0x3a3
panic(0x1318620, 0x15f7420)
/usr/local/Cellar/go/1.13.6/libexec/src/runtime/panic.go:679 +0x1b2
io/ioutil.readAll.func1(0xc00012b600)
/usr/local/Cellar/go/1.13.6/libexec/src/io/ioutil/ioutil.go:30 +0x101
panic(0x1318620, 0x15f7420)
/usr/local/Cellar/go/1.13.6/libexec/src/runtime/panic.go:679 +0x1b2
bytes.(*Buffer).ReadFrom(0xc00012b598, 0x0, 0x0, 0x1620940, 0xc00012b5c0, 0x12c76b8)
/usr/local/Cellar/go/1.13.6/libexec/src/bytes/buffer.go:204 +0x80
io/ioutil.readAll(0x0, 0x0, 0x200, 0x0, 0x0, 0x0, 0x0, 0x0)
/usr/local/Cellar/go/1.13.6/libexec/src/io/ioutil/ioutil.go:36 +0x100
io/ioutil.ReadAll(...)
/usr/local/Cellar/go/1.13.6/libexec/src/io/ioutil/ioutil.go:45
gopkg.in/h2non/gock%2ev1.MatchBody(0xc00017c000, 0xc000148270, 0xc00012b601, 0x0, 0x0)
/Users/marcin/go/pkg/mod/gopkg.in/h2non/[email protected]/matchers.go:169 +0x10c
gopkg.in/h2non/gock%2ev1.(*MockMatcher).Match(0xc00015a0c0, 0xc00017c000, 0xc000148270, 0x161fde0, 0x2, 0xa)
/Users/marcin/go/pkg/mod/gopkg.in/h2non/[email protected]/matcher.go:111 +0x77
gopkg.in/h2non/gock%2ev1.(*Mocker).Match(0xc00014a240, 0xc00017c000, 0x1, 0x8, 0xc00012b758)
/Users/marcin/go/pkg/mod/gopkg.in/h2non/[email protected]/mock.go:113 +0x143
gopkg.in/h2non/gock%2ev1.MatchMock(0xc00017c000, 0x30, 0x13616c0, 0xc00012b800, 0x4500000)
/Users/marcin/go/pkg/mod/gopkg.in/h2non/[email protected]/matcher.go:126 +0x7b
gopkg.in/h2non/gock%2ev1.(*Transport).RoundTrip(0xc00000e3a0, 0xc00017c000, 0x0, 0x0, 0x0)
/Users/marcin/go/pkg/mod/gopkg.in/h2non/[email protected]/transport.go:59 +0xae
net/http.send(0xc00017c000, 0x13ea1c0, 0xc00000e3a0, 0x0, 0x0, 0x0, 0xc00015c028, 0x203000, 0x1, 0x0)
/usr/local/Cellar/go/1.13.6/libexec/src/net/http/client.go:250 +0x443
net/http.(*Client).send(0x1602fc0, 0xc00017c000, 0x0, 0x0, 0x0, 0xc00015c028, 0x0, 0x1, 0x136efc0)
/usr/local/Cellar/go/1.13.6/libexec/src/net/http/client.go:174 +0xfa
net/http.(*Client).do(0x1602fc0, 0xc00017c000, 0x0, 0x0, 0x0)
/usr/local/Cellar/go/1.13.6/libexec/src/net/http/client.go:641 +0x3ce
net/http.(*Client).Do(...)
/usr/local/Cellar/go/1.13.6/libexec/src/net/http/client.go:509
net/http.(*Client).Get(0x1602fc0, 0xc00017a000, 0x1d, 0x2, 0x2, 0xc00017a000)
/usr/local/Cellar/go/1.13.6/libexec/src/net/http/client.go:398 +0xbb
net/http.Get(...)
/usr/local/Cellar/go/1.13.6/libexec/src/net/http/client.go:370
github.com/NebulousLabs/go-skynet.DownloadFile(0xc0001780c0, 0x53, 0x137e311, 0x10, 0x137a32c, 0x1, 0x137ec6b, 0x12, 0x0, 0x0)
/Users/marcin/Dropbox/Repos/go-skynet/skynet.go:234 +0x1d8
github.com/NebulousLabs/go-skynet/tests.TestUploadAndDownloadFile(0xc000104100)
/Users/marcin/Dropbox/Repos/go-skynet/tests/integration_test.go:65 +0x693
testing.tRunner(0xc000104100, 0x1393778)
/usr/local/Cellar/go/1.13.6/libexec/src/testing/testing.go:909 +0xc9
created by testing.(*T).Run
/usr/local/Cellar/go/1.13.6/libexec/src/testing/testing.go:960 +0x350
FAIL github.com/NebulousLabs/go-skynet/tests 0.340s
I'm new to gock
and I'm fiddling with it to get some hands-on experience. This is when I got a panic and 1st it wasn't trivial what's going on. As I understand it now: I got a panic
because I set an HTTP body matcher on a GET request. Could we maybe improve the user experience, maybe just by panicking sooner, i.e., when setting the body matcher?
Here is how to reproduce the panic:
package main
import (
"log"
"net/http"
"github.com/h2non/gock"
)
func main() {
const url = "http://example.com"
gock.New(url).BodyString("foo")
if _, err := http.Get(url); err != nil {
log.Fatal(err)
}
}
The panic itself:
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x4d39dd]
goroutine 1 [running]:
io/ioutil.readAll.func1(0xc0001158a8)
/usr/lib/go/src/io/ioutil/ioutil.go:30 +0x106
panic(0x6c1b20, 0x8edce0)
/usr/lib/go/src/runtime/panic.go:969 +0x175
bytes.(*Buffer).ReadFrom(0xc000115830, 0x0, 0x0, 0x70f3c0, 0x10, 0x0)
/usr/lib/go/src/bytes/buffer.go:204 +0x7d
io/ioutil.readAll(0x0, 0x0, 0x200, 0x0, 0x0, 0x0, 0x0, 0x0)
/usr/lib/go/src/io/ioutil/ioutil.go:36 +0xe5
io/ioutil.ReadAll(...)
/usr/lib/go/src/io/ioutil/ioutil.go:45
github.com/h2non/gock.MatchBody(0xc00010e000, 0xc00009d5f0, 0x7f52ef684001, 0x0, 0x0)
/home/frncmx/code/src/github.com/h2non/gock/matchers.go:174 +0x10e
github.com/h2non/gock.(*MockMatcher).Match(0xc0000a82e0, 0xc00010e000, 0xc00009d5f0, 0x108, 0x0, 0xc00004e9e0)
/home/frncmx/code/src/github.com/h2non/gock/matcher.go:113 +0x77
github.com/h2non/gock.(*Mocker).Match(0xc00009ade0, 0xc00010e000, 0x1, 0x255e2, 0xc00004ea40)
/home/frncmx/code/src/github.com/h2non/gock/mock.go:113 +0x145
github.com/h2non/gock.MatchMock(0xc00010e000, 0xc00004eaf8, 0x40efb0, 0xc00009ae40, 0x30)
/home/frncmx/code/src/github.com/h2non/gock/matcher.go:128 +0x7b
github.com/h2non/gock.(*Transport).RoundTrip(0xc0000a8280, 0xc00010e000, 0x0, 0x0, 0x0)
/home/frncmx/code/src/github.com/h2non/gock/transport.go:59 +0x95
net/http.send(0xc00010e000, 0x767a80, 0xc0000a8280, 0x0, 0x0, 0x0, 0xc0000b6040, 0x203000, 0x1, 0x0)
/usr/lib/go/src/net/http/client.go:252 +0x453
net/http.(*Client).send(0x8f9940, 0xc00010e000, 0x0, 0x0, 0x0, 0xc0000b6040, 0x0, 0x1, 0xc00010e000)
/usr/lib/go/src/net/http/client.go:176 +0xff
net/http.(*Client).do(0x8f9940, 0xc00010e000, 0x0, 0x0, 0x0)
/usr/lib/go/src/net/http/client.go:718 +0x45f
net/http.(*Client).Do(...)
/usr/lib/go/src/net/http/client.go:586
net/http.(*Client).Get(0x8f9940, 0x710115, 0x12, 0xc0000b2288, 0x3, 0x8)
/usr/lib/go/src/net/http/client.go:475 +0xbe
net/http.Get(...)
/usr/lib/go/src/net/http/client.go:447
main.main()
/home/frncmx/.config/JetBrains/GoLand2020.2/scratches/scratch_7.go:13 +0xbd
I think the root cause might be the same with #70
Hi,
It's not obvious to me how I can mock only the URLs I want and let the other requests pass.
requestMock := gock.New("test.com")
// Return empty list of tokens
requestMock.Get("/api/v1/users").
Persist().
Reply(200).
JSON(map[string][]string{})
When running the tests I get:
Expected error:
<*url.Error | 0xc000a2d440>: {
Op: "Get",
URL: "http://127.0.0.1:34161/api?timeout=32s",
Err: {
s: "gock: cannot match any request",
},
}
Get http://127.0.0.1:34161/api?timeout=32s: gock: cannot match any request
not to have occurred
I don't want to mock http://127.0.0.1:34161/api?timeout=32s
.
I have tried .EnableNetworking()
, but I don't get the mocked response. I get something like this instead:
{"error": "Get test.com/api/v1/users: unsupported protocol scheme \"\""}
Hey @h2non
Just wanted to say thank you on behalf of my team and I (we're currently hosted on Bitbucket) for creating such an invaluable tool that we use daily in our product.
Love, Anak Kandang Team.
From Jakarta, Indonesia.
AddMatch only use once in a go program?
package main
import (
"fmt"
"net/http"
"regexp"
"gopkg.in/h2non/gock.v1"
)
func test_a() {
defer gock.Off()
gock.New("http://httpbin.org").Get("/").
AddMatcher(func(req *http.Request, ereq *gock.Request) (bool, error) {
matched, err := regexp.MatchString("/aa/[A-Za-z0-9]{6}/ii/[A-Za-z0-9]{6}/calculator", req.URL.Path)
return matched && "GET" == req.Method, err
}).
Reply(204).
SetHeader("Server", "gock")
res, err := http.Get("http://httpbin.org/aa/123456/ii/123456/calculator")
if err != nil {
fmt.Errorf("Error: %s", err)
}
fmt.Printf("Status: %d\n", res.StatusCode)
fmt.Printf("Server header: %s\n", res.Header.Get("Server"))
}
func test_b() {
defer gock.Off()
gock.New("http://httpbin.org").
Get("/application").
Reply(200).
SetHeader("Server", "gockbin")
res, err := http.Get("http://httpbin.org/application")
if err != nil {
fmt.Errorf("Error: %s", err)
}
fmt.Printf("Status: %d\n", res.StatusCode)
fmt.Printf("Server header: %s\n", res.Header.Get("Server"))
}
func main() {
test_a()
test_b()
}
This would more appropriately be an issue on h2non/parth repo, but unfortunately issues are not enabled there. It's also not really resolvable with a pull request, unfortunately. (It's also possible to resolve purely in gock, see the end of this issue)
Currently, go.mod
has the dependency:
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542
This commit corresponds to the h2non/[email protected] tag.
As a result, downstream go.sum
files end up with an entry for v2.0.1+incompatible
because the target commit/tag is still using a v0/v1 path (no /v2
suffix) but is tagged as v2.0.1
.
This then breaks the sumdb verification:
github.com/h2non/[email protected]+incompatible: reading https://proxy.golang.org/github.com/h2non/parth/@v/v2.0.1+incompatible.zip: 410 Gone
server response: not found: github.com/h2non/[email protected]+incompatible: invalid version: +incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required
Would it be possible to merge the changes from h2non/parth@master branch to h2non/parth@v2 branch while ensuring that the module path ends with /v2
in go.mod
and tagging a new version from that? Afterwards, gock
could be updated to use the appropriately semantically versioned module.
Alternatively, since the only (current?) difference between h2non/parth and the original codemodus/parth is the module path, and the upstream does use proper semantic versions, gock could be changed to use that directly. If this is preferable, let me know, and I will happily open a pull request to make the change here!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.