Module swanling::swanling[][src]

Expand description

Helpers and objects for building Swanling load tests.

Swanling manages load tests with a series of objects:

  • SwanlingTaskSet each user is assigned a task set, which is a collection of tasks.
  • SwanlingTask tasks define one or more web requests and are assigned to task sets.
  • SwanlingUser a user state responsible for repeatedly running all tasks in the assigned task set.
  • SwanlingRequest optional metrics collected for each URL/method pair.

Creating Task Sets

A SwanlingTaskSet is created by passing in a &str name to the new function, for example:

use swanling::prelude::*;

let mut loadtest_tasks = taskset!("LoadtestTasks");

Task Set Weight

A weight can be applied to a task set, controlling how often it is assigned to SwanlingUser threads. The larger the integer value of weight, the more the task set will be assigned to user threads. In the following example, FooTasks will be assigned to users twice as often as Bar tasks. We could have just added a weight of 2 to FooTasks and left the default weight of 1 assigned to BarTasks for the same weighting:

use swanling::prelude::*;

fn main() -> Result<(), SwanlingError> {
    let mut foo_tasks = taskset!("FooTasks").set_weight(10)?;
    let mut bar_tasks = taskset!("BarTasks").set_weight(5)?;

    Ok(())
}

Task Set Host

A default host can be assigned to a task set, which will be used only if the --host CLI option is not set at run-time. For example, this can configure your load test to run against your local development environment by default, allowing the --host option to override host when you want to load test production. You can also assign different hosts to different task sets if this is desirable:

use swanling::prelude::*;

let mut foo_tasks = taskset!("FooTasks").set_host("http://www.local");
let mut bar_tasks = taskset!("BarTasks").set_host("http://www2.local");

Task Set Wait Time

Wait time is specified as a low-high integer range. Each time a task completes in the task set, the user will pause for a random number of seconds inclusively between the low and high wait times. In the following example, users loading foo tasks will sleep 0 to 3 seconds after each task completes, and users loading bar tasks will sleep 5 to 10 seconds after each task completes.

use swanling::prelude::*;

let mut foo_tasks = taskset!("FooTasks").set_wait_time(0, 3).unwrap();
let mut bar_tasks = taskset!("BarTasks").set_wait_time(5, 10).unwrap();

Creating Tasks

A SwanlingTask must include a pointer to a function which will be executed each time the task is run.

use swanling::prelude::*;

let mut a_task = task!(task_function);

/// A very simple task that loads the front page.
async fn task_function(user: &SwanlingUser) -> SwanlingTaskResult {
    let _swanling = user.get("/").await?;

    Ok(())
}

Task Name

A name can be assigned to a task, and will be displayed in metrics about all requests made by the task.

use swanling::prelude::*;

let mut a_task = task!(task_function).set_name("a");

/// A very simple task that loads the front page.
async fn task_function(user: &SwanlingUser) -> SwanlingTaskResult {
    let _swanling = user.get("/").await?;

    Ok(())
}

Task Weight

Individual tasks can be assigned a weight, controlling how often the task runs. The larger the value of weight, the more it will run. In the following example, a_task runs 3 times as often as b_task:

use swanling::prelude::*;

fn main() -> Result<(), SwanlingError> {
    let mut a_task = task!(a_task_function).set_weight(9)?;
    let mut b_task = task!(b_task_function).set_weight(3)?;

    Ok(())
}

/// A very simple task that loads the "a" page.
async fn a_task_function(user: &SwanlingUser) -> SwanlingTaskResult {
    let _swanling = user.get("/a/").await?;

    Ok(())
}

/// Another very simple task that loads the "b" page.
async fn b_task_function(user: &SwanlingUser) -> SwanlingTaskResult {
    let _swanling = user.get("/b/").await?;

    Ok(())
}

Task Sequence

Tasks can also be configured to run in a sequence. For example, a task with a sequence value of 1 will always run before a task with a sequence value of 2. Weight can be applied to sequenced tasks, so for example a task with a weight of 2 and a sequence of 1 will run two times before a task with a sequence of 2. Task sets can contain tasks with sequence values and without sequence values, and in this case all tasks with a sequence value will run before tasks without a sequence value. In the following example, a_task runs before b_task, which runs before c_task:

