scenario

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2026 License: AGPL-3.0 Imports: 16 Imported by: 0

Documentation

Overview

Package scenario reads LoadWave's YAML configuration and turns it into the two things the rest of the system needs: a wire-format test plan, and — for tests written declaratively rather than in Go — a set of runnable scenarios.

Index

Constants

View Source
const (
	ExecutorConstantVUs = "constant-vus"
	ExecutorRampingVUs  = "ramping-vus"
)

Executor names accepted in configuration.

View Source
const (
	VarVUID      = "__vu"
	VarIteration = "__iteration"
	VarShard     = "__shard"
	VarShards    = "__shards"
	VarRandom    = "__random"
	VarUUID      = "__uuid"
	VarTimestamp = "__timestamp"
	VarUnixMilli = "__unixMilli"
)

Built-in variable names, all prefixed so they cannot collide with a user's own declarations.

View Source
const DefaultScenarioName = "default"

DefaultScenarioName is the scenario synthesised for a bare --url run.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// Name identifies the test in the dashboard and in result files.
	Name string `yaml:"name,omitempty"`

	// BaseURL is prefixed to every relative request path.
	BaseURL string `yaml:"baseURL,omitempty"`

	Load       LoadConfig        `yaml:"load"`
	HTTP       HTTPConfig        `yaml:"http"`
	Tags       map[string]string `yaml:"tags,omitempty"`
	Thresholds []Threshold       `yaml:"thresholds,omitempty"`

	// WorkersPerAgent is how many worker processes each agent should spawn.
	// Zero lets each agent decide from its own core count.
	WorkersPerAgent int `yaml:"workersPerAgent,omitempty"`

	// BetweenRequests pauses after every request, whatever its outcome: a
	// duration such as "1s", or a range such as "500ms-2s".
	//
	// This is the run's pacing floor, and it is why a scenario with no think
	// time of its own does not loop as fast as the network allows — or, when
	// its request fails instantly, as fast as the CPU allows. Empty applies
	// one second. Set it to "0" for a throughput test, where flat out is the
	// point.
	//
	// Individual steps override it, including down to none.
	BetweenRequests string `yaml:"betweenRequests,omitempty"`

	// Scenarios lists what to run. An entry with steps is a declarative
	// scenario defined here; an entry with only a name and weight refers to
	// a scenario compiled into the binary through the Go SDK. Leaving the
	// list empty runs every scenario the binary has registered.
	Scenarios []ScenarioConfig `yaml:"scenarios,omitempty"`
}

Config is a complete LoadWave test file.

func FromPlan

func FromPlan(plan *loadwavev1.TestPlan) (*Config, error)

FromPlan recovers the configuration a plan was built from.

Workers use this to rebuild the HTTP settings and declarative scenarios. A plan with no embedded configuration — one assembled programmatically rather than from a file — yields a configuration carrying just the base URL, which is enough for a run whose scenarios are all compiled into the binary.

func Parse

func Parse(data []byte) (*Config, error)

Parse reads a configuration from YAML.

Unknown fields are rejected rather than ignored. A silently misspelled key in a load test is a costly kind of bug: the run appears to work and quietly measures something other than what was asked for.

func (*Config) BetweenRequestsPause

func (c *Config) BetweenRequestsPause() loadwave.Pause

BetweenRequestsPause resolves the run's pacing, default included.

Every caller must go through this rather than reading the raw field. An empty field means "use the default", and treating it as the zero Pause reports — and applies — flat out, which is the opposite of what an unconfigured run should do.

func (*Config) BuildScenarios

func (c *Config) BuildScenarios(registry *loadwave.Registry) error

BuildScenarios compiles every declarative scenario in the configuration and registers it.

Scenarios that only reference compiled-in Go code are skipped, since they are already in the registry. A name that collides with a registered Go scenario is an error rather than an override: silently shadowing compiled code with YAML would be a genuinely confusing thing to debug.

func (*Config) HTTPOptions

func (c *Config) HTTPOptions() loadwave.HTTPOptions

HTTPOptions renders the HTTP settings for the SDK's client factory.

func (*Config) Plan

