loadgen

package
v1.10.9 Latest Latest
Warning

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

Go to latest
Published: Mar 14, 2023 License: MIT Imports: 18 Imported by: 0

README

Loadgen

A simple protocol agnostic load tool for Go code

Motivation

We are using a lot of custom protocols and blockchain interactions in our tests

A lot of wide-used tools like ddosify k6 JMeter Locust can't cover our cases or using them going to create additional efforts

They contain a lot of functionality that we don't need:

  • Extensive HTTP testing
  • JSON/UI configuration
  • Complicated load scheduling code
  • Vendor locked clusterization and scaling solutions

They can't allow us to:

  • Reuse our Go code for custom protocols and blockchains
  • Reuse our test setup logic and chaos experiments
  • Unify all testing/setup logic in Go

So we've implemented a simple tool with goals in mind:

  • Reuse our Go code, write consistent setup/test scripts
  • Have slim codebase (500-1k loc)
  • Be able to perform synthetic load testing for request-based protocols in Go with RPS bound load (http, tcp, etc.)
  • Be able to perform synthetic load testing for streaming protocols in Go with Instances bound load (ws, wsrpc, etc.)
  • Be scalable in k8s without complicated configuration or vendored UI interfaces
  • Be non-opinionated about reporting, be able to push any arbitrary data to Loki without sacrificing performance

How to use

Docs is TBD for the time being, check test implementations

Dashboard is private, you can find it in K8s tests -> Loadgen

  • examples for full-fledged generator tests with Loki, you can also use them to validate performance of loadgen

  • implementation of an RPS type gun

  • implementation of an Instance type gun

Debug & Profile

Start pyroscope

docker compose up

Run TestLocalTrace from examples with or without Loki

Documentation

Index

Constants

View Source
const (
	DefaultCallTimeout       = 1 * time.Minute
	DefaultStatsPollInterval = 5 * time.Second
	UntilStopDuration        = 99999 * time.Hour
)
View Source
const (
	RPSScheduleType       string = "rps_schedule"
	InstancesScheduleType string = "instance_schedule"
)
View Source
const (
	// DefaultStepChangePrecision is default amount of steps in which we split a schedule
	DefaultStepChangePrecision = 10
)

Variables

View Source
var (
	ErrNoCfg             = errors.New("config is nil")
	ErrNoImpl            = errors.New("either \"gun\" or \"instanceTemplate\" implementation must provided")
	ErrNoSched           = errors.New("no schedule segments were provided")
	ErrWrongScheduleType = errors.New("schedule type must be RPSScheduleType or InstancesScheduleType, use package constants")
	ErrCallTimeout       = errors.New("generator request call timeout")
	ErrStartFrom         = errors.New("from must be > 0")
	ErrInvalidSteps      = errors.New("both \"Steps\" and \"StepsDuration\" must be defined in a schedule segment")
	ErrNoGun             = errors.New("rps load scheduleSegments selected but gun implementation is nil")
	ErrNoInstance        = errors.New("instanceTemplate load scheduleSegments selected but instanceTemplate implementation is nil")
)

Functions

This section is empty.

Types

type CallResult

type CallResult struct {
	Failed     bool          `json:"failed,omitempty"`
	Timeout    bool          `json:"timeout,omitempty"`
	Duration   time.Duration `json:"duration"`
	StartedAt  *time.Time    `json:"started_at,omitempty"`
	FinishedAt *time.Time    `json:"finished_at,omitempty"`
	Data       interface{}   `json:"data,omitempty"`
	Error      string        `json:"error,omitempty"`
}

CallResult represents basic call result info

type Config added in v1.10.9

type Config struct {
	T          *testing.T
	LoadType   string
	Labels     map[string]string
	LokiConfig *client.LokiConfig
	Schedule   []*Segment

	StatsPollInterval time.Duration
	CallTimeout       time.Duration
	Gun               Gun
	Instance          Instance
	Logger            zerolog.Logger
	SharedData        interface{}
	// contains filtered or unexported fields
}

Config is for shared load test data and configuration

func (*Config) Validate added in v1.10.9

func (lgc *Config) Validate() error

type Generator added in v1.10.5

type Generator struct {
	Log zerolog.Logger

	ResponsesWaitGroup *sync.WaitGroup

	ResponsesCtx context.Context

	ResponsesChan chan CallResult
	// contains filtered or unexported fields
}

Generator generates load with some RPS

func NewLoadGenerator

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

NewLoadGenerator creates a new instanceTemplate for a contract, shoots for scheduled RPS until timeout, test logic is defined through Gun