use swanling::prelude::*;

let mut a_task = task!(a_task_function).set_sequence(1);
let mut b_task = task!(b_task_function).set_sequence(2);
let mut c_task = task!(c_task_function);

/// A very simple task that loads the "a" page.
async fn a_task_function(user: &SwanlingUser) -> SwanlingTaskResult {
    let _swanling = user.get("/a/").await?;

    Ok(())
}

/// Another very simple task that loads the "b" page.
async fn b_task_function(user: &SwanlingUser) -> SwanlingTaskResult {
    let _swanling = user.get("/b/").await?;

    Ok(())
}

/// Another very simple task that loads the "c" page.
async fn c_task_function(user: &SwanlingUser) -> SwanlingTaskResult {
    let _swanling = user.get("/c/").await?;

    Ok(())
}

Task On Start

Tasks can be flagged to only run when a user first starts. This can be useful if you’d like your load test to use a logged-in user. It is possible to assign sequences and weights to on_start functions if you want to have multiple tasks run in a specific order at start time, and/or the tasks to run multiple times. A task can be flagged to run both on start and on stop.

use swanling::prelude::*;

let mut a_task = task!(a_task_function).set_sequence(1).set_on_start();

/// A very simple task that loads the "a" page.
async fn a_task_function(user: &SwanlingUser) -> SwanlingTaskResult {
    let _swanling = user.get("/a/").await?;

    Ok(())
}

Task On Stop

Tasks can be flagged to only run when a user stops. This can be useful if you’d like your load test to simulate a user logging out when it finishes. It is possible to assign sequences and weights to on_stop functions if you want to have multiple tasks run in a specific order at stop time, and/or the tasks to run multiple times. A task can be flagged to run both on start and on stop.

use swanling::prelude::*;

let mut b_task = task!(b_task_function).set_sequence(2).set_on_stop();

/// Another very simple task that loads the "b" page.
async fn b_task_function(user: &SwanlingUser) -> SwanlingTaskResult {
    let _swanling = user.get("/b/").await?;

    Ok(())
}

Controlling User

When Swanling starts, it creates one or more SwanlingUsers, assigning a single SwanlingTaskSet to each. This user is then used to generate load. Behind the scenes, Swanling is leveraging the reqwest::client to load web pages, and Swanling can therefor do anything reqwest can do.

The most common request types are GET and POST, but HEAD, PUT, PATCH and DELETE are also supported.

GET

A helper to make a GET request of a path and collect relevant metrics. Automatically prepends the correct host.

use swanling::prelude::*;

let mut task = task!(get_function);

/// A very simple task that makes a GET request.
async fn get_function(user: &SwanlingUser) -> SwanlingTaskResult {
    let _swanling = user.get("/path/to/foo/").await?;

    Ok(())
}

The returned response is a reqwest::Response struct. You can use it as you would any Reqwest Response.

POST

A helper to make a POST request of a string value to the path and collect relevant metrics. Automatically prepends the correct host. The returned response is a reqwest::Response

use swanling::prelude::*;

let mut task = task!(post_function);

/// A very simple task that makes a POST request.
async fn post_function(user: &SwanlingUser) -> SwanlingTaskResult {
    let _swanling = user.post("/path/to/foo/", "string value to post").await?;

    Ok(())
}

License

Copyright 2020 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.

Structs

The elements needed to build an individual user state on a Regatta Worker.

Object created by log_debug() and written to log to assist in debugging.

The response to a SwanlingRequest

An individual task within a SwanlingTaskSet.

An individual task set.

An individual user state, repeatedly running all SwanlingTasks in a specific SwanlingTaskSet.

Enums

Supported HTTP methods.

An enumeration of all errors a SwanlingTask can return.

Commands sent from the parent thread to the user threads, and from the manager to the worker processes.

Functions

A helper to determine which host should be prepended to relative load test paths in this TaskSet.

Type Definitions

The function type of a swanling task function.

Swanling tasks return a result, which is empty on success, or contains a SwanlingTaskError on error.