Documentation ¶
Index ¶
- Constants
- Variables
- func CheckDashboardAlerts(grafanaClient *grafana.Client, from, to time.Time, dashboardUID string) ([]grafana.Annotation, error)
- func ExecCmd(command string) error
- func ExecCmdWithStreamFunc(command string, outputFunction func(string)) error
- func GetLocalK8sDeps() (*kubernetes.Clientset, *rest.Config, error)
- func GetLogger(t *testing.T, componentName string) zerolog.Logger
- func LabelsMapToModel(m map[string]string) model.LabelSet
- type AlertChecker
- type Config
- type Generator
- func (g *Generator) Errors() []string
- func (g *Generator) GetData() *ResponseData
- func (g *Generator) InputSharedData() interface{}
- func (g *Generator) Pause()
- func (g *Generator) Resume()
- func (g *Generator) Run(wait bool) (interface{}, bool)
- func (g *Generator) Stats() *Stats
- func (g *Generator) StatsJSON() map[string]interface{}
- func (g *Generator) Stop() (interface{}, bool)
- func (g *Generator) Wait() (interface{}, bool)
- type GrafanaOpts
- type Gun
- type HTTPMockServer
- type HTTPMockServerConfig
- type K8sClient
- type LokiClient
- type LokiConfig
- type LokiLogWrapper
- type MockGun
- type MockGunConfig
- type MockHTTPGun
- type MockHTTPGunConfig
- type MockVirtualUser
- type MockVirtualUserConfig
- type MockWSServer
- type Profile
- type Response
- type ResponseData
- type Responses
- type Sampler
- type SamplerConfig
- type ScheduleType
- type Segment
- type SegmentType
- type SliceBuffer
- type Stats
- type VUControl
- type VirtualUser
- type WSMockVU
- type WSMockVUConfig
Constants ¶
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" )
const (
CallGroupLabel = "call_group"
)
const (
// DefaultStepChangePrecision is default amount of steps in which we split a schedule
DefaultStepChangePrecision = 10
)
const (
K8sStatePollInterval = 1 * time.Second
)
const (
LogLevelEnvVar = "WASP_LOG_LEVEL"
)
Variables ¶
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") ErrMissingSegmentType = errors.New("Segment Type myst be set") 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 _") )
Functions ¶
func CheckDashboardAlerts ¶
func CheckDashboardAlerts(grafanaClient *grafana.Client, from, to time.Time, dashboardUID string) ([]grafana.Annotation, error)
CheckDashboardAlerts retrieves alert annotations from a Grafana dashboard within the specified time range. It returns the sorted alerts and an error if any alert is in the alerting state. Use it to verify the status of dashboard alerts after a run.
func ExecCmd ¶
ExecCmd executes the provided command string and logs its output. It returns an error if the command fails to run or exits with a non-zero status.
func ExecCmdWithStreamFunc ¶
ExecCmdWithStreamFunc runs the specified command and streams its output and error lines to the provided outputFunction. It enables real-time handling of command execution output.
func GetLocalK8sDeps ¶
func GetLocalK8sDeps() (*kubernetes.Clientset, *rest.Config, error)
GetLocalK8sDeps retrieves the local Kubernetes Clientset and REST configuration. It is used to initialize a Kubernetes client for interacting with the cluster.
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
NewAlertChecker creates a new AlertChecker using Grafana configurations from environment variables. It retrieves GRAFANA_URL and GRAFANA_TOKEN, ensuring they are set. Use this function to set up alert checking in tests.
func (*AlertChecker) AnyAlerts ¶
func (m *AlertChecker) AnyAlerts(dashboardUUID, requirementLabelValue string) ([]grafana.AlertGroupsResponse, error)
AnyAlerts retrieves alert groups from Grafana and checks for alerts matching the specified dashboard UUID and requirement label value. It returns the matching alert groups, enabling users to identify and respond to specific alert conditions.
type Config ¶
type Config struct { T *testing.T `json:"-"` GenName string `json:"generator_name"` LoadType ScheduleType `json:"load_type"` Labels map[string]string `json:"-"` LokiConfig *LokiConfig `json:"-"` Schedule []*Segment `json:"schedule"` RateLimitUnitDuration time.Duration `json:"rate_limit_unit_duration"` CallResultBufLen int `json:"-"` StatsPollInterval time.Duration `json:"-"` CallTimeout time.Duration `json:"call_timeout"` SetupTimeout time.Duration `json:"-"` TeardownTimeout time.Duration `json:"-"` FailOnErr bool `json:"-"` Gun Gun `json:"-"` VU VirtualUser `json:"-"` Logger zerolog.Logger `json:"-"` SamplerConfig *SamplerConfig `json:"-"` // contains filtered or unexported fields }
Config is for shared load test data and configuration
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 ¶
NewGenerator initializes a Generator with the provided configuration. It validates the config, sets up contexts, logging, and labels. Use it to create a Generator for managing service schedules and data collection.
func (*Generator) Errors ¶
Errors returns a slice of error messages collected by the Generator. Use this to access all errors encountered during the generation process.
func (*Generator) GetData ¶
func (g *Generator) GetData() *ResponseData
GetData retrieves the aggregated response data from the Generator. Use it to access all collected responses after processing is complete.
func (*Generator) InputSharedData ¶
func (g *Generator) InputSharedData() interface{}
InputSharedData retrieves the shared data from the generator's configuration. It allows access to common data shared across different components or processes.
func (*Generator) Pause ¶
func (g *Generator) Pause()
Pause signals the generator to stop its operations. It is used to gracefully halt the generator when pausing activities is required.
func (*Generator) Resume ¶
func (g *Generator) Resume()
Resume resumes the Generator, allowing it to continue operations after being paused. It is typically used to restart paused Generators within a Profile or management structure.
func (*Generator) Run ¶
Run starts the Generator’s scheduling and execution workflows, managing logging and metrics. If wait is true, it waits for all processes to complete and returns the results. Use Run to execute generator tasks either synchronously or asynchronously.
func (*Generator) Stats ¶
Stats returns the current statistics of the Generator. It allows callers to access and monitor the generator's state.
func (*Generator) StatsJSON ¶
StatsJSON returns the generator's current statistics as a JSON-compatible map. It is used to capture and transmit real-time metrics for monitoring and analysis.
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 ¶
Gun is basic interface for some synthetic load test implementation Call performs one request according to some RPS schedule
type HTTPMockServer ¶
func NewHTTPMockServer ¶
func NewHTTPMockServer(cfg *HTTPMockServerConfig) *HTTPMockServer
NewHTTPMockServer initializes an HTTP mock server with configurable latencies and response codes. If cfg is nil, default settings are applied. Use it to simulate HTTP endpoints for testing purposes.
func (*HTTPMockServer) Run ¶
func (s *HTTPMockServer) Run()
Run starts the HTTPMockServer in a separate goroutine. It enables the server to handle incoming HTTP requests concurrently.
func (*HTTPMockServer) URL ¶
func (s *HTTPMockServer) URL() string
URL returns the base URL of the HTTPMockServer. Use it to configure clients to send requests to the mock server during testing.
type HTTPMockServerConfig ¶
type K8sClient ¶
type K8sClient struct { ClientSet *kubernetes.Clientset RESTConfig *rest.Config }
K8sClient high level k8s client
func NewK8sClient ¶
func NewK8sClient() *K8sClient
NewK8sClient initializes and returns a new K8sClient for interacting with the local Kubernetes cluster. It is used to perform operations such as synchronizing groups and managing cluster profiles.
func (*K8sClient) TrackJobs ¶
func (m *K8sClient) TrackJobs(ctx context.Context, nsName, syncLabel string, jobNum int, keepJobs bool) error
TrackJobs monitors Kubernetes jobs in the specified namespace and label selector until the desired number succeed or a failure occurs. It optionally removes jobs upon completion based on the keepJobs flag.
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 initializes a new LokiClient with the given LokiConfig. It validates the configuration, sets up authentication, and prepares the client for interacting with Loki for logging purposes.
func (*LokiClient) Handle ¶
Handle sends a log entry with the given labels, timestamp, and message to the Loki service. It checks error thresholds and returns an error if sending fails or limits are exceeded.
func (*LokiClient) HandleStruct ¶
HandleStruct marshals the provided struct to JSON and sends it to Loki with the specified labels and timestamp. Use this function to log structured data in a decentralized logging system.
func (*LokiClient) StopNow ¶
func (m *LokiClient) StopNow()
StopNow gracefully terminates the Loki client, ensuring all active streams are closed and resources are released. Use this function to stop Loki when shutting down services or when Loki is no longer needed.
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 returns a LokiConfig initialized with default parameters. It serves as a base configuration for Loki clients, allowing users to customize settings as needed.
func NewEnvLokiConfig ¶
func NewEnvLokiConfig() *LokiConfig
NewEnvLokiConfig creates a LokiConfig populated with settings from environment variables.
func NewLokiConfig ¶
func NewLokiConfig(endpoint *string, tenant *string, basicAuth *string, token *string) *LokiConfig
NewLokiConfig initializes a LokiConfig with the provided endpoint, tenant, basicAuth, and token. Use it to customize connection settings for the Loki logging service.
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
NewLokiLogWrapper initializes a LokiLogWrapper with the specified maximum number of errors. It is used to track and limit error occurrences within the LokiClient.
func (*LokiLogWrapper) Log ¶
func (m *LokiLogWrapper) Log(kvars ...interface{}) error
Log processes and forwards log entries to Loki, handling malformed messages and recording errors. It ensures error limits are respected and logs at appropriate levels for monitoring purposes.
func (*LokiLogWrapper) SetClient ¶
func (m *LokiLogWrapper) SetClient(c *LokiClient)
SetClient assigns a LokiClient to the LokiLogWrapper. Use it to link the log wrapper with a specific Loki client instance for managing log operations.
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 creates a new MockGun instance using the provided configuration. It is used to simulate gun behavior for testing or development purposes.
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 initializes a MockHTTPGun with the given configuration. It sets up the HTTP client and data storage, enabling simulated HTTP interactions for testing.
func (*MockHTTPGun) Call ¶
func (m *MockHTTPGun) Call(l *Generator) *Response
Call sends an HTTP GET request to the configured target URL and returns the response data. It is used to simulate HTTP calls for testing or load generation purposes.
type MockHTTPGunConfig ¶
type MockHTTPGunConfig struct {
TargetURL string
}
MockHTTPGunConfig configures a mock HTTP gun
type MockVirtualUser ¶
MockVirtualUser is a mock virtual user
func NewMockVU ¶
func NewMockVU(cfg *MockVirtualUserConfig) *MockVirtualUser
NewMockVU creates a new MockVirtualUser with the provided configuration. It initializes control structures and prepares data storage. Use this function to simulate virtual users for testing decentralized services.
func (*MockVirtualUser) Call ¶
func (m *MockVirtualUser) Call(l *Generator)
Call simulates a virtual user's call to the Generator. It sends a Response to the Generator's ResponsesChan, which may indicate success, failure, or timeout based on the mock configuration.
func (*MockVirtualUser) Clone ¶
func (m *MockVirtualUser) Clone(_ *Generator) VirtualUser
Clone returns a copy of the MockVirtualUser with a new VUControl and duplicated configuration. It is used to create independent virtual user instances for load testing.
func (*MockVirtualUser) Setup ¶
func (m *MockVirtualUser) Setup(_ *Generator) error
Setup initializes the VirtualUser using the provided Generator. It prepares necessary resources and returns an error if the setup process fails.
func (*MockVirtualUser) Teardown ¶
func (m *MockVirtualUser) Teardown(_ *Generator) error
Teardown cleans up the VirtualUser by releasing resources and performing necessary shutdown procedures. It returns an error if the teardown process fails, allowing callers to handle cleanup failures appropriately.
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)
ServeHTTP upgrades the HTTP connection to a WebSocket and continuously sends predefined responses. It is used to mock WebSocket server behavior for testing purposes.
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 and returns a new Profile instance. It initializes the ProfileID with a unique identifier, an empty slice of Generators, and a WaitGroup for synchronization. Use it to instantiate profiles with default settings.
func (*Profile) Add ¶
Add appends a Generator to the Profile. If an error is provided, it records the bootstrap error and does not add the Generator.
func (*Profile) Pause ¶
func (m *Profile) Pause()
Pause suspends all generators within the profile. It is used to temporarily halt all generator operations managed by the profile.
func (*Profile) Resume ¶
func (m *Profile) Resume()
Resume resumes all generators associated with the profile, allowing them to continue their operations.
func (*Profile) Run ¶
Run executes the profile's generators, manages Grafana annotations, and handles alert checks. If wait is true, it waits for all generators to complete before proceeding. It returns the updated Profile and any encountered error.
func (*Profile) Wait ¶
func (m *Profile) Wait()
Wait blocks until all generators associated with the Profile have finished executing, ensuring all operations are complete before proceeding.
func (*Profile) WithGrafana ¶
func (m *Profile) WithGrafana(opts *GrafanaOpts) *Profile
WithGrafana configures the Profile with Grafana settings. It initializes the Grafana client using the provided options and returns the updated Profile instance.
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 ¶
NewResponses creates a Responses instance using the provided channel. It enables concurrent processing and management of Response objects.
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 a Sampler using the provided SamplerConfig. If cfg is nil, a default configuration is applied. Use this to initialize sampling behavior for tracking successful call results.
func (*Sampler) ShouldRecord ¶
ShouldRecord determines whether a Response should be recorded based on its status and the sampler's configuration. It updates the provided Stats with the decision. Returns true to record the response or false to skip it.
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 `json:"from"` Duration time.Duration `json:"duration"` Type SegmentType `json:"type"` StartTime time.Time `json:"time_start"` EndTime time.Time `json:"time_end"` }
Segment load test schedule segment
func Combine ¶
Combine merges multiple slices of Segment pointers into a single slice. It is useful for aggregating segment data from various sources.
func CombineAndRepeat ¶
CombineAndRepeat concatenates multiple Segment slices and repeats the combined sequence the specified number of times. It returns a single slice containing the repeated segments. Panics with ErrNoSchedule if no segments are provided.
func Plain ¶
Plain creates a slice containing a single Segment starting at `from` with the specified `duration`. It is used to initialize basic segments with defined timing.
func Steps ¶
Steps generates a slice of Segment pointers starting from 'from', incremented by 'increase' for each of 'steps' steps. Each Segment has a duration equal to the total duration divided by the number of steps. Use this function to create uniformly distributed segments over a specified time period.
type SegmentType ¶ added in v1.50.4
type SegmentType string
const ( SegmentType_Plain SegmentType = "plain" SegmentType_Steps SegmentType = "steps" )
type SliceBuffer ¶
SliceBuffer keeps Capacity of type T, after len => cap overrides old data
func NewSliceBuffer ¶
func NewSliceBuffer[T any](cap int) *SliceBuffer[T]
NewSliceBuffer creates a new SliceBuffer with the specified capacity. It provides an efficient way to store and manage a fixed number of elements, enabling optimized access and manipulation in concurrent and decentralized applications.
func (*SliceBuffer[T]) Append ¶
func (m *SliceBuffer[T]) Append(s T)
Append adds an element to the SliceBuffer. When the buffer reaches its capacity, it overwrites the oldest item. This function is useful for maintaining a fixed-size, circular collection of elements.
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 a new VUControl instance used to manage the lifecycle and control of a virtual user.
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 ¶
WSMockVU ws mock virtual user
func NewWSMockVU ¶
func NewWSMockVU(cfg *WSMockVUConfig) *WSMockVU
NewWSMockVU initializes a WSMockVU with the provided configuration. It sets up control mechanisms and data storage, enabling the simulation of a WebSocket virtual user for testing scenarios.
func (*WSMockVU) Call ¶
Call reads a WebSocket message from the connection and sends the response with a timestamp to the generator's ResponsesChan. It is used by a virtual user to handle incoming WebSocket data during execution.
func (*WSMockVU) Clone ¶
func (m *WSMockVU) Clone(_ *Generator) VirtualUser
Clone creates a new VirtualUser instance based on the current WSMockVU. It is used to instantiate additional virtual users for scaling load tests.