wasp

package module
v0.0.0-...-c2b60f3 Latest Latest
Warning

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

Go to latest
Published: Nov 21, 2024 License: MIT Imports: 47 Imported by: 3

README

wasp

Go Report Card Component Tests E2E tests gopherbadger-tag-do-not-edit

Scalable protocol-agnostic load testing library for Go

Goals

  • Easy to reuse any custom client Go code
  • Easy to grasp
  • Have a slim codebase (500-1k loc)
  • No test harness or CLI, easy to integrate and run with plain go test
  • Have a predictable performance footprint
  • Easy to create synthetic or user-based scenarios
  • Scalable in k8s without complicated configuration or vendored UI interfaces
  • Non-opinionated reporting, push any data to Loki

Setup

We are using nix for deps, see installation guide

nix develop

Run example tests with Grafana + Loki

make start

Insert GRAFANA_TOKEN created in previous command

export LOKI_TOKEN=
export LOKI_URL=http://localhost:3030/loki/api/v1/push
export GRAFANA_URL=http://localhost:3000
export GRAFANA_TOKEN=
export DATA_SOURCE_NAME=Loki
export DASHBOARD_FOLDER=LoadTests
export DASHBOARD_NAME=Wasp

make dashboard

Run some tests:

make test_loki

Open your Grafana dashboard

In case you deploy to your own Grafana check DASHBOARD_FOLDER and DASHBOARD_NAME, defaults are LoadTests dir and dashboard is called Wasp

Remove environment:

make stop

Test Layout and examples

Check examples to understand what is the easiest way to structure your tests, run them both locally and remotely, at scale, inside k8s

Run pyroscope test

make pyro_start
make test_pyro_rps
make test_pyro_vu
make pyro_stop

Open pyroscope

You can also use trace.out in the root folder with Go default tracing UI

How it works

img.png

Check this doc for more examples and project overview

Loki debug

You can check all the messages the tool sends with env var WASP_LOG_LEVEL=trace

If Loki client fail to deliver a batch test will proceed, if you experience Loki issues, consider setting Timeout in LokiConfig or set MaxErrors: 10 to return an error after N Loki errors

MaxErrors: -1 can be used to ignore all the errors

Default Promtail settings are:

&LokiConfig{
    TenantID:                os.Getenv("LOKI_TENANT_ID"),
    URL:                     os.Getenv("LOKI_URL"),
    Token:                   os.Getenv("LOKI_TOKEN"),
    BasicAuth:               os.Getenv("LOKI_BASIC_AUTH"),
    MaxErrors:               10,
    BatchWait:               5 * time.Second,
    BatchSize:               500 * 1024,
    Timeout:                 20 * time.Second,
    DropRateLimitedBatches:  false,
    ExposePrometheusMetrics: false,
    MaxStreams:              600,
    MaxLineSize:             999999,
    MaxLineSizeTruncate:     false,
}

If you see errors like

ERR Malformed promtail log message, skipping Line=["level",{},"component","client","host","...","msg","batch add err","tenant","","error",{}]

Try to increase MaxStreams even more or check your Loki configuration

WASP Dashboard

Basic dashboard:

dashboard_img

Reusing Dashboard Components

You can integrate components from the WASP dashboard into your custom dashboards.

Example:

import (
    waspdashboard "github.com/goplugin/wasp/dashboard"
)

func BuildCustomLoadTestDashboard(dashboardName string) (dashboard.Builder, error) {
    // Custom key,value used to query for panels
    panelQuery := map[string]string{
		"branch": `=~"${branch:pipe}"`,
		"commit": `=~"${commit:pipe}"`,
        "network_type": `="testnet"`,
	}

	return dashboard.New(
		dashboardName,
        waspdashboard.WASPLoadStatsRow("Loki", panelQuery),
		waspdashboard.WASPDebugDataRow("Loki", panelQuery, true),
        # other options
    )
}

Annotate Dashboards and Monitor Alerts

To enable dashboard annotations and alert monitoring, utilize the WithGrafana() function in conjunction with wasp.Profile. This approach allows for the integration of dashboard annotations and the evaluation of dashboard alerts.

