1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
|
## go-vcr
[](https://travis-ci.org/dnaeon/go-vcr)
[](https://godoc.org/github.com/dnaeon/go-vcr)
[](https://goreportcard.com/report/github.com/dnaeon/go-vcr)
[](https://codecov.io/gh/dnaeon/go-vcr)
`go-vcr` simplifies testing by recording your HTTP interactions and
replaying them in future runs in order to provide fast, deterministic
and accurate testing of your code.
`go-vcr` was inspired by the [VCR library for Ruby](https://github.com/vcr/vcr).
## Installation
Install `go-vcr` by executing the command below:
```bash
$ go get github.com/dnaeon/go-vcr/recorder
```
## Usage
Here is a simple example of recording and replaying
[etcd](https://github.com/coreos/etcd) HTTP interactions.
You can find other examples in the `example` directory of this
repository as well.
```go
package main
import (
"log"
"time"
"github.com/dnaeon/go-vcr/recorder"
"github.com/coreos/etcd/client"
"golang.org/x/net/context"
)
func main() {
// Start our recorder
r, err := recorder.New("fixtures/etcd")
if err != nil {
log.Fatal(err)
}
defer r.Stop() // Make sure recorder is stopped once done with it
// Create an etcd configuration using our transport
cfg := client.Config{
Endpoints: []string{"http://127.0.0.1:2379"},
HeaderTimeoutPerRequest: time.Second,
Transport: r, // Inject as transport!
}
// Create an etcd client using the above configuration
c, err := client.New(cfg)
if err != nil {
log.Fatalf("Failed to create etcd client: %s", err)
}
// Get an example key from etcd
etcdKey := "/foo"
kapi := client.NewKeysAPI(c)
resp, err := kapi.Get(context.Background(), etcdKey, nil)
if err != nil {
log.Fatalf("Failed to get etcd key %s: %s", etcdKey, err)
}
log.Printf("Successfully retrieved etcd key %s: %s", etcdKey, resp.Node.Value)
}
```
## Custom Request Matching
During replay mode, You can customize the way incoming requests are
matched against the recorded request/response pairs by defining a
Matcher function. For example, the following matcher will match on
method, URL and body:
```go
r, err := recorder.New("fixtures/matchers")
if err != nil {
log.Fatal(err)
}
defer r.Stop() // Make sure recorder is stopped once done with it
r.SetMatcher(func(r *http.Request, i cassette.Request) bool {
if r.Body == nil {
return cassette.DefaultMatcher(r, i)
}
var b bytes.Buffer
if _, err := b.ReadFrom(r.Body); err != nil {
return false
}
r.Body = ioutil.NopCloser(&b)
return cassette.DefaultMatcher(r, i) && (b.String() == "" || b.String() == i.Body)
})
```
## Protecting Sensitive Data
You often provide sensitive data, such as API credentials, when making
requests against a service.
By default, this data will be stored in the recorded data but you probably
don't want this.
Removing or replacing data before it is stored can be done by adding one or
more `Filter`s to your `Recorder`.
Here is an example that removes the `Authorization` header from all requests:
```go
r, err := recorder.New("fixtures/filters")
if err != nil {
log.Fatal(err)
}
defer r.Stop() // Make sure recorder is stopped once done with it
// Add a filter which removes Authorization headers from all requests:
r.AddFilter(func(i *cassette.Interaction) error {
delete(i.Request.Headers, "Authorization")
return nil
})
```
### Sensitive data in responses
Filters added using `*Recorder.AddFilter` are applied within VCR's custom `http.Transport`. This means that if you edit a response in such a filter then subsequent test code will see the edited response. This may not be desirable in all cases. For instance, if a response body contains an OAuth access token that is needed for subsequent requests, then redact the access token in `SaveFilter` will result in authorization failures.
Another way to edit recorded interactions is to use `*Recorder.AddSaveFilter`. Filters added with this method are applied just before interactions are saved when `*Recorder.Stop` is called.
```go
r, err := recorder.New("fixtures/filters")
if err != nil {
log.Fatal(err)
}
defer r.Stop() // Make sure recorder is stopped once done with it
// Your test code will continue to see the real access token and
// it is redacted before the recorded interactions are saved
r.AddSaveFilter(func(i *cassette.Interaction) error {
if strings.Contains(i.URL, "/oauth/token") {
i.Response.Body = `{"access_token": "[REDACTED]"}`
}
return nil
})
```
## Passing Through Requests
Sometimes you want to allow specific requests to pass through to the remote
server without recording anything.
Globally, you can use `ModeDisabled` for this, but if you want to disable the
recorder for individual requests, you can add `Passthrough` functions to the
recorder. The function takes a pointer to the original request, and returns a
boolean, indicating if the request should pass through to the remote server.
Here's an example to pass through requests to a specific endpoint:
```go
// Pass through the request to the remote server if the path matches "/login".
r.AddPassthrough(func(req *http.Request) bool {
return req.URL.Path == "/login"
})
```
## License
`go-vcr` is Open Source and licensed under the
[BSD License](http://opensource.org/licenses/BSD-2-Clause)
|