Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple and variable speed Decrease attack phases #450

Merged
merged 7 commits into from
Apr 27, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
o don't allow `--test-plan` together with `--users`, `--startup-time`, `--hatch-rate`, `--run-time`, `--no-reset-metrics`, `--manager` and `--worker`
o internal `AttackPhase`s renamed: `Starting` -> `Increase`, `Running` -> `Maintain`, `Stopping` -> `Decrease`
- [#449](https://github.com/tag1consulting/goose/pull/449) **API change**: rename `GooseTaskSet` -> `Scenario`, `GooseTask` -> `Transaction`, `GooseTaskResult` -> `TransationResult`, `GooseTaskEror` -> `TransactionError`, `WeightedGooseTasks` -> `WeightedTransactions`, `GooseTaskFunction` -> `TransactionFunction`, `test_start_task` -> `test_start_transaction`, `test_stop_task` -> `test_stop_transaction`, `register_task` -> `register_transaction`, `task!` -> `transaction!`, `--no-task-metrics` -> `--no-transaction-metrics`, `GooseTaskError` -> `TransactionError`
- [#450](https://github.com/tag1consulting/goose/pull/450) add support for variable speed and multiple decrease AttackPhases

## 0.15.2 December 13, 2021
- [#391](https://github.com/tag1consulting/goose/pull/391) properly sleep for configured `set_wait_time()` walking regularly to exit quickly if the load test ends
Expand Down
2 changes: 1 addition & 1 deletion src/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1189,7 +1189,7 @@ impl GooseAttack {
{
self.metrics.history.push(TestPlanHistory::step(
TestPlanStepAction::Decreasing,
self.metrics.users,
goose_attack_run_state.active_users,
));
self.set_attack_phase(
goose_attack_run_state,
Expand Down
4 changes: 2 additions & 2 deletions src/goose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2494,10 +2494,10 @@ impl<'a> GooseRequestBuilder<'a> {
/// ```rust
/// use goose::prelude::*;
///
/// let mut a_task = transaction!(task_function);
/// let mut a_transaction = transaction!(transaction_function);
///
/// // Make a named request.
/// async fn task_function(user: &mut GooseUser) -> TransactionResult {
/// async fn transaction_function(user: &mut GooseUser) -> TransactionResult {
/// // Manually create a GooseRequestBuilder object.
/// let goose_request = GooseRequest::builder()
/// // Set a relative path to request.
Expand Down
483 changes: 281 additions & 202 deletions src/lib.rs

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,9 +321,11 @@ pub(crate) async fn manager_main(mut goose_attack: GooseAttack) -> GooseAttack {
* 1_000.0;
let maximum_hatched = hatch_rate * goose_attack.test_plan.steps[1].1 as f32;
if maximum_hatched < goose_attack.configuration.users.unwrap() as f32 {
goose_attack.metrics.users = maximum_hatched as usize;
goose_attack.metrics.maximum_users = maximum_hatched as usize;
goose_attack.metrics.total_users = maximum_hatched as usize;
} else {
goose_attack.metrics.users = goose_attack.configuration.users.unwrap();
goose_attack.metrics.maximum_users = goose_attack.configuration.users.unwrap();
goose_attack.metrics.total_users = goose_attack.configuration.users.unwrap();
}

// Worker control loop.
Expand Down
39 changes: 18 additions & 21 deletions src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -842,11 +842,13 @@ pub struct GooseMetrics {
pub history: Vec<TestPlanHistory>,
/// Total number of seconds the load test ran.
pub duration: usize,
/// Total number of users simulated during this load test.
/// Maximum number of users simulated during this load test.
///
/// This value may be smaller than what was configured at start time if the test
/// didn't run long enough for all configured users to start.
pub users: usize,
pub maximum_users: usize,
/// Total number of users simulated during this load test.
pub total_users: usize,
/// Tracks details about each request made during the load test.
///
/// Can be disabled with the `--no-metrics` run-time option, or with
Expand Down Expand Up @@ -2182,17 +2184,9 @@ impl Serialize for GooseMetrics {
{
let mut s = serializer.serialize_struct("GooseMetrics", 10)?;
s.serialize_field("hash", &self.hash)?;
// Convert started field to a unix timestamp.
/* @TODO: Fixme
let timestamp = if let Some(started) = self.started {
started.timestamp()
} else {
0
};
s.serialize_field("started", &timestamp)?;
*/
s.serialize_field("duration", &self.duration)?;
s.serialize_field("users", &self.users)?;
s.serialize_field("maximum_users", &self.maximum_users)?;
s.serialize_field("total_users", &self.total_users)?;
s.serialize_field("requests", &self.requests)?;
s.serialize_field("transactions", &self.transactions)?;
s.serialize_field("errors", &self.errors)?;
Expand Down Expand Up @@ -2364,8 +2358,8 @@ impl GooseAttack {
Ok(())
}

// When the [`GooseAttack`](./struct.GooseAttack.html) goes from the `Starting`
// phase to the `Running` phase, optionally flush metrics.
// When the [`GooseAttack`](./struct.GooseAttack.html) goes from the `Increasing`
// phase to the `Maintaining` phase, optionally flush metrics.
pub(crate) async fn reset_metrics(
&mut self,
goose_attack_run_state: &mut GooseAttackRunState,
Expand All @@ -2388,9 +2382,9 @@ impl GooseAttack {

if self.metrics.display_metrics {
// Users is required here so unwrap() is safe.
if self.metrics.users < users {
if goose_attack_run_state.active_users < users {
println!(
"{} of {} users hatched, timer expired, resetting metrics (disable with --no-reset-metrics).\n", self.metrics.users, users
"{} of {} users hatched, timer expired, resetting metrics (disable with --no-reset-metrics).\n", goose_attack_run_state.active_users, users
);
} else {
println!(
Expand All @@ -2405,16 +2399,19 @@ impl GooseAttack {
&self.configuration,
&self.defaults,
)?;
} else if self.metrics.users < users {
} else if goose_attack_run_state.active_users < users {
println!(
"{} of {} users hatched, timer expired.\n",
self.metrics.users, users
goose_attack_run_state.active_users, users
);
} else {
println!("All {} users hatched.\n", self.metrics.users);
println!(
"All {} users hatched.\n",
goose_attack_run_state.active_users
);
}
} else {
println!("{} users hatched.", self.metrics.users);
println!("{} users hatched.", goose_attack_run_state.active_users);
}

// Restart the timer now that all threads are launched.
Expand Down Expand Up @@ -2637,7 +2634,7 @@ impl GooseAttack {
let test_start_time = self.metrics.history.first().unwrap().timestamp;

// Prepare report summary variables.
let users = self.metrics.users.to_string();
let users = self.metrics.maximum_users.to_string();

let mut steps_overview = String::new();
for step in self.metrics.history.windows(2) {
Expand Down
15 changes: 9 additions & 6 deletions src/test_plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,18 @@ impl TestPlan {
}
}

// Determine the maximum number of users configured during the test plan.
pub(crate) fn max_users(&self) -> usize {
let mut max_users = 0;
// Determine the total number of users required by the test plan.
pub(crate) fn total_users(&self) -> usize {
let mut total_users: usize = 0;
let mut previous: usize = 0;
for step in &self.steps {
if step.0 > max_users {
max_users = step.0;
// Add to total_users every time there is an increase.
if step.0 > previous {
total_users += step.0 - previous;
}
previous = step.0
}
max_users
total_users
}
}

Expand Down
2 changes: 1 addition & 1 deletion tests/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ fn validate_closer_test(
assert!(difference >= -2 && difference <= 2);

// Verify that Goose started the correct number of users.
assert!(goose_metrics.users == configuration.users.unwrap());
assert!(goose_metrics.total_users == configuration.users.unwrap());
}

// Helper to run the test, takes a flag for indicating if running in standalone
Expand Down
2 changes: 1 addition & 1 deletion tests/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ fn validate_one_scenario(
assert!(about_metrics.fail_count == 0);

// Users were correctly configured through the controller.
assert!(goose_metrics.users == USERS);
assert!(goose_metrics.total_users == USERS);

// Host was not configured at start time.
assert!(configuration.host.is_empty());
Expand Down
16 changes: 8 additions & 8 deletions tests/defaults.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ const DEBUG_LOG: &str = "debug-test.log";
const LOG_FORMAT: GooseLogFormat = GooseLogFormat::Raw;
const THROTTLE_REQUESTS: usize = 10;
const EXPECT_WORKERS: usize = 2;
// Increase, Increase, Maintain, Increase, Decrease
const TEST_PLAN: &str = "4,1;8,1;12,1;12,1;14,1;0,0";
const TEST_PLAN_MAX_USERS: usize = 14;
const TEST_PLAN_RUN_TIME: usize = 5;
const TEST_PLAN_STEPS: usize = 6;
// Increase, Increase, Decrease, Increase, Maintain, Decrease, Decrease
const TEST_PLAN: &str = "4,1;8,1;4,2;10,2;10,1;4,1;0,1";
const TEST_PLAN_MAX_USERS: usize = 10;
const TEST_PLAN_RUN_TIME: usize = 8;
const TEST_PLAN_STEPS: usize = 7;

// There are multiple test variations in this file.
#[derive(Clone)]
Expand Down Expand Up @@ -134,7 +134,7 @@ fn validate_test(
match test_type {
TestType::NotTestPlan => {
// Verify that Goose started the correct number of users.
assert!(goose_metrics.users == USERS);
assert!(goose_metrics.total_users == USERS);

// Requests are made while GooseUsers are hatched, and then for run_time seconds.
// Verify that the test ran as long as it was supposed to.
Expand All @@ -153,7 +153,7 @@ fn validate_test(
max_users = step.users;
}
}
assert!(goose_metrics.users == max_users);
assert!(goose_metrics.maximum_users == max_users);
assert!(TEST_PLAN_MAX_USERS == max_users);

// Be sure there's history for all load test steps. Add +1 to include "shutdown".
Expand Down Expand Up @@ -730,6 +730,6 @@ async fn test_defaults_no_metrics() {
// Confirm that we did not track metrics.
assert!(goose_metrics.requests.is_empty());
assert!(goose_metrics.transactions.is_empty());
assert!(goose_metrics.users == USERS);
assert!(goose_metrics.total_users == USERS);
assert!(goose_metrics.duration == RUN_TIME);
}
2 changes: 1 addition & 1 deletion tests/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ fn validate_error(
assert!(a_404_metrics.success_count == 0);

// Verify that Goose started the correct number of users.
assert!(goose_metrics.users == configuration.users.unwrap());
assert!(goose_metrics.total_users == configuration.users.unwrap());
}

// Returns the appropriate scenario needed to build these tests.
Expand Down
2 changes: 1 addition & 1 deletion tests/one_taskset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ fn validate_one_scenario(
assert!(about_metrics.fail_count == 0);

// Verify that Goose started the correct number of users.
assert!(goose_metrics.users == configuration.users.unwrap());
assert!(goose_metrics.total_users == configuration.users.unwrap());
}

// Returns the appropriate scenario needed to build these tests.
Expand Down