Example:

_, err = wasp.NewProfile().
    WithGrafana(grafanaOpts).
    Add(wasp.NewGenerator(getLatestReportByTimestampCfg)).
    Run(true)
require.NoError(t, err)

Where:

type GrafanaOpts struct {
	GrafanaURL                   string        `toml:"grafana_url"`
	GrafanaToken                 string        `toml:"grafana_token_secret"`
	WaitBeforeAlertCheck         time.Duration `toml:"grafana_wait_before_alert_check"`                  // Cooldown period to wait before checking for alerts
	AnnotateDashboardUIDs        []string      `toml:"grafana_annotate_dashboard_uids"`                  // Grafana dashboardUIDs to annotate start and end of the run
	CheckDashboardAlertsAfterRun []string      `toml:"grafana_check_alerts_after_run_on_dashboard_uids"` // Grafana dashboardIds to check for alerts after run
}

Documentation

Index

Constants

View Source
const (
	DefaultRequestsCPU    = "1000m"
	DefaultRequestsMemory = "512Mi"
	DefaultLimitsCPU      = "1000m"
	DefaultLimitsMemory   = "512Mi"
)

k8s pods resources

View Source
const (
	DefaultCallTimeout           = 1 * time.Minute
	DefaultSetupTimeout          = 1 * time.Minute
	DefaultTeardownTimeout       = 1 * time.Minute
	DefaultStatsPollInterval     = 5 * time.Second
	DefaultRateLimitUnitDuration = 1 * time.Second
	DefaultCallResultBufLen      = 50000
	DefaultGenName               = "Generator"
)
View Source
const (
	CallGroupLabel = "call_group"
)
View Source
const (
	// DefaultStepChangePrecision is default amount of steps in which we split a schedule
	DefaultStepChangePrecision = 10
)
View Source
const (
	K8sStatePollInterval = 1 * time.Second
)
View Source
const (
	LogLevelEnvVar = "WASP_LOG_LEVEL"
)

Variables

View Source
var (
	ErrNoNamespace = errors.New("namespace is empty")
	ErrNoJobs      = errors.New("HelmValues should contain \"jobs\" field used to scale your cluster jobs, jobs must be > 0")
)
View Source
var (
	ResourcesThresholdCheckInterval = 5 * time.Second
	// CPUIdleThresholdPercentage is default CPU idle threshold
	CPUIdleThresholdPercentage = 20
	// MEMFreeThresholdPercentage is default MEM free threshold
	MEMFreeThresholdPercentage = 0
)
View Source
var (
	ErrNoCfg                  = errors.New("config is nil")
	ErrNoImpl                 = errors.New("either \"gun\" or \"vu\" implementation must provided")
	ErrNoSchedule             = errors.New("no schedule segments were provided")
	ErrInvalidScheduleType    = errors.New("schedule type must be either of wasp.RPS, wasp.VU, use package constants")
	ErrCallTimeout            = errors.New("generator request call timeout")
	ErrSetupTimeout           = errors.New("generator request setup timeout")
	ErrSetup                  = errors.New("generator request setup error")
	ErrTeardownTimeout        = errors.New("generator request teardown timeout")
	ErrTeardown               = errors.New("generator request teardown error")
	ErrStartFrom              = errors.New("from must be > 0")
	ErrInvalidSegmentDuration = errors.New("SegmentDuration must be defined")
	ErrNoGun                  = errors.New("rps load scheduleSegments selected but gun implementation is nil")
	ErrNoVU                   = errors.New("vu load scheduleSegments selected but vu implementation is nil")
	ErrInvalidLabels          = errors.New("invalid Loki labels, labels should be [a-z][A-Z][0-9] and _")
)
View Source
var DefaultBuildScript []byte

TODO: remove the whole stuff in favor of remote-runner

View Source
var DefaultDockerIgnorefile []byte
View Source
var DefaultDockerfile []byte

Functions

func CPUCheckLoop

func CPUCheckLoop()

