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://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 true {TracksLoaded:0 TracksRecorded:1 TracksPlayed:0} 404 text/html 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://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 true - 404 text/html true - {TracksLoaded:0 TracksRecorded:2 TracksPlayed:0} 404 text/html true - 404 text/html 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" "time" "strings" "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://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 true 404 text/html true 405 true 405 true {TracksLoaded:0 TracksRecorded:4 TracksPlayed:0} 404 text/html true 404 text/html true 405 true 405 true {TracksLoaded:4 TracksRecorded:0 TracksPlayed:4}
Index ¶
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 ¶ added in v1.6.0
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 BodyFilterFunc ¶
BodyFilterFunc is a hook function that is used to filter the Body.
Typically this can be used to remove / amend undesirable body elements from the request.
For instance, if your application sends requests with a timestamp held in a part of the body, you likely want to remove it or force a static timestamp via BodyFilterFunc to ensure that the request body matches those saved on the cassette's track.
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.
type HeaderFilterFunc ¶ added in v1.4.0
HeaderFilterFunc is a hook function that is used to filter the Header.
It works like BodyFilterFunc but applies to the header.
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.
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 RequestBodyFilterFunc BodyFilterFunc // ResponseHeaderFilterFunc 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. ResponseHeaderFilterFunc HeaderFilterFunc // ResponseBodyFilterFunc can be used to modify the body of the response. // This is useful when a fingerprint is exchanged and expected to match between request and response. ResponseBodyFilterFunc BodyFilterFunc 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.