loadgen

package
v1.10.4 Latest Latest
Warning

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

Go to latest
Published: Feb 24, 2023 License: MIT Imports: 12 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

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

Variables

View Source
var (
	ErrNoCfg        = errors.New("config is nil")
	ErrNoImpl       = errors.New("either \"gun\" or \"instance\" implementation must provided")
	ErrCallTimeout  = errors.New("generator request call timeout")
	ErrStartFrom    = errors.New("StartFrom must be > 0")
	ErrScheduleType = errors.New("schedule type must be \"rps_schedule\" or \"instance_schedule\"")
)

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 GeneratorStats

type GeneratorStats struct {
	CurrentRPS       atomic.Int64 `json:"currentRPS"`
	CurrentInstances atomic.Int64 `json:"currentInstances"`
	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"`
}

GeneratorStats basic generator load stats

type Gun

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

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

type Instance

type Instance interface {
	Run(l *LoadGenerator)
}

Instance is basic interface to run load instances

type LoadGenerator

type LoadGenerator struct {
	ResponsesCtx context.Context
	// contains filtered or unexported fields
}

LoadGenerator generates load with some RPS

func NewLoadGenerator

func NewLoadGenerator(cfg *LoadGeneratorConfig) (*LoadGenerator, error)

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

func (*LoadGenerator) Errors

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

Errors get all calls errors

func (*LoadGenerator) GetData

func (l *LoadGenerator) GetData() *ResponseData

GetData get all calls data

func (*LoadGenerator) Run

func (l *LoadGenerator) Run()

Run runs load loop until timeout or stop

func (*LoadGenerator) Stats

func (l *LoadGenerator) Stats() *GeneratorStats

Stats get all load stats

func (*LoadGenerator) StatsJSON

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

StatsJSON get all load stats for export

func (*LoadGenerator) Stop

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

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

func (*LoadGenerator) Wait

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

Wait waits until test ends

type LoadGeneratorConfig

type LoadGeneratorConfig struct {
	T                 *testing.T
	Labels            map[string]string
	LokiConfig        *client.LokiConfig
	Schedule          *LoadSchedule
	Duration          time.Duration
	StatsPollInterval time.Duration
	CallTimeout       time.Duration
	Gun               Gun
	Instance          Instance
	Logger            zerolog.Logger
	SharedData        interface{}
}

LoadGeneratorConfig is for shared load test data and configuration

func (*LoadGeneratorConfig) Validate

func (lgc *LoadGeneratorConfig) Validate() error

type LoadSchedule

type LoadSchedule struct {
	Type          string
	StartFrom     int64
	Increase      int64
	StageInterval time.Duration
	Limit         int64
}

LoadSchedule load test schedule

func (*LoadSchedule) Validate

func (ls *LoadSchedule) Validate() error

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

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 MockInstance

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

MockInstance is a mock instance

func NewMockInstance

func NewMockInstance(cfg *MockInstanceConfig) *MockInstance

NewMockInstance create a mock instance

func (*MockInstance) Run

func (m *MockInstance) Run(l *LoadGenerator)

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 instance

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

Jump to

Keyboard shortcuts

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