CPUCheckLoop is called once by any generator, makes sense only in cluster runs on Linux

func CheckDashboardAlerts

func CheckDashboardAlerts(grafanaClient *grafana.Client, from, to time.Time, dashboardUID string) ([]grafana.Annotation, error)

CheckDashobardAlerts checks for alerts in the given dashboardUUIDs between from and to times

func ExecCmd

func ExecCmd(command string) error

ExecCmd executes os command, logging both streams

func ExecCmdWithStreamFunc

func ExecCmdWithStreamFunc(command string, outputFunction func(string)) error

ExecCmdWithStreamFunc executes command with stream function

func GetLocalK8sDeps

func GetLocalK8sDeps() (*kubernetes.Clientset, *rest.Config, error)

GetLocalK8sDeps get local k8s context config

func GetLogger

func GetLogger(t *testing.T, componentName string) zerolog.Logger

GetLogger instantiates a logger that takes into account the test context and the log level

func LabelsMapToModel

func LabelsMapToModel(m map[string]string) model.LabelSet

LabelsMapToModel create model.LabelSet from map of labels

Types

type AlertChecker

type AlertChecker struct {
	RequirementLabelKey string
	T                   *testing.T
	// contains filtered or unexported fields
}

AlertChecker is checking alerts according to dashboardUUID and requirements labels

func NewAlertChecker

func NewAlertChecker(t *testing.T) *AlertChecker

func (*AlertChecker) AnyAlerts

func (m *AlertChecker) AnyAlerts(dashboardUUID, requirementLabelValue string) ([]grafana.AlertGroupsResponse, error)

AnyAlerts check if any alerts with dashboardUUID have been raised

type ClusterConfig

type ClusterConfig struct {
	ChartPath            string
	Namespace            string
	KeepJobs             bool
	UpdateImage          bool
	DockerCmdExecPath    string
	DockerfilePath       string
	DockerIgnoreFilePath string
	BuildScriptPath      string
	BuildCtxPath         string
	ImageTag             string
	RegistryName         string
	RepoName             string
	HelmDeployTimeoutSec string
	HelmValues           map[string]string
	// contains filtered or unexported fields
}

ClusterConfig defines k8s jobs settings

func (*ClusterConfig) Defaults

func (m *ClusterConfig) Defaults(a int) error

func (*ClusterConfig) Validate

func (m *ClusterConfig) Validate() (err error)

type ClusterProfile

type ClusterProfile struct {
	Ctx    context.Context
	Cancel context.CancelFunc
	// contains filtered or unexported fields
}

ClusterProfile is a k8s cluster test for some workload profile

func NewClusterProfile

func NewClusterProfile(cfg *ClusterConfig) (*ClusterProfile, error)

NewClusterProfile creates new cluster profile

func (*ClusterProfile) Run

func (m *ClusterProfile) Run() error

Run starts a new test

type Config

type Config struct {
	T                     *testing.T
	GenName               string
	LoadType              ScheduleType
	Labels                map[string]string
	LokiConfig            *LokiConfig
	Schedule              []*Segment
	RateLimitUnitDuration time.Duration
	CallResultBufLen      int
	StatsPollInterval     time.Duration
	CallTimeout           time.Duration
	SetupTimeout          time.Duration
	TeardownTimeout       time.Duration
	FailOnErr             bool
	Gun                   Gun
	VU                    VirtualUser
	Logger                zerolog.Logger
	SharedData            interface{}
	SamplerConfig         *SamplerConfig
	// contains filtered or unexported fields
}

Config is for shared load test data and configuration

func (*Config) Validate

func (lgc *Config) Validate() error

type Generator

type Generator struct {
	Cfg *Config

	Log zerolog.Logger

	ResponsesWaitGroup *sync.WaitGroup

	ResponsesCtx context.Context

	ResponsesChan chan *Response
	Responses     *Responses
	// contains filtered or unexported fields
}

Generator generates load with some RPS

func NewGenerator

func NewGenerator(cfg *Config) (*Generator, error)

