[][src]Struct goose::goose::GooseUser

pub struct GooseUser {
    pub task_sets_index: usize,
    pub client: Arc<Mutex<Client>>,
    pub weighted_bucket: Arc<AtomicUsize>,
    pub weighted_bucket_position: Arc<AtomicUsize>,
    pub base_url: Arc<RwLock<Url>>,
    pub min_wait: usize,
    pub max_wait: usize,
    pub config: GooseConfiguration,
    pub parent: Option<UnboundedSender<GooseRawRequest>>,
    pub weighted_users_index: usize,
    pub weighted_on_start_tasks: Vec<Vec<usize>>,
    pub weighted_tasks: Vec<Vec<usize>>,
    pub weighted_on_stop_tasks: Vec<Vec<usize>>,
    pub task_request_name: Option<String>,
    pub request_name: Option<String>,
    pub load_test_hash: u64,
}

An individual user state, repeatedly running all GooseTasks in a specific GooseTaskSet.

Fields

task_sets_index: usize

An index into the internal GooseTest.task_sets vector, indicating which GooseTaskSet is running.

client: Arc<Mutex<Client>>

Client used to make requests, managing sessions and cookies.

weighted_bucket: Arc<AtomicUsize>

Integer value tracking the sequenced bucket user is running tasks from.

weighted_bucket_position: Arc<AtomicUsize>

Integer value tracking the current task user is running.

base_url: Arc<RwLock<Url>>

The base URL to prepend to all relative paths.

min_wait: usize

Minimum amount of time to sleep after running a task.

max_wait: usize

Maximum amount of time to sleep after running a task.

config: GooseConfiguration

A local copy of the global GooseConfiguration.

parent: Option<UnboundedSender<GooseRawRequest>>

Channel

weighted_users_index: usize

