Struct goose::GooseAttack

source ·
pub struct GooseAttack { /* private fields */ }
Expand description

Global internal state for the load test.

Implementations§

source§

impl GooseAttack

Goose’s internal global state.

source

pub fn initialize() -> Result<GooseAttack, GooseError>

Load configuration and initialize a GooseAttack.

Example
use goose::prelude::*;

let mut goose_attack = GooseAttack::initialize();
source

pub fn initialize_with_config( configuration: GooseConfiguration ) -> Result<GooseAttack, GooseError>

Initialize a GooseAttack with an already loaded configuration.

This is generally used by Worker instances and tests.

Example
use goose::GooseAttack;
use goose::config::GooseConfiguration;
use gumdrop::Options;

let configuration = GooseConfiguration::parse_args_default_or_exit();
let mut goose_attack = GooseAttack::initialize_with_config(configuration);
source

pub fn set_scheduler(self, scheduler: GooseScheduler) -> Self

Define the order Scenarios are allocated to new GooseUsers as they are launched.

By default, Scenarios are allocated to new GooseUsers in a round robin style. For example, if Scenario A has a weight of 5, Scenario B has a weight of 3, and you launch 20 users, they will be launched in the following order: A, B, A, B, A, B, A, A, A, B, A, B, A, B, A, A, A, B, A, B

Note that the following pattern is repeated: A, B, A, B, A, B, A, A

If reconfigured to schedule serially, then they will instead be allocated in the following order: A, A, A, A, A, B, B, B, A, A, A, A, A, B, B, B, A, A, A, A

In the serial case, the following pattern is repeated: A, A, A, A, A, B, B, B

In the following example, Scenarios are allocated to launching GooseUsers in a random order. This means running the test multiple times can generate different amounts of load, as depending on your weighting rules you may have a different number of GooseUsers running each Scenario each time.

Example
use goose::prelude::*;

#[tokio::main]
async fn main() -> Result<(), GooseError> {
    GooseAttack::initialize()?
        .set_scheduler(GooseScheduler::Random)
        .register_scenario(scenario!("A Scenario")
            .set_weight(5)?
            .register_transaction(transaction!(a_transaction))
        )
        .register_scenario(scenario!("B Scenario")
            .set_weight(3)?
            .register_transaction(transaction!(b_transaction))
        );

    Ok(())
}

async fn a_transaction(user: &mut GooseUser) -> TransactionResult {
    let _goose = user.get("/foo").await?;

    Ok(())
}

async fn b_transaction(user: &mut GooseUser) -> TransactionResult {
    let _goose = user.get("/bar").await?;

    Ok(())
}
source

pub fn register_scenario(self, scenario: Scenario) -> Self

A load test must contain one or more Scenarios be registered into Goose’s global state with this method for it to run.

Example
use goose::prelude::*;

#[tokio::main]
async fn main() -> Result<(), GooseError> {
    GooseAttack::initialize()?
        .register_scenario(scenario!("ExampleScenario")
            .register_transaction(transaction!(example_transaction))
        )
        .register_scenario(scenario!("OtherScenario")
            .register_transaction(transaction!(other_transaction))
        );

    Ok(())
}

async fn example_transaction(user: &mut GooseUser) -> TransactionResult {
    let _goose = user.get("/foo").await?;

    Ok(())
}

async fn other_transaction(user: &mut GooseUser) -> TransactionResult {
    let _goose = user.get("/bar").await?;

    Ok(())
}
source

pub fn test_start(self, transaction: Transaction) -> Self

Optionally define a transaction to run before users are started and all transactions start running. This is would generally be used to set up anything required for the load test.

The GooseUser used to run the test_start transactions is not preserved and does not otherwise affect the subsequent GooseUsers that run the rest of the load test. For example, if the GooseUser logs in during test_start, subsequent GooseUser do not retain this session and are therefor not already logged in.

Example
use goose::prelude::*;

#[tokio::main]
async fn main() -> Result<(), GooseError> {
    GooseAttack::initialize()?
        .test_start(transaction!(setup));

    Ok(())
}

async fn setup(user: &mut GooseUser) -> TransactionResult {
    // do stuff to set up load test ...

    Ok(())
}
source

pub fn test_stop(self, transaction: Transaction) -> Self

Optionally define a transaction to run after all users have finished running all defined transactions. This would generally be used to clean up anything that was specifically set up for the load test.

Example
use goose::prelude::*;

#[tokio::main]
async fn main() -> Result<(), GooseError> {
    GooseAttack::initialize()?
        .test_stop(transaction!(teardown));

    Ok(())
}

async fn teardown(user: &mut GooseUser) -> TransactionResult {
    // do stuff to tear down the load test ...

    Ok(())
}
source

pub async fn execute(self) -> Result<GooseMetrics, GooseError>

Execute the GooseAttack load test.

Example
use goose::prelude::*;

#[tokio::main]
async fn main() -> Result<(), GooseError> {
    let _goose_metrics = GooseAttack::initialize()?
        .register_scenario(scenario!("ExampleTransaction")
            .register_transaction(transaction!(example_transaction).set_weight(2)?)
            .register_transaction(transaction!(another_example_transaction).set_weight(3)?)
            // Goose must run against a host, point to localhost so test starts.
            .set_host("http://localhost")
        )
        // Exit after one second so test doesn't run forever.
        .set_default(GooseDefault::RunTime, 1)?
        .execute()
        .await?;

    Ok(())
}

async fn example_transaction(user: &mut GooseUser) -> TransactionResult {
    let _goose = user.get("/foo").await?;

    Ok(())
}

async fn another_example_transaction(user: &mut GooseUser) -> TransactionResult {
    let _goose = user.get("/bar").await?;

    Ok(())
}

Trait Implementations§

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> Downcast for Twhere T: Any,

source§

fn into_any(self: Box<T, Global>) -> Box<dyn Any, Global>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
source§

fn into_any_rc(self: Rc<T, Global>) -> Rc<dyn Any, Global>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
source§

impl<T> DowncastSync for Twhere T: Any + Send + Sync,

source§

fn into_any_arc(self: Arc<T, Global>) -> Arc<dyn Any + Send + Sync, Global>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

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

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

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

§

fn vzip(self) -> V

source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

impl<T> GooseUserData for Twhere T: Send + Sync + 'static,