NewGenerator creates a new generator, shoots for scheduled RPS until timeout, test logic is defined through Gun or VirtualUser

func (*Generator) Errors

func (g *Generator) Errors() []string

Errors get all calls errors

func (*Generator) GetData

func (g *Generator) GetData() *ResponseData

GetData get all calls data

func (*Generator) InputSharedData

func (g *Generator) InputSharedData() interface{}

InputSharedData returns the SharedData passed in Generator config

func (*Generator) Pause

func (g *Generator) Pause()

Pause pauses execution of a generator

func (*Generator) Resume

func (g *Generator) Resume()

Resume resumes execution of a generator

func (*Generator) Run

func (g *Generator) Run(wait bool) (interface{}, bool)

Run runs load loop until timeout or stop

func (*Generator) Stats

func (g *Generator) Stats() *Stats

Stats get all load stats

func (*Generator) StatsJSON

func (g *Generator) StatsJSON() map[string]interface{}

StatsJSON get all load stats for export

func (*Generator) Stop

func (g *Generator) Stop() (interface{}, bool)

Stop stops load generator, waiting for all calls for either finish or timeout this method is external so Gun/VU implementations can stop the generator

func (*Generator) Wait

func (g *Generator) Wait() (interface{}, bool)

Wait waits until test ends

type GrafanaOpts

type GrafanaOpts struct {
	GrafanaURL                   string        `toml:"grafana_url"`
	GrafanaToken                 string        `toml:"grafana_token_secret"`
	WaitBeforeAlertCheck         time.Duration `toml:"grafana_wait_before_alert_check"`                 // Cooldown period to wait before checking for alerts
	AnnotateDashboardUID         string        `toml:"grafana_annotate_dashboard_uid"`                  // Grafana dashboardUID to annotate start and end of the run
	CheckDashboardAlertsAfterRun string        `toml:"grafana_check_alerts_after_run_on_dashboard_uid"` // Grafana dashboardUID to check for alerts after run
}

type Gun

type Gun interface {
	Call(l *Generator) *Response
}

Gun is basic interface for some synthetic load test implementation Call performs one request according to some RPS schedule

type HTTPMockServer

type HTTPMockServer struct {
	Sleep time.Duration
	// contains filtered or unexported fields
}

func NewHTTPMockServer

func NewHTTPMockServer(cfg *HTTPMockServerConfig) *HTTPMockServer

func (*HTTPMockServer) Run

func (s *HTTPMockServer) Run()

func (*HTTPMockServer) URL

func (s *HTTPMockServer) URL() string

type HTTPMockServerConfig

type HTTPMockServerConfig struct {
	FirstAPILatency   time.Duration
	FirstAPIHTTPCode  int
	SecondAPILatency  time.Duration
	SecondAPIHTTPCode int
}

type K8sClient

type K8sClient struct {
	ClientSet  *kubernetes.Clientset
	RESTConfig *rest.Config
}

K8sClient high level k8s client

func NewK8sClient

func NewK8sClient() *K8sClient

NewK8sClient creates a new k8s client with a REST config

func (*K8sClient) TrackJobs

func (m *K8sClient) TrackJobs(ctx context.Context, nsName, syncLabel string, jobNum int, keepJobs bool) error

TrackJobs tracks both jobs and their pods until they succeed or fail

type LokiClient

type LokiClient struct {
	lokiClient.Client
	// contains filtered or unexported fields
}

LokiClient is a Loki/Promtail client wrapper

func NewLokiClient

func NewLokiClient(extCfg *LokiConfig) (*LokiClient, error)

NewLokiClient creates a new Promtail client

func (*LokiClient) Handle

func (m *LokiClient) Handle(ls model.LabelSet, t time.Time, s string) error

Handle handles adding a new label set and a message to the batch

func (*LokiClient) HandleStruct

func (m *LokiClient) HandleStruct(ls model.LabelSet, t time.Time, st interface{}) error

HandleStruct handles adding a new label set and a message to the batch, marshalling JSON from struct

func (*LokiClient) StopNow