An index into the internal `GooseTest.weighted_users, indicating which weighted GooseTaskSet is running.

weighted_on_start_tasks: Vec<Vec<usize>>

A weighted list of all tasks that run when the user first starts.

weighted_tasks: Vec<Vec<usize>>

A weighted list of all tasks that this user runs once started.

weighted_on_stop_tasks: Vec<Vec<usize>>

A weighted list of all tasks that run when the user stops.

task_request_name: Option<String>

Optional name of all requests made within the current task.

request_name: Option<String>

Optional name of all requests made within the current task.

load_test_hash: u64

Load test hash.

Implementations

impl GooseUser[src]

pub fn new(
    task_sets_index: usize,
    base_url: Url,
    min_wait: usize,
    max_wait: usize,
    configuration: &GooseConfiguration,
    load_test_hash: u64
) -> Self
[src]

Create a new user state.

pub fn single(base_url: Url, configuration: &GooseConfiguration) -> Self[src]

Create a new single-use user.

pub async fn build_url<'_, '_>(&'_ self, path: &'_ str) -> String[src]

A helper that prepends a base_url to all relative paths.

A base_url is determined per user thread, using the following order of precedence:

  1. --host (host specified on the command line when running load test)
  2. GooseTaskSet.host (default host defined for the current task set)
  3. GooseAttack.host (default host defined for the current load test)

pub async fn get<'_, '_>(&'_ self, path: &'_ str) -> GooseResponse[src]

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

(If you need to set headers, change timeouts, or otherwise make use of the reqwest::RequestBuilder object, you can instead call goose_get which returns a RequestBuilder, then call goose_send to invoke the request.)

Calls to user.get return a GooseResponse object which contains a copy of the request you made (response.request), and the response (response.response).

Example

    use goose::prelude::*;

    let mut task = task!(get_function);

    /// A very simple task that makes a GET request.
    async fn get_function(user: &GooseUser) {
      let _response = user.get("/path/to/foo/");
    }

pub async fn get_named<'_, '_, '_>(
    &'_ self,
    path: &'_ str,
    request_name: &'_ str
) -> GooseResponse
[src]

A helper to make a named GET request of a path and collect relevant statistics. Automatically prepends the correct host. Naming a request only affects collected statistics.

Calls to user.get_named return a GooseResponse object which contains a copy of the request you made (response.request), and the response (response.response).

Example

    use goose::prelude::*;

    let mut task = task!(get_function);

    /// A very simple task that makes a GET request.
    async fn get_function(user: &GooseUser) {
      let _response = user.get_named("/path/to/foo/", "foo");
    }

pub async fn post<'_, '_, '_>(
    &'_ self,
    path: &'_ str,
    body: &'_ str
) -> GooseResponse
[src]

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

(If you need to set headers, change timeouts, or otherwise make use of the reqwest::RequestBuilder object, you can instead call goose_post which returns a RequestBuilder, then call goose_send to invoke the request.)

Calls to user.post return a GooseResponse object which contains a copy of the request you made (response.request), and the response (response.response).

Example

    use goose::prelude::*;

    let mut task = task!(post_function);

    /// A very simple task that makes a POST request.
    async fn post_function(user: &GooseUser) {
      let _response = user.post("/path/to/foo/", "BODY BEING POSTED");
    }

pub async fn post_named<'_, '_, '_, '_>(
    &'_ self,
    path: &'_ str,
    request_name: &'_ str,
    body: &'_ str
) -> GooseResponse
[src]

A helper to make a named POST request of a path and collect relevant statistics. Automatically prepends the correct host. Naming a request only affects collected statistics.

Calls to user.post return a GooseResponse object which contains a copy of the request you made (response.request), and the response (response.response).

Example

    use goose::prelude::*;

    let mut task = task!(post_function);

    /// A very simple task that makes a POST request.
    async fn post_function(user: &GooseUser) {
      let _response = user.post_named("/path/to/foo/", "foo", "BODY BEING POSTED");
    }

pub async fn head<'_, '_>(&'_ self, path: &'_ str) -> GooseResponse[src]

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

(If you need to set headers, change timeouts, or otherwise make use of the reqwest::RequestBuilder object, you can instead call goose_head which returns a RequestBuilder, then call goose_send to invoke the request.)

Calls to user.head return a GooseResponse object which contains a copy of the request you made (response.request), and the response (response.response).

Example

    use goose::prelude::*;

    let mut task = task!(head_function);

    /// A very simple task that makes a HEAD request.
    async fn head_function(user: &GooseUser) {
      let _response = user.head("/path/to/foo/");
    }

pub async fn head_named<'_, '_, '_>(
    &'_ self,
    path: &'_ str,
    request_name: &'_ str
) -> GooseResponse
[src]

A helper to make a named HEAD request of a path and collect relevant statistics. Automatically prepends the correct host. Naming a request only affects collected statistics.

Calls to user.head return a GooseResponse object which contains a copy of the request you made (response.request), and the response (response.response).

Example

    use goose::prelude::*;

    let mut task = task!(head_function);

    /// A very simple task that makes a HEAD request.
    async fn head_function(user: &GooseUser) {
      let _response = user.head_named("/path/to/foo/", "foo");
    }

pub async fn delete<'_, '_>(&'_ self, path: &'_ str) -> GooseResponse[src]

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

(If you need to set headers, change timeouts, or otherwise make use of the reqwest::RequestBuilder object, you can instead call goose_delete which returns a RequestBuilder, then call goose_send to invoke the request.)

Calls to user.delete return a GooseResponse object which contains a copy of the request you made (response.request), and the response (response.response).

Example

    use goose::prelude::*;

    let mut task = task!(delete_function);

    /// A very simple task that makes a DELETE request.
    async fn delete_function(user: &GooseUser) {
      let _response = user.delete("/path/to/foo/");
    }

pub async fn delete_named<'_, '_, '_>(
    &'_ self,
    path: &'_ str,
    request_name: &'_ str
) -> GooseResponse
[src]

A helper to make a named DELETE request of a path and collect relevant statistics. Automatically prepends the correct host. Naming a request only affects collected statistics.

Calls to user.delete return a GooseResponse object which contains a copy of the request you made (response.request), and the response (response.response).

Example

    use goose::prelude::*;

    let mut task = task!(delete_function);

    /// A very simple task that makes a DELETE request.
    async fn delete_function(user: &GooseUser) {
      let _response = user.delete_named("/path/to/foo/", "foo");
    }

pub async fn goose_get<'_, '_>(&'_ self, path: &'_ str) -> RequestBuilder[src]

Prepends the correct host on the path, then prepares a reqwest::RequestBuilder object for making a GET request.

(You must then call goose_send on this object to actually execute the request.)

Example

    use goose::prelude::*;

    let mut task = task!(get_function);

    /// A simple task that makes a GET request, exposing the Reqwest
    /// request builder.
    async fn get_function(user: &GooseUser) {
      let request_builder = user.goose_get("/path/to/foo").await;
      let response = user.goose_send(request_builder, None).await;
    }

pub async fn goose_post<'_, '_>(&'_ self, path: &'_ str) -> RequestBuilder[src]

Prepends the correct host on the path, then prepares a reqwest::RequestBuilder object for making a POST request.

(You must then call goose_send on this object to actually execute the request.)

Example

    use goose::prelude::*;

    let mut task = task!(post_function);

    /// A simple task that makes a POST request, exposing the Reqwest
    /// request builder.
    async fn post_function(user: &GooseUser) {
      let request_builder = user.goose_post("/path/to/foo").await;
      let response = user.goose_send(request_builder, None).await;
    }

pub async fn goose_head<'_, '_>(&'_ self, path: &'_ str) -> RequestBuilder[src]

Prepends the correct host on the path, then prepares a reqwest::RequestBuilder object for making a HEAD request.

(You must then call goose_send on this object to actually execute the request.)

Example

    use goose::prelude::*;

    let mut task = task!(head_function);

    /// A simple task that makes a HEAD request, exposing the Reqwest
    /// request builder.
    async fn head_function(user: &GooseUser) {
      let request_builder = user.goose_head("/path/to/foo").await;
      let response = user.goose_send(request_builder, None).await;
    }

pub async fn goose_put<'_, '_>(&'_ self, path: &'_ str) -> RequestBuilder[src]

Prepends the correct host on the path, then prepares a reqwest::RequestBuilder object for making a PUT request.

(You must then call goose_send on this object to actually execute the request.)

Example

    use goose::prelude::*;

    let mut task = task!(put_function);

    /// A simple task that makes a PUT request, exposing the Reqwest
    /// request builder.
    async fn put_function(user: &GooseUser) {
      let request_builder = user.goose_put("/path/to/foo").await;
      let response = user.goose_send(request_builder, None).await;
    }

pub async fn goose_patch<'_, '_>(&'_ self, path: &'_ str) -> RequestBuilder[src]

Prepends the correct host on the path, then prepares a reqwest::RequestBuilder object for making a PATCH request.

(You must then call goose_send on this object to actually execute the request.)

Example

    use goose::prelude::*;

    let mut task = task!(patch_function);

    /// A simple task that makes a PUT request, exposing the Reqwest
    /// request builder.
    async fn patch_function(user: &GooseUser) {
      let request_builder = user.goose_patch("/path/to/foo").await;
      let response = user.goose_send(request_builder, None).await;
    }

pub async fn goose_delete<'_, '_>(&'_ self, path: &'_ str) -> RequestBuilder[src]

Prepends the correct host on the path, then prepares a reqwest::RequestBuilder object for making a DELETE request.

(You must then call goose_send on this object to actually execute the request.)

Example

    use goose::prelude::*;

    let mut task = task!(delete_function);

    /// A simple task that makes a DELETE request, exposing the Reqwest
    /// request builder.
    async fn delete_function(user: &GooseUser) {
      let request_builder = user.goose_delete("/path/to/foo").await;
      let response = user.goose_send(request_builder, None).await;
    }

pub async fn goose_send<'_, '_>(
    &'_ self,
    request_builder: RequestBuilder,
    request_name: Option<&'_ str>
) -> GooseResponse
[src]

Builds the provided reqwest::RequestBuilder object and then executes the response. If statistics are being displayed, it also captures request statistics.

It is possible to build and execute a RequestBuilder object directly with Reqwest without using this helper function, but then Goose is unable to capture statistics.

Calls to user.goose_send return a GooseResponse object which contains a copy of the request you made (response.request), and the response (response.response).

Example

    use goose::prelude::*;

    let mut task = task!(get_function);

    /// A simple task that makes a GET request, exposing the Reqwest
    /// request builder.
    async fn get_function(user: &GooseUser) {
      let request_builder = user.goose_get("/path/to/foo").await;
      let response = user.goose_send(request_builder, None).await;
    }

pub fn set_success(&self, request: &mut GooseRawRequest)[src]

Manually mark a request as a success.

By default, Goose will consider any response with a 2xx status code as a success. It may be valid in your test for a non-2xx HTTP status code to be returned. A copy of your original request is returned with the response, and a mutable copy must be included when setting a request as a success.

Example

    use goose::prelude::*;

    let mut task = task!(get_function);

    /// A simple task that makes a GET request.
    async fn get_function(user: &GooseUser) {
        let mut response = user.get("/404").await;
        match &response.response {
            Ok(r) => {
                // We expect a 404 here.
                if r.status() == 404 {
                    user.set_success(&mut response.request);
                }
            },
            Err(_) => (),
        }
    }

pub fn set_failure(&self, request: &mut GooseRawRequest)[src]

Manually mark a request as a failure.

By default, Goose will consider any response with a 2xx status code as a success. You may require more advanced logic, in which a 2xx status code is actually a failure. A copy of your original request is returned with the response, and a mutable copy must be included when setting a request as a failure.

Example

    use goose::prelude::*;

    let mut task = task!(loadtest_index_page);

    async fn loadtest_index_page(user: &GooseUser) {
        let mut response = user.get_named("/", "index").await;
        // Extract the response Result.
        match response.response {
            Ok(r) => {
                // We only need to check pages that returned a success status code.
                if r.status().is_success() {
                    match r.text().await {
                        Ok(text) => {
                            // If the expected string doesn't exist, this page load
                            // was a failure.
                            if !text.contains("this string must exist") {
                                // As this is a named request, pass in the name not the URL
                                user.set_failure(&mut response.request);
                            }
                        }
                        // Empty page, this is a failure.
                        Err(_) => user.set_failure(&mut response.request),
                    }
                }
            },
            // Invalid response, this is already a failure.
            Err(_) => (),
        }
    }

pub async fn set_client_builder<'_>(&'_ self, builder: ClientBuilder)[src]

Manually build a Reqwest client.

By default, Goose configures two options when building a Reqwest client. The first configures Goose to report itself as the user agent requesting web pages (ie goose/0.8.0). The second option configures Reqwest to store cookies, which is generally necessary if you aim to simulate logged in users.

Default configuration:

use reqwest::Client;

static APP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));

let builder = Client::builder()
  .user_agent(APP_USER_AGENT)
  .cookie_store(true);

Alternatively, you can use this function to manually build a Reqwest client with custom configuration. Available options are found in the Reqwest ClientBuilder documentation.

When manually building a Reqwest client, there are a few things to be aware of:

  • Manually building a client in test_start will only affect requests made during test setup;
  • Manually building a client in test_stop will only affect requests made during test teardown;
  • A manually built client is specific to a single Goose thread -- if you are generating a large load test with many users, each will need to manually build their own client (typically you'd do this in a Task that is registered with set_on_start() in each Task Set requiring a custom client;
  • Manually building a client will completely replace the automatically built client with a brand new one, so any configuration, cookies or headers set in the previously built client will be gone;
  • You must include all desired configuration, as you are completely replacing Goose defaults. For example, if you want Goose clients to store cookies, you will have to include .cookie_store(true).

In the following example, the Goose client is configured with a different user agent, sets a default header on every request, and stores cookies.

Example

use goose::prelude::*;

task!(setup_custom_client).set_on_start();

async fn setup_custom_client(user: &GooseUser) {
  use reqwest::{Client, header};

  // Build a custom HeaderMap to include with all requests made by this client.
  let mut headers = header::HeaderMap::new();
  headers.insert("X-Custom-Header", header::HeaderValue::from_str("custom value").unwrap());

  let builder = Client::builder()
    .default_headers(headers)
    .user_agent("custom user agent")
    .cookie_store(true);

  user.set_client_builder(builder);
}

pub async fn set_base_url<'_, '_>(&'_ self, host: &'_ str)[src]

Some websites use multiple domains to serve traffic, redirecting depending on the user's roll. For this reason, Goose needs to respect a redirect of the base_url and subsequent paths should be built from the redirect domain.

For example, if the base_url (ie --host) is set to foo.example.com and the load test requests /login, thereby loading http://foo.example.com/login and this request gets redirected by the server to http://foo-secure.example.com/, subsequent requests made by this user need to be against the new foo-secure.example.com domain. (Further, if the base_url is again redirected, such as when loading http://foo-secure.example.com/logout, the user should again follow for subsequent requests, perhaps in this case back to foo.example.com.)

Load tests can also request absolute URLs, and if these URLs are redirected it does not affect the base_url of the load test. For example, if foo.example.com is the base url, and the load test requests http://bar.example.com (a different domain) and this request gets redirected to http://other.example.com, subsequent relative requests would still be made against foo.example.com.

This functionality is used internally by Goose to follow redirects of the base_url, but it is also available to be manually invoked from a load test such as in the following example.

Example

use goose::prelude::*;

GooseAttack::initialize()
    .register_taskset(taskset!("LoadtestTasks").set_host("http//foo.example.com/")
        .set_wait_time(0, 3)
        .register_task(task!(task_foo).set_weight(10))
        .register_task(task!(task_bar))
    )
    .execute();

    async fn task_foo(user: &GooseUser) {
      let _response = user.get("/");
    }

    async fn task_bar(user: &GooseUser) {
      // Before this task runs, all requests are being made against
      // http://foo.example.com, after this task runs all subsequent
      // requests are made against http://bar.example.com/.
      user.set_base_url("http://bar.example.com/");
      let _response = user.get("/");
    }

Trait Implementations

impl Clone for GooseUser[src]

impl Debug for GooseUser[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

impl<V, T> VZip<V> for T where
    V: MultiLane<T>,