Skip to content
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 DiscardOnSave field to Interaction type #81

Merged
merged 1 commit into from
Oct 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 30 additions & 3 deletions cassette/cassette.go
Expand Up @@ -123,10 +123,23 @@ type Response struct {
// Interaction type contains a pair of request/response for a
// single HTTP interaction between a client and a server
type Interaction struct {
ID int `yaml:"id"`
Request Request `yaml:"request"`
// ID is the id of the interaction
ID int `yaml:"id"`

// Request is the recorded request
Request Request `yaml:"request"`

// Response is the recorded response
Response Response `yaml:"response"`
replayed bool `yaml:"-"`

// DiscardOnSave if set to true will discard the interaction
// as a whole and it will not be part of the final
// interactions when saving the cassette on disk.
DiscardOnSave bool `yaml:"-"`

// replayed is true when this interaction has been played
// already.
replayed bool `yaml:"-"`
}

// GetHTTPRequest converts the recorded interaction request to
Expand Down Expand Up @@ -301,6 +314,20 @@ func (c *Cassette) Save() error {
}
}

// Filter out interactions which should be discarded. While
// discarding interactions we should also fix the interaction
// IDs, so that we don't introduce gaps in the final results.
nextId := 0
interactions := make([]*Interaction, 0)
for _, i := range c.Interactions {
if !i.DiscardOnSave {
i.ID = nextId
interactions = append(interactions, i)
nextId += 1
}
}
c.Interactions = interactions

// Marshal to YAML and save interactions
data, err := yaml.Marshal(c)
if err != nil {
Expand Down
79 changes: 79 additions & 0 deletions recorder/recorder_test.go
Expand Up @@ -1225,3 +1225,82 @@ func TestInvalidRecorderMode(t *testing.T) {
t.Fatal("expected recorder to fail with invalid mode")
}
}

func TestDiscardInteractionsOnSave(t *testing.T) {
tests := []testCase{
{
method: http.MethodPost,
body: "foo",
wantBody: "POST go-vcr\nfoo",
wantStatus: http.StatusOK,
wantContentLength: 15,
path: "/api/v1/foo",
},
{
method: http.MethodPost,
body: "bar",
wantBody: "POST go-vcr\nbar",
wantStatus: http.StatusOK,
wantContentLength: 15,
path: "/api/v1/bar",
},
}

server := newEchoHttpServer()
serverUrl := server.URL

cassPath, err := newCassettePath("test_discard_interactions_on_save")
if err != nil {
t.Fatal(err)
}

// Create recorder
rec, err := recorder.New(cassPath)
if err != nil {
t.Fatal(err)
}

if rec.Mode() != recorder.ModeRecordOnce {
t.Fatal("recorder is not in the correct mode")
}

if rec.IsRecording() != true {
t.Fatal("recorder is not recording")
}

// The following hook function will be used to determine
// whether an interaction is to be discarded when saving the
// cassette on disk.
hook := func(i *cassette.Interaction) error {
if i.Request.Method == http.MethodPost && i.Request.Body == "foo" {
i.DiscardOnSave = true
}

return nil
}
rec.AddHook(hook, recorder.AfterCaptureHook)

ctx := context.Background()
client := rec.GetDefaultClient()
for _, test := range tests {
if err := test.run(client, ctx, serverUrl); err != nil {
t.Fatal(err)
}
}

// Stop recorder and verify cassette
rec.Stop()

cass, err := cassette.Load(cassPath)
if err != nil {
t.Fatal(err)
}

// We should have one interaction less than our test cases
// when reading the cassette from disk.
wantInteractions := len(tests) - 1
gotInteractions := len(cass.Interactions)
if wantInteractions != gotInteractions {
t.Fatalf("expected %d interactions, got %d", wantInteractions, gotInteractions)
}
}