func (m *LokiClient) StopNow()

StopNow stops the client goroutine

type LokiConfig

type LokiConfig struct {
	// URL url to Loki endpoint
	URL string `yaml:"url"`
	// Token is Loki authorization token
	Token string `yaml:"token"`
	// BasicAuth is a basic login:password auth string
	BasicAuth string `yaml:"basic_auth"`
	// MaxErrors max amount of errors to ignore before exiting
	MaxErrors int
	// BatchWait max time to wait until sending a new batch
	BatchWait time.Duration
	// BatchSize size of a messages batch
	BatchSize int
	// Timeout is batch send timeout
	Timeout time.Duration
	// BackoffConfig backoff configuration
	BackoffConfig backoff.Config
	// Headers are additional request headers
	Headers map[string]string
	// The tenant ID to use when pushing logs to Loki (empty string means
	// single tenant mode)
	TenantID string
	// When enabled, Promtail will not retry batches that get a
	// 429 'Too Many Requests' response from the distributor. Helps
	// prevent HOL blocking in multitenant deployments.
	DropRateLimitedBatches bool
	// ExposePrometheusMetrics if enabled exposes Promtail Prometheus metrics
	ExposePrometheusMetrics bool
	MaxStreams              int
	MaxLineSize             int
	MaxLineSizeTruncate     bool
}

LokiConfig is simplified subset of a Promtail client configuration

func DefaultLokiConfig

func DefaultLokiConfig() *LokiConfig

DefaultLokiConfig is reasonable common settings for Loki batches

func NewEnvLokiConfig

func NewEnvLokiConfig() *LokiConfig

NewEnvLokiConfig creates new config from connection params as env vars

func NewLokiConfig

func NewLokiConfig(endpoint *string, tenant *string, basicAuth *string, token *string) *LokiConfig

NewLokiConfig this is used when you have marshalled data from CTF

type LokiLogWrapper

type LokiLogWrapper struct {
	MaxErrors int
	// contains filtered or unexported fields
}

LokiLogWrapper wraps Loki errors received through logs, handles them

func NewLokiLogWrapper

func NewLokiLogWrapper(maxErrors int) *LokiLogWrapper

func (*LokiLogWrapper) Log

func (m *LokiLogWrapper) Log(kvars ...interface{}) error

func (*LokiLogWrapper) SetClient

func (m *LokiLogWrapper) SetClient(c *LokiClient)

type MockGun

type MockGun struct {
	Data []string
	// contains filtered or unexported fields
}

MockGun is a mock gun

func NewMockGun

func NewMockGun(cfg *MockGunConfig) *MockGun

NewMockGun create a mock gun

func (*MockGun) Call

func (m *MockGun) Call(l *Generator) *Response

Call implements example gun call, assertions on response bodies should be done here

type MockGunConfig

type MockGunConfig struct {
	// FailRatio in percentage, 0-100
	FailRatio int
	// TimeoutRatio in percentage, 0-100
	TimeoutRatio int
	// CallSleep time spent waiting inside a call
	CallSleep time.Duration
	// InternalStop break the test immediately
	InternalStop bool
}

MockGunConfig configures a mock gun

type MockHTTPGun

type MockHTTPGun struct {
	Data []string
	// contains filtered or unexported fields
}

MockHTTPGun is a mock gun

func NewHTTPMockGun

func NewHTTPMockGun(cfg *MockHTTPGunConfig) *MockHTTPGun

NewHTTPMockGun create an HTTP mock gun

func (*MockHTTPGun) Call

func (m *MockHTTPGun) Call(l *Generator) *Response

Call implements example gun call, assertions on response bodies should be done here

type MockHTTPGunConfig

type MockHTTPGunConfig struct {
	TargetURL string
}

MockHTTPGunConfig configures a mock HTTP gun

type MockVirtualUser

type MockVirtualUser struct {
	*VUControl

	Data []string
	// contains filtered or unexported fields
}

MockVirtualUser is a mock virtual user

func NewMockVU

func NewMockVU(cfg *MockVirtualUserConfig) *MockVirtualUser

