Documentation
¶
Overview ¶
Package vlatte holds what every vlatte mock server shares: mocks, scopes, matchers, delays, events, recipes and assertions.
Tests usually import a protocol package instead:
- github.com/caffeine-projects/vlatte/mockhttp for HTTP
- github.com/caffeine-projects/vlatte/mockgrpc for gRPC
and github.com/caffeine-projects/vlatte/match for request matchers.
Index ¶
- Constants
- Variables
- func CheckTemplateDataProviders[In any](providers []TemplateDataProvider[In]) error
- func NotCalled[M Mock](t TestingT, inspector Inspector[M]) bool
- func ProvideTemplateData[In any](providers []TemplateDataProvider[In], in In) (map[string]any, error)
- func Times[M Mock](t TestingT, inspector Inspector[M], expected int64) bool
- type Base
- func (app *Base[TM, A]) AssertCalled(t TestingT) bool
- func (app *Base[TM, A]) AssertNotCalled(t TestingT) bool
- func (app *Base[TM, A]) AssertNumberOfCalls(t TestingT, expected int64) bool
- func (app *Base[TM, A]) Clean(ctx context.Context) error
- func (app *Base[TM, A]) Disable()
- func (app *Base[TM, A]) Enable()
- func (app *Base[TM, A]) Hits() int64
- func (app *Base[TM, A]) ListCalled() []TM
- func (app *Base[TM, A]) ListPending() []TM
- func (app *Base[TM, A]) Mock(builders ...Builder[TM, A]) (*Scope[TM], error)
- func (app *Base[TM, A]) MustMock(builders ...Builder[TM, A]) *Scope[TM]
- func (app *Base[TM, A]) Remock(ctx context.Context, old *Scope[TM], builders ...Builder[TM, A]) (*Scope[TM], error)
- func (app *Base[TM, A]) RemockWith(ctx context.Context, old *Scope[TM], swap Swap[TM], builders ...Builder[TM, A]) (*Scope[TM], error)
- func (app *Base[TM, A]) Unmock(ctx context.Context, scope *Scope[TM]) error
- type Builder
- type Claimer
- type CleanupT
- type Configurer
- type Delay
- type Descriptor
- func DescribeFail(key string, err error) Descriptor
- func DescribeKeyOnly(key string) Descriptor
- func DescribeKeyOnlyMaybe(key string, item any) Descriptor
- func DescribeKeyValuePairs(key string, props ...any) Descriptor
- func DescribeMaybeItems(key string, items []any) Descriptor
- func DescribeMultiArgs(key string, props ...any) Descriptor
- func DescribeRoot[T DescriptorPropsType](props T) Descriptor
- func DescribeSingleArg(key string, item any) Descriptor
- func IsSelfDescriptive(v any) (Descriptor, bool)
- func NewDescriptor[T DescriptorPropsType](key string, props T) Descriptor
- func (d Descriptor) Err() error
- func (d Descriptor) IsArray() bool
- func (d Descriptor) IsMap() bool
- func (d Descriptor) MarshalJSON() ([]byte, error)
- func (d Descriptor) Marshallable() (any, error)
- func (d Descriptor) Merge(m map[string]any) error
- func (d Descriptor) String() string
- func (d Descriptor) Validate() error
- type DescriptorProps
- type DescriptorPropsType
- type Eval
- type Evaluators
- type EventArgs
- type EventConfig
- type EventConfigs
- type EventFunc
- type EventListener
- type EventPreparer
- type EventRegistry
- type EventRunner
- type Events
- type Explanation
- type ExplanationItem
- type Flow
- type GetEvals
- type GoTemplateEngine
- type GoTemplateOption
- type Inspector
- type KV
- type KVReloader
- type Kind
- type Kit
- type Listener
- type LogLevel
- type LogVerbosity
- type Matcher
- type MatcherArg
- type MemoryStore
- func (s *MemoryStore[B]) Clear(_ context.Context) error
- func (s *MemoryStore[B]) Delete(_ context.Context, ids ...string) error
- func (s *MemoryStore[B]) Health(context.Context) error
- func (s *MemoryStore[B]) List(ctx context.Context) (iter.Seq[B], error)
- func (s *MemoryStore[B]) Pick(_ context.Context, id string) (B, error)
- func (s *MemoryStore[B]) PickAll(_ context.Context) ([]B, error)
- func (s *MemoryStore[B]) Replace(_ context.Context, old []B, mocks ...B) error
- func (s *MemoryStore[B]) Store(_ context.Context, mocks ...B) error
- type Misses
- type Mock
- type MockBuilder
- type MockBuilderFunc
- type Mocks
- type NearMiss
- type OnComplete
- type Parameters
- type Pipe
- type PipeFunc
- type Recipe
- type RecipeFunc
- type RecipeInput
- type RecordBody
- type RecordCodec
- type RecordFiles
- type RecordOptions
- type RecordRepeats
- type RecordResult
- type RecordSession
- func (s *RecordSession[X, Q, S]) Done() <-chan struct{}
- func (s *RecordSession[X, Q, S]) NewBody() *RecordBody
- func (s *RecordSession[X, Q, S]) Record(x X, size int) bool
- func (s *RecordSession[X, Q, S]) Status() RecordStatus
- func (s *RecordSession[X, Q, S]) Stop(ctx context.Context) (*RecordResult, error)
- type RecordStatus
- type RecordedMock
- type Recording
- type Replier
- type ReplierFactory
- type Scope
- func (s *Scope[B]) AssertCalled(t TestingT) bool
- func (s *Scope[B]) AssertNotCalled(t TestingT) bool
- func (s *Scope[B]) AssertNumberOfCalls(t TestingT, expected int64) bool
- func (s *Scope[B]) Called() bool
- func (s *Scope[B]) Clear(ctx context.Context) error
- func (s *Scope[B]) Delete(ctx context.Context, ids ...string) error
- func (s *Scope[B]) Disable()
- func (s *Scope[B]) Enable()
- func (s *Scope[B]) Exists(id string) bool
- func (s *Scope[B]) Hits() int64
- func (s *Scope[B]) IDs() []string
- func (s *Scope[B]) ListCalled() []B
- func (s *Scope[B]) ListPending() []B
- func (s *Scope[B]) Mock(id string) B
- func (s *Scope[B]) Mocks() []B
- func (s *Scope[B]) Pending() bool
- type Scopes
- func (s *Scopes[B, A]) Add(builders ...Builder[B, A]) (*Scope[B], error)
- func (s *Scopes[B, A]) All() []*Scope[B]
- func (s *Scopes[B, A]) Remove(ctx context.Context, scope *Scope[B]) error
- func (s *Scopes[B, A]) Replace(ctx context.Context, old *Scope[B], builders ...Builder[B, A]) (*Scope[B], error)
- type Selector
- type SelfDescriptive
- type Server
- type Sink
- type Stage
- type Stateful
- type Store
- type Swap
- type Template
- type TemplateDataProvider
- type TemplateEngine
- type TestingT
Examples ¶
Constants ¶
const ( FailureNoMatch = "no-match" // no mock matched the request FailureMatch = "match" // finding a mock failed: a matcher or the store returned an error FailureReply = "reply" // a mock matched, and its reply failed FailurePanic = "panic" // serving the request panicked )
Values of HeaderFailure.
const ( HeaderFailure = "VLatte-Error" HeaderMatchedMockID = "VLatte-Matched-Mock-Id" // ID of the mock that matched HeaderMatchedMockName = "VLatte-Matched-Mock-Name" // name of the mock that matched, when it has one HeaderMatchedMockHits = "VLatte-Matched-Mock-Hits" // hits of the mock that matched, this request included HeaderMatchedMockSource = "VLatte-Matched-Mock-Source" // file the mock that matched was loaded from (HTTP) HeaderRequestID = "VLatte-Request-Id" // ID of the request, as logs, templates and the journal see it (HTTP; gRPC with a journal) HeaderProxied = "VLatte-Proxied" // "true" when a proxy answered instead of a mock (HTTP) )
Headers (HTTP) or metadata keys (gRPC) a server adds to its answers. gRPC sends them lowercased, as metadata keys are.
const ( LogLevelDebug = LogLevel(zerolog.DebugLevel) LogLevelInfo = LogLevel(zerolog.InfoLevel) LogLevelWarn = LogLevel(zerolog.WarnLevel) LogLevelError = LogLevel(zerolog.ErrorLevel) // LogLevelNone writes only the entries that have no level. LogLevelNone = LogLevel(zerolog.NoLevel) // LogLevelDisabled writes nothing. LogLevelDisabled = LogLevel(zerolog.Disabled) )
Log levels. The default logger writes the entries at its level and above.
Variables ¶
var ( // ErrDescriptorKeyEmpty is the panic of the constructors given an empty key, and the error of [Descriptor.Validate] // on a descriptor without one. ErrDescriptorKeyEmpty = errors.New("descriptor: key is empty") // ErrDescriptorSpecNotValidType is the error of [Descriptor.Validate] and [Descriptor.Marshallable] on a descriptor // whose Props is not []any, map[string]any, a [Descriptor] or nil, and of [Descriptor.Merge] on one whose Props is // not a map. ErrDescriptorSpecNotValidType = errors.New("descriptor: spec is not a valid type") // ErrDescriptorKeyAlreadyExists is the error of [Descriptor.Merge] when the map already holds the descriptor's key. ErrDescriptorKeyAlreadyExists = errors.New("descriptor: key already exists") )
var ( // ErrMatchPanicked is wrapped by the error of a match whose matcher panicked, such as that of [Eval.Match], with // the panic value. ErrMatchPanicked = errors.New("mock: panic") // ErrMatching is wrapped by the error of [Mocks.Find] when a matcher fails or panics, with the name of its mock. ErrMatching = errors.New("mock: matching") )
var ( // ErrAbort is the cause of a flow a stage aborted, with [Flow.Abort] or by returning an error that matches it. // The server cuts the stream: an HTTP/1 connection is closed, and an HTTP/2 stream is reset. ErrAbort = errors.New("flow: aborted") // ErrReset aborts a flow, as [ErrAbort] does, with a TCP reset where the connection allows one: its unsent data // is dropped and the peer reads a reset, not an end. Elsewhere, such as over HTTP/2, it cuts the stream. ErrReset = errors.New("flow: reset") )
var ( // ErrRecording is returned when a recording starts while another one runs. ErrRecording = errors.New("recorder: already recording") // ErrNotRecording is returned when there is no recording to stop. ErrNotRecording = errors.New("recorder: not recording") )
var ( // ErrStarted is returned when a server that started starts again: a server starts once. ErrStarted = errors.New("server: already started") // ErrOutboundRefused is the error of a connection a server refused to open, to an address its outbound rules // refuse: see OutboundAllow in [github.com/caffeine-projects/vlatte/mockhttp.Config] and in // [github.com/caffeine-projects/vlatte/mockgrpc.Config]. ErrOutboundRefused = errors.New("server: the address is refused by the outbound rules") )
var ( // ErrNotFound is returned by [Store.Pick] when no mock with the given ID exists. ErrNotFound = errors.New("store: mock not found") // ErrDuplicateID is returned by [Store.Store] when the ID of a mock is already stored, or repeated in the call. ErrDuplicateID = errors.New("store: mock id already in use") )
var ErrEventAlreadyRegistered = errors.New("vlatte: event already registered")
ErrEventAlreadyRegistered is returned by EventRegistry.Register when a listener has the name already.
var ErrKVKeyNotFound = errors.New("kv: key not found")
ErrKVKeyNotFound is the error of KV.Get for a key that isn't stored.
var ErrTemplateDataKeyExists = errors.New("server: two template data providers have the same key")
ErrTemplateDataKeyExists says two template data providers of a server have the same key.
Functions ¶
func CheckTemplateDataProviders ¶
func CheckTemplateDataProviders[In any](providers []TemplateDataProvider[In]) error
CheckTemplateDataProviders returns ErrTemplateDataKeyExists when two providers have the same key: templates could read only one of them.
func ProvideTemplateData ¶
func ProvideTemplateData[In any](providers []TemplateDataProvider[In], in In) (map[string]any, error)
ProvideTemplateData returns the data providers give for in, by their key. It returns the error of the first that fails, which names it.
func Times ¶
Times asserts that the inspector recorded exactly expected hits.
Example ¶
package main
import (
"fmt"
"io"
"net/http"
"github.com/caffeine-projects/vlatte"
"github.com/caffeine-projects/vlatte/mockhttp"
)
// exampleT reports what fails on the standard output, as a test's *testing.T reports it in the test's log.
type exampleT struct{}
func (exampleT) Helper() {}
func (exampleT) Logf(format string, a ...any) { fmt.Printf(format+"\n", a...) }
func (exampleT) Error(a ...any) { fmt.Println(a...) }
func (exampleT) Errorf(format string, a ...any) { fmt.Printf(format+"\n", a...) }
// get sends a GET of path to m, with header, and returns the status and body of the answer.
func get(m *mockhttp.Server, path string, header http.Header) (int, string) {
req, err := http.NewRequest(http.MethodGet, m.URL(path), nil)
if err != nil {
panic(err)
}
req.Header = header
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
panic(err)
}
return res.StatusCode, string(body)
}
func main() {
t := exampleT{} // a test's *testing.T
m := mockhttp.MustNew(mockhttp.Setup().Silent())
m.MustStart()
defer m.Close()
// The scope MustMock returns is an Inspector of its mocks; the server is one of all its mocks.
scope := m.MustMock(mockhttp.Getf("/hello").Reply(mockhttp.OK()))
get(m, "/hello", nil)
get(m, "/hello", nil)
fmt.Println(vlatte.Times(t, scope, 2))
}
Output: true
Types ¶
type Base ¶
Base is what every mock server shares: it adds mocks to its store in scopes, and asserts on them. A protocol's server embeds it.
func (*Base[TM, A]) AssertCalled ¶
AssertCalled asserts that all mocks associated with this instance were called at least once.
func (*Base[TM, A]) AssertNotCalled ¶
AssertNotCalled asserts that none of the mocks associated with this instance were called.
func (*Base[TM, A]) AssertNumberOfCalls ¶
AssertNumberOfCalls asserts that the sum of matched request hits is equal to the given expected value.
func (*Base[TM, A]) ListCalled ¶
func (app *Base[TM, A]) ListCalled() []TM
ListCalled returns the mocks of every scope that were called at least once. It leaves out mocks stored outside every scope, such as those the admin API added.
func (*Base[TM, A]) ListPending ¶
func (app *Base[TM, A]) ListPending() []TM
ListPending returns the mocks of every scope that were not called. It leaves out mocks stored outside every scope, such as those the admin API added.
func (*Base[TM, A]) Mock ¶
Mock adds one or multiple request mocks. A mock stored outside every scope, such as one the admin API added, gives way to a new mock with its ID. It returns a Scope instance that allows control of the added mocks and also checks if they were called or not.
func (*Base[TM, A]) MustMock ¶
MustMock adds one or multiple request mocks. It returns a Scope instance that allows control of the added mocks and also checks if they were called or not. It panics if any error occurs.
func (*Base[TM, A]) Remock ¶
func (app *Base[TM, A]) Remock(ctx context.Context, old *Scope[TM], builders ...Builder[TM, A]) (*Scope[TM], error)
Remock builds builders and swaps their mocks for those of old in one step, so a request finds the mocks of old or the new ones, never neither, and returns their scope, which takes the place of old. With a nil old, it adds the mocks, as Mock does. A mock stored outside every scope, such as one the admin API added, gives way to a new mock with its ID. It changes nothing when a builder fails, when the store refuses the mocks, for example over an ID in use in another scope, or when old isn't tracked: replaced or unmocked already, or another server's.
func (*Base[TM, A]) RemockWith ¶
func (app *Base[TM, A]) RemockWith(ctx context.Context, old *Scope[TM], swap Swap[TM], builders ...Builder[TM, A]) (*Scope[TM], error)
RemockWith does what Remock does, and swaps the mocks swap returns in the same step, so a request finds the mocks of old and those swap drops, or the new ones and those it adds, never a mix. It changes nothing when swap fails. A nil swap swaps nothing more.
type Builder ¶
Builder describes a Mock builder. Build returns a new mock on each call and must not change the builder, so a builder can be built for several servers, or more than once for one.
type Claimer ¶
type Claimer interface {
Claim(arg MatcherArg) bool
}
Claimer is a matcher whose mock takes a turn when Mocks.Find picks it, before the mock answers, such as the turn of a scenario's state. Claim takes the turn, and reports false when another request took it since the matcher matched: Find then looks for a mock again. Claim gets the argument Match gets, made again for the request, and the mock whose turn it takes, which MatcherArg.Mock returns. The next request sees the turn taken, even while the mock still answers, and the turn stays taken when the mock then fails to answer.
Match changes no state, so a report of a request no mock matched runs it. Claim reports false only when Match would now report false, or Find looks again forever, until its context ends. A mock has at most one Claimer: a turn taken stays taken when the next Claimer of the mock loses its own.
type CleanupT ¶
type CleanupT interface {
Cleanup(func())
}
CleanupT is an interface that allows for cleanup functions to be registered. Usually used in testing with testing.T.
type Configurer ¶
Configurer lets users configure the Mock API.
type Delay ¶
Delay picks how long a mock waits before it replies. It is called for each reply, so it can pick a different duration each time.
func Jitter ¶
Jitter returns a Delay picked at random around avg, spread over deviation percent of avg: with an avg of 100ms and a deviation of 20, it picks from 90ms to just under 110ms. A deviation that leaves no spread, such as 0, gives avg every time. It panics when deviation is greater than 200: the spread would then reach below zero.
func UniformDistribution ¶
UniformDistribution returns a Delay picked at random from minMillis to maxMillis milliseconds, both included. It panics when maxMillis is lower than minMillis.
type Descriptor ¶
type Descriptor struct {
Key string
Props DescriptorProps
// contains filtered or unexported fields
}
Descriptor describes a type. Props decides how it marshals:
Descriptor{Key: "eq", Props: []any{"a", 1}} renders ["eq","a",1]
Descriptor{Key: "eq", Props: nil} renders ["eq"]
Descriptor{Key: "eq", Props: map[string]any{"a": 1}} renders {"a":1}
A map leaves Key out: Descriptor.Merge places it under Key in a parent map. A Descriptor as Props renders as that descriptor.
func DescribeFail ¶
func DescribeFail(key string, err error) Descriptor
DescribeFail creates a descriptor of something a description can't hold, such as a function. Encoding it, or any description that holds it, fails with err, rather than describe it as something else. It panics with ErrDescriptorKeyEmpty if key is empty.
func DescribeKeyOnly ¶
func DescribeKeyOnly(key string) Descriptor
DescribeKeyOnly creates a descriptor with the given key and no arguments: it renders as a list of the key alone. It panics with ErrDescriptorKeyEmpty if key is empty.
func DescribeKeyOnlyMaybe ¶
func DescribeKeyOnlyMaybe(key string, item any) Descriptor
DescribeKeyOnlyMaybe creates a descriptor with the given key and, when item is SelfDescriptive, its description as the only argument. Any other item is ignored, as in DescribeKeyOnly.
func DescribeKeyValuePairs ¶
func DescribeKeyValuePairs(key string, props ...any) Descriptor
DescribeKeyValuePairs creates a descriptor with the given key and the list of key/value pairs. It panics with ErrDescriptorKeyEmpty if key is empty, and panics if props has an odd length or a key in props is not a string.
func DescribeMaybeItems ¶
func DescribeMaybeItems(key string, items []any) Descriptor
DescribeMaybeItems is a helper function to create a descriptor with items that might be also SelfDescriptive descriptive. In the case the child is not a SelfDescriptive descriptive type, it will be ignored. It panics with ErrDescriptorKeyEmpty if key is empty.
func DescribeMultiArgs ¶
func DescribeMultiArgs(key string, props ...any) Descriptor
DescribeMultiArgs creates a descriptor with the given key and the list of properties. It panics with ErrDescriptorKeyEmpty if key is empty.
func DescribeRoot ¶
func DescribeRoot[T DescriptorPropsType](props T) Descriptor
DescribeRoot creates the top-level descriptor of a description, with the key "root" and the given props.
func DescribeSingleArg ¶
func DescribeSingleArg(key string, item any) Descriptor
DescribeSingleArg creates a descriptor with the given key and item as its only argument. It panics with ErrDescriptorKeyEmpty if key is empty.
func IsSelfDescriptive ¶
func IsSelfDescriptive(v any) (Descriptor, bool)
IsSelfDescriptive returns the description of v and true if v is SelfDescriptive, or a zero Descriptor and false.
func NewDescriptor ¶
func NewDescriptor[T DescriptorPropsType](key string, props T) Descriptor
NewDescriptor creates a descriptor with the given key and props. It panics with ErrDescriptorKeyEmpty if key is empty.
func (Descriptor) Err ¶
func (d Descriptor) Err() error
Err returns why d can't be described, as DescribeFail gave it, or nil.
func (Descriptor) IsArray ¶
func (d Descriptor) IsArray() bool
IsArray reports whether d's Props is an []any. A nil Props, which also renders as an array, is not one.
func (Descriptor) IsMap ¶
func (d Descriptor) IsMap() bool
IsMap reports whether d's Props is a map[string]any: d renders without its key, for Descriptor.Merge.
func (Descriptor) MarshalJSON ¶
func (d Descriptor) MarshalJSON() ([]byte, error)
MarshalJSON implements the json.Marshaler interface. It will marshal the Descriptor based on the Descriptor.Marshallable function return.
func (Descriptor) Marshallable ¶
func (d Descriptor) Marshallable() (any, error)
Marshallable returns the Descriptor in a format that can be marshalled by any encoder.
func (Descriptor) Merge ¶
func (d Descriptor) Merge(m map[string]any) error
Merge merges the descriptor into the given map. It will return an error if the key already exists in the map.
func (Descriptor) String ¶
func (d Descriptor) String() string
String returns the string representation of the descriptor.
func (Descriptor) Validate ¶
func (d Descriptor) Validate() error
Validate returns ErrDescriptorKeyEmpty if d has no key, the error DescribeFail gave it, or an error wrapping ErrDescriptorSpecNotValidType if its Props is not a type it marshals.
type DescriptorProps ¶
type DescriptorProps any
DescriptorProps describes the properties of a SelfDescriptive describle type.
type DescriptorPropsType ¶
type DescriptorPropsType interface {
[]any | map[string]any | Descriptor
}
DescriptorPropsType is the constraint of the props NewDescriptor and DescribeRoot take: the types a Descriptor marshals.
type Eval ¶
type Eval[TIn any] struct { // Key describes to which specific part within the HTTP request parts a matcher is associated. // Eg.: a matcher for Header(Content-Type), the key would be "Content-Type". // A matcher can be associated to, for example the whole Header. // In this case, the key will be empty even if the matcher targets just one header name. Key string // Target is the index of the target of this evaluator. // Eg.: If this evaluator is targeting the header, the target should specify it, regardeless of which header name. // So, every evaluator targeting the header should have the same target value. Target int // Matcher associated with this [Eval]. Matcher Matcher // Selector will extract the [http.Request] or a specific field of it and feed it to the associated [Matcher]. Selector Selector[TIn] }
Eval describes a matching evaluator. It contains all the necessary information to evaluate a match against something, eg.: the HTTP request or a piece of it. It also contains data to better describe mismatches.
func (*Eval[TIn]) Arg ¶
func (e *Eval[TIn]) Arg(ctx context.Context, sub *Explanation, in TIn) MatcherArg
Arg returns the argument the matcher of e gets for in: the value its Selector selects, or nil without one, with an explanation under sub. A mock server that reads a matcher of the mock Find picked, such as a scenario's to journal its move, gives it the same argument.
type Evaluators ¶
Evaluators is a list of evaluators.
func (Evaluators[M, TIn]) Eval ¶
func (e Evaluators[M, TIn]) Eval(ctx context.Context, sub *Explanation, in TIn) (bool, error)
Eval evaluates the input against all evaluators from a single Mock. Normally this function is used together with Mocks.Find
type EventArgs ¶
type EventArgs interface {
Kind() Kind
Kit() Kit
Parameters() Parameters
}
EventArgs is the common argument type for all events. Event-specific interfaces (e.g. OnComplete) extend this.
type EventConfig ¶
type EventConfig struct {
Name string
Parameters Parameters
// Dir is where relative files of the parameters open from, such as the directory of the mock file that defines
// the event. "" is the working directory.
Dir string
// Listener, when set, runs the event in place of the listener registered under Name, which then only names the
// event in errors: it needs no registration. Its Parameters reach it as they are: [EventPreparer] doesn't apply.
// Events set in Go can carry one, as [github.com/caffeine-projects/vlatte/mockhttp.Builder.Callback] does. Mock
// files can't, and a mock's description leaves out the events that carry one.
Listener EventListener[OnComplete]
// AfterResponse has the response go out without waiting for the event, which runs on until it ends or the server
// closes: an app that needs its callback once it has its answer, such as a webhook's, gets it. The event starts
// as the response goes out, so it may start before the client reads it: a delay, such as a webhook's, sends it
// later. A test waits on what the event does, such as its target getting the webhook. Its failure is reported as
// any event's, but the journal entry of the request, recorded by then, doesn't tell it.
AfterResponse bool
}
EventConfig describes a named event and its parameters (e.g. for mock definitions).
type EventConfigs ¶
type EventConfigs []EventConfig
EventConfigs lists the events of one kind, such as the on_complete events of a mock.
func (EventConfigs) Has ¶
func (e EventConfigs) Has(name string) bool
Has reports whether an event of the list has the given name.
type EventFunc ¶
EventFunc is a function that implements the EventListener interface.
type EventListener ¶
EventListener is an interface for handling an event with type-safe args.
type EventPreparer ¶
type EventPreparer interface {
Prepare(cfg EventConfig, engine TemplateEngine) (Parameters, error)
}
EventPreparer is an optional interface of event listeners. Prepare checks the parameters of an event when the mock that names the listener is built, and those of global events when the server is built, so a mistake fails the mock instead of each event. It returns the parameters Run receives, such as decoded, and can compile their templates with engine, the server's.
type EventRegistry ¶
type EventRegistry[T EventArgs] struct { // contains filtered or unexported fields }
EventRegistry is a generic registry of named listeners for one event type. Use one registry per event kind (e.g. OnComplete, OnMatch) so new events can be added without changing this type.
func NewEventRegistry ¶
func NewEventRegistry[T EventArgs]() *EventRegistry[T]
NewEventRegistry creates a new registry for an event type.
func (*EventRegistry[T]) Has ¶
func (r *EventRegistry[T]) Has(name string) bool
Has reports whether a listener is registered for the given name.
func (*EventRegistry[T]) Prepare ¶
func (r *EventRegistry[T]) Prepare(cfg EventConfig, engine TemplateEngine) (Parameters, error)
Prepare returns the parameters of cfg as the listener named cfg.Name prepares them, when it is an EventPreparer. Otherwise, or when no listener has that name, it returns them as they are.
func (*EventRegistry[T]) Register ¶
func (r *EventRegistry[T]) Register(name string, evt EventListener[T]) error
Register adds a listener under name. A name already registered keeps its listener: Register fails with ErrEventAlreadyRegistered.
type EventRunner ¶
type EventRunner struct {
Listeners *Listener
Global *Events
// contains filtered or unexported fields
}
EventRunner runs the events of mocks, such as on_complete ones, each in a goroutine of its own, and cancels them when its server closes.
func NewEventRunner ¶
func NewEventRunner(listeners *Listener, global *Events) *EventRunner
NewEventRunner creates an EventRunner that runs the listeners registered in listeners, and the events of global before those of each mock. A nil listeners has no listener registered, and a nil global no event.
func (*EventRunner) Close ¶
func (r *EventRunner) Close()
Close cancels the context of the events running, so the requests waiting for them end, and runs no event after. It returns once the events that run after the response have ended.
func (*EventRunner) OnComplete ¶
func (r *EventRunner) OnComplete(ctx context.Context, mock Mock, argsFn func(ctx context.Context, cfg EventConfig) OnComplete, onErr func(err error))
OnComplete runs the on_complete events of mock, global events first, each in a goroutine of its own, and returns once they all have, but those set to run after the response: an event neither waits for nor stops another, and the request waits for the others, so a test checks what they did right after the response. See EventConfig.AfterResponse. Each listener runs with what argsFn returns and a context with the values of ctx, the request's, such as a trace: the client leaving doesn't end it, and Close does. argsFn gets it too. onErr gets the error, or the panic, of each event that fails, unless Close canceled it, worded like the errors of mocks that name a listener that isn't registered. A closed runner runs nothing.
type Events ¶
type Events struct {
OnComplete EventConfigs
}
Events holds the events of a mock, or the global events of a server, by kind.
type Explanation ¶
type Explanation struct {
Name string
Items []ExplanationItem
Children []*Explanation
Parent *Explanation
}
Explanation records why a mock matched a request or not, as a tree of named blocks. MatcherArg.Explain hands one to each matcher. A nil *Explanation records nothing; its methods are safe to call.
func NewExplanation ¶
func NewExplanation() *Explanation
NewExplanation returns an empty root Explanation.
func (*Explanation) AddMessage ¶
func (e *Explanation) AddMessage(message string)
AddMessage records a message in this block. On a nil Explanation, it does nothing.
func (*Explanation) Root ¶
func (e *Explanation) Root() bool
Root reports whether e is the root of its tree. A nil Explanation has no parent, so it reports true.
func (*Explanation) Sub ¶
func (e *Explanation) Sub(name string) *Explanation
Sub adds a child block with the given name and returns it. On a nil Explanation, it returns nil, which records nothing.
type ExplanationItem ¶
type ExplanationItem struct {
Message string
}
ExplanationItem is a message recorded in an Explanation.
type Flow ¶
type Flow struct {
// contains filtered or unexported fields
}
Flow is one stream through pipes: a response body, the bytes of a response on the wire, a request body, one direction of a connection. Each pipe has its Stage in it, and the sink comes last.
A flow is a Stage itself: its caller calls Write, Flush and Close, one call at a time, and Close once the stream ends. Once its Flow.Context ends, Write and Flush return the cause.
func NewFlow ¶
NewFlow opens the stages of pipes in a new flow, in front of sink, from the last pipe to the first. The flow's context derives from ctx, typically the request's, so its stages stop when the client leaves. Pipes can be shared, such as a mock's pipes across its concurrent requests: NewFlow neither keeps nor changes pipes.
func (*Flow) Abort ¶
Abort aborts the flow, from any goroutine, such as a stage's timer: it ends the flow's context with a cause that matches ErrAbort and err, which may be nil. Pass ErrReset for a reset. The first end wins: once the flow ended, Abort does nothing.
func (*Flow) Close ¶
Close ends the stream: the stages pass on what they hold and end, in order, then the sink. Then the flow's context ends. Close returns once the last stage did, so nothing reaches the sink after it. Closing again does nothing.
func (*Flow) Context ¶
Context returns the flow's context. It ends when the context the flow was made with does, when a stage aborts the flow, or once the flow is closed. context.Cause tells which: a cause that matches ErrAbort is an abort.
type GetEvals ¶
type GetEvals[M Mock, TIn any] func(m M) Evaluators[M, TIn]
GetEvals is a function that returns a list of evaluators of a given Mock. Normally Mock will have a function that returns a list of evaluators.
type GoTemplateEngine ¶
type GoTemplateEngine struct {
// contains filtered or unexported fields
}
GoTemplateEngine compiles Go templates, of package text/template. Servers use it when no other engine is set. It is safe for concurrent use. Create one with NewGoTemplateEngine.
text/template, and not html/template, is the package for mocks: templates write bodies of any type, such as JSON and XML, and headers, URLs and file names, which html/template would escape for HTML. Escape on purpose with the html, js and urlquery functions, or with toJSON for a JSON value.
Besides the functions of text/template, templates can call those below. A function's last argument is the value it works on, so it pipes, as in {{ .Request.Header.Get "X-Name" | trimSpace | toUpper }}, but for the list functions, which take the list first, as Go's append does. A function given a bad argument, such as an unknown algorithm or a number that isn't one, fails the template, so a mock never answers with a broken body.
- JSON: toJSON (a value as JSON, such as a quoted and escaped string), fromJSON, JSONPath and JSONPathAll (what a JSONPath selects), deleteJSONPath and mergePatch (RFC 7386), which read a value or JSON text, and indentJSON and compactJSON.
- Strings: toUpper, toLower, trimSpace, title, upperFirst, truncate, replaceAll, split, join, substring and slug, which count runes, not bytes; regexpFind, regexpSubmatch, regexpReplaceAll and regexpMatch, with Go's regexp syntax; contains, for a substring, a list item or a map key; default, for a value that is nil, "" or empty.
- Numbers: add, sub, mul, div and mod, on ints when both operands are integers and on float64s otherwise, and toInt and toFloat, which convert numbers and numeric strings, such as a query parameter.
- Lists: list, append, insert, remove, randomItem, shuffle, reverse and sortBy, which return new lists.
- XML: xpath, the text of what an XPath 1.0 expression selects, and xpathNodes, the nodes it selects.
- Time: now, the current time.Time; formatTime and parseTime, with Go layouts, the names of those of package time, such as RFC3339, and unix and unixMilli; timeAdd, by a Go duration or such as "3 days"; inZone; and truncateTime, such as to "first day of month".
- Encoding: base64Encode and base64Decode, queryUnescape and parseQuery.
- Random: uuid, randomString, randomInt and randomFloat. They are not for secrets.
- Hashes: hash, such as {{ hash "sha256" "hex" .Request.Body.String }}, and hmac.
- env: the value of an environment variable WithEnv allows. A name env is given as a literal and isn't allowed fails the template when it compiles.
- Tokens: jwt, a JWT signed with a key WithSigningKey added, as in {{ jwt "key-1" $claims }}, where the claims are JSON text or a map, such as fromJSON returns, and the token holds them and no other; and jwks, the JWK Set of the public halves of the keys named, as in {{ jwks "key-1" "key-2" }}. A key named as a literal that the engine doesn't hold fails the template when it compiles.
A missing map key is an error, so a typo doesn't render as "<no value>". Read an optional key with index, which gives the zero value, as in {{ with index .Extra "name" }}{{ . }}{{ end }}, or change the rule with WithMissingKey.
func MustNewGoTemplateEngine ¶
func MustNewGoTemplateEngine(opts ...GoTemplateOption) *GoTemplateEngine
MustNewGoTemplateEngine is like NewGoTemplateEngine but panics if an option fails.
func NewGoTemplateEngine ¶
func NewGoTemplateEngine(opts ...GoTemplateOption) (*GoTemplateEngine, error)
NewGoTemplateEngine creates a GoTemplateEngine.
Example ¶
package main
import (
"os"
"strings"
"github.com/caffeine-projects/vlatte"
)
func main() {
engine := vlatte.MustNewGoTemplateEngine(vlatte.WithTemplateFuncs(map[string]any{
"shout": strings.ToUpper,
}))
tmpl, err := engine.Compile("greeting", `{{ shout .Name }}!`)
if err != nil {
panic(err)
}
if err := tmpl.Execute(os.Stdout, map[string]any{"Name": "ada"}); err != nil {
panic(err)
}
}
Output: ADA!
Example (Pkce) ¶
package main
import (
"os"
"github.com/caffeine-projects/vlatte"
)
func main() {
// The S256 code challenge of a PKCE code verifier (RFC 7636): base64url, without padding, of its SHA-256.
engine := vlatte.MustNewGoTemplateEngine()
tmpl, err := engine.Compile("challenge", `{{ hash "sha256" "base64url" .Verifier }}`)
if err != nil {
panic(err)
}
if err := tmpl.Execute(os.Stdout, map[string]any{"Verifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"}); err != nil {
panic(err)
}
}
Output: E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
func (*GoTemplateEngine) Compile ¶
func (e *GoTemplateEngine) Compile(name, text string) (Template, error)
Compile parses text as a Go template. The error is text/template's, such as "template: body:1: unclosed action", or names an environment variable env is given and the engine doesn't allow, or a key jwt or jwks is given and the engine doesn't hold.
type GoTemplateOption ¶
type GoTemplateOption func(*GoTemplateEngine) error
GoTemplateOption configures a GoTemplateEngine.
func WithEnv ¶
func WithEnv(names ...string) GoTemplateOption
WithEnv allows templates to read the environment variables names with env. Names are exact and case-sensitive, and each call adds to the names allowed. Without it, templates read none: env fails for every name.
func WithMissingKey ¶
func WithMissingKey(mode string) GoTemplateOption
WithMissingKey sets what a template does with a missing map key, as the missingkey option of text/template: "error" stops it with an error, the default; "default" and "invalid" print "<no value>"; "zero" prints the zero value of the map's element type, which is "<no value>" too for a map[string]any.
func WithSigningKey ¶
func WithSigningKey(kid, alg string, key crypto.Signer) GoTemplateOption
WithSigningKey adds key, which jwt signs with as kid and jwks publishes the public half of, with algorithm alg: RS256, RS384, RS512, PS256, PS384 or PS512 for an *rsa.PrivateKey of 2048 bits or more; ES256, ES384 or ES512 for an *ecdsa.PrivateKey on P-256, P-384 or P-521; EdDSA for an ed25519.PrivateKey. HMAC algorithms are refused: no provider publishes the secret of one, so a client that accepts them is the bug a mock should catch. An empty or repeated kid, or a key that doesn't fit alg, is an error. The engine never prints a private key: templates read only the tokens and the public halves.
func WithTemplateFuncs ¶
func WithTemplateFuncs(funcs map[string]any) GoTemplateOption
WithTemplateFuncs adds functions templates can call, by name. A function replaces a built-in one of the same name. Each must be a function text/template can call: one result, or two with an error second.
type Inspector ¶
Inspector reports the hits and the calls of a group of mocks, such as a Scope or a whole server, for Times and NotCalled.
type KV ¶
type KV interface {
// Get returns a copy of the value stored under k, or an error that wraps [ErrKVKeyNotFound] when there is none.
Get(ctx context.Context, k string) ([]byte, error)
// Has reports whether a value is stored under k. An empty value is stored.
Has(ctx context.Context, k string) (bool, error)
// Set stores a copy of v under k, replacing the value there.
Set(ctx context.Context, k string, v []byte) error
// Del removes the value under k. Removing a key that isn't stored is not an error.
Del(ctx context.Context, k string) error
// Keys returns every key stored, in no set order.
Keys(ctx context.Context) ([]string, error)
}
KV stores the values templates read as .KV, by key. A server reads it for every request it serves, so it must be safe for concurrent use. ctx is the request's, or an event's own, which outlives a client that leaves.
type KVReloader ¶
type KVReloader interface {
KV
// Reload replaces every value with those of the store's source: values set since the last load are gone, and
// keys removed since come back. When the source can't be loaded, it returns the error and keeps the values it had.
Reload(ctx context.Context) error
}
KVReloader is a KV that loads its values again from where they came from, such as the file of NewCSVKV. The admin API's POST /kv/reload reloads one.
func MustNewCSVKV ¶
func MustNewCSVKV(path string) KVReloader
MustNewCSVKV is like NewCSVKV, but panics when the file can't be loaded.
func NewCSVKV ¶
func NewCSVKV(path string) (KVReloader, error)
NewCSVKV returns a KVReloader that starts with the keys and values of the CSV file at path, and keeps them in memory: KV.Set and KV.Del change the store, never the file, and KVReloader.Reload loads the file again in place of every value. The first row of the file is the header key,value, and each other row is a key and its value, quoted as RFC 4180 says. Keys and values keep their spaces, an empty value is stored, and a UTF-8 byte order mark at the start is dropped. It fails, naming the line, when the header is missing, or when a row doesn't hold two fields, has an empty key or repeats a key; the error quotes keys, never values. When the file can't be read, the error wraps the one of os.ReadFile, such as io/fs.ErrNotExist.
type Kind ¶
type Kind string
Kind names the protocol of a mock server, such as "http". Each protocol package declares its own, for example mockhttp.Kind, so adding a protocol doesn't change this package. Protocol-neutral components, such as event listeners (Listener, OnComplete), can use it to tell their inputs apart.
type Kit ¶
type Kit interface {
// TemplateEngine is the engine of the server, so a component's templates call the same functions as the
// templates of replies.
TemplateEngine() TemplateEngine
// Data is the template data of the request being served.
Data() any
// Logger is the server's logger, never nil, so a component logs where the server does, and as little: a server
// that is silent gives one that logs nothing.
Logger() *zerolog.Logger
// Transport is what the server sends HTTP requests through, never nil, so a component's requests, such as
// webhooks, share its settings and connections, and their connections don't outlive the server.
Transport() http.RoundTripper
// Dir is where relative files open from: the directory of the mock file that defines what is served, such as an
// event, or "" for the working directory, as for what is defined in Go.
Dir() string
}
Kit is what the mock pipeline gives its components, such as event listeners: the server's dependencies and services, and what they serve, never its settings.
type Listener ¶
type Listener struct {
OnComplete *EventRegistry[OnComplete]
}
Listener holds registries for each event kind. Add new event types by defining an interface (embedding EventArgs), adding a field here, and initializing it in NewListener.
func NewListener ¶
func NewListener() *Listener
NewListener creates a Listener with all event registries initialized.
type LogVerbosity ¶
type LogVerbosity int8
LogVerbosity defines the verbosity of the logs.
const ( // LogBasic logs the requests and their answers without their headers or bodies. LogBasic LogVerbosity = iota // LogHeader adds the headers, with those the server redacts redacted. LogHeader // LogBody adds the bodies. LogBody )
Log verbosities, each logging what the one before it does, and more.
func (LogVerbosity) String ¶
func (l LogVerbosity) String() string
String implements fmt.Stringer. It returns "none" for a value that is not a verbosity.
type Matcher ¶
type Matcher interface {
Name() string
Match(arg MatcherArg) (bool, error)
}
Matcher matches values.
func MatcherFunc ¶
func MatcherFunc(name string, fn func(arg MatcherArg) (bool, error)) Matcher
MatcherFunc returns a Matcher named name that matches with fn.
Example ¶
package main
import (
"fmt"
"io"
"net/http"
"github.com/caffeine-projects/vlatte"
"github.com/caffeine-projects/vlatte/mockhttp"
)
// get sends a GET of path to m, with header, and returns the status and body of the answer.
func get(m *mockhttp.Server, path string, header http.Header) (int, string) {
req, err := http.NewRequest(http.MethodGet, m.URL(path), nil)
if err != nil {
panic(err)
}
req.Header = header
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
panic(err)
}
return res.StatusCode, string(body)
}
func main() {
// A matcher of your own, for a check package match doesn't have: an even number of characters.
even := vlatte.MatcherFunc("even", func(arg vlatte.MatcherArg) (bool, error) {
s, ok := arg.Value().(string)
return ok && len(s)%2 == 0, nil
})
m := mockhttp.MustNew(mockhttp.Setup().Silent())
m.MustStart()
defer m.Close()
m.MustMock(mockhttp.Getf("/pairs").Header("X-Code", even).Reply(mockhttp.OK()))
matched, _ := get(m, "/pairs", http.Header{"X-Code": {"ab"}})
unmatched, _ := get(m, "/pairs", http.Header{"X-Code": {"abc"}})
fmt.Println(matched, unmatched)
}
Output: 200 418
type MatcherArg ¶
type MatcherArg struct {
// contains filtered or unexported fields
}
MatcherArg is the argument a Matcher gets: the value to match, with the context and the explanation of the match.
func NewMatcherArg ¶
func NewMatcherArg(ctx context.Context, exp *Explanation, v any) MatcherArg
NewMatcherArg creates a MatcherArg for v, such as for a matcher that hands part of its value to another. exp, which records why the value matched or not, can be nil.
func (*MatcherArg) Context ¶
func (a *MatcherArg) Context() context.Context
Context returns the context of the match, such as that of the request.
func (*MatcherArg) Explain ¶
func (a *MatcherArg) Explain() *Explanation
Explain returns the optional explain block for recording Matcher messages. E.g. why a Matcher did not match).
func (*MatcherArg) Mock ¶
func (a *MatcherArg) Mock() Mock
Mock returns the mock whose turn a Claimer takes, in the argument of its Claim. It is nil in the argument of Match, which has no turn to take.
func (*MatcherArg) Value ¶
func (a *MatcherArg) Value() any
Value returns the value to match, such as the part of the request the Selector of an Eval selected.
type MemoryStore ¶
type MemoryStore[B Mock] struct { // contains filtered or unexported fields }
MemoryStore is a Store that keeps its mocks in memory.
func (*MemoryStore[B]) Clear ¶
func (s *MemoryStore[B]) Clear(_ context.Context) error
Clear removes every mock, and closes them once the store is unlocked.
func (*MemoryStore[B]) Delete ¶
func (s *MemoryStore[B]) Delete(_ context.Context, ids ...string) error
Delete removes the mocks with the given IDs, skipping those it doesn't hold, and closes the removed mocks that implement io.Closer once the store is unlocked. It never fails.
func (*MemoryStore[B]) Health ¶
func (s *MemoryStore[B]) Health(context.Context) error
Health returns nil: a memory store is always ready.
func (*MemoryStore[B]) List ¶
List returns the enabled mocks, in the order they match, as they were when List was called. It never fails.
func (*MemoryStore[B]) Pick ¶
func (s *MemoryStore[B]) Pick(_ context.Context, id string) (B, error)
Pick returns the mock with the given ID, enabled or not. It fails with ErrNotFound when no mock has it.
func (*MemoryStore[B]) PickAll ¶
func (s *MemoryStore[B]) PickAll(_ context.Context) ([]B, error)
PickAll returns every mock, enabled or not, in the order they match. It never fails.
func (*MemoryStore[B]) Replace ¶
func (s *MemoryStore[B]) Replace(_ context.Context, old []B, mocks ...B) error
Replace removes the mocks of old it holds, the very instances, and stores mocks, in one step. A mock of old that it stores again keeps its place, so it matches in the same order. It changes nothing when an ID of mocks is held by a mock it keeps, or repeated in the call.
type Misses ¶
Misses are the mocks Mocks.Find tried for a request, and that didn't match it, each with the part it stopped at: none once a mock matched. The zero value is ready to use. A server may reuse one, a request at a time, such as through a sync.Pool: Find starts it over, and Reset lets go of what it kept.
func (*Misses[M, TIn]) NearMisses ¶
func (m *Misses[M, TIn]) NearMisses(ctx context.Context, describe func(*Eval[TIn]) string) []NearMiss
NearMisses returns the mocks that came closest to matching the request Find found no mock for: at most 3, those that differ in the fewest parts of the request first, then those with the most parts that passed, in the order Find tried them. A part that keeps state, such as a Times used up, is no part of the request: a mock that missed by it alone comes first. describe names the part of the request an evaluator checks, such as "header Accept"; a part whose matcher failed with an error names it too.
No matcher runs twice for a request: each mock goes on from the part Find stopped at, which failed, and only the parts after it run now. Of those, it skips the Stateful ones, as running them may change their state, and runs the Claimer ones, whose Match changes nothing, such as a scenario's. A mock none of whose request parts passed is left out, unless it differs in none.
The report is whole even once ctx, the request's, is done, as when its client left: the matchers get a context with its values that isn't.
type Mock ¶
type Mock interface {
ID() string
Name() string
Priority() int
Hits() int64
Called() bool
Enabled() bool
Enable()
Disable()
Events() Events
String() string
}
Mock is what the core needs from a protocol's mock: identity, ordering, state, hits and events. Protocol packages add what only they use, such as callbacks or pipes, on their own mock types.
A mock that holds something to release, such as the connections of an HTTP client, implements io.Closer: the store closes it when it leaves, and a builder's mock that never makes it into the store is closed too.
A store tells mocks apart by identity, as when it replaces the very mocks it was given: a mock is a pointer, or another type Go can compare, never a struct holding a slice, a map or a func.
type MockBuilder ¶
MockBuilder knows how to turn a raw mock definition (content + extension) into a concrete Mock for a specific mock server implementation.
It exists so generic tooling (such as the admin API) can stay transport-agnostic: each mock server (HTTP, gRPC, ...) plugs in its own builder that understands its own mock format.
type MockBuilderFunc ¶
MockBuilderFunc adapts a plain function to the MockBuilder interface.
func (MockBuilderFunc[B]) BuildFromBytes ¶
func (f MockBuilderFunc[B]) BuildFromBytes(content []byte, extension string) (B, error)
BuildFromBytes implements MockBuilder.
type Mocks ¶
Mocks is a list of sorted eligible mocks. This list can searched for a match.
func (Mocks[M, TIn]) Find ¶
func (mocks Mocks[M, TIn]) Find( ctx context.Context, sub *Explanation, in TIn, evals GetEvals[M, TIn], misses *Misses[M, TIn], ) (M, bool, error)
Find tries to find an exact match in the mocks. It returns the mock that matched and a boolean indicating if a match was found. misses, when not nil, starts over and keeps each mock that didn't match, with the part it stopped at, which Misses.NearMisses goes on from.
The mock found has taken the turn of its Claimer matcher. When another request took it first, Find looks again from the first mock, as the mocks now match in the state that request left. A retry adds to sub. Find stops with the error of ctx once it ends.
type NearMiss ¶
type NearMiss struct {
MockID string `json:"mock_id"`
Name string `json:"name,omitempty"`
Passed int `json:"passed"`
Total int `json:"total"`
Failed []string `json:"failed,omitempty"`
Skipped []string `json:"skipped,omitempty"`
}
NearMiss is a mock that came close to matching a request: Passed of the Total parts it checked matched. Failed names the parts that didn't, and Skipped those it didn't check, which keep state, such as a scenario's, that matching never reached.
type OnComplete ¶
OnComplete is the event of a mock that replied. Its listeners run each in a goroutine of its own, and the response ends once they all have: see EventRunner.
type Parameters ¶
type Parameters any
Parameters holds the parameters of an event, as a mock file decodes them or Go code sets them. What they hold is up to the listener of the event.
type Pipe ¶
Pipe makes its Stage of each Flow it is part of, in front of next: the rest of the flow. A pipe keeps what lasts the whole flow in its stage, such as a count of the bytes it passed. A mock's pipes make the stages of all its responses: Open must be safe for concurrent use.
flow gives the stage the flow's context, and a way to abort it from a timer: see Flow.Abort.
type PipeFunc ¶
PipeFunc is a Pipe with no state, an adapter for ordinary functions: its stage calls it for each write, with the flow's context, and passes Flush and Close on.
Example:
PipeFunc(func(ctx context.Context, b []byte, next Stage) (int, error) {
if _, err := next.Write(bytes.ToUpper(b)); err != nil {
return 0, err
}
return len(b), nil
})
Example ¶
package main
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"github.com/caffeine-projects/vlatte"
"github.com/caffeine-projects/vlatte/mockhttp"
)
// get sends a GET of path to m, with header, and returns the status and body of the answer.
func get(m *mockhttp.Server, path string, header http.Header) (int, string) {
req, err := http.NewRequest(http.MethodGet, m.URL(path), nil)
if err != nil {
panic(err)
}
req.Header = header
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
panic(err)
}
return res.StatusCode, string(body)
}
func main() {
// A pipe sees the bytes of the answer on their way to the client: this one shouts them.
shout := vlatte.PipeFunc(func(_ context.Context, b []byte, next vlatte.Stage) (int, error) {
if _, err := next.Write(bytes.ToUpper(b)); err != nil {
return 0, err
}
return len(b), nil
})
m := mockhttp.MustNew(mockhttp.Setup().Silent())
m.MustStart()
defer m.Close()
m.MustMock(mockhttp.Getf("/hello").Pipe(shout).Reply(mockhttp.OK().PlainText("hello")))
fmt.Println(get(m, "/hello", nil))
}
Output: 200 HELLO
type Recipe ¶
type Recipe[B Mock, A Server[B, A]] interface { Prep(ctx context.Context, input *RecipeInput[B, A]) error }
Recipe prepares a mock server, such as by adding mocks to it. The Prep method of a server runs recipes in order, and stops at the first that fails.
type RecipeFunc ¶
RecipeFunc is a function that implements Recipe.
func (RecipeFunc[B, A]) Prep ¶
func (f RecipeFunc[B, A]) Prep(ctx context.Context, input *RecipeInput[B, A]) error
Prep implements Recipe.
type RecipeInput ¶
RecipeInput is what a Recipe prepares: Server is the mock server.
type RecordBody ¶
type RecordBody struct {
// contains filtered or unexported fields
}
RecordBody captures a body as it is sent. It keeps it in memory up to MaxInlineBody. Past that, a goroutine of its own writes it to a file of the recording's directory, so the size of the body never holds memory. A sender faster than the disk waits for it, a second in all at most: a body the disk falls further behind, or larger than MaxBodySize, isn't kept. Its call isn't recorded, and Err says why.
func (*RecordBody) Bytes ¶
func (b *RecordBody) Bytes() ([]byte, bool)
Bytes returns the body once closed, when it stayed in memory. It returns false when it went to a file, or wasn't kept.
func (*RecordBody) Discard ¶
func (b *RecordBody) Discard()
Discard drops the body, and the file it went to: its call won't be recorded. A placed body is the recording's.
func (*RecordBody) Err ¶
func (b *RecordBody) Err() error
Err returns why the body wasn't kept, or nil.
func (*RecordBody) Keep ¶
func (b *RecordBody) Keep(p []byte)
Keep keeps p, the next bytes of the body. It waits for the disk only when the body goes to its file faster than the disk takes it, as the type says. It does nothing once the body is closed or dropped. p is the caller's again when Keep returns.
type RecordCodec ¶
type RecordCodec[X, Q, S any] interface { // Name names the mock of x for people, such as "GET /items?page=2". Its file names start with it. Name(x X) string // Request returns what a playback of x matches. files places the bodies it holds. Request(x X, files *RecordFiles) (Q, error) // Response returns what x answered. files places the bodies it holds. Response(x X, files *RecordFiles) (S, error) // Mock returns the mock file of m, which has one response at least: a value written as JSON, then as the format of // the recording. Mock(m *RecordedMock[Q, S]) any }
RecordCodec is what a protocol tells a RecordSession: how a call it captured, X, reads as a mock. Q is the request section of the mock, what it matches, and S a response section, what it replies with. Both are written as JSON with encoding/json/v2, such as structs with json tags. Calls whose Q writes the same JSON are the same request: they play back as one mock, so Q must write equivalent requests the same way.
type RecordFiles ¶
type RecordFiles struct {
// contains filtered or unexported fields
}
RecordFiles places the bodies of one call: inline in its mock file, or in files next to it, written with the mock. Files are named after their content, so equal bodies share one.
func (*RecordFiles) Place ¶
Place returns where body goes. It goes inline when text is true and the recording neither writes every body to a file nor finds body longer than MaxInlineBody; otherwise to a file next to the mock file, whose name it returns, and which ext ends, such as ".json". Place keeps body until the mock is written: the caller doesn't change it after.
func (*RecordFiles) PlaceSpooled ¶
func (f *RecordFiles) PlaceSpooled(b *RecordBody, ext string) (string, error)
PlaceSpooled places a body that went to a file while it was captured: the file moves next to the mock file, under the name it returns, which ext ends. It waits for the file to be written. It fails when the body wasn't kept, or stayed in memory: Place takes its Bytes.
type RecordOptions ¶
type RecordOptions[Q, S any] struct { // Dir is where the mock files and body files go. It is created when missing. Dir string // Format is the format of the mock files: json, yaml or yml. Format string // Repeats is what the recording keeps of a request that comes again. 0 means RecordSequence. Repeats RecordRepeats // BodyFiles writes every body to a file of its own, instead of inline in the mock file. BodyFiles bool // MaxInlineBody is how much of a body stays in memory; a larger body goes to a file while it is captured. A text // body that stays in memory is written inline in the mock file. 0 means 1 MiB. MaxInlineBody int64 // MaxBodySize bounds the bodies recorded: a call with a larger one isn't recorded. 0 means 1 GiB; a negative // value means no limit. MaxBodySize int64 // Transforms change each mock before it is written, in order. A transform that fails skips the mock, and so do // transforms that leave it no response. Transforms []func(*RecordedMock[Q, S]) error Logger *zerolog.Logger }
RecordOptions configures a RecordSession.
type RecordRepeats ¶
type RecordRepeats int
RecordRepeats is what a recording keeps of the calls that repeat a request.
const ( // RecordSequence keeps every response, in the order they came: the mock replies with them in turn, then with the // last one again. When every response is the same, it keeps one. It is the default, which zero means. RecordSequence RecordRepeats = iota + 1 // RecordFirst keeps the first response only. RecordFirst )
type RecordResult ¶
type RecordResult struct {
Recordings []Recording
Status RecordStatus
}
RecordResult is what a recording wrote, in the order its requests first came.
type RecordSession ¶
type RecordSession[X, Q, S any] struct { // contains filtered or unexported fields }
RecordSession records the calls of a protocol as mock files, off the request path. Record queues a call and returns at once; a goroutine of the session turns calls into mocks and writes them. Calls of one request make one mock.
func MustNewRecordSession ¶
func MustNewRecordSession[X, Q, S any](c RecordCodec[X, Q, S], o RecordOptions[Q, S]) *RecordSession[X, Q, S]
MustNewRecordSession is NewRecordSession, and panics when it fails.
func NewRecordSession ¶
func NewRecordSession[X, Q, S any](c RecordCodec[X, Q, S], o RecordOptions[Q, S]) (*RecordSession[X, Q, S], error)
NewRecordSession starts a recording into o.Dir, which it creates when missing. It removes the files a recording that ended unexpectedly left half written there: one recording writes to a directory at a time.
func (*RecordSession[X, Q, S]) Done ¶
func (s *RecordSession[X, Q, S]) Done() <-chan struct{}
Done closes once the recording stopped and wrote everything it took.
func (*RecordSession[X, Q, S]) NewBody ¶
func (s *RecordSession[X, Q, S]) NewBody() *RecordBody
NewBody returns a body to capture into, for a call of this session.
func (*RecordSession[X, Q, S]) Record ¶
func (s *RecordSession[X, Q, S]) Record(x X, size int) bool
Record queues x, a call to record, and returns at once. size is what x holds in memory. It returns false when the recording stopped, or when the calls waiting to be written hold too much already. A call the session doesn't record is discarded: when X has a Discard method, the session calls it.
func (*RecordSession[X, Q, S]) Status ¶
func (s *RecordSession[X, Q, S]) Status() RecordStatus
Status counts the calls of the recording.
func (*RecordSession[X, Q, S]) Stop ¶
func (s *RecordSession[X, Q, S]) Stop(ctx context.Context) (*RecordResult, error)
Stop stops taking calls, writes those it took, and returns what it wrote. Calls still being captured aren't recorded. It waits for the writing, or for ctx: when ctx ends first, it returns ctx's error, and a later Stop waits again. Done closes once the writing ends. The error joins the calls and mocks that failed.
type RecordStatus ¶
type RecordStatus struct {
// Active is true while the recording takes calls.
Active bool
// Calls is how many calls it took.
Calls int64
// Mocks is how many mocks it wrote.
Mocks int64
// Dropped is how many calls it refused, because too many waited to be written.
Dropped int64
// Failed is how many calls and mocks it couldn't record.
Failed int64
}
RecordStatus counts the calls of a recording.
type RecordedMock ¶
type RecordedMock[Q, S any] struct { // ID names the mock and its file. A transform can't change it. ID string Name string Request Q Responses []S }
RecordedMock is a mock a recording made: a request, and the responses recorded for it, in the order they came.
type Recording ¶
type Recording struct {
ID string
Name string
// File is the path of the mock file.
File string
// BodyFiles are the names of its body files, next to the mock file.
BodyFiles []string
// Responses is how many responses it replies with.
Responses int
}
Recording is a mock a recording wrote.
type Replier ¶
Replier makes the reply of a mock to input, which holds the request the mock matched. A ReplierFactory makes one for each mock.
type ReplierFactory ¶
ReplierFactory makes the Replier of a mock. A mock builder calls NewReplier once for each mock it builds, with the server A it builds the mock for, so:
- each mock gets a Replier of its own: what it keeps, such as compiled templates or a position in a sequence, belongs to that mock;
- one factory can serve many mocks and servers, and changing it later changes only the mocks built afterwards.
NewReplier must not change the factory: mocks for different servers can be built at the same time. The Replier must not share a map or slice that the methods of the factory change. A factory that holds other factories calls their NewReplier.
type Scope ¶
type Scope[B Mock] struct { // contains filtered or unexported fields }
Scope keeps a reference to a group of mocks.
func NewScope ¶
NewScope creates a Scope that holds references to the given mocks and store. With a Scope instance, it is possible to verify if one or a group of mocks were called, how many times they were called and so on.
func (*Scope[B]) AssertCalled ¶
AssertCalled reports an error if there are still pending Mock instances.
func (*Scope[B]) AssertNotCalled ¶
AssertNotCalled reports an error if any mock was called.
func (*Scope[B]) AssertNumberOfCalls ¶
AssertNumberOfCalls asserts that the sum of matched request hits is equal to the given expected value.
func (*Scope[B]) Called ¶
Called returns true if all Scope Mock instances were called at least once.
func (*Scope[B]) Delete ¶
Delete removes the mocks of this scope with the given IDs from the store. IDs of other mocks are ignored. A mock that left the store some other way stays out, even when its ID now names another mock: mocks are told apart by identity, so Mock implementations must be comparable, as pointers are.
func (*Scope[B]) Disable ¶
func (s *Scope[B]) Disable()
Disable disables all Mock instances kept in this Scope. Disabled Mocks will be ignored during matching.
func (*Scope[B]) Enable ¶
func (s *Scope[B]) Enable()
Enable enables all Mock instances kept in this Scope.
func (*Scope[B]) ListCalled ¶
func (s *Scope[B]) ListCalled() []B
ListCalled returns all Mock instances that were called.
func (*Scope[B]) ListPending ¶
func (s *Scope[B]) ListPending() []B
ListPending returns all Mock instances that were not called at least once.
type Scopes ¶
Scopes is a collection of Scope instances with coordinated add and retrieval.
func (*Scopes[B, A]) Add ¶
Add builds every builder, then stores the mocks in one call and returns their scope. It stores nothing when a builder fails, and reports every failing builder by index, or when the store refuses the mocks, for example over an ID already in use.
func (*Scopes[B, A]) All ¶
All returns the scopes tracked, in the order they were added. A scope that replaced another takes its place.
func (*Scopes[B, A]) Replace ¶
func (s *Scopes[B, A]) Replace(ctx context.Context, old *Scope[B], builders ...Builder[B, A]) (*Scope[B], error)
Replace builds every builder, then swaps the mocks for those of old in one step, so a reader finds the mocks of old or the new ones, never neither, and returns their scope, which takes the place of old. With a nil old, it adds the mocks, as Add does. A mock stored outside every scope, such as one the admin API added, gives way in the same step to a new mock with its ID. It changes nothing when old isn't tracked, when a builder fails, reporting every failing builder by index, or when the store refuses the mocks, for example over an ID in use in another scope. Once replaced, old holds no mocks.
type Selector ¶
Selector selects a value from the parameter input. The return value could be the input itself or a specific field of it.
type SelfDescriptive ¶
type SelfDescriptive interface {
Describe() Descriptor
}
SelfDescriptive is an interface that allows a type to describe itself.
type Server ¶
type Server[B Mock, A any] interface { Hits() int64 Enable() Disable() Clean(ctx context.Context) error Mock(builders ...Builder[B, A]) (*Scope[B], error) }
Server is the interface every mock server implements. It covers both mock registration and lifecycle management.
type Sink ¶
Sink is a Stage that ends a flow: it writes what it gets to W.
func (*Sink) Flush ¶
Flush flushes W when it can, with a Flush() error method, such as a bufio.Writer has.
type Stage ¶
Stage is a pipe's part of one Flow. Write follows io.Writer: n is how much of b the stage took, which is len(b) when it passed b on changed, in parts, later, or not at all.
A stage decides what goes on to next: b as it is, changed or in parts, later, or nothing. It fails the flow by returning an error. One that matches ErrAbort or ErrReset aborts it. Flush passes on what the stage holds, then flushes next. Close passes on what it holds, then closes next.
The flow's caller calls a stage one call at a time. A stage may call next from a goroutine of its own, as one that delays its writes does: its calls never overlap, and all of them end before its Close returns. b is the caller's, as for io.Writer: a stage must not change its bytes, and copies it to keep it once Write returned. The flow clips every b, so append always copies it. Once the flow's Flow.Context ends, a stage drops what it holds, returns from Close at once, and its goroutines and timers end: what it passes on from then on doesn't reach the sink.
type Stateful ¶
type Stateful interface {
SetState() error
}
Stateful describes a matcher that has post processes that need to be executed after the matched mock is served. Dedicated for stateful matchers.
type Store ¶
type Store[T Mock] interface { List(ctx context.Context) (iter.Seq[T], error) // Store adds mocks. It fails with ErrDuplicateID, storing none of them, // when an ID is already stored or repeated in the call. Store(ctx context.Context, mocks ...T) error // Replace removes the mocks of old it holds and stores mocks, in one step: a reader finds the mocks of old or // the new ones, never neither. Mocks are told apart by identity, so a mock of old that left the store stays out, // even when its ID now names another mock; Mock implementations must be comparable, as pointers are. // It fails with ErrDuplicateID, changing nothing, when an ID of mocks is held by a mock it keeps, // or repeated in the call. Replace(ctx context.Context, old []T, mocks ...T) error Pick(ctx context.Context, id string) (T, error) PickAll(ctx context.Context) ([]T, error) Delete(ctx context.Context, ids ...string) error Clear(ctx context.Context) error // Health returns an error when the store can't serve its mocks, such as when the database behind it is down. The // admin API answers GET /readyz with it. Health(ctx context.Context) error }
Store holds the mocks of a server. Replace, Delete and Clear close the mocks they remove that implement io.Closer, once the store is unlocked; a mock Replace stores again stays open, and keeps its place in the order mocks match.
type Swap ¶
Swap gives Base.RemockWith more mocks to swap in the same step. built are the mocks of the builders, and gone the stored mocks they take the place of: those of the old scope, and those outside every scope whose IDs built take. Swap returns the stored mocks to remove too, and the mocks to add too. The new scope doesn't hold those: they stay the caller's, to close when RemockWith fails.
type Template ¶
type Template interface {
// Execute writes the template applied to data to w. A mock executes its templates for every request it serves,
// so Execute must be safe for concurrent use.
Execute(w io.Writer, data any) error
}
Template is a compiled template.
type TemplateDataProvider ¶
TemplateDataProvider adds data to the templates of a server's mocks, which read it as .Provided.<Key>. In is what the server gives it for each request it serves, such as a mockhttp.TemplateDataProviderInput.
type TemplateEngine ¶
type TemplateEngine interface {
// Compile parses text. name says which template it is in errors, such as "body" or "header.X-Id".
Compile(name, text string) (Template, error)
}
TemplateEngine compiles templates: the bodies, headers and body file names of replies, the parts of multipart bodies, and the parameters of events, such as webhooks. A server compiles all of them with one engine.
Templates compile when a mock is built, so one that doesn't compile fails the mock rather than a request. A body file whose content is a template compiles when a request reads it, since its name can depend on the request, so Compile must be safe for concurrent use.
GoTemplateEngine is the engine vlatte ships, and the default. Another engine, such as one for Handlebars, plugs in by implementing this interface.
Source Files
¶
- assert.go
- base.go
- config.go
- delay.go
- descriptor.go
- doc.go
- eval.go
- eventlistener.go
- events.go
- explanation.go
- failure.go
- flow.go
- header.go
- inspector.go
- kind.go
- kit.go
- kv.go
- kv_csv.go
- log.go
- matcher.go
- mock.go
- near_miss.go
- parameters.go
- recipe.go
- record_body.go
- record_session.go
- recording.go
- reply.go
- scope.go
- server.go
- stateful.go
- store.go
- template.go
- testing.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package admin is the admin API of a mock server: a RESTful HTTP server of its own, on its own address, that lists, adds and changes the server's mocks, and reads its journal, while it runs.
|
Package admin is the admin API of a mock server: a RESTful HTTP server of its own, on its own address, that lists, adds and changes the server's mocks, and reads its journal, while it runs. |
|
cmd
|
|
|
vlatte
command
Command vlatte runs a mock server: it serves the mock files under testdata/vlatte/_mocks in the working directory, and an admin API on an address of its own.
|
Command vlatte runs a mock server: it serves the mock files under testdata/vlatte/_mocks in the working directory, and an admin API on an address of its own. |
|
Package fault provides pipes that make a mock answer wrong, to test how a client handles a server that fails: no answer at all, a malformed one, garbage, a reset connection, a body that trickles in, a slow or distant network.
|
Package fault provides pipes that make a mock answer wrong, to test how a client handles a server that fails: no answer at all, a malformed one, garbage, a reset connection, a body that trickles in, a slow or distant network. |
|
faultbuild
Package faultbuild builds the faults of package github.com/caffeine-projects/vlatte/fault from the fault specs of mock files: an object whose type names the fault and whose other keys are its parameters, such as {"type": "latency", "latency": "300ms", "jitter": "60ms"}.
|
Package faultbuild builds the faults of package github.com/caffeine-projects/vlatte/fault from the fault specs of mock files: an object whose type names the fault and whose other keys are its parameters, such as {"type": "latency", "latency": "300ms", "jitter": "60ms"}. |
|
internal
|
|
|
admin
Package admin serves the admin API of a mock server: a RESTful HTTP server of its own, on its own address, the same for mock servers of every protocol.
|
Package admin serves the admin API of a mock server: a RESTful HTTP server of its own, on its own address, the same for mock servers of every protocol. |
|
admin/handler
Package handler holds the admin operations of a mock server, and the units of the admin API that serve them over HTTP.
|
Package handler holds the admin operations of a mock server, and the units of the admin API that serve them over HTTP. |
|
adminapi
Package adminapi is what a mock server and its admin API share: what the server gives the admin API, its Capabilities, and the API that serves them.
|
Package adminapi is what a mock server and its admin API share: what the server gives the admin API, its Capabilities, and the API that serves them. |
|
atomicfile
Package atomicfile writes files that readers find whole, or not at all.
|
Package atomicfile writes files that readers find whole, or not at all. |
|
bodyfile
Package bodyfile opens the files bodies are read from, such as a reply's body_file.
|
Package bodyfile opens the files bodies are read from, such as a reply's body_file. |
|
buildinfo
Package buildinfo reports which vlatte a program was built with.
|
Package buildinfo reports which vlatte a program was built with. |
|
config
Package config loads settings from files, environment variables and command-line arguments into a configuration struct, following a schema that names, types and documents every setting.
|
Package config loads settings from files, environment variables and command-line arguments into a configuration struct, following a schema that names, types and documents every setting. |
|
httpx
Package httpx holds the small HTTP helpers the mock servers and the webhook package share.
|
Package httpx holds the small HTTP helpers the mock servers and the webhook package share. |
|
jose
Package jose signs and verifies JSON Web Signatures (RFC 7515) in compact form, and converts public keys to and from JSON Web Keys (RFC 7517), for the asymmetric algorithms of RFC 7518 and RFC 8037.
|
Package jose signs and verifies JSON Web Signatures (RFC 7515) in compact form, and converts public keys to and from JSON Web Keys (RFC 7517), for the asymmetric algorithms of RFC 7518 and RFC 8037. |
|
kvtest
Package kvtest checks that a key-value store keeps the contract of github.com/caffeine-projects/vlatte.KV.
|
Package kvtest checks that a key-value store keeps the contract of github.com/caffeine-projects/vlatte.KV. |
|
kvview
Package kvview gives templates the key-value store of a mock server, as text.
|
Package kvview gives templates the key-value store of a mock server, as text. |
|
mockid
Package mockid checks the IDs of mocks, which name them in admin API paths, such as /mocks/{id}.
|
Package mockid checks the IDs of mocks, which name them in admin API paths, such as /mocks/{id}. |
|
mpart
Package mpart writes multipart bodies, for replies and webhooks, with mime/multipart.Writer: their model, the checks of the model, and the tables that decode it from mock files.
|
Package mpart writes multipart bodies, for replies and webhooks, with mime/multipart.Writer: their model, the checks of the model, and the tables that decode it from mock files. |
|
sse
Package sse writes Server-Sent Events, the text/event-stream bodies of the WHATWG HTML standard, for replies: their model, the checks of the model, and the stream that sends them one by one, with their delays.
|
Package sse writes Server-Sent Events, the text/event-stream bodies of the WHATWG HTML standard, for replies: their model, the checks of the model, and the stream that sends them one by one, with their delays. |
|
tmplfunc
Package tmplfunc holds the functions of vlatte's Go template engine.
|
Package tmplfunc holds the functions of vlatte's Go template engine. |
|
value
Package value is the data model that documents, settings and matchers share: how JSON is read, how text reads as a bool or a number, and how values compare.
|
Package value is the data model that documents, settings and matchers share: how JSON is read, how text reads as a bool or a number, and how values compare. |
|
xmldoc
Package xmldoc reads XML documents into trees that keep them as written, and navigates them for XPath.
|
Package xmldoc reads XML documents into trees that keep them as written, and navigates them for XPath. |
|
Package journal keeps the requests a mock server serves, of any protocol, whatever their outcome, so a test can verify after the fact what the code under test sent: a changelog of JSON lines in segment files, with an index in memory that narrows queries.
|
Package journal keeps the requests a mock server serves, of any protocol, whatever their outcome, so a test can verify after the fact what the code under test sent: a changelog of JSON lines in segment files, with an index in memory that narrows queries. |
|
Package match provides request matchers, such as Equal, JSONPath, All and Not.
|
Package match provides request matchers, such as Equal, JSONPath, All and Not. |
|
internal/timetext
Package timetext reads dates and times as the date and time matchers write them.
|
Package timetext reads dates and times as the date and time matchers write them. |
|
matchbuild
Package matchbuild builds matchers from the matcher specs of mock files: a list whose first item names the matcher and whose other items are its arguments, such as ["contains", "x"] or ["jsonpath", "$.a", ["gt", 1]].
|
Package matchbuild builds matchers from the matcher specs of mock files: a list whose first item names the matcher and whose other items are its arguments, such as ["contains", "x"] or ["jsonpath", "$.a", ["gt", 1]]. |
|
matchrepeat
Package matchrepeat limits how many times a mock is served: Repeat matches until a mock has been served the given number of times.
|
Package matchrepeat limits how many times a mock is served: Repeat matches until a mock has been served the given number of times. |
|
matchscenario
Package matchscenario serves mocks in turn, as a scenario moves from state to state.
|
Package matchscenario serves mocks in turn, as a scenario moves from state to state. |
|
matchscenario/scenariotest
Package scenariotest checks that a mock server serves scenarios as github.com/caffeine-projects/vlatte/match/matchscenario defines them.
|
Package scenariotest checks that a mock server serves scenarios as github.com/caffeine-projects/vlatte/match/matchscenario defines them. |
|
Package mockgrpc runs gRPC mock servers for tests, and for the vlatte command.
|
Package mockgrpc runs gRPC mock servers for tests, and for the vlatte command. |
|
internal/protobuf
Package protobuf holds the gRPC service definitions used by the mockgrpc tests.
|
Package protobuf holds the gRPC service definitions used by the mockgrpc tests. |
|
Package mockhttp runs HTTP mock servers for tests.
|
Package mockhttp runs HTTP mock servers for tests. |
|
e2e/internal/githubapp
Package githubapp is a small web app that signs users in with GitHub, through the OAuth web flow of an OAuth app with PKCE, and reads their profile, repositories and issues with the GitHub REST API.
|
Package githubapp is a small web app that signs users in with GitHub, through the OAuth web flow of an OAuth app with PKCE, and reads their profile, repositories and issues with the GitHub REST API. |
|
e2e/internal/oidcapp
Package oidcapp is a small web app that signs users in with an OpenID Connect provider, through the authorization code flow with PKCE, and reads their profile from the provider's userinfo endpoint.
|
Package oidcapp is a small web app that signs users in with an OpenID Connect provider, through the authorization code flow with PKCE, and reads their profile from the provider's userinfo endpoint. |
|
e2e/internal/testcert
command
Command testcert writes a self-signed certificate and its key, cert.pem and key.pem, to the working directory.
|
Command testcert writes a self-signed certificate and its key, cert.pem and key.pem, to the working directory. |
|
internal/mid
Package mid contains utilities to handle middlewares and also common middlewares used internally.
|
Package mid contains utilities to handle middlewares and also common middlewares used internally. |
|
recipe
|
|
|
http/githubauth
Package githubauth provides a recipe that prepares an HTTP mock server to stand in for "Sign in with GitHub": the OAuth web flow of an OAuth app, and the profile of the user who signs in.
|
Package githubauth provides a recipe that prepares an HTTP mock server to stand in for "Sign in with GitHub": the OAuth web flow of an OAuth app, and the profile of the user who signs in. |
|
http/oidc
Package oidc provides a recipe that prepares an HTTP mock server to stand in for an OpenID Connect provider: "Sign in with ..." through the authorization code flow, with discovery, a JWKS, ID tokens the server signs, PKCE and userinfo.
|
Package oidc provides a recipe that prepares an HTTP mock server to stand in for an OpenID Connect provider: "Sign in with ..." through the authorization code flow, with discovery, a JWKS, ID tokens the server signs, PKCE and userinfo. |
|
http/proxyall
Package proxyall provides a recipe that prepares an HTTP mock server to send the requests no other mock matches to a real service: mock the endpoints a test cares about, and let everything else reach the service as it is.
|
Package proxyall provides a recipe that prepares an HTTP mock server to send the requests no other mock matches to a real service: mock the endpoints a test cares about, and let everything else reach the service as it is. |
|
Package verify checks the requests a mock server served, of any protocol, from its journal: which came, how many, by when, and in what order.
|
Package verify checks the requests a mock server served, of any protocol, from its journal: which came, how many, by when, and in what order. |
|
Package webhook sends webhooks: HTTP requests a mock makes after it replies.
|
Package webhook sends webhooks: HTTP requests a mock makes after it replies. |