use gumdrop::Options;
use httpmock::{Method::GET, MockServer};
use goose::config::GooseConfiguration;
use goose::prelude::*;
const PATH: &str = "/one";
const HTML: &str = r#"
<!DOCTYPE html>
<head>
<title>Title 1234ABCD</title>
</head>
<body>
<p>Test text on the page.</p>
</body>
"#;
pub async fn get_path_valid(user: &mut GooseUser) -> TransactionResult {
let goose = user.get(PATH).await?;
goose_eggs::validate_and_load_static_assets(
user,
goose,
&goose_eggs::Validate::builder()
.title("1234ABCD")
.not_title("Example")
.text("Test text")
.text("<!DOCTYPE html>")
.not_text("<!DocType html>")
.header_value("foo", "bar")
.not_header("bar")
.build(),
)
.await?;
Ok(())
}
fn build_configuration(server: &MockServer) -> GooseConfiguration {
let server_url = server.base_url();
let configuration = vec![
"--users",
"1",
"--hatch-rate",
"4",
"--iterations",
"1",
"--host",
&server_url,
"--co-mitigation",
"disabled",
"--quiet",
];
GooseConfiguration::parse_args_default(&configuration)
.expect("failed to parse options and generate a configuration")
}
async fn run_load_test(server: &MockServer) -> GooseMetrics {
let goose_metrics = build_load_test(
build_configuration(server),
vec![scenario!("LoadTest").register_transaction(transaction!(get_path_valid))],
None,
None,
)
.execute()
.await
.unwrap();
assert!(goose_metrics.total_users == 1);
if goose_metrics.requests.len() != 1 {
println!("EXPECTED ONE REQUEST: {:#?}", goose_metrics.requests);
}
assert!(goose_metrics.requests.len() == 1);
goose_metrics
}
#[allow(dead_code)]
pub fn build_load_test(
configuration: GooseConfiguration,
scenarios: Vec<Scenario>,
start_transaction: Option<&Transaction>,
stop_transaction: Option<&Transaction>,
) -> GooseAttack {
let mut goose = crate::GooseAttack::initialize_with_config(configuration).unwrap();
for scenario in scenarios {
goose = goose.register_scenario(scenario.clone());
}
if let Some(transaction) = start_transaction {
goose = goose.test_start(transaction.clone());
}
if let Some(transaction) = stop_transaction {
goose = goose.test_stop(transaction.clone());
}
goose
}
#[tokio::test]
async fn test_valid() {
let server = MockServer::start();
let mock_endpoint =
server.mock(|when, then| {
when.method(GET).path(PATH);
then.status(200)
.header("foo", "bar")
.body(HTML);
});
let goose_metrics = run_load_test(&server).await;
assert!(mock_endpoint.hits() == 1);
if !goose_metrics.errors.is_empty() {
println!("UNEXPECTED ERRORS: {:#?}", goose_metrics.errors);
}
assert!(goose_metrics.errors.is_empty());
}
#[tokio::test]
async fn test_invalid_status() {
let server = MockServer::start();
let mock_endpoint =
server.mock(|when, then| {
when.method(GET).path(PATH);
then.status(404)
.header("foo", "bar")
.body(HTML);
});
let goose_metrics = run_load_test(&server).await;
assert!(mock_endpoint.hits() == 1);
if goose_metrics.errors.len() != 1 {
println!("EXPECTED ONE ERRORS: {:#?}", goose_metrics.errors);
}
assert!(goose_metrics.errors.len() == 1);
}
#[tokio::test]
async fn test_invalid_header() {
let server = MockServer::start();
let mock_endpoint =
server.mock(|when, then| {
when.method(GET).path(PATH);
then.status(200)
.header("bar", "foo")
.body(HTML);
});
let goose_metrics = run_load_test(&server).await;
assert!(mock_endpoint.hits() == 1);
if goose_metrics.errors.len() != 1 {
println!("EXPECTED ONE ERRORS: {:#?}", goose_metrics.errors);
}
assert!(goose_metrics.errors.len() == 1);
}
#[tokio::test]
async fn test_invalid_header_value() {
let server = MockServer::start();
let mock_endpoint =
server.mock(|when, then| {
when.method(GET).path(PATH);
then.status(200)
.header("foo", "invalid")
.body(HTML);
});
let goose_metrics = run_load_test(&server).await;
assert!(mock_endpoint.hits() == 1);
if goose_metrics.errors.len() != 1 {
println!("EXPECTED ONE ERRORS: {:#?}", goose_metrics.errors);
}
assert!(goose_metrics.errors.len() == 1);
}