Documentation ¶
Overview ¶
Package govcr records and replays HTTP interactions for offline unit / behavioural / integration tests thereby acting as an HTTP mock.
This project was inspired by php-vcr which is a PHP port of VCR for ruby.
For usage and more information, please refer to the project's README at:
https://github.com/seborama/govcr
Example (Number1SimpleVCR) ¶
Example_simpleVCR is an example use of govcr. It shows how to use govcr in the simplest case when the default http.Client suffices.
package main import ( "fmt" "io/ioutil" "strings" "github.com/seborama/govcr" ) const example1CassetteName = "MyCassette1" func runTestEx1() { // Create vcr and make http call vcr := govcr.NewVCR(example1CassetteName, nil) resp, _ := vcr.Client.Get("http://www.example.com/foo") // Show results fmt.Printf("%d ", resp.StatusCode) fmt.Printf("%s ", resp.Header.Get("Content-Type")) body, _ := ioutil.ReadAll(resp.Body) resp.Body.Close() fmt.Printf("%v ", strings.Contains(string(body), "domain in examples without prior coordination or asking for permission.")) fmt.Printf("%+v\n", vcr.Stats()) } // Example_simpleVCR is an example use of govcr. // It shows how to use govcr in the simplest case when the default // http.Client suffices. func main() { // Delete cassette to enable live HTTP call govcr.DeleteCassette(example1CassetteName, "") // 1st run of the test - will use live HTTP calls runTestEx1() // 2nd run of the test - will use playback runTestEx1() }
Output: 404 text/html; charset=UTF-8 true {TracksLoaded:0 TracksRecorded:1 TracksPlayed:0} 404 text/html; charset=UTF-8 true {TracksLoaded:1 TracksRecorded:0 TracksPlayed:1}
Example (Number2CustomClientVCR1) ¶
Example2 is an example use of govcr. It shows the use of a VCR with a custom Client. Here, the app executes a GET request.
package main import ( "crypto/tls" "fmt" "io/ioutil" "net/http" "strings" "time" "github.com/seborama/govcr" ) const example2CassetteName = "MyCassette2" // myApp is an application container. type myApp struct { httpClient *http.Client } func (app *myApp) Get(url string) (*http.Response, error) { return app.httpClient.Get(url) } func (app *myApp) Post(url string) (*http.Response, error) { // beware: don't use a ReadCloser, only a Reader! body := strings.NewReader(`{"Msg": "This is an example request"}`) return app.httpClient.Post(url, "application/json", body) } func runTestEx2(app *myApp) { var samples = []struct { f func(string) (*http.Response, error) body string }{ {app.Get, "domain in examples without prior coordination or asking for permission."}, {app.Post, "404 - Not Found"}, } // Instantiate VCR. vcr := govcr.NewVCR(example2CassetteName, &govcr.VCRConfig{ Client: app.httpClient, }) // Inject VCR's http.Client wrapper. // The original transport has been preserved, only just wrapped into VCR's. app.httpClient = vcr.Client for _, td := range samples { // Run HTTP call resp, _ := td.f("https://www.example.com/foo") // Show results fmt.Printf("%d ", resp.StatusCode) fmt.Printf("%s ", resp.Header.Get("Content-Type")) body, _ := ioutil.ReadAll(resp.Body) resp.Body.Close() fmt.Printf("%v - ", strings.Contains(string(body), td.body)) } fmt.Printf("%+v\n", vcr.Stats()) } // Example2 is an example use of govcr. // It shows the use of a VCR with a custom Client. // Here, the app executes a GET request. func main() { // Create a custom http.Transport. tr := http.DefaultTransport.(*http.Transport) tr.TLSClientConfig = &tls.Config{ InsecureSkipVerify: true, // just an example, not recommended } // Create an instance of myApp. // It uses the custom Transport created above and a custom Timeout. app := &myApp{ httpClient: &http.Client{ Transport: tr, Timeout: 15 * time.Second, }, } // Delete cassette to enable live HTTP call govcr.DeleteCassette(example2CassetteName, "") // 1st run of the test - will use live HTTP calls runTestEx2(app) // 2nd run of the test - will use playback runTestEx2(app) }
Output: 404 text/html; charset=UTF-8 true - 404 text/html; charset=UTF-8 true - {TracksLoaded:0 TracksRecorded:2 TracksPlayed:0} 404 text/html; charset=UTF-8 true - 404 text/html; charset=UTF-8 true - {TracksLoaded:2 TracksRecorded:0 TracksPlayed:2}
Example (Number3HeaderExclusionVCR) ¶
Example_simpleVCR is an example use of govcr. It shows how to use govcr in the simplest case when the default http.Client suffices.
package main import ( "fmt" "io/ioutil" "net/http" "strings" "time" "github.com/seborama/govcr" ) const example3CassetteName = "MyCassette3" func runTestEx4() { var samples = []struct { method string body string }{ {"GET", "domain in examples without prior coordination or asking for permission."}, {"POST", "404 - Not Found"}, {"PUT", ""}, {"DELETE", ""}, } // Create vcr vcr := govcr.NewVCR(example3CassetteName, &govcr.VCRConfig{ ExcludeHeaderFunc: func(key string) bool { // HTTP headers are case-insensitive return strings.ToLower(key) == "x-custom-my-date" }, }) for _, td := range samples { // Create a request with our custom header req, _ := http.NewRequest(td.method, "http://www.example.com/foo", nil) req.Header.Add("X-Custom-My-Date", time.Now().String()) // Make http call resp, _ := vcr.Client.Do(req) // Show results fmt.Printf("%d ", resp.StatusCode) fmt.Printf("%s ", resp.Header.Get("Content-Type")) body, _ := ioutil.ReadAll(resp.Body) resp.Body.Close() fmt.Printf("%v ", strings.Contains(string(body), td.body)) } fmt.Printf("%+v\n", vcr.Stats()) } // Example_simpleVCR is an example use of govcr. // It shows how to use govcr in the simplest case when the default // http.Client suffices. func main() { // Delete cassette to enable live HTTP call govcr.DeleteCassette(example3CassetteName, "") // 1st run of the test - will use live HTTP calls runTestEx4() // 2nd run of the test - will use playback runTestEx4() }
Output: 404 text/html; charset=UTF-8 true 404 text/html; charset=UTF-8 true 404 text/html; charset=UTF-8 true 404 text/html; charset=UTF-8 true {TracksLoaded:0 TracksRecorded:4 TracksPlayed:0} 404 text/html; charset=UTF-8 true 404 text/html; charset=UTF-8 true 404 text/html; charset=UTF-8 true 404 text/html; charset=UTF-8 true {TracksLoaded:4 TracksRecorded:0 TracksPlayed:4}
Index ¶
- func CassetteExistsAndValid(cassetteName, cassettePath string) bool
- func DeleteCassette(cassetteName, cassettePath string) error
- func GetFirstValue(hdr http.Header, key string) string
- type ExcludeHeaderFunc
- type RequestFilterFunc
- type ResponseFilterFunc
- type Stats
- type VCRConfig
- type VCRControlPanel
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CassetteExistsAndValid ¶
CassetteExistsAndValid verifies a cassette file exists and is seemingly valid.
func DeleteCassette ¶
DeleteCassette removes the cassette file from disk.
func GetFirstValue ¶
GetFirstValue is a utility function that extracts the first value of a header key. The reason for this function is that some servers require case sensitive headers which prevent the use of http.Header.Get() as it expects header keys to be canonicalized.
Types ¶
type ExcludeHeaderFunc ¶
ExcludeHeaderFunc is a hook function that is used to filter the Header.
Typically this can be used to remove / amend undesirable custom headers from the request.
For instance, if your application sends requests with a timestamp held in a custom header, you likely want to exclude it from the comparison to ensure that the request headers are considered a match with those saved on the cassette's track.
Parameters:
- parameter 1 - Name of header key in the Request
Return value: true - exclude header key from comparison false - retain header key for comparison
type RequestFilterFunc ¶
RequestFilterFunc is a hook function that is used to filter the Request Header / Body.
Typically this can be used to remove / amend undesirable header / body elements from the request.
For instance, if your application sends requests with a timestamp held in a part of the header / body, you likely want to remove it or force a static timestamp via RequestFilterFunc to ensure that the request body matches those saved on the cassette's track.
It is important to note that this differs from ExcludeHeaderFunc in that the former does not modify the header (it only returns a bool) whereas this function can be used to modify the header.
Parameters:
- parameter 1 - Copy of http.Header of the Request
- parameter 2 - Copy of string of the Request's Body
Return values:
- value 1 - Request's amended header
- value 2 - Request's amended body
type ResponseFilterFunc ¶
ResponseFilterFunc is a hook function that is used to filter the Response Header / Body.
It works similarly to RequestFilterFunc but applies to the Response and also receives a copy of the Request's header (if you need to pick info from it to override the response).
Parameters:
- parameter 1 - Copy of http.Header of the Response
- parameter 2 - Copy of string of the Response's Body
- parameter 3 - Copy of http.Header of the Request
Return values:
- value 1 - Response's amended header
- value 2 - Response's amended body
type Stats ¶
type Stats struct { // TracksLoaded is the number of tracks that were loaded from the cassette. TracksLoaded int // TracksRecorded is the number of new tracks recorded by VCR. TracksRecorded int // TracksPlayed is the number of tracks played back straight from the cassette. // I.e. tracks that were already present on the cassette and were played back. TracksPlayed int }
Stats holds information about the cassette and VCR runtime.
type VCRConfig ¶
type VCRConfig struct { Client *http.Client ExcludeHeaderFunc ExcludeHeaderFunc 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. ResponseFilterFunc ResponseFilterFunc DisableRecording bool Logging bool CassettePath string }
VCRConfig holds a set of options for the VCR.
type VCRControlPanel ¶
VCRControlPanel holds the parts of a VCR that can be interacted with. Client is the HTTP client associated with the VCR.
func NewVCR ¶
func NewVCR(cassetteName string, vcrConfig *VCRConfig) *VCRControlPanel
NewVCR creates a new VCR and loads a cassette. A RoundTripper can be provided when a custom Transport is needed (for example to provide certificates, etc)
func (*VCRControlPanel) Stats ¶
func (vcr *VCRControlPanel) Stats() Stats
Stats returns Stats about the cassette and VCR session.