Skip to content

Commit

Permalink
continued documentation cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeremy Andrews committed Sep 14, 2021
1 parent 428e38f commit 87f8580
Show file tree
Hide file tree
Showing 20 changed files with 113 additions and 57 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Have you ever been attacked by a goose?

## Overview

Goose is a Rust load testing tool inspired by [Locust](https://locust.io/). User behavior is defined with standard Rust code. Load tests are applications that have a dependency on the Goose library. Web requests are made with the [Reqwest](https://docs.rs/reqwest) HTTP Client.
Goose is a [Rust](https://www.rust-lang.org/) load testing tool inspired by [Locust](https://locust.io/). User behavior is defined with standard Rust code. Load tests are applications that have a dependency on the Goose library. Web requests are made with the [Reqwest](https://docs.rs/reqwest) HTTP Client.

### Documentation

Expand Down
5 changes: 4 additions & 1 deletion src/docs/goose-book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@
- [Scheduling Users And Tasks](config/scheduler.md)
- [RustLS](config/rustls.md)

- [Examples](examples/overview.md)
- [Examples](example/overview.md)
- [Simple](example/simple.md)
- [Simple Closure](example/simple-closure.md)
- [Simple Session](example/simple-session.md)

- [Controllers](controller/overview.md)
- [Telnet Controller](controller/telnet.md)
Expand Down
2 changes: 1 addition & 1 deletion src/docs/goose-book/src/config/rustls.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ By default Reqwest (and therefore Goose) uses the system-native transport layer

```toml
[dependencies]
goose = { version = "^0.13", default-features = false, features = ["rustls-tls"] }
goose = { version = "^0.14", default-features = false, features = ["rustls-tls"] }
```
20 changes: 10 additions & 10 deletions src/docs/goose-book/src/config/scheduler.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
# Scheduling Users And Tasks

When starting a load test, Goose assigns one `GooseTaskSet` to each `GooseUser` thread. By default, it assigns `GooseTaskSet`s (and then `GooseTask`s within the task set) in a round robin order. As new `GooseUser` threads are launched, the first will be assigned the first defined `GooseTaskSet`, the next will be assigned the next defined `GooseTaskSet`, and so on, looping through all available `GooseTaskSet`s. Weighting is respected during this process, so if one `GooseTaskSet` is weighted heavier than others, that `GooseTaskSet` will get assigned to `GooseUser`s more at the end of the launching process.
When starting a load test, Goose assigns one [`GooseTaskSet`](https://docs.rs/goose/*/goose/goose/struct.GooseTaskSet.html) to each [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html) thread. By default, it assigns [`GooseTaskSet`](https://docs.rs/goose/*/goose/goose/struct.GooseTaskSet.html) (and then [`GooseTask`](https://docs.rs/goose/*/goose/goose/struct.GooseTask.html) within the task set) 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 [`GooseTaskSet`](https://docs.rs/goose/*/goose/goose/struct.GooseTaskSet.html), the next will be assigned the next defined [`GooseTaskSet`](https://docs.rs/goose/*/goose/goose/struct.GooseTaskSet.html), and so on, looping through all available [`GooseTaskSet`](https://docs.rs/goose/*/goose/goose/struct.GooseTaskSet.html). Weighting is respected during this process, so if one [`GooseTaskSet`](https://docs.rs/goose/*/goose/goose/struct.GooseTaskSet.html) is weighted heavier than others, that [`GooseTaskSet`](https://docs.rs/goose/*/goose/goose/struct.GooseTaskSet.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` can be configured to instead launch `GooseTaskSet`s and `GooseTask`s in a `Serial` or a `Random order`. When configured to allocate in a `Serial` order, `GooseTaskSet`s and `GooseTask`s are launched in the extact order they are defined in the load test (see below for more detail on how this works). When configured to allocate in a `Random` order, running the same load test multiple times can lead to different amounts of load being generated.
The [`GooseScheduler`](https://docs.rs/goose/*/goose/enum.GooseScheduler.html) can be configured to instead launch [`GooseTaskSet`](https://docs.rs/goose/*/goose/goose/struct.GooseTaskSet.html) and [`GooseTask`](https://docs.rs/goose/*/goose/goose/struct.GooseTask.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, [`GooseTaskSet`](https://docs.rs/goose/*/goose/goose/struct.GooseTaskSet.html) and [`GooseTask`](https://docs.rs/goose/*/goose/goose/struct.GooseTask.html) are launched in the extact 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, running the same load test multiple times can lead to different amounts of load being generated.

Prior to Goose `0.10.6` `GooseTaskSet`s were allocated in a serial order. Prior to Goose `0.11.1` `GooseTask`s were allocated in a serial order. To restore the old behavior, you can use the `GooseAttack::set_scheduler()` method as follows:
Prior to Goose `0.10.6` [`GooseTaskSet`](https://docs.rs/goose/*/goose/goose/struct.GooseTaskSet.html) were allocated in a serial order. Prior to Goose `0.11.1` [`GooseTask`](https://docs.rs/goose/*/goose/goose/struct.GooseTask.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 randomize the order that `GooseTaskSet`s and `GooseTask`s are allocated, you can instead configure as follows:
To instead randomize the order that [`GooseTaskSet`](https://docs.rs/goose/*/goose/goose/struct.GooseTaskSet.html) and [`GooseTask`](https://docs.rs/goose/*/goose/goose/struct.GooseTask.html) are allocated, 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 therefor how Goose behaves even if the `.set_scheduler()` method is not called at all:
The following configuration is possible but superfluous because it is the scheduling default, and is therefor 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()?
Expand Down Expand Up @@ -56,23 +56,23 @@ async fn main() -> Result<(), GooseError> {

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

If Goose is told to launch only two users, the first GooseUser will run `TaskSet1` and the second user will run `TaskSet2`. Even though `TaskSet1` has a weight of 2 `GooseUser`s are allocated round-robin so with only two users the second instance of `TaskSet1` is never launched.
If Goose is told to launch only two users, the first [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html) will run `TaskSet1` and the second user will run `TaskSet2`. Even though `TaskSet1` 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 `TaskSet1` is never launched.

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

## 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`s will launch `TaskSet1` as it has a weight of 2. `TaskSet2` will not get assigned to either of the users.
If Goose is told to launch only two users, then both [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html) will launch `TaskSet1` as it has a weight of 2. `TaskSet2` will not get assigned to either of the users.

Both `GooseUser`s running `TaskSet1` will then launch tasks repeatedly in the following order: `task1`, `task1`, `task2`. If it runs through twice, then it runs all of the following tasks in the following order: `task1`, `task1`, `task2`, `task1`, `task1`, `task2`.
Both [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html) running `TaskSet1` will then launch tasks repeatedly in the following order: `task1`, `task1`, `task2`. If it runs through twice, then it runs all of the following tasks in the following order: `task1`, `task1`, `task2`, `task1`, `task1`, `task2`.

## Random Scheduler

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

If Goose is told to launch only two users, the first will be randomly assigned either `TaskSet1` or `TaskSet2`. Regardless of which is assigned to the first user, the second will again be randomly assigned either `TaskSet1` or `TaskSet2`. If the load test is stopped and run again, there users are randomly re-assigned, there is no consistency between load test runs.

Each `GooseUser` will run tasks in a random order. The random order will be determined at start time and then will run repeatedly in this random order as long as the user runs.
Each [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html) will run tasks in a random order. The random order will be determined at start time and then will run repeatedly in this random order as long as the user runs.

2 changes: 1 addition & 1 deletion src/docs/goose-book/src/controller/telnet.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
goose> ?
goose 0.13.3 controller commands:
goose 0.14.4 controller commands:
help (?) this help
exit (quit) exit controller
start start an idle load test
Expand Down
8 changes: 8 additions & 0 deletions src/docs/goose-book/src/example/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Simple Example

Goose includes several examples to demonstrate load test functionality, including:
- [Simple](https://github.com/tag1consulting/goose/blob/main/examples/simple.rs)
- [Simple Closure](https://github.com/tag1consulting/goose/blob/main/examples/simple_closure.rs)
- [Simple With Session](https://github.com/tag1consulting/goose/blob/main/examples/simple_with_session.rs)
- [Drupal Loadtest](https://github.com/tag1consulting/goose/blob/main/examples/drupal_loadtest.rs)
- [Umami](https://github.com/tag1consulting/goose/tree/main/examples/umami)
9 changes: 9 additions & 0 deletions src/docs/goose-book/src/example/simple-closure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Simple Closure Example

The [`examples/simple_closure.rs`](https://github.com/tag1consulting/goose/blob/main/examples/simple_closure.rs) example loads three different pages on a web site. Instead of defining a hard coded [`GooseTask`](https://docs.rs/goose/*/goose/goose/struct.GooseTask.html) function for each, the paths are passed in via a [vector](https://doc.rust-lang.org/std/vec/index.html) and the [GooseTaskFunction](https://docs.rs/goose/*/goose/goose/type.GooseTaskFunction.html) is dynamically created in a [closure](https://doc.rust-lang.org/rust-by-example/fn/closures.html).

## Source Code

```rust,ignore
{{#include ../../../../../examples/simple_closure.rs}}
```
11 changes: 11 additions & 0 deletions src/docs/goose-book/src/example/simple-session.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Simple With Session Example

The [`examples/simple_with_session.rs`](https://github.com/tag1consulting/goose/blob/main/examples/simple_with_session.rs) example demonstrates how you can add JWT authentication support to your load test, making use of the [`GooseUserData`](https://docs.rs/goose/*/goose/goose/trait.GooseUserData.html) marker trait. In this example, the session is recorded in the [`GooseUser`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html) object with [`set_session_data`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html#method.set_session_data), and retrieved with [`get_session_data_unchecked`](https://docs.rs/goose/*/goose/goose/struct.GooseUser.html#method.get_session_data_unchecked).

_This example will panic if you run it without setting up a proper load test environment that actually sets the expected JWT token._

## Source Code

```rust,ignore
{{#include ../../../../../examples/simple_with_session.rs}}
```
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
# Simple Example
# Simple Example

Goose includes several examples to demonstrate load test functionality, including:
- [Simple](https://github.com/tag1consulting/goose/blob/main/examples/simple.rs)
- [Simple Closure](https://github.com/tag1consulting/goose/blob/main/examples/simple_closure.rs)
- [Simple With Session](https://github.com/tag1consulting/goose/blob/main/examples/simple_with_session.rs)
- [Drupal Loadtest](https://github.com/tag1consulting/goose/blob/main/examples/drupal_loadtest.rs)
- [Umami](https://github.com/tag1consulting/goose/tree/main/examples/umami)

The `examples/simple.rs` example copies the simple load test documented on the locust.io web page, rewritten in Rust for Goose. It uses minimal advanced functionality, but demonstrates how to GET and POST pages. It defines a single Task Set which has the user log in and then load a couple of pages.
The [`examples/simple.rs`](https://github.com/tag1consulting/goose/blob/main/examples/simple.rs) example copies the simple load test documented on the [locust.io web page](https://locust.io/), rewritten in Rust for Goose. It uses minimal advanced functionality, but demonstrates how to GET and POST pages. It defines a single Task Set which has the user log in and then load a couple of pages.

Goose can make use of all available CPU cores. By default, it will launch 1 user per core, and it can be configured to launch many more. The following was configured instead to launch 1,024 users. Each user randomly pauses 5 to 15 seconds after each task is loaded, so it's possible to spin up a large number of users. Here is a snapshot of `top` when running this example on a 1-core VM with 10G of available RAM -- there were ample resources to launch considerably more "users", though `ulimit` had to be resized:

Expand All @@ -20,4 +13,10 @@ MiB Swap: 10237.0 total, 10237.0 free, 0.0 used. 8606.9 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1339 goose 20 0 1235480 758292 8984 R 3.0 7.4 0:06.56 simple
```
```

## Source Code

```rust,ignore
{{#include ../../../../../examples/simple.rs}}
```
2 changes: 1 addition & 1 deletion src/docs/goose-book/src/gaggle/technical.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ When writing load test applications, you can default to compiling in the Gaggle

```toml
[dependencies]
goose = { version = "^0.13", features = ["gaggle"] }
goose = { version = "^0.14", features = ["gaggle"] }
```
4 changes: 2 additions & 2 deletions src/docs/goose-book/src/getting-started/metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ All 1024 users hatched.
Running: 2021-08-12 10:55:42 - 2021-08-12 11:05:09 (duration: 00:10:00)
Stopping: 2021-08-12 11:05:09 - 2021-08-12 11:05:11 (duration: 00:00:02)

goose v0.13.3
goose v0.14.0
------------------------------------------------------------------------------
```

Additional details about how metrics are collected, stored, and displayed can be found [in the developer documentation](https://docs.rs/goose/0.13.3/goose/metrics/index.html).
Additional details about how metrics are collected, stored, and displayed can be found [in the developer documentation](https://docs.rs/goose/*/goose/metrics/index.html).
2 changes: 1 addition & 1 deletion src/docs/goose-book/src/getting-started/runtime-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

The `-h` flag will show all run-time configuration options available to Goose load tests. For example, you can pass the `-h` flag to our example loadtest as follows, `cargo run --release -- -h`:

```bash
```ignore
Usage: target/release/loadtest [OPTIONS]
Options available when launching a Goose load test.
Expand Down
2 changes: 1 addition & 1 deletion src/docs/goose-book/src/getting-started/tips.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Tips

* Avoid `unwrap()` in your task functions -- Goose generates a lot of load, and this tends to trigger errors. Embrace Rust's warnings and properly handle all possible errors, this will save you time debugging later.
* When writing load tests, avoid [`unwrap()`](https://doc.rust-lang.org/std/option/enum.Option.html#method.unwrap) (and variations) in your task functions -- Goose generates a lot of load, and this tends to trigger errors. Embrace Rust's warnings and properly handle all possible errors, this will save you time debugging later.
* When running your load test, use the cargo `--release` flag to generate optimized code. This can generate considerably more load test traffic. Learn more about this and other optimizations in ["The golden Goose egg, a compile-time adventure"](https://www.tag1consulting.com/blog/golden-goose-egg-compile-time-adventure).
Loading

0 comments on commit 87f8580

Please sign in to comment.