use httpmock::{
Method::{GET, POST},
MockRef, MockServer,
};
use serial_test::serial;
mod common;
use goose::prelude::*;
use goose::GooseConfiguration;
const INDEX_PATH: &str = "/";
const SETUP_PATH: &str = "/setup";
const TEARDOWN_PATH: &str = "/teardown";
const INDEX_KEY: usize = 0;
const SETUP_KEY: usize = 1;
const TEARDOWN_KEY: usize = 2;
const EXPECT_WORKERS: usize = 2;
const USERS: &str = "4";
#[derive(Clone)]
enum TestType {
Start,
Stop,
StartAndStop,
}
pub async fn setup(user: &GooseUser) -> GooseTaskResult {
let _goose = user.post(SETUP_PATH, "setting up load test").await?;
Ok(())
}
pub async fn teardown(user: &GooseUser) -> GooseTaskResult {
let _goose = user
.post(TEARDOWN_PATH, "cleaning up after load test")
.await?;
Ok(())
}
pub async fn get_index(user: &GooseUser) -> GooseTaskResult {
let _goose = user.get(INDEX_PATH).await?;
Ok(())
}
fn setup_mock_server_endpoints(server: &MockServer) -> Vec<MockRef> {
vec![
server.mock(|when, then| {
when.method(GET).path(INDEX_PATH);
then.status(201);
}),
server.mock(|when, then| {
when.method(POST).path(SETUP_PATH);
then.status(205);
}),
server.mock(|when, then| {
when.method(POST).path(TEARDOWN_PATH);
then.status(200);
}),
]
}
fn common_build_configuration(
server: &MockServer,
worker: Option<bool>,
manager: Option<usize>,
) -> GooseConfiguration {
if let Some(expect_workers) = manager {
common::build_configuration(
&server,
vec![
"--manager",
"--expect-workers",
&expect_workers.to_string(),
"--users",
USERS,
"--hatch-rate",
USERS,
],
)
} else if worker.is_some() {
common::build_configuration(&server, vec!["--worker"])
} else {
common::build_configuration(&server, vec!["--users", USERS, "--hatch-rate", USERS])
}
}
fn validate_test(test_type: &TestType, mock_endpoints: &[MockRef]) {
assert!(mock_endpoints[INDEX_KEY].hits() > 0);
match test_type {
TestType::Start => {
mock_endpoints[SETUP_KEY].assert_hits(1);
mock_endpoints[TEARDOWN_KEY].assert_hits(0);
}
TestType::Stop => {
mock_endpoints[SETUP_KEY].assert_hits(0);
mock_endpoints[TEARDOWN_KEY].assert_hits(1);
}
TestType::StartAndStop => {
mock_endpoints[SETUP_KEY].assert_hits(1);
mock_endpoints[TEARDOWN_KEY].assert_hits(1);
}
}
}
fn build_goose_attack(test_type: &TestType, configuration: GooseConfiguration) -> GooseAttack {
let taskset = taskset!("LoadTest").register_task(task!(get_index).set_weight(9).unwrap());
let start_task = task!(setup);
let stop_task = task!(teardown);
match test_type {
TestType::Start => {
common::build_load_test(configuration, &taskset, Some(&start_task), None)
}
TestType::Stop => common::build_load_test(configuration, &taskset, None, Some(&stop_task)),
TestType::StartAndStop => {
common::build_load_test(configuration, &taskset, Some(&start_task), Some(&stop_task))
}
}
}
fn run_standalone_test(test_type: TestType) {
let server = MockServer::start();
let mock_endpoints = setup_mock_server_endpoints(&server);
let configuration = common_build_configuration(&server, None, None);
let goose_attack = build_goose_attack(&test_type, configuration);
common::run_load_test(goose_attack, None);
validate_test(&test_type, &mock_endpoints);
}
fn run_gaggle_test(test_type: TestType) {
let server = MockServer::start();
let mock_endpoints = setup_mock_server_endpoints(&server);
let worker_configuration = common_build_configuration(&server, Some(true), None);
let goose_attack = build_goose_attack(&test_type, worker_configuration);
let worker_handles = common::launch_gaggle_workers(goose_attack, EXPECT_WORKERS);
let manager_configuration = common_build_configuration(&server, None, Some(EXPECT_WORKERS));
let goose_attack = build_goose_attack(&test_type, manager_configuration);
common::run_load_test(goose_attack, Some(worker_handles));
validate_test(&test_type, &mock_endpoints);
}
#[test]
fn test_setup() {
run_standalone_test(TestType::Start);
}
#[test]
#[cfg_attr(not(feature = "gaggle"), ignore)]
#[serial]
fn test_setup_gaggle() {
run_gaggle_test(TestType::Start);
}
#[test]
fn test_teardown() {
run_standalone_test(TestType::Stop);
}
#[test]
#[cfg_attr(not(feature = "gaggle"), ignore)]
#[serial]
fn test_teardown_gaggle() {
run_gaggle_test(TestType::Stop);
}
#[test]
fn test_setup_teardown() {
run_standalone_test(TestType::StartAndStop);
}
#[test]
#[cfg_attr(not(feature = "gaggle"), ignore)]
#[serial]
fn test_setup_teardown_gaggle() {
run_gaggle_test(TestType::StartAndStop);
}