use httpmock::{Method::GET, Mock, MockServer};
use serial_test::serial;
use std::sync::Mutex;
mod common;
use goose::prelude::*;
const ERROR_PATH: &str = "/error";
const HEADER_NAME: &str = "x-goose-test";
const HEADER_VALUE: &str = "639";
const EXPECTED_HEADERS: [&str; 2] = [
"(\"authorization\", Sensitive)",
"(\"x-goose-test\", \"639\")",
];
const EXPECTED_JSON: &str =
r#""headers":["(\"authorization\", Sensitive)","(\"x-goose-test\", \"639\")"]"#;
static CAPTURED_HEADERS: Mutex<Vec<Vec<String>>> = Mutex::new(Vec::new());
enum TestType {
NoLog,
Requests,
Debug,
Error,
}
pub async fn get_error_with_headers(user: &mut GooseUser) -> TransactionResult {
let request_builder = user
.get_request_builder(&GooseMethod::Get, ERROR_PATH)?
.bearer_auth("0123456789abcdef0123456789abcdef01234567")
.header(HEADER_NAME, HEADER_VALUE);
let goose_request = GooseRequest::builder()
.set_request_builder(request_builder)
.build();
let mut goose = user.request(goose_request).await?;
CAPTURED_HEADERS
.lock()
.unwrap()
.push(goose.request.raw.headers.clone());
if let Ok(r) = goose.response {
let headers = &r.headers().clone();
if !r.status().is_success() {
return user.set_failure(
"loaded /error and got non-200 message",
&mut goose.request,
Some(headers),
None,
);
}
}
Ok(())
}
fn setup_mock_server_endpoint(server: &MockServer) -> Mock<'_> {
server.mock(|when, then| {
when.method(GET).path(ERROR_PATH);
then.status(503);
})
}
async fn run_header_test(test_type: TestType) {
let log_file = match test_type {
TestType::NoLog => "",
TestType::Requests => "request-headers-request-log.json",
TestType::Debug => "request-headers-debug-log.json",
TestType::Error => "request-headers-error-log.json",
};
CAPTURED_HEADERS.lock().unwrap().clear();
let server = MockServer::start();
let mock_endpoint = setup_mock_server_endpoint(&server);
let mut configuration_flags = match test_type {
TestType::NoLog => vec![],
TestType::Requests => vec!["--request-log", log_file, "--request-format", "json"],
TestType::Debug => vec!["--debug-log", log_file, "--debug-format", "json"],
TestType::Error => vec!["--error-log", log_file, "--error-format", "json"],
};
configuration_flags.extend(vec![
"--users",
"1",
"--increase-rate",
"1",
"--run-time",
"1",
]);
let configuration = common::build_configuration(&server, configuration_flags);
common::run_load_test(
common::build_load_test(
configuration,
vec![scenario!("LoadTest").register_transaction(transaction!(get_error_with_headers))],
None,
None,
),
None,
)
.await;
assert!(mock_endpoint.calls() > 0);
let captured = CAPTURED_HEADERS.lock().unwrap().clone();
assert!(!captured.is_empty());
match test_type {
TestType::NoLog => {
for headers in &captured {
assert!(headers.is_empty(), "unexpected headers: {:?}", headers);
}
}
_ => {
for headers in &captured {
assert_eq!(headers, &EXPECTED_HEADERS);
}
let log = std::fs::read_to_string(log_file).unwrap();
assert!(!log.is_empty());
for line in log.lines() {
assert!(
line.contains(EXPECTED_JSON),
"log line missing headers: {}",
line
);
}
common::cleanup_files(vec![log_file]);
}
}
}
#[tokio::test]
#[serial]
async fn test_request_headers_no_log() {
run_header_test(TestType::NoLog).await;
}
#[tokio::test]
#[serial]
async fn test_request_headers_request_log() {
run_header_test(TestType::Requests).await;
}
#[tokio::test]
#[serial]
async fn test_request_headers_debug_log() {
run_header_test(TestType::Debug).await;
}
#[tokio::test]
#[serial]
async fn test_request_headers_error_log() {
run_header_test(TestType::Error).await;
}