NewMockVU create a mock virtual user

func (*MockVirtualUser) Call

func (m *MockVirtualUser) Call(l *Generator)

func (*MockVirtualUser) Clone

func (m *MockVirtualUser) Clone(_ *Generator) VirtualUser

func (*MockVirtualUser) Setup

func (m *MockVirtualUser) Setup(_ *Generator) error

func (*MockVirtualUser) Teardown

func (m *MockVirtualUser) Teardown(_ *Generator) error

type MockVirtualUserConfig

type MockVirtualUserConfig struct {
	// FailRatio in percentage, 0-100
	FailRatio int
	// TimeoutRatio in percentage, 0-100
	TimeoutRatio int
	// CallSleep time spent waiting inside a call
	CallSleep       time.Duration
	SetupSleep      time.Duration
	SetupFailure    bool
	TeardownSleep   time.Duration
	TeardownFailure bool
}

MockVirtualUserConfig configures a mock virtual user

type MockWSServer

type MockWSServer struct {
	// Logf controls where logs are sent.
	Logf  func(f string, v ...interface{})
	Sleep time.Duration
}

func (MockWSServer) ServeHTTP

func (s MockWSServer) ServeHTTP(w http.ResponseWriter, r *http.Request)

type Profile

type Profile struct {
	ProfileID  string // Unique identifier for the profile
	Generators []*Generator
	// contains filtered or unexported fields
}

Profile is a set of concurrent generators forming some workload profile

func NewProfile

func NewProfile() *Profile

NewProfile creates new VU or Gun profile from parts

func (*Profile) Add

func (m *Profile) Add(g *Generator, err error) *Profile

func (*Profile) Pause

func (m *Profile) Pause()

Pause pauses execution of all generators

func (*Profile) Resume

func (m *Profile) Resume()

Resume resumes execution of all generators

func (*Profile) Run

func (m *Profile) Run(wait bool) (*Profile, error)

Run runs all generators and wait until they finish

func (*Profile) Wait

func (m *Profile) Wait()

Wait waits until all generators have finished the workload

func (*Profile) WithGrafana

func (m *Profile) WithGrafana(opts *GrafanaOpts) *Profile

type Response

type Response struct {
	Failed     bool          `json:"failed,omitempty"`
	Timeout    bool          `json:"timeout,omitempty"`
	StatusCode string        `json:"status_code,omitempty"`
	Path       string        `json:"path,omitempty"`
	Duration   time.Duration `json:"duration"`
	StartedAt  *time.Time    `json:"started_at,omitempty"`
	FinishedAt *time.Time    `json:"finished_at,omitempty"`
	Group      string        `json:"group"`
	Data       interface{}   `json:"data,omitempty"`
	Error      string        `json:"error,omitempty"`
}

Response represents basic result info

type ResponseData

type ResponseData struct {
	OKData *SliceBuffer[any]

	OKResponses *SliceBuffer[*Response]

	FailResponses *SliceBuffer[*Response]
	// contains filtered or unexported fields
}

ResponseData includes any request/response data that a gun might store ok* slices usually contains successful responses and their verifications if their done async fail* slices contains CallResult with response data and an error

type Responses

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

func NewResponses

func NewResponses(ch chan *Response) *Responses

func (*Responses) Err

func (m *Responses) Err(r *resty.Response, group string, err error)

func (*Responses) OK

func (m *Responses) OK(r *resty.Response, group string)

type Sampler

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

Sampler is a CallResult filter that stores a percentage of successful call results errored and timed out results are always stored

func NewSampler

func NewSampler(cfg *SamplerConfig) *Sampler

NewSampler creates new Sampler

func (*Sampler) ShouldRecord

func (m *Sampler) ShouldRecord(cr *Response, s *Stats) bool

ShouldRecord return true if we should save CallResult

type SamplerConfig

type SamplerConfig struct {
	SuccessfulCallResultRecordRatio int
}

type ScheduleType

type ScheduleType string
const (
	RPS ScheduleType = "rps_schedule"
	VU  ScheduleType = "vu_schedule"
)

