dnaeon / go-vcr

Record and replay your HTTP interactions for fast, deterministic and accurate tests
BSD 2-Clause "Simplified" License
1.26k stars 77 forks source link

go-vcr does not work with `google/go-github` and/or `golang.org/x/oauth2` library #59

Closed AnalogJ closed 3 years ago

AnalogJ commented 3 years ago

I'm attempting to record and playback interactions with the Github API (using the google/go-github library). However my interactions are not being recorded to cassettes. The "same" code is tested and working with other libraries, so I'm not sure what's going on. For additional context, I had previously used the https://github.com/seborama/govcr library, and it was able to record the interactions correctly (though I removed it because it seems to be unmaintained).

Here's a simplified version of my test suite. It passes, but does not create any recordings. If I had to guess, there's some internal magic in the oauth2.Transport that go-vcr can't hook into.

package example_test

import (
    "context"
    "github.com/dnaeon/go-vcr/cassette"
    "github.com/dnaeon/go-vcr/recorder"
    "github.com/google/go-github/v33/github"
    "github.com/stretchr/testify/require"
    "golang.org/x/oauth2"
    "net/http"
    "path"
    "testing"
)

func TestGithub(t *testing.T) {
    //custom http.Transport, since github uses oauth2 authentication
    ts := oauth2.StaticTokenSource(
        &oauth2.Token{AccessToken: "YOUR_GITHUB_TOKEN"},
    )

    tr := &oauth2.Transport{
        Base:  http.DefaultTransport,
        Source: oauth2.ReuseTokenSource(nil, ts),
    }

    // Start our recorder
    vcrRecorder, err := recorder.NewAsMode(path.Join("testdata", "fixtures", t.Name()), recorder.ModeRecording, tr)
    require.NoError(t, err)

    // Filter out dynamic & sensitive data/headers
    // Your test code will continue to see the real access token and
    // it is redacted before the recorded interactions are saved
        // =====> commenting out this section has no impact on missing recording
    vcrRecorder.AddSaveFilter(func(i *cassette.Interaction) error {
        delete(i.Request.Headers, "Authorization")
        delete(i.Request.Headers, "User-Agent")
        i.Request.Headers["Authorization"] = []string{"Basic UExBQ0VIT0xERVI6UExBQ0VIT0xERVI="} //PLACEHOLDER:PLACEHOLDER

        return nil
    })

        // custom http.client
    httpClient := &http.Client{
        Transport: vcrRecorder,
    }

    ghClient := github.NewClient(httpClient)

    // =====> actual test, should create cassettes, but does not.
    _, _, err = ghClient.Users.Get(context.Background(), "")

    require.NoError(t, err)
}
dnaeon commented 3 years ago

Hey @AnalogJ ,

I don't see in your example code a call to vcrRecorder.Stop().

Once you are done with the recording you should explicitly call vcrRecorder.Stop(), which is when saving of the cassettes happens.

Can you try this code?

package example_test

import (
    "context"
    "github.com/dnaeon/go-vcr/cassette"
    "github.com/dnaeon/go-vcr/recorder"
    "github.com/google/go-github/v33/github"
    "github.com/stretchr/testify/require"
    "golang.org/x/oauth2"
    "net/http"
    "path"
    "testing"
)

func TestGithub(t *testing.T) {
    //custom http.Transport, since github uses oauth2 authentication
    ts := oauth2.StaticTokenSource(
        &oauth2.Token{AccessToken: "YOUR_GITHUB_TOKEN"},
    )

    tr := &oauth2.Transport{
        Base:  http.DefaultTransport,
        Source: oauth2.ReuseTokenSource(nil, ts),
    }

    // Start our recorder
    vcrRecorder, err := recorder.NewAsMode(path.Join("testdata", "fixtures", t.Name()), recorder.ModeRecording, tr)
    require.NoError(t, err)
        defer vcrRecorder.Stop() // NEWLY ADDED CODE HERE

    // Filter out dynamic & sensitive data/headers
    // Your test code will continue to see the real access token and
    // it is redacted before the recorded interactions are saved
        // =====> commenting out this section has no impact on missing recording
    vcrRecorder.AddSaveFilter(func(i *cassette.Interaction) error {
        delete(i.Request.Headers, "Authorization")
        delete(i.Request.Headers, "User-Agent")
        i.Request.Headers["Authorization"] = []string{"Basic UExBQ0VIT0xERVI6UExBQ0VIT0xERVI="} //PLACEHOLDER:PLACEHOLDER

        return nil
    })

        // custom http.client
    httpClient := &http.Client{
        Transport: vcrRecorder,
    }

    ghClient := github.NewClient(httpClient)

    // =====> actual test, should create cassettes, but does not.
    _, _, err = ghClient.Users.Get(context.Background(), "")

    require.NoError(t, err)
}
AnalogJ commented 3 years ago

🤦 I had that in the teardown function of test suites testing other libraries, but I missed it for github. Adding it fixed the issue, closing.

Thanks for your help @dnaeon !