Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Simple Example

The examples/simple.rs example copies the simple load test documented on the locust.io web page, rewritten in Rust for Goose. It shows how to GET and POST pages, with one scenario.

The dashboard's KPI row and its requests and failures per second chart: Users reads 1,024 of 1,024, RPS reads 108, and the Fail % tile, cut at the image's right edge, reads 0.00%; the chart rises to about 200 requests a second during the 16 second ramp, falls back, and holds near 100 with no failures

cargo run --release --features dashboard --example simple -- --host http://127.0.0.1:8080 -u 1024 -r 64 -t 3m --no-reset-metrics --dashboard -q, against a local nginx server that answers POST /login, / and /about/ with 200, 120 seconds in.

Each user logs in once with POST /login, then loads / and /about/ in turn, pausing 5 to 15 seconds after each of those two but not after the login. During the ramp each new user sends its login and its first page before its first pause, which is why the chart starts near 128 a second (64 new users a second, each sending two requests). From about 5 seconds in, the first users come back from their pauses and add to that, so it climbs to about 200 until all 1,024 users have started, then drops when the new users stop. After that the pause holds 1,024 users to about 100 requests a second.

A separate run measured Goose itself: -u 1024 -r 64 -t 120s --no-telnet -q, without the dashboard or the telnet Controller, against the same server on an Apple M5 Max. While all 1,024 users ran, Goose held at 77 MB of memory and used under 3% of one core. It made 12,245 requests in the 120 seconds after the last user started, and none of them failed.

With -q Goose does not print the dashboard’s address when it starts: open http://127.0.0.1:5118 while the test runs. If that tab is still open when the run ends, Goose prints the address and waits for Ctrl-C.

Complete Source Code

//! Simple Goose load test example. Duplicates the simple example on the
//! Locust project page (<https://locust.io/>).
//!
//! ## License
//!
//! Copyright 2020-2022 Jeremy Andrews
//!
//! Licensed under the Apache License, Version 2.0 (the "License");
//! you may not use this file except in compliance with the License.
//! You may obtain a copy of the License at
//!
//! <http://www.apache.org/licenses/LICENSE-2.0>
//!
//! Unless required by applicable law or agreed to in writing, software
//! distributed under the License is distributed on an "AS IS" BASIS,
//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//! See the License for the specific language governing permissions and
//! limitations under the License.

use goose::prelude::*;
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), GooseError> {
    GooseAttack::initialize()?
        // In this example, we only create a single scenario, named "WebsiteUser".
        .register_scenario(
            scenario!("WebsiteUser")
                // After each transactions runs, sleep randomly from 5 to 15 seconds.
                .set_wait_time(Duration::from_secs(5), Duration::from_secs(15))?
                // This transaction only runs one time when the user first starts.
                .register_transaction(transaction!(website_login).set_on_start())
                // These next two transactions run repeatedly as long as the load test is running.
                .register_transaction(transaction!(website_index))
                .register_transaction(transaction!(website_about)),
        )
        .execute()
        .await?;

    Ok(())
}

/// Demonstrates how to log in when a user starts. We flag this transaction as an
/// on_start transaction when registering it above. This means it only runs one time
/// per user, when the user thread first starts.
async fn website_login(user: &mut GooseUser) -> TransactionResult {
    let params = [("username", "test_user"), ("password", "")];
    let _ = user
        .post_form("/login", &params)
        .await?
        .discard_body()
        .await;

    Ok(())
}

/// A very simple transaction that simply loads the front page.
async fn website_index(user: &mut GooseUser) -> TransactionResult {
    let _ = user.get("/").await?.discard_body().await;

    Ok(())
}

/// A very simple transaction that simply loads the about page.
async fn website_about(user: &mut GooseUser) -> TransactionResult {
    let _ = user.get("/about/").await?.discard_body().await;

    Ok(())
}