-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add advanced filtering #32
Conversation
When running tests where multiple request types are used, it if quite difficult to set up proper filtering. To help this, I made it possible to chain multiple filters and check URL and method. Furthermore the URL can now be modified. For future-proofing the Request and Response structs can now be extended with more stuff without breaking compatibility. If you like this, I can add some tests for the new functionality.
Fix documentation.
After doing some examples I've decided to re-write some of the stuff... It is a bit too clunky to use now. |
Add body replacement example.
@seborama I have added examples for using the specific filtering. If there is more I can do, please let me know. I think it is now reasonably easy to use and allows for much flexibility. Adding some unit tests to the filters should be fairly easy if you like it overall. |
Hi @klauspost, Thanks for contributing. Regards |
I just noticed you have also posted some examples... |
To give the overall picture, I need some tests to test functionality that can do multiple calls to the same endpoint. The endpoint will return unique IDs, so I need to be able to flexibly adjust content of the returned bodies. URLs typically have IDs as well, so I need to be able to still match content even though IDs change. A huge pain point was that it wasn't possible to do URL/method matching, so transforms would only happen when specific combinations were hit. This will record requests with request transformations applied, so "transformed" requests would be stored and allow for more flexible matching. The unmodified request is given to the response filters, so they can still operate on the full information given. |
govcr.go
Outdated
// Original filter is unmodified. | ||
func (r RequestFilter) OnPath(pathRegEx string) RequestFilter { | ||
if pathRegEx == "" { | ||
pathRegEx = "*" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't a valid regex.
Use "."
or ".*"
govcr.go
Outdated
// Original filter is unmodified. | ||
func (r ResponseFilter) OnPath(pathRegEx string) ResponseFilter { | ||
if pathRegEx == "" { | ||
pathRegEx = "*" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"*"
is not a valid regex.
use "."
or ".*"
govcr.go
Outdated
*r = v | ||
} | ||
|
||
// First one or more filters before the current ones. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prepend
rather?
govcr.go
Outdated
} | ||
|
||
// First one or more filters before the current ones. | ||
func (r ResponseFilters) First(filters ...ResponseFilter) ResponseFilters { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prepend
rather?
govcr.go
Outdated
@@ -270,8 +532,23 @@ type RequestFilterFunc func(http.Header, []byte) (*http.Header, *[]byte) | |||
// Return values: | |||
// - value 1 - Response's amended header | |||
// - value 2 - Response's amended body | |||
// Deprecated: Use ResponseFilterFunc instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're going to go down this road, let's get rid off ResponseFilterFunc
altogether.
This would form v3 of govcr.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Just didn't want to break it unless you were fine with it.
govcr.go
Outdated
@@ -28,12 +30,21 @@ const defaultCassettePath = "./govcr-fixtures/" | |||
type VCRConfig struct { | |||
Client *http.Client | |||
ExcludeHeaderFunc ExcludeHeaderFunc | |||
|
|||
// Deprecated, use RequestFilter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're going to go down this road, let's get rid of RequestFilterFunc
altogether.
This would form v3 of govcr.
govcr.go
Outdated
RequestFilterFunc RequestFilterFunc | ||
|
||
// ResponseFilterFunc can be used to modify the header of the response. | ||
// This is useful when a fingerprint is exchanged and expected to match between request and response. | ||
// Deprecated, use ResponseFilter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're going to go down this road, let's get rid of ResponseFilterFunc
altogether.
This would form v3 of govcr.
} | ||
|
||
// print outcome. | ||
fmt.Println("Status code:", resp.StatusCode, " (should be 404 on real and 202 on replay)") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should form the basis of a formal go example test (as in the root folder xxx_examplen_test.go
and some unit tests too.
|
||
// Add header if method was "GET" | ||
govcr.ResponseFilter(func(resp govcr.Response) govcr.Response { | ||
resp.Header.Add("method-was-get", "true") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
best to use a different value such as present
or added
etc
when using 'true', this is converted to a boolean by the http client which then cannot be displayed by Println().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure what you mean, it prints fine:
method-was-post: true (should be true on replay on POST)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ha, odd! On my environment the word 'true' is missing (go 1.11.1)
|
||
// Add header if method was "POST" | ||
govcr.ResponseFilter(func(resp govcr.Response) govcr.Response { | ||
resp.Header.Add("method-was-post", "true") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
best to use a different value such as present
or added
etc
when using 'true', this is converted to a boolean by the http client which then cannot be displayed by Println().
govcr.go
Outdated
// ResponseFilters is a slice of ResponseFilter | ||
type ResponseFilters []ResponseFilter | ||
|
||
// ResponseContext provides the response parameters. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a ResponseContext
govcr.go
Outdated
} | ||
} | ||
|
||
// AddHeaderValue will add or overwrite a header to the request |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Method says RequestAddHeaderValue?
govcr.go
Outdated
} | ||
} | ||
|
||
// DeleteHeaderKeys will delete one or more header keys on the request |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Method says RequestDeleteHeaderKeys
govcr.go
Outdated
} | ||
} | ||
|
||
// ResponseDeleteHeader will delete one or more headers on the response when returned from vcr playback. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Method says ResponseDeleteHeaderKeys
govcr.go
Outdated
} | ||
} | ||
|
||
// Chain one or more filters after the current one and return as single filter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Invalid comment: method name is Append
Hi, Great contribution! I think this PR should take us straight to the long outstanding v3 of govcr. I have some comments:
On a more philosophical note, I am concerned with Regards. |
Indeed. Didn't want to spend the time upfront if you didn't like the concept.
👍
👍
Technically it is not much that couldn't be achieved before, just in a more available interface. Things like testing external interfaces often includes complex logic, and having it available for advanced needs can be a positive. |
Sounds good. I realise there's quite a bit in my comments. Don't feel coerced into doing all. I can pick up some of it if you like. |
Remove Append and make Prepend operate on pointer and not return new slice.
No problem. I have added tests for all new functions and added the examples as tests as well. Made a few tweaks. I removed "Append" and changed "Prepend" to not return the updated slice - seems to just be a way of forgetting to re-assign the returned value. I can't really tell if I don't have plans for more changes unless you ask me to :) |
Thanks. Let me know when you're happy with the PR and I'll merge it. It would be nice if at least the docs were updated 😄 |
Sorry I'm reading this on my mobile and I seem to consistently fail to read your messages in whole. I just noticed you said you're done. I'll merge when I get a chance. Thanks for your time and for sharing your contributions. I'm sure many people will be grateful too. Bonne chance! |
When running tests where multiple request types are used, it if quite difficult to set up proper filtering.
To help this, I made it possible to chain multiple filters and check URL and method.
Furthermore the URL can now be modified.
For future-proofing the Request and Response structs can now be extended with more stuff without breaking compatibility.
If you like this, I can add some tests for the new functionality.