type Segment

type Segment struct {
	From     int64
	Duration time.Duration
}

Segment load test schedule segment

func Combine

func Combine(segs ...[]*Segment) []*Segment

Combine combines profile segments

func CombineAndRepeat

func CombineAndRepeat(times int, segs ...[]*Segment) []*Segment

CombineAndRepeat combines and repeats profile segments

func Plain

func Plain(from int64, duration time.Duration) []*Segment

Plain create a constant workload Segment

func Steps

func Steps(from, increase int64, steps int, duration time.Duration) []*Segment

Steps creates a series of increasing/decreasing Segments

func (*Segment) Validate

func (ls *Segment) Validate() error

type SliceBuffer

type SliceBuffer[T any] struct {
	Idx      int
	Capacity int
	Data     []T
}

SliceBuffer keeps Capacity of type T, after len => cap overrides old data

func NewSliceBuffer

func NewSliceBuffer[T any](cap int) *SliceBuffer[T]

NewSliceBuffer creates new limited capacity slice

func (*SliceBuffer[T]) Append

func (m *SliceBuffer[T]) Append(s T)

Append appends T if len <= cap, overrides old data otherwise

type Stats

type Stats struct {
	// TODO: update json labels with dashboards on major release
	CurrentRPS      atomic.Int64 `json:"currentRPS"`
	CurrentTimeUnit int64        `json:"current_time_unit"`
	CurrentVUs      atomic.Int64 `json:"currentVUs"`
	LastSegment     atomic.Int64 `json:"last_segment"`
	CurrentSegment  atomic.Int64 `json:"current_schedule_segment"`
	SamplesRecorded atomic.Int64 `json:"samples_recorded"`
	SamplesSkipped  atomic.Int64 `json:"samples_skipped"`
	RunPaused       atomic.Bool  `json:"runPaused"`
	RunStopped      atomic.Bool  `json:"runStopped"`
	RunFailed       atomic.Bool  `json:"runFailed"`
	Success         atomic.Int64 `json:"success"`
	Failed          atomic.Int64 `json:"failed"`
	CallTimeout     atomic.Int64 `json:"callTimeout"`
	Duration        int64        `json:"load_duration"`
}

Stats basic generator load stats

type VUControl

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

VUControl is a base VU that allows us to control the schedule and bring VUs up and down

func NewVUControl

func NewVUControl() *VUControl

NewVUControl creates new base VU that allows us to control the schedule and bring VUs up and down

func (*VUControl) Stop

func (m *VUControl) Stop(_ *Generator)

Stop stops virtual user execution

func (*VUControl) StopChan

func (m *VUControl) StopChan() chan struct{}

StopChan returns stop chan

type VirtualUser

type VirtualUser interface {
	Call(l *Generator)
	Clone(l *Generator) VirtualUser
	Setup(l *Generator) error
	Teardown(l *Generator) error
	Stop(l *Generator)
	StopChan() chan struct{}
}

VirtualUser is basic interface to run virtual users load you should use it if: - your protocol is stateful, ex.: ws, grpc - you'd like to have some VirtualUser modelling, perform sequential requests

type WSMockVU

type WSMockVU struct {
	*VUControl

	Data []string
	// contains filtered or unexported fields
}

WSMockVU ws mock virtual user

func NewWSMockVU

func NewWSMockVU(cfg *WSMockVUConfig) *WSMockVU

NewWSMockVU create a ws mock virtual user

func (*WSMockVU) Call

func (m *WSMockVU) Call(l *Generator)

Call create a virtual user firing read requests against mock ws server

func (*WSMockVU) Clone

func (m *WSMockVU) Clone(_ *Generator) VirtualUser

func (*WSMockVU) Setup

func (m *WSMockVU) Setup(l *Generator) error

func (*WSMockVU) Teardown

func (m *WSMockVU) Teardown(_ *Generator) error

type WSMockVUConfig

type WSMockVUConfig struct {
	TargetURl string
}

WSMockVUConfig ws mock config

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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