WASP - Using Profiles
In this section, we’ll explore the most complex scenario: using a VirtualUser
to represent a user and a Gun
to generate background load. We’ll also introduce a new load segment type that varies over time.
To bind together different Generators
(such as a Gun
or a VirtualUser
), we’ll use a Profile
. Think of it as the highest-level abstraction that fully describes the load profile.
Gun
and VirtualUser
We’ll skip defining both the Gun
and the VirtualUser
, as they are nearly identical to previous examples. However, for the VirtualUser
, we’ll use a handy wrapper for sending Response
back to the channel. See if you can spot it:
// represents user login
func (m *VirtualUser) requestOne(l *wasp.Generator) {
var result map[string]interface{}
r, err := m.client.R().
SetResult(&result).
Get(m.target)
if err != nil {
l.Responses.Err(r, GroupAuth, err)
return
}
l.Responses.OK(r, GroupAuth)
}
note
You might have noticed GroupAuth
constant passed to OK()
and Err()
methods. This is used to group responses in the dashboard.
You can read more about it here.
Background Load Schedule for the Gun
For the RPS Gun
, we’ll define a schedule where:
- During the first 10 seconds, the RPS increases by 2.5 every second.
- For the next 40 seconds, it remains steady at 5 RPS.
epsilonSchedule := wasp.Combine(
// wasp.Steps(from, increase, steps, duration)
wasp.Steps(1, 1, 4, 10*time.Second), // Start at 1 RPS, increment by 1 RPS in 4 steps over 10 seconds (1 increment every 2.5 seconds)
// wasp.Plain(count, duration)
wasp.Plain(5, 40*time.Second)) // Hold 5 RPS for 40 seconds
Virtual User Schedule
For the VirtualUser
, the schedule will:
- Start with 1 user for the first 10 seconds.
- Add 1 user every 3 seconds for 30 seconds.
- Gradually reduce from 10 users to 0 over 10 seconds.
thetaSchedule := wasp.Combine(
// wasp.Plain(count, duration)
wasp.Plain(1, 10*time.Second), // 1 user for the first 10 seconds
// wasp.Steps(from, increase, steps, duration)
wasp.Steps(1, 1, 9, 30*time.Second), // Increment by 1 user every ~3 seconds over 30 seconds
// wasp.Steps(from, increase, steps, duration)
wasp.Steps(10, -1, 10, 10*time.Second)) // Decrement by 1 user every second over 10 seconds
Defining the Profile
We’ll now define our Profile
to combine both the Gun
and the VirtualUser
:
_, err := wasp.NewProfile().
Add(wasp.NewGenerator(&wasp.Config{
T: t,
LoadType: wasp.VU,
GenName: "Theta",
Schedule: thetaSchedule,
VU: NewExampleScenario(srv.URL()),
LokiConfig: wasp.NewEnvLokiConfig(),
})).
Add(wasp.NewGenerator(&wasp.Config{
T: t,
LoadType: wasp.RPS,
GenName: "Epsilon",
Schedule: epsilonSchedule,
Gun: NewExampleHTTPGun(srv.URL()),
LokiConfig: wasp.NewEnvLokiConfig(),
})).
Run(true)
Conclusion
And that’s it! You’ve created a complex load profile that simulates a growing number of users alongside a background load that varies over time. Notice the .Run(true)
method, which blocks until all the Profile
's generators have finished.
You can find the full example here.
note
The error
returned by the .Run(true)
function of a Profile
might indicate the following:
- load generator did not start and instead returned an error
- or if
Profile
was created withWithGrafana
option that enabledCheckDashboardAlertsAfterRun
that at some alerts fired. To check for errors during load generation, you need to call theErrors()
method on eachGenerator
within theProfile
.
note
Currently, it’s not possible to have a "waiting" schedule that doesn’t generate any load.
To implement such logic, start one Profile
in a goroutine and use time.Sleep
before starting the second Profile
or start use a combination .Run(false)
and .Wait()
methods.
Both examples of can be found here.
What’s Next?
Now that you know how to generate load, it’s time to learn how to monitor and assert on it. Let’s move on to the next section: Testing Alerts.