func (c *Config) Plan() (*loadwavev1.TestPlan, error)

Plan converts the configuration into the wire-format test plan the coordinator distributes.

func (*Config) Validate

func (c *Config) Validate() error

Validate checks the configuration for internal consistency.

type Duration

type Duration time.Duration

Duration is a time.Duration that reads from YAML as "30s" or "5m".

func (Duration) MarshalYAML

func (d Duration) MarshalYAML() (any, error)

MarshalYAML implements yaml.InterfaceMarshaler.

func (Duration) Std

func (d Duration) Std() time.Duration

Std returns the underlying time.Duration.

func (*Duration) UnmarshalYAML

func (d *Duration) UnmarshalYAML(data []byte) error

UnmarshalYAML implements yaml.BytesUnmarshaler.

type HTTPConfig

type HTTPConfig struct {
	Timeout               Duration          `yaml:"timeout"`
	Headers               map[string]string `yaml:"headers,omitempty"`
	UserAgent             string            `yaml:"userAgent"`
	InsecureSkipTLSVerify bool              `yaml:"insecureSkipTLSVerify"`
	MaxIdleConnsPerHost   int               `yaml:"maxIdleConnsPerHost"`
	DisableKeepAlives     bool              `yaml:"disableKeepAlives"`
	DisableCompression    bool              `yaml:"disableCompression"`
	FollowRedirects       bool              `yaml:"followRedirects"`
	MaxRedirects          int               `yaml:"maxRedirects"`
	IsolatePerVU          bool              `yaml:"isolatePerVU"`
	DiscardBody           bool              `yaml:"discardBody"`
	MaxBodyBytes          int64             `yaml:"maxBodyBytes"`
	Proxy                 string            `yaml:"proxy"`
}

HTTPConfig mirrors the tunable parts of loadwave.HTTPOptions.

type LoadConfig

type LoadConfig struct {
	// Executor is "constant-vus" or "ramping-vus". Empty defaults to
	// constant-vus.
	Executor string `yaml:"executor"`

	VUs      int      `yaml:"vus"`
	Duration Duration `yaml:"duration"`

	Stages []StageConfig `yaml:"stages,omitempty"`

	// MaxIterationRate caps iterations started per second across the whole
	// run. Zero leaves the VU count as the only control.
	MaxIterationRate int `yaml:"maxIterationRate"`

	// Iterations stops the run after this many iterations in total.
	Iterations uint64 `yaml:"iterations"`

	// GracefulStop is how long in-flight iterations get to finish.
	GracefulStop Duration `yaml:"gracefulStop"`
}

LoadConfig describes the shape of the load over time.

type Path

type Path struct {
	// contains filtered or unexported fields
}

Path is a compiled accessor into a decoded JSON document.

This is deliberately not JSONPath. Declarative scenarios need to pull an id out of a response and put it in the next URL; supporting filters, wildcards and recursive descent would mean a query language to document, test and explain, in exchange for capabilities a load test almost never wants. What is supported is field access and array indexing, in either dotted or bracketed form:

id
$.data.token
items.0.sku
items[0].sku

func ParsePath

func ParsePath(expr string) (*Path, error)

ParsePath compiles a capture expression.

func (*Path) Extract

func (p *Path) Extract(data []byte) (string, error)

Extract decodes a JSON document and pulls out the value at this path, rendered as a string.

func (*Path) String

func (p *Path) String() string

String returns the original expression.

type ScenarioConfig

type ScenarioConfig struct {
	Name        string            `yaml:"name,omitempty"`
	Weight      int               `yaml:"weight,omitempty"`
	Description string            `yaml:"description,omitempty"`
	Vars        map[string]string `yaml:"vars,omitempty"`
	Steps       []StepConfig      `yaml:"steps,omitempty"`
}

ScenarioConfig is one entry in a configuration's scenario list.

An entry carrying steps defines the scenario here, declaratively. An entry with only a name refers to a scenario compiled into the binary through the Go SDK, and exists just to set its weight.

type StageConfig

type StageConfig struct {
	Duration Duration `yaml:"duration"`
	Target   int      `yaml:"target"`
}

