goose 0.19.0

A load testing framework inspired by Locust.
Documentation
# Scheduling Scenarios And Transactions

When starting a load test, Goose assigns one [`Scenario`](https://docs.rs/goose/*/goose/goose/struct.Scenario.html) to each [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html) thread. By default, it assigns [`Scenario`](https://docs.rs/goose/*/goose/goose/struct.Scenario.html) (and then [`Transaction`](https://docs.rs/goose/*/goose/goose/struct.Transaction.html) within the scenario) in a round robin order. As new [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html) threads are launched, the first will be assigned the first defined [`Scenario`](https://docs.rs/goose/*/goose/goose/struct.Scenario.html), the next will be assigned the next defined [`Scenario`](https://docs.rs/goose/*/goose/goose/struct.Scenario.html), and so on, looping through all available [`Scenario`](https://docs.rs/goose/*/goose/goose/struct.Scenario.html). Weighting is respected during this process, so if one [`Scenario`](https://docs.rs/goose/*/goose/goose/struct.Scenario.html) is weighted heavier than others, that [`Scenario`](https://docs.rs/goose/*/goose/goose/struct.Scenario.html) will get assigned to [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html) more at the end of the launching process.

The [`GooseScheduler`](https://docs.rs/goose/*/goose/enum.GooseScheduler.html) can be configured to instead launch [`Scenario`](https://docs.rs/goose/*/goose/goose/struct.Scenario.html) and [`Transaction`](https://docs.rs/goose/*/goose/goose/struct.Transaction.html) in a [`Serial`](https://docs.rs/goose/*/goose/enum.GooseScheduler.html#variant.Serial) or a [`Random order`](https://docs.rs/goose/*/goose/enum.GooseScheduler.html#variant.Random). When configured to allocate in a [`Serial`](https://docs.rs/goose/*/goose/enum.GooseScheduler.html#variant.Serial) order, [`Scenario`](https://docs.rs/goose/*/goose/goose/struct.Scenario.html) and [`Transaction`](https://docs.rs/goose/*/goose/goose/struct.Transaction.html) are launched in the exact order they are defined in the load test (see below for more detail on how this works). When configured to allocate in a [`Random`](https://docs.rs/goose/*/goose/enum.GooseScheduler.html#variant.Random) order, Scenarios are assigned to users at random and each Scenario's transactions run in a random order, so running the same load test multiple times can lead to different amounts of load being generated.

Prior to Goose `0.10.6` [`Scenario`](https://docs.rs/goose/*/goose/goose/struct.Scenario.html) were allocated in a serial order. Prior to Goose `0.11.1` [`Transaction`](https://docs.rs/goose/*/goose/goose/struct.Transaction.html) were allocated in a serial order. To restore the old behavior, you can use the [`GooseAttack::set_scheduler()`](https://docs.rs/goose/*/goose/struct.GooseAttack.html#method.set_scheduler) method as follows:

```rust,ignore
    GooseAttack::initialize()?
        .set_scheduler(GooseScheduler::Serial);
```

To instead assign [`Scenario`](https://docs.rs/goose/*/goose/goose/struct.Scenario.html) to users at random, and to run each Scenario's transactions in a random order, you can instead configure as follows:

```rust,ignore
    GooseAttack::initialize()?
        .set_scheduler(GooseScheduler::Random);
```

The following configuration is possible but superfluous because it is the scheduling default, and is therefore how Goose behaves even if the [`.set_scheduler()`](https://docs.rs/goose/*/goose/struct.GooseAttack.html#method.set_scheduler) method is not called at all:

```rust,ignore
    GooseAttack::initialize()?
        .set_scheduler(GooseScheduler::RoundRobin);
```

## Scheduling Example

The following simple example helps illustrate how the different schedulers work.

```rust,ignore
use goose::prelude::*;

#[tokio::main]
async fn main() -> Result<(), GooseError> {
    GooseAttack::initialize()?
        .register_scenario(scenario!("Scenario1")
            .register_transaction(transaction!(transaction1).set_weight(2)?)
            .register_transaction(transaction!(transaction2))
            .set_weight(2)?
        )
        .register_scenario(scenario!("Scenario2")
            .register_transaction(transaction!(transaction1))
            .register_transaction(transaction!(transaction2).set_weight(2)?)
        )
        .execute()
        .await?;

    Ok(())
}
```

## Round Robin Scheduler

This first example assumes the default of `.set_scheduler(GooseScheduler::RoundRobin)`.

If Goose is told to launch only two users, one [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html) will run `Scenario1` and the other will run `Scenario2`. Even though `Scenario1` has a weight of 2 [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html) are allocated round-robin so with only two users the second instance of `Scenario1` is never launched. Goose launches the allocated users from the end of the list, so the first user launched runs `Scenario2` and the second runs `Scenario1`. The first user launched is `"user":0` in the request, transaction and scenario logs, and `[user 1]: launching user` in the console.

The [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html) running `Scenario1` will then launch transactions repeatedly in the following order: `transaction1`, `transaction2`, `transaction1`. If it runs through twice, then it runs all of the following transactions in the following order: `transaction1`, `transaction2`, `transaction1`, `transaction1`, `transaction2`, `transaction1`.

## Serial Scheduler

This second example assumes the manual configuration of `.set_scheduler(GooseScheduler::Serial)`.

If Goose is told to launch only two users, then both [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html) will launch `Scenario1` as it has a weight of 2. `Scenario2` will not get assigned to either of the users.

Both [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html) running `Scenario1` will then launch transactions repeatedly in the following order: `transaction1`, `transaction1`, `transaction2`. If it runs through twice, then it runs all of the following transactions in the following order: `transaction1`, `transaction1`, `transaction2`, `transaction1`, `transaction1`, `transaction2`.

## Random Scheduler

This third example assumes the manual configuration of `.set_scheduler(GooseScheduler::Random)`.

Goose fills its list of users by picking a Scenario at random and taking one of that Scenario's weighted places, until every place is taken. With weights of 2 and 1 the list holds `Scenario1` twice and `Scenario2` once, in a random order. If Goose is told to launch only two users, they may both run `Scenario1`, or one may run each, but never both `Scenario2`. If the load test is stopped and run again, the users are randomly re-assigned; there is no consistency between load test runs.

Goose builds each Scenario's list of transactions as the Serial scheduler does, then shuffles the whole list once when the load test starts. Every [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html) running that Scenario runs the same shuffled order, over and over, and the next run of the load test gets a new order. With `Scenario1` the order is one of `transaction1`, `transaction1`, `transaction2`; `transaction1`, `transaction2`, `transaction1`; or `transaction2`, `transaction1`, `transaction1`.

Sequenced transactions are shuffled only within their sequence, so every transaction of a lower sequence still runs before any of a higher one. Transactions set with `set_on_start()` or `set_on_stop()` keep the Serial order.