Documentation
¶
Overview ¶
Package vcr is a pure-Go (CGO=0, stdlib-only) reimplementation of the Ruby gem "vcr" (https://github.com/vcr/vcr). It records HTTP interactions to "cassettes" and replays them on subsequent runs, so tests become deterministic and offline.
The library is the cassette store, request matcher, and record/replay state machine. It deliberately does NOT perform HTTP or read a wall clock itself: those are seams supplied by the caller (in particular the rbgo binding, which intercepts its bound Net::HTTP). This keeps the whole package deterministic and testable with an in-memory filesystem.
Seams ¶
- Filesystem: FS is a struct of func fields (ReadFile/WriteFile/MkdirAll). OSFS returns the os-backed implementation; tests inject an in-memory one.
- Clock: VCR.Now supplies the timestamp stored as recorded_at.
- HTTP: Cassette.Interact takes a doer func(Request) (Response, error) that performs the real request only when the cassette must record. The rbgo binding supplies a doer wired to Net::HTTP.
Record modes ¶
- RecordOnce replay if the cassette exists, otherwise record.
- RecordNone replay only; an unknown request is an error.
- RecordNewEpisodes replay known requests, record new ones.
- RecordAll never replay; always (re-)record.
Cassette format ¶
Cassettes are serialized to VCR's default YAML schema: a top-level http_interactions sequence of {request, response, recorded_at} maps. The serializer is a small purpose-built emitter/parser (no third-party YAML dependency) that round-trips the schema byte-for-byte.
The intended Ruby surface, provided by the rbgo binding on top of this package, is:
VCR.configure { |c| c.cassette_library_dir = "..."; c.default_record_mode = :once }
VCR.use_cassette("name", record: :new_episodes) { ... }
Index ¶
- func MarshalCassette(interactions []Interaction) []byte
- func MatchBody(recorded, incoming Request) bool
- func MatchHeaders(recorded, incoming Request) bool
- func MatchMethod(recorded, incoming Request) bool
- func MatchURI(recorded, incoming Request) bool
- type Body
- type Cassette
- func (c *Cassette) CanRecord() bool
- func (c *Cassette) Interact(req Request, doer func(Request) (Response, error)) (Response, error)
- func (c *Cassette) Interactions() []Interaction
- func (c *Cassette) Mode() RecordMode
- func (c *Cassette) Play(req Request) (Response, bool)
- func (c *Cassette) Record(req Request, resp Response)
- type CassetteOptions
- type FS
- type FormatError
- type Interaction
- type RecordMode
- type Request
- type RequestMatcher
- type Response
- type Status
- type UnhandledRequestError
- type VCR
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func MarshalCassette ¶
func MarshalCassette(interactions []Interaction) []byte
MarshalCassette serializes interactions to VCR's default cassette YAML schema. The output round-trips through ParseCassette byte-for-byte.
func MatchHeaders ¶
MatchHeaders matches on the full set of request headers (names and their ordered values).
func MatchMethod ¶
MatchMethod matches on the HTTP method.
Types ¶
type Body ¶
Body models the {encoding, string} pair VCR stores for both request and response bodies.
type Cassette ¶
type Cassette struct {
// Name is the cassette name as passed to UseCassette (without the .yml
// extension added for the on-disk path).
Name string
// contains filtered or unexported fields
}
Cassette is an ordered list of recorded interactions plus the record/replay state machine for a single VCR.use_cassette scope. It is created by VCR.UseCassette; the block receives it and drives replay/record through Cassette.Interact (or the lower-level Cassette.Play/Cassette.Record).
func (*Cassette) CanRecord ¶
CanRecord reports whether the active record mode permits recording a new interaction into this cassette.
func (*Cassette) Interact ¶
Interact is the full record/replay decision for one request. It models what the rbgo binding does around a bound Net::HTTP call:
- Unless the mode is RecordAll, it tries to replay a matching interaction.
- Otherwise, if the mode permits recording, it invokes doer to perform the real request and records the result.
- Otherwise it returns an *UnhandledRequestError.
doer is the HTTP seam: the caller performs the real request. It is only called when the cassette must record.
func (*Cassette) Interactions ¶
func (c *Cassette) Interactions() []Interaction
Interactions returns a copy of the interactions the cassette currently holds (loaded from disk plus any recorded during this scope).
func (*Cassette) Mode ¶
func (c *Cassette) Mode() RecordMode
Mode returns the cassette's record mode.
func (*Cassette) Play ¶
Play returns the response of the first unplayed recorded interaction whose request matches req under the cassette's matchers, and true. If no interaction matches it returns the zero Response and false. Unless playback repeats are allowed, each recorded interaction is played at most once.
type CassetteOptions ¶
type CassetteOptions struct {
RecordMode *RecordMode
Matchers []RequestMatcher
AllowPlaybackRepeats *bool
}
CassetteOptions overrides per-cassette settings for a single UseCassette call. Nil pointers/empty slices mean "inherit the VCR default".
type FS ¶
type FS struct {
ReadFile func(name string) ([]byte, error)
WriteFile func(name string, data []byte, perm os.FileMode) error
MkdirAll func(path string, perm os.FileMode) error
}
FS is the filesystem seam. Its func fields mirror the os package so tests can inject an in-memory implementation and drive every error branch deterministically. Use OSFS for the os-backed implementation.
type FormatError ¶
type FormatError struct {
Msg string
}
FormatError indicates that cassette bytes could not be parsed as a valid VCR cassette.
func (*FormatError) Error ¶
func (e *FormatError) Error() string
type Interaction ¶
Interaction is one recorded request/response pair with the time it was recorded.
func ParseCassette ¶
func ParseCassette(data []byte) ([]Interaction, error)
ParseCassette parses cassette bytes in VCR's YAML schema into interactions.
type RecordMode ¶
type RecordMode int
RecordMode selects how a cassette reconciles incoming requests with what it already holds. It mirrors VCR's :once/:none/:new_episodes/:all symbols.
const ( // RecordOnce replays recorded interactions; it records new ones only when the // cassette did not already exist on disk. RecordOnce RecordMode = iota // RecordNone replays only; an unmatched request is an error. RecordNone // RecordNewEpisodes replays known interactions and records new ones. RecordNewEpisodes // RecordAll never replays and always records, re-writing the cassette. RecordAll )
func ParseRecordMode ¶
func ParseRecordMode(s string) (RecordMode, error)
ParseRecordMode maps a VCR record-mode name to a RecordMode. It accepts both the bare name ("once") and the Ruby symbol spelling (":once").
func (RecordMode) String ¶
func (m RecordMode) String() string
String returns the VCR symbol name (without the leading colon).
type Request ¶
Request is the recorded/incoming HTTP request as VCR models it. Headers maps a header name to its ordered list of values, matching the YAML schema.
type RequestMatcher ¶
RequestMatcher reports whether an incoming request should be considered a match for a previously recorded request. The first argument is the recorded request, the second is the incoming one, mirroring VCR's request matchers.
func DefaultMatchers ¶
func DefaultMatchers() []RequestMatcher
DefaultMatchers returns VCR's default matcher set: method and URI.
type UnhandledRequestError ¶
type UnhandledRequestError struct {
CassetteName string
Request Request
RecordMode RecordMode
}
UnhandledRequestError is returned when an incoming request matches no recorded interaction and the active record mode does not permit recording it. It corresponds to VCR's Errors::UnhandledHTTPRequestError.
func (*UnhandledRequestError) Error ¶
func (e *UnhandledRequestError) Error() string
type VCR ¶
type VCR struct {
// CassetteDir is the directory cassettes are read from and written to
// (Ruby: cassette_library_dir).
CassetteDir string
// RecordMode is the default record mode for cassettes that do not override it
// (Ruby: default_record_mode).
RecordMode RecordMode
// Matchers is the default matcher set; empty means DefaultMatchers.
Matchers []RequestMatcher
// AllowPlaybackRepeats lets a single recorded interaction be replayed more
// than once (Ruby: allow_playback_repeats).
AllowPlaybackRepeats bool
// FS is the filesystem seam. Zero value is unusable; use OSFS or an injected
// implementation.
FS FS
// Now is the clock seam used for recorded_at. Nil means time.Now.
Now func() time.Time
}
VCR is the top-level configuration and cassette manager. It corresponds to Ruby's VCR module configured via VCR.configure.
func New ¶
func New() *VCR
New returns a VCR with the conventional defaults: cassette directory "fixtures/vcr_cassettes", record mode :once, the default matchers, and the os-backed filesystem.
func (*VCR) UseCassette ¶
UseCassette inserts the named cassette, runs fn with it, then ejects it, writing the cassette back to disk when the scope recorded anything (or when the mode is RecordAll). It mirrors VCR.use_cassette(name, options) { ... }.
A missing cassette file is not an error (it means "no prior recordings"); any other filesystem error, and any cassette parse error, is returned. When fn returns an error the cassette is still ejected, and fn's error takes precedence over an eject error.