StageConfig is one leg of a ramping profile.

type StepConfig

type StepConfig struct {
	// Name labels the step's metrics. Defaults to the method and path with
	// variable segments collapsed.
	Name string `yaml:"name,omitempty"`

	// Method and URL state the request explicitly. Alternatively use one of
	// the shorthands below, which set both at once.
	Method string `yaml:"method,omitempty"`
	URL    string `yaml:"url,omitempty"`

	Get    string `yaml:"get,omitempty"`
	Post   string `yaml:"post,omitempty"`
	Put    string `yaml:"put,omitempty"`
	Patch  string `yaml:"patch,omitempty"`
	Delete string `yaml:"delete,omitempty"`
	Head   string `yaml:"head,omitempty"`

	Headers map[string]string `yaml:"headers,omitempty"`
	Query   map[string]string `yaml:"query,omitempty"`

	// At most one body form may be set.
	JSON any               `yaml:"json,omitempty"`
	Form map[string]string `yaml:"form,omitempty"`
	Body string            `yaml:"body,omitempty"`

	// Expect lists acceptable status codes. A response outside the list
	// fails the step's check and ends the iteration.
	Expect []int `yaml:"expect,omitempty"`

	// Capture pulls values out of the JSON response into variables that
	// later steps can interpolate with ${name}.
	Capture map[string]string `yaml:"capture,omitempty"`

	// Think pauses instead of making a request. Either a fixed duration
	// ("2s") or a range ("1s-3s") drawn uniformly.
	Think string `yaml:"think,omitempty"`

	Timeout Duration `yaml:"timeout,omitempty"`

	// BetweenRequests overrides the run's pacing for this step alone: a
	// duration, a range, or "0" for no pause at all. Empty uses the run's
	// setting.
	BetweenRequests string `yaml:"betweenRequests,omitempty"`
}

StepConfig is one action in a declarative scenario: either an HTTP request or a pause.

func (StepConfig) ResolvedRequest

func (s StepConfig) ResolvedRequest() (method, target string, err error)

ResolvedRequest returns the method and URL a step's explicit fields or shorthand resolve to, for callers outside this package that need to describe a step — such as the dashboard rendering one back into its builder form.

type Template

type Template struct {
	// contains filtered or unexported fields
}

Template is a string with ${name} placeholders, parsed once and rendered once per use.

Declarative steps render their URL, headers and body on every iteration — tens of thousands of times a second across a fleet — so the parse is done when the scenario is built rather than in the hot path, and a template with no placeholders costs nothing at all to render.

func MustParseTemplate

func MustParseTemplate(s string) *Template

MustParseTemplate is ParseTemplate for templates known good at build time.

func ParseTemplate

func ParseTemplate(s string) (*Template, error)

ParseTemplate compiles a template string.

func (*Template) IsStatic

func (t *Template) IsStatic() bool

IsStatic reports whether the template has no placeholders.

func (*Template) Render

func (t *Template) Render(vars *Vars) string

Render substitutes the placeholders. Unknown names render as empty strings rather than failing: a capture that did not fire should produce a request that visibly misses, not an iteration that dies before making one.

func (*Template) String

func (t *Template) String() string

String returns the original template text.

type Threshold

type Threshold struct {
	Metric      string  `yaml:"metric"`
	Stat        string  `yaml:"stat"`
	Op          string  `yaml:"op"`
	Value       float64 `yaml:"value"`
	AbortOnFail bool    `yaml:"abortOnFail"`
}

Threshold is a pass/fail assertion evaluated when the run ends.

type Vars

type Vars struct {
	// contains filtered or unexported fields
}

Vars holds one iteration's variables: those declared on the scenario, those captured from earlier responses, and a handful of built-ins.

func NewVars

func NewVars(vu *loadwave.VU, declared map[string]string) *Vars

NewVars creates a variable scope seeded with the scenario's declarations.

func (*Vars) Get

func (v *Vars) Get(name string) string

Get resolves a variable, checking user values before built-ins so a scenario can shadow one deliberately.

func (*Vars) Set

func (v *Vars) Set(name, value string)

Set records a captured value.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL