Skip to content

Commit

Permalink
Merge pull request #358 from finnefloyd/task-wait
Browse files Browse the repository at this point in the history
Allow to set duration instead of seconds for task wait configuration
  • Loading branch information
jeremyandrews authored Sep 2, 2021
2 parents 1f81d47 + 8612e6e commit 3d31a02
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 148 deletions.
4 changes: 3 additions & 1 deletion examples/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
//! See the License for the specific language governing permissions and
//! limitations under the License.

use std::time::Duration;

use goose::prelude::*;

fn main() -> Result<(), GooseError> {
Expand All @@ -25,7 +27,7 @@ fn main() -> Result<(), GooseError> {
.register_taskset(
taskset!("WebsiteUser")
// After each task runs, sleep randomly from 5 to 15 seconds.
.set_wait_time(5, 15)?
.set_wait_time(Duration::from_secs(5), Duration::from_secs(15))?
// This task only runs one time when the user first starts.
.register_task(task!(website_login).set_on_start())
// These next two tasks run repeatedly as long as the load test is running.
Expand Down
3 changes: 2 additions & 1 deletion examples/simple_closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ use goose::prelude::*;

use std::boxed::Box;
use std::sync::Arc;
use std::time::Duration;

fn main() -> Result<(), GooseError> {
let mut taskset = taskset!("WebsiteUser")
// After each task runs, sleep randomly from 5 to 15 seconds.
.set_wait_time(5, 15)?;
.set_wait_time(Duration::from_secs(5), Duration::from_secs(15))?;

let paths = vec!["/", "/about", "/our-team"];
for request_path in paths {
Expand Down
4 changes: 3 additions & 1 deletion examples/simple_with_session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
//! See the License for the specific language governing permissions and
//! limitations under the License.

use std::time::Duration;

use goose::prelude::*;
use serde::Deserialize;

Expand All @@ -36,7 +38,7 @@ fn main() -> Result<(), GooseError> {
.register_taskset(
taskset!("WebsiteUser")
// After each task runs, sleep randomly from 5 to 15 seconds.
.set_wait_time(5, 15)?
.set_wait_time(Duration::from_secs(5), Duration::from_secs(15))?
// This task only runs one time when the user first starts.
.register_task(task!(website_signup).set_on_start())
// These next two tasks run repeatedly as long as the load test is running.
Expand Down
8 changes: 5 additions & 3 deletions examples/umami/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ mod common;
mod english;
mod spanish;

use std::time::Duration;

use goose::prelude::*;

use crate::admin::*;
Expand All @@ -17,7 +19,7 @@ fn main() -> Result<(), GooseError> {
.register_taskset(
taskset!("Anonymous English user")
.set_weight(40)?
.set_wait_time(0, 3)?
.set_wait_time(Duration::from_secs(0), Duration::from_secs(3))?
.register_task(task!(front_page_en).set_name("anon /").set_weight(2)?)
.register_task(task!(basic_page_en).set_name("anon /en/basicpage"))
.register_task(task!(article_listing_en).set_name("anon /en/articles/"))
Expand All @@ -44,7 +46,7 @@ fn main() -> Result<(), GooseError> {
.register_taskset(
taskset!("Anonymous Spanish user")
.set_weight(9)?
.set_wait_time(0, 3)?
.set_wait_time(Duration::from_secs(0), Duration::from_secs(3))?
.register_task(task!(front_page_es).set_name("anon /es/").set_weight(2)?)
.register_task(task!(basic_page_es).set_name("anon /es/basicpage"))
.register_task(task!(article_listing_es).set_name("anon /es/articles/"))
Expand All @@ -70,7 +72,7 @@ fn main() -> Result<(), GooseError> {
.register_taskset(
taskset!("Admin user")
.set_weight(1)?
.set_wait_time(3, 10)?
.set_wait_time(Duration::from_secs(0), Duration::from_secs(3))?
.register_task(task!(log_in).set_on_start().set_name("auth /en/user/login"))
.register_task(task!(front_page_en).set_name("auth /").set_weight(2)?)
.register_task(task!(article_listing_en).set_name("auth /en/articles/"))
Expand Down
111 changes: 48 additions & 63 deletions src/goose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,18 @@
//!
//! ### 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
//! Wait time is specified as a low-high duration range. Each time a task completes in
//! the task set, the user will pause for a random number of milliseconds 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.
//!
//! ```rust
//! use goose::prelude::*;
//! use std::time::Duration;
//!
//! let mut foo_tasks = taskset!("FooTasks").set_wait_time(0, 3).unwrap();
//! let mut bar_tasks = taskset!("BarTasks").set_wait_time(5, 10).unwrap();
//! let mut foo_tasks = taskset!("FooTasks").set_wait_time(Duration::from_secs(0), Duration::from_secs(3)).unwrap();
//! let mut bar_tasks = taskset!("BarTasks").set_wait_time(Duration::from_secs(5), Duration::from_secs(10)).unwrap();
//! ```
//! ## Creating Tasks
//!
Expand Down Expand Up @@ -290,6 +291,7 @@ use reqwest::{header, Client, ClientBuilder, RequestBuilder, Response};
use serde::{Deserialize, Serialize};
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use std::time::Duration;
use std::{fmt, str};
use std::{future::Future, pin::Pin, time::Instant};
use tokio::sync::RwLock;
Expand Down Expand Up @@ -468,10 +470,8 @@ pub struct GooseTaskSet {
pub task_sets_index: usize,
/// An integer value that controls the frequency that this task set will be assigned to a user.
pub weight: usize,
/// An integer value indicating the minimum number of seconds a user will sleep after running a task.
pub min_wait: usize,
/// An integer value indicating the maximum number of seconds a user will sleep after running a task.
pub max_wait: usize,
/// An range of duration indicating the interval a user will sleep after running a task.
pub task_wait: Option<(Duration, Duration)>,
/// A vector containing one copy of each [`GooseTask`](./struct.GooseTask.html) that will
/// run by users running this task set.
pub tasks: Vec<GooseTask>,
Expand Down Expand Up @@ -507,8 +507,7 @@ impl GooseTaskSet {
name: name.to_string(),
task_sets_index: usize::max_value(),
weight: 1,
min_wait: 0,
max_wait: 0,
task_wait: None,
tasks: Vec::new(),
weighted_tasks: Vec::new(),
weighted_on_start_tasks: Vec::new(),
Expand Down Expand Up @@ -589,26 +588,31 @@ impl GooseTaskSet {
self
}

/// Configure a task_set to to pause after running each task. The length of the pause will be randomly
/// selected from `min_weight` to `max_wait` inclusively. For example, if `min_wait` is `0` and
/// `max_weight` is `2`, the user will randomly sleep for 0, 1 or 2 seconds after each task completes.
/// Configure a duration per task_set to pause after running each task. The length of the pause will be randomly
/// selected from `min_wait` to `max_wait` inclusively. For example, if `min_wait` is `Duration::from_secs(0)` and
/// `max_wait` is `Duration::from_secs(2)`, the user will randomly sleep between 0 and 2_000 milliseconds after each task completes.
///
/// # Example
/// ```rust
/// use goose::prelude::*;
/// use std::time::Duration;
///
/// fn main() -> Result<(), GooseError> {
/// taskset!("ExampleTasks").set_wait_time(0, 1)?;
/// taskset!("ExampleTasks").set_wait_time(Duration::from_secs(0), Duration::from_secs(1))?;
///
/// Ok(())
/// }
/// ```
pub fn set_wait_time(mut self, min_wait: usize, max_wait: usize) -> Result<Self, GooseError> {
pub fn set_wait_time(
mut self,
min_wait: Duration,
max_wait: Duration,
) -> Result<Self, GooseError> {
trace!(
"{} set_wait time: min: {} max: {}",
"{} set_wait time: min: {}ms max: {}ms",
self.name,
min_wait,
max_wait
min_wait.as_millis(),
max_wait.as_millis()
);
if min_wait > max_wait {
return Err(GooseError::InvalidWaitTime {
Expand All @@ -619,8 +623,7 @@ impl GooseTaskSet {
.to_string(),
});
}
self.min_wait = min_wait;
self.max_wait = max_wait;
self.task_wait.replace((min_wait, max_wait));

Ok(self)
}
Expand Down Expand Up @@ -734,10 +737,6 @@ pub struct GaggleUser {
pub task_sets_index: usize,
/// The base URL to prepend to all relative paths.
pub base_url: Arc<RwLock<Url>>,
/// Minimum amount of time to sleep after running a task.
pub min_wait: usize,
/// Maximum amount of time to sleep after running a task.
pub max_wait: usize,
/// A local copy of the global GooseConfiguration.
pub config: GooseConfiguration,
/// Load test hash.
Expand All @@ -748,17 +747,13 @@ impl GaggleUser {
pub fn new(
task_sets_index: usize,
base_url: Url,
min_wait: usize,
max_wait: usize,
configuration: &GooseConfiguration,
load_test_hash: u64,
) -> Self {
trace!("new gaggle user");
GaggleUser {
task_sets_index,
base_url: Arc::new(RwLock::new(base_url)),
min_wait,
max_wait,
config: configuration.clone(),
load_test_hash,
}
Expand Down Expand Up @@ -832,10 +827,6 @@ pub struct GooseUser {
pub client: Client,
/// The base URL to prepend to all relative paths.
pub base_url: Url,
/// Minimum amount of time to sleep after running a task.
pub min_wait: usize,
/// Maximum amount of time to sleep after running a task.
pub max_wait: usize,
/// A local copy of the global [`GooseConfiguration`](../struct.GooseConfiguration.html).
pub config: GooseConfiguration,
/// Channel to logger.
Expand Down Expand Up @@ -868,8 +859,6 @@ impl GooseUser {
pub fn new(
task_sets_index: usize,
base_url: Url,
min_wait: usize,
max_wait: usize,
configuration: &GooseConfiguration,
load_test_hash: u64,
) -> Result<Self, GooseError> {
Expand All @@ -886,8 +875,6 @@ impl GooseUser {
task_sets_index,
client,
base_url,
min_wait,
max_wait,
config: configuration.clone(),
logger: None,
throttle: None,
Expand All @@ -905,7 +892,7 @@ impl GooseUser {

/// Create a new single-use user.
pub fn single(base_url: Url, configuration: &GooseConfiguration) -> Result<Self, GooseError> {
let mut single_user = GooseUser::new(0, base_url, 0, 0, configuration, 0)?;
let mut single_user = GooseUser::new(0, base_url, configuration, 0)?;
// Only one user, so index is 0.
single_user.weighted_users_index = 0;
// Do not throttle [`test_start`](../struct.GooseAttack.html#method.test_start) (setup) and
Expand Down Expand Up @@ -2233,12 +2220,13 @@ impl GooseUser {
/// # Example
/// ```rust
/// use goose::prelude::*;
/// use std::time::Duration;
///
/// fn main() -> Result<(), GooseError> {
/// let _goose_metrics = GooseAttack::initialize()?
/// .register_taskset(taskset!("LoadtestTasks")
/// .set_host("http://foo.example.com/")
/// .set_wait_time(0, 3)?
/// .set_wait_time(Duration::from_secs(0), Duration::from_secs(3))?
/// .register_task(task!(task_foo).set_weight(10)?)
/// .register_task(task!(task_bar))
/// )
Expand Down Expand Up @@ -2619,8 +2607,7 @@ mod tests {
assert_eq!(task_set.name, "foo");
assert_eq!(task_set.task_sets_index, usize::max_value());
assert_eq!(task_set.weight, 1);
assert_eq!(task_set.min_wait, 0);
assert_eq!(task_set.max_wait, 0);
assert_eq!(task_set.task_wait, None);
assert!(task_set.host.is_none());
assert_eq!(task_set.tasks.len(), 0);
assert_eq!(task_set.weighted_tasks.len(), 0);
Expand All @@ -2633,8 +2620,7 @@ mod tests {
assert_eq!(task_set.weighted_tasks.len(), 0);
assert_eq!(task_set.task_sets_index, usize::max_value());
assert_eq!(task_set.weight, 1);
assert_eq!(task_set.min_wait, 0);
assert_eq!(task_set.max_wait, 0);
assert_eq!(task_set.task_wait, None);
assert!(task_set.host.is_none());

// Different task can be registered.
Expand All @@ -2643,8 +2629,7 @@ mod tests {
assert_eq!(task_set.weighted_tasks.len(), 0);
assert_eq!(task_set.task_sets_index, usize::max_value());
assert_eq!(task_set.weight, 1);
assert_eq!(task_set.min_wait, 0);
assert_eq!(task_set.max_wait, 0);
assert_eq!(task_set.task_wait, None);
assert!(task_set.host.is_none());

// Same task can be registered again.
Expand All @@ -2653,8 +2638,7 @@ mod tests {
assert_eq!(task_set.weighted_tasks.len(), 0);
assert_eq!(task_set.task_sets_index, usize::max_value());
assert_eq!(task_set.weight, 1);
assert_eq!(task_set.min_wait, 0);
assert_eq!(task_set.max_wait, 0);
assert_eq!(task_set.task_wait, None);
assert!(task_set.host.is_none());

// Setting weight only affects weight field.
Expand All @@ -2663,8 +2647,7 @@ mod tests {
assert_eq!(task_set.tasks.len(), 3);
assert_eq!(task_set.weighted_tasks.len(), 0);
assert_eq!(task_set.task_sets_index, usize::max_value());
assert_eq!(task_set.min_wait, 0);
assert_eq!(task_set.max_wait, 0);
assert_eq!(task_set.task_wait, None);
assert!(task_set.host.is_none());

// Weight can be changed.
Expand All @@ -2678,27 +2661,33 @@ mod tests {
assert_eq!(task_set.tasks.len(), 3);
assert_eq!(task_set.weighted_tasks.len(), 0);
assert_eq!(task_set.task_sets_index, usize::max_value());
assert_eq!(task_set.min_wait, 0);
assert_eq!(task_set.max_wait, 0);

// Host field can be changed.
task_set = task_set.set_host("https://bar.example.com/");
assert_eq!(task_set.host, Some("https://bar.example.com/".to_string()));

// Wait time only affects wait time fields.
task_set = task_set.set_wait_time(1, 10).unwrap();
assert_eq!(task_set.min_wait, 1);
assert_eq!(task_set.max_wait, 10);
task_set = task_set
.set_wait_time(Duration::from_secs(1), Duration::from_secs(10))
.unwrap();
assert_eq!(
task_set.task_wait,
Some((Duration::from_secs(1), Duration::from_secs(10)))
);
assert_eq!(task_set.host, Some("https://bar.example.com/".to_string()));
assert_eq!(task_set.weight, 5);
assert_eq!(task_set.tasks.len(), 3);
assert_eq!(task_set.weighted_tasks.len(), 0);
assert_eq!(task_set.task_sets_index, usize::max_value());

// Wait time can be changed.
task_set = task_set.set_wait_time(3, 9).unwrap();
assert_eq!(task_set.min_wait, 3);
assert_eq!(task_set.max_wait, 9);
task_set = task_set
.set_wait_time(Duration::from_secs(3), Duration::from_secs(9))
.unwrap();
assert_eq!(
task_set.task_wait,
Some((Duration::from_secs(3), Duration::from_secs(9)))
);
}

#[test]
Expand Down Expand Up @@ -2786,10 +2775,8 @@ mod tests {
const HOST: &str = "http://example.com/";
let configuration = GooseConfiguration::parse_args_default(&EMPTY_ARGS).unwrap();
let base_url = get_base_url(Some(HOST.to_string()), None, None).unwrap();
let user = GooseUser::new(0, base_url, 0, 0, &configuration, 0).unwrap();
let user = GooseUser::new(0, base_url, &configuration, 0).unwrap();
assert_eq!(user.task_sets_index, 0);
assert_eq!(user.min_wait, 0);
assert_eq!(user.max_wait, 0);
assert_eq!(user.weighted_users_index, usize::max_value());

// Confirm the URLs are correctly built using the default_host.
Expand All @@ -2815,9 +2802,7 @@ mod tests {
Some("http://www.example.com/".to_string()),
)
.unwrap();
let user2 = GooseUser::new(0, base_url, 1, 3, &configuration, 0).unwrap();
assert_eq!(user2.min_wait, 1);
assert_eq!(user2.max_wait, 3);
let user2 = GooseUser::new(0, base_url, &configuration, 0).unwrap();

// Confirm the URLs are correctly built using the task_set_host.
let url = user2.build_url("/foo").unwrap();
Expand Down Expand Up @@ -2876,7 +2861,7 @@ mod tests {
// Confirm Goose can build a base_url that includes a path.
const HOST_WITH_PATH: &str = "http://example.com/with/path/";
let base_url = get_base_url(Some(HOST_WITH_PATH.to_string()), None, None).unwrap();
let user = GooseUser::new(0, base_url, 0, 0, &configuration, 0).unwrap();
let user = GooseUser::new(0, base_url, &configuration, 0).unwrap();

// Confirm the URLs are correctly built using the default_host that includes a path.
let url = user.build_url("foo").unwrap();
Expand Down
Loading

0 comments on commit 3d31a02

Please sign in to comment.