Categorygithub.com/smartcontractkit/chainlink-testing-framework/wasp

# 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/smartcontractkit/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
}

# Packages

No description provided by the author

# Functions

CheckDashobardAlerts checks for alerts in the given dashboardUUIDs between from and to times.
Combine combines profile segments.
CombineAndRepeat combines and repeats profile segments.
CPUCheckLoop is called once by any generator, makes sense only in cluster runs on Linux.
DefaultLokiConfig is reasonable common settings for Loki batches.
ExecCmd executes os command, logging both streams.
ExecCmdWithStreamFunc executes command with stream function.
GetLocalK8sDeps get local k8s context config.
GetLogger instantiates a logger that takes into account the test context and the log level.
LabelsMapToModel create model.LabelSet from map of labels.
No description provided by the author
NewClusterProfile creates new cluster profile.
NewEnvLokiConfig creates new config from connection params as env vars.
NewGenerator creates a new generator, shoots for scheduled RPS until timeout, test logic is defined through Gun or VirtualUser.
NewHTTPMockGun create an HTTP mock gun.
No description provided by the author
NewK8sClient creates a new k8s client with a REST config.
NewLokiClient creates a new Promtail client.
NewLokiConfig this is used when you have marshalled data from CTF.
No description provided by the author
NewMockGun create a mock gun.
NewMockVU create a mock virtual user.
NewProfile creates new VU or Gun profile from parts.
No description provided by the author
NewSampler creates new Sampler.
NewSliceBuffer creates new limited capacity slice.
NewVUControl creates new base VU that allows us to control the schedule and bring VUs up and down.
NewWSMockVU create a ws mock virtual user.
Plain create a constant workload Segment.
Steps creates a series of increasing/decreasing Segments.

# Constants

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
k8s pods resources.
k8s pods resources.
No description provided by the author
k8s pods resources.
k8s pods resources.
No description provided by the author
No description provided by the author
DefaultStepChangePrecision is default amount of steps in which we split a schedule.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author

# Variables

CPUIdleThresholdPercentage is default CPU idle threshold.
TODO: remove the whole stuff in favor of remote-runner.
go:embed DockerfileWasp.
go:embed DockerfileWasp.dockerignore.
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
MEMFreeThresholdPercentage is default MEM free threshold.
No description provided by the author

# Structs

AlertChecker is checking alerts according to dashboardUUID and requirements labels.
ClusterConfig defines k8s jobs settings.
ClusterProfile is a k8s cluster test for some workload profile.
Config is for shared load test data and configuration.
Generator generates load with some RPS.
No description provided by the author
No description provided by the author
No description provided by the author
K8sClient high level k8s client.
LokiClient is a Loki/Promtail client wrapper.
LokiConfig is simplified subset of a Promtail client configuration.
LokiLogWrapper wraps Loki errors received through logs, handles them.
MockGun is a mock gun.
MockGunConfig configures a mock gun.
MockHTTPGun is a mock gun.
MockHTTPGunConfig configures a mock HTTP gun.
MockVirtualUser is a mock virtual user.
MockVirtualUserConfig configures a mock virtual user.
No description provided by the author
Profile is a set of concurrent generators forming some workload profile.
Response represents basic result info.
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.
No description provided by the author
Sampler is a CallResult filter that stores a percentage of successful call results errored and timed out results are always stored.
No description provided by the author
Segment load test schedule segment.
SliceBuffer keeps Capacity of type T, after len => cap overrides old data.
Stats basic generator load stats.
VUControl is a base VU that allows us to control the schedule and bring VUs up and down.
WSMockVU ws mock virtual user.
WSMockVUConfig ws mock config.

# Interfaces

Gun is basic interface for some synthetic load test implementation Call performs one request according to some RPS schedule.
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 aliases

No description provided by the author