func (*Generator) Errors added in v1.10.5

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

Errors get all calls errors

func (*Generator) GetData added in v1.10.5

func (l *Generator) GetData() *ResponseData

GetData get all calls data

func (*Generator) InputSharedData added in v1.10.8

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

InputSharedData returns the SharedData passed in Generator config

func (*Generator) Run added in v1.10.5

func (l *Generator) Run()

Run runs load loop until timeout or stop

func (*Generator) Stats added in v1.10.5

func (l *Generator) Stats() *Stats

Stats get all load stats

func (*Generator) StatsJSON added in v1.10.5

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

StatsJSON get all load stats for export

func (*Generator) Stop added in v1.10.5

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

Stop stops load generator, waiting for all calls for either finish or timeout

func (*Generator) Wait added in v1.10.5

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

Wait waits until test ends

type Gun

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

Gun is basic interface to run limited load with a contract call and save all transactions

type HTTPMockServer added in v1.10.8

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

func NewHTTPMockServer added in v1.10.8

func NewHTTPMockServer(sleep time.Duration) *HTTPMockServer

func (*HTTPMockServer) Run added in v1.10.8

func (s *HTTPMockServer) Run()

type Instance

type Instance interface {
	Run(l *Generator)
	Stop(l *Generator)
	Clone(l *Generator) Instance
}

Instance is basic interface to run load instances

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) CallResult

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
}

MockGunConfig configures a mock gun

type MockHTTPGun added in v1.10.8

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

MockHTTPGun is a mock gun

func NewHTTPMockGun added in v1.10.8

func NewHTTPMockGun(cfg *MockHTTPGunConfig) *MockHTTPGun

NewHTTPMockGun create an HTTP mock gun

func (*MockHTTPGun) Call added in v1.10.8

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

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

type MockHTTPGunConfig added in v1.10.8

type MockHTTPGunConfig struct {
	TargetURL string
}

MockHTTPGunConfig configures a mock HTTP gun

type MockInstance

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

MockInstance is a mock instanceTemplate

func NewMockInstance

func NewMockInstance(cfg MockInstanceConfig) MockInstance

NewMockInstance create a mock instanceTemplate

func (MockInstance) Clone added in v1.10.9

func (m MockInstance) Clone(l *Generator) Instance

func (MockInstance) Run

func (m MockInstance) Run(l *Generator)

func (MockInstance) Stop added in v1.10.9

func (m MockInstance) Stop(l *Generator)

type MockInstanceConfig

type MockInstanceConfig 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
}

MockInstanceConfig configures a mock instanceTemplate

type MockWSServer added in v1.10.8

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

func (MockWSServer) ServeHTTP added in v1.10.8

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

type ResponseData

type ResponseData struct {
	OKData []interface{}

	OKResponses []CallResult

	FailResponses []CallResult
	// 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 Segment added in v1.10.9

type Segment struct {
	From         int64
	Increase     int64
	Steps        int64
	StepDuration time.Duration
	// contains filtered or unexported fields
}

Segment load test schedule segment

func Combine added in v1.10.9

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

func CombineAndRepeat added in v1.10.9

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

func Line added in v1.10.9

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

func Plain added in v1.10.9

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

func (*Segment) Validate added in v1.10.9

func (ls *Segment) Validate(cfg *Config) error

type Stats added in v1.10.9

type Stats struct {
	CurrentRPS       atomic.Int64 `json:"currentRPS"`
	CurrentInstances atomic.Int64 `json:"currentInstances"`
	LastSegment      atomic.Int64 `json:"last_segment"`
	CurrentSegment   atomic.Int64 `json:"current_schedule_segment"`
	CurrentStep      atomic.Int64 `json:"current_schedule_step"`
	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"`
}

Stats basic generator load stats

type WSMockConfig added in v1.10.8

type WSMockConfig struct {
	TargetURl string
}

WSMockConfig ws mock config

type WSMockInstance added in v1.10.8

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

WSMockInstance ws mock mock

func NewWSMockInstance added in v1.10.8

func NewWSMockInstance(cfg WSMockConfig) WSMockInstance

NewWSMockInstance create a ws mock instanceTemplate

func (WSMockInstance) Clone added in v1.10.9

func (m WSMockInstance) Clone(l *Generator) Instance

func (WSMockInstance) Run added in v1.10.8

func (m WSMockInstance) Run(l *Generator)

Run create an instanceTemplate firing read requests against mock ws server

func (WSMockInstance) Stop added in v1.10.9

func (m WSMockInstance) Stop(l *Generator)

Jump to

Keyboard shortcuts

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