Comments (8)
I use Filter solve this problem
`func filter(req *http.Request) bool {
matched, _ := regexp.MatchString("/aa/[A-Za-z0-9]{6}/ii/[A-Za-z0-9]{6}/calculator", req.URL.Path)
return matched && "GET" == req.Method
}
func test_a() {
defer gock.Off()
gock.New("http://httpbin.org").Filter(filter).
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"))
}`
from gock.
It does this probably because we modify the DefaultMathcer. I tried to add DefaultMatcher = NewMatcher()
to OffAll, to check my theory and to me the behavior becomes more logical. But I speak only about this one case. Dunno if changing this breaks some other consistent behavior that I am not aware of.
from gock.
Same here. So the matchers somehow live forever in your stack even if you call gock.Off()? Is this a feature or a bug? I could work around by using filters too.
from gock.
@JusbeR It's intended. If you want to clean any unmatched request from the mock store, you should call gock.OffAll()
instead.
from gock.
Hmm, it feels like I am not getting something here now. If I run this:
package main
import (
"log"
"net/http"
"gopkg.in/h2non/gock.v1"
)
func NewGockClient() *http.Client {
c := &http.Client{Transport: &http.Transport{}}
gock.InterceptClient(c)
return c
}
func failingMatcher() {
log.Println("Failing matcher")
defer gock.OffAll()
gock.New("https://example.com").
Get("/api").
AddMatcher(func(req *http.Request, ereq *gock.Request) (bool, error) { return false, nil }).
Reply(200).
BodyString("{}")
c := NewGockClient()
req, _ := http.NewRequest("GET", "https://example.com/api", nil)
_, err := c.Do(req)
if err != nil {
log.Println("Failed:", err)
} else {
log.Println("Ok")
}
}
func noMatcher() {
log.Println("No matcher")
defer gock.OffAll()
gock.New("https://example.com").
Get("/api").
Reply(200).
BodyString("{}")
c := NewGockClient()
req, _ := http.NewRequest("GET", "https://example.com/api", nil)
_, err := c.Do(req)
if err != nil {
log.Println("Failed:", err)
} else {
log.Println("Ok")
}
}
func main() {
noMatcher()
failingMatcher()
noMatcher()
}
I get:
2018/08/15 08:47:34 No matcher
2018/08/15 08:47:34 Ok
2018/08/15 08:47:34 Failing matcher
2018/08/15 08:47:34 Failed: Get https://example.com/api: gock: cannot match any request
2018/08/15 08:47:34 No matcher
2018/08/15 08:47:34 Failed: Get https://example.com/api: gock: cannot match any request
Which should not happen after the OffAll
call?
from gock.
I just ran into this, and agree that the problem is that AddMatcher()
is modifying DefaultMatcher
. This is because, if you call gock.New()
, which calls NewMock()
under the hood, you'll get a mock with matcher
set to DefaultMatcher
. Adding a matcher results in DefaultMatcher.Add(myFunc)
, which will modify DefaultMatcher
by appending myFunc
to its array of match functions. The effect will be felt by any subsequent tests that call gock.New()
.
The result: the presence of an AddMatcher()
in one test is breaking subsequent tests, irrespective of whether gock.Off()
or gock.OffAll()
is used.
My workaround for now is to change this:
gock.New(someURL).
Get(somePath).
AddMatcher(someMatchFunc).
Reply(...)
to this:
gock.New(someURL).
Get(somePath).
SetMatcher(gock.NewMatcher()).
AddMatcher(someMatchFunc).
Reply(...)
This assigns the mock a brand-new matcher object. The new matcher has the same battery of matching functions that DefaultMatcher
does out of the box, which is what I want. Furthermore, because the mock now has its own local matcher object, AddMatcher
only modifies that mock in isolation.
Though this seems to work, I am not happy with this solution – few programmers are going to expect AddMatcher
to be modifying global state out of the box, and SetMatcher()
is very easy to forget! Some options I'd like to put on the table to fix this:
- Change
NewMock()
to callNewMatcher()
instead of usingDefaultMatcher
. Downside: anybody who expectedNewMock()
to useDefaultMatcher
prototypically would be broken. - Change
NewMock()
to cloneDefaultMatcher
– e.g. usingDefaultMatcher.Get()
to get the array of matching funcs, and passing those to a newMockMatcher
. This means any changes you make toDefaultMatcher
will apply to new mocks going forward, which preserves that existing behavior. This seems to me the least elegant, but perhaps the most backwards-compatible, solution. - Change the semantics of
Matcher
to make it immutable –Add()
,Set()
, andFlush()
give you a newMatcher
instead of modifying the existing one, a laappend()
and slices. This is, of course, a breaking API change.
Thoughts?
from gock.
@ods94065 Thanks for the comment here. I review the issue and your points makes sense to me. I don't recall why I have decided to modify package-level state to be honest, but reviewing it now, I think it was a design mistake.
Options 1 and 2 seems reasonable to me and it's pretty much what I had in mind. Will push a fix soon. I might have some negative side-effects to some users, but I will not consider it a breaking change.
The good thing about the option 2 is that users that want to have globally shared matches can still rely on it by using gock.DefaultMatcher
methods.
from gock.
@h2non Any progress on this? I just hit the same bug, and I'm happy to spend some time fixing it using one of the above suggestion if that helps
from gock.
Related Issues (20)
- gock issue while mocking Prometheus with URL escaped query parameters HOT 3
- Mocking InsecureSkipVerify requests HOT 1
- TestResponderPreExpiredContext fails with go1.16 and up
- test code with EnableNetworking does not pass through header info
- Matching an array in the request body
- Header does not set if header exists and EnableNetworking() HOT 1
- is there any solution to generate response in the runtime? HOT 1
- use JSON() as post body matcher, does the order of fields in the body affect matching result HOT 1
- Lack of clarity about the usage of `gock.New` and how it only matches hosts
- Want to take over toxy, but you can't open a New Issue on archived repos.
- Gock is not intercepting unit tests request
- Support for custom mime types HOT 4
- [Question] How to mock two urls and corresponding responses. HOT 2
- Race condition in mock.go file
- can not mock successfully when using `gock.EnableNetworking()` HOT 4
- not matching GET request
- panic on go 1.17 HOT 1
- How to test google api using gock?
- Mocked response with 301 status code and location header returns an error HOT 1
- My tests fail with GitHub Actions: mocks seem to be ignored 🤷 HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from gock.