From 509293c12398443ffd113b3c524643774762b0db Mon Sep 17 00:00:00 2001 From: Jeremy Andrews Date: Wed, 20 Dec 2023 11:19:27 +0100 Subject: [PATCH 1/6] test that per-user sessions are working --- CHANGELOG.md | 1 + tests/session.rs | 166 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 tests/session.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c3ac19a..064f9e69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - [#565](https://github.com/tag1consulting/goose/pull/565) add `--accept-invalid-certs` to skip validation of https certificates - [#568](https://github.com/tag1consulting/goose/pull/568) don't panic when truncating non utf-8 string - [#574](https://github.com/tag1consulting/goose/pull/574) update [`http`](https://docs.rs/http), [`itertools`](https://docs.rs/itertools) [`nix`](https://docs.rs/nix), [`rustls`](https://docs.rs/rustls/), and [`serial_test`](https://docs.rs/serial_test) + - [#575](https://github.com/tag1consulting/goose/pull/575) add test coverage for sessions ## 0.17.2 August 28, 2023 - [#557](https://github.com/tag1consulting/goose/pull/557) speed up user initialization on Linux diff --git a/tests/session.rs b/tests/session.rs new file mode 100644 index 00000000..ed790c09 --- /dev/null +++ b/tests/session.rs @@ -0,0 +1,166 @@ +use httpmock::{Method::GET, Method::POST, Mock, MockServer}; + +mod common; + +use goose::config::GooseConfiguration; +use goose::prelude::*; + +// In this test the SessionData is a simple String. +struct SessionData(String); + +// The actual session data that is set and later validated. +const SESSION_DATA: &str = "This is my session data."; + +// Paths used in load tests performed during these tests. +const SESSION_PATH: &str = "/session"; + +// Indexes to the above paths. +const POST_SESSION_KEY: usize = 0; +const GET_SESSION_KEY: usize = 1; + +// How many users to simulate, each with their own session. +const USERS: &str = "10"; + +// Test transaction. +pub async fn set_session_data(user: &mut GooseUser) -> TransactionResult { + // Confirm that we start with empty session data. + let session_data = user.get_session_data::(); + assert!(session_data.is_none()); + + // We don't really have to make a request here, but we can... + let _goose = user.post(SESSION_PATH, SESSION_DATA).await?; + + // Store data in the session, unique per user. + user.set_session_data(SessionData(format!( + "{}.{}", + SESSION_DATA, user.weighted_users_index + ))); + + // Confirm that we now have session data. + let session_data = user.get_session_data::(); + assert!(session_data.is_some()); + + Ok(()) +} + +// Test transaction. +pub async fn validate_session_data(user: &mut GooseUser) -> TransactionResult { + // We don't really have to make a request here, but we can... + let _goose = user.get(SESSION_PATH).await?; + + // Confirm that we now have session data. + let session_data = user.get_session_data::(); + assert!(session_data.is_some()); + + // Confirm tht the session data is valid. + if let Some(data) = session_data { + // Validate that session data is unique-per-user. + assert!(data.0 == format!("{}.{}", SESSION_DATA, user.weighted_users_index)); + } else { + panic!("no session data !?"); + } + + Ok(()) +} + +// All tests in this file run against common endpoints. +fn setup_mock_server_endpoints(server: &MockServer) -> Vec { + vec![ + // Set up SESSION_PATH, store in vector at POST_SESSION_KEY. + server.mock(|when, then| { + when.method(POST).path(SESSION_PATH); + then.status(200); + }), + // Set up SESSION_PATH, store in vector at GET_SESSION_KEY. + server.mock(|when, then| { + when.method(GET).path(SESSION_PATH); + then.status(200); + }), + ] +} + +// Build appropriate configuration for these tests. +fn common_build_configuration(server: &MockServer, custom: &mut Vec<&str>) -> GooseConfiguration { + // Common elements in all our tests. + let mut configuration = vec!["--users", USERS, "--hatch-rate", USERS, "--run-time", "2"]; + + // Custom elements in some tests. + configuration.append(custom); + + // Return the resulting configuration. + common::build_configuration(server, configuration) +} + +// Helper to confirm all variations generate appropriate results. +fn validate_requests(goose_metrics: &GooseMetrics, mock_endpoints: &[Mock]) { + // Convert USERS to a usize. + let users = USERS.parse::().expect("usize"); + + // Confirm that we loaded the mock endpoints. + assert!(mock_endpoints[POST_SESSION_KEY].hits() == users); + assert!(mock_endpoints[GET_SESSION_KEY].hits() > users); + + // Extract the POST and GET requests out of goose metrics. + let post_metrics = goose_metrics + .requests + .get(&format!("POST {}", SESSION_PATH)) + .unwrap(); + let get_metrics = goose_metrics + .requests + .get(&format!("GET {}", SESSION_PATH)) + .unwrap(); + + // We POST and GET the same path. + assert!(post_metrics.path == get_metrics.path); + // We made POST requests. + assert!(post_metrics.method == GooseMethod::Post); + // We made GET requests. + assert!(get_metrics.method == GooseMethod::Get); + // We made only 1 POST request per user. + assert!(post_metrics.success_count == users); + // We made more than 1 GET request per user. + assert!(get_metrics.success_count > users); + // There were no POST errors. + assert!(post_metrics.fail_count == 0); + // There were no GET errors. + assert!(get_metrics.fail_count == 0); +} + +// Returns the appropriate scenario needed to build these tests. +fn get_transactions() -> Scenario { + scenario!("LoadTest") + // Set up the sesssion only one time + .register_transaction(transaction!(set_session_data).set_on_start()) + // Validate the session repeateldy. + .register_transaction(transaction!(validate_session_data)) +} + +// Helper to run all standalone tests. +async fn run_standalone_test() { + // Start the mock server. + let server = MockServer::start(); + + // Setup the endpoints needed for this test on the mock server. + let mock_endpoints = setup_mock_server_endpoints(&server); + + let mut configuration_flags = vec!["--no-reset-metrics"]; + + // Build common configuration elements. + let configuration = common_build_configuration(&server, &mut configuration_flags); + + // Run the Goose Attack. + let goose_metrics = common::run_load_test( + common::build_load_test(configuration.clone(), vec![get_transactions()], None, None), + None, + ) + .await; + + // Confirm that the load test ran correctly. + validate_requests(&goose_metrics, &mock_endpoints); +} + +#[tokio::test] +// Test a single scenario with multiple weighted transactions. +async fn test_session() { + run_standalone_test().await; +} From a587610bfc07c7070e2c388ee249934578cfc1f2 Mon Sep 17 00:00:00 2001 From: Jeremy Andrews Date: Tue, 19 Dec 2023 17:46:11 +0100 Subject: [PATCH 2/6] also test per-client cookies --- tests/session.rs | 259 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 222 insertions(+), 37 deletions(-) diff --git a/tests/session.rs b/tests/session.rs index ed790c09..22eae4d5 100644 --- a/tests/session.rs +++ b/tests/session.rs @@ -1,4 +1,5 @@ use httpmock::{Method::GET, Method::POST, Mock, MockServer}; +use reqwest::header; mod common; @@ -13,15 +14,36 @@ const SESSION_DATA: &str = "This is my session data."; // Paths used in load tests performed during these tests. const SESSION_PATH: &str = "/session"; +const COOKIE_PATH: &str = "/cookie"; -// Indexes to the above paths. +// Indexes to the above paths, used to validate tests. const POST_SESSION_KEY: usize = 0; const GET_SESSION_KEY: usize = 1; +const POST_COOKIE_KEY_0: usize = 2; +const GET_COOKIE_KEY_0: usize = 3; +const POST_COOKIE_KEY_1: usize = 4; +const GET_COOKIE_KEY_1: usize = 5; +const POST_COOKIE_KEY_2: usize = 6; +const GET_COOKIE_KEY_2: usize = 7; +const POST_COOKIE_KEY_3: usize = 8; +const GET_COOKIE_KEY_3: usize = 9; // How many users to simulate, each with their own session. -const USERS: &str = "10"; +const SESSION_USERS: &str = "10"; + +// How many users to simulate, each with their own cookie. +const COOKIE_USERS: &str = "4"; + +// There are multiple test variations in this file. +#[derive(Clone)] +enum TestType { + // Test sessions. + Session, + // Test cookies. + Cookie, +} -// Test transaction. +// Create a unqiue session per-user. pub async fn set_session_data(user: &mut GooseUser) -> TransactionResult { // Confirm that we start with empty session data. let session_data = user.get_session_data::(); @@ -43,7 +65,7 @@ pub async fn set_session_data(user: &mut GooseUser) -> TransactionResult { Ok(()) } -// Test transaction. +// Verify that the per-user session data is correct. pub async fn validate_session_data(user: &mut GooseUser) -> TransactionResult { // We don't really have to make a request here, but we can... let _goose = user.get(SESSION_PATH).await?; @@ -63,8 +85,52 @@ pub async fn validate_session_data(user: &mut GooseUser) -> TransactionResult { Ok(()) } +// Set a cookie that is unique per-user. +pub async fn set_cookie(user: &mut GooseUser) -> TransactionResult { + // Per-user cookie name. + let cookie_name = format!("TestCookie{}", user.weighted_users_index); + + // Per-user cookie path. + let cookie_path = format!("{}{}", COOKIE_PATH, user.weighted_users_index); + + // Set the Cookie. + let request_builder = user + .get_request_builder(&GooseMethod::Post, &cookie_path)? + .header("Cookie", format!("{}=foo", cookie_name)); + let goose_request = GooseRequest::builder() + .set_request_builder(request_builder) + .build(); + let goose = user.request(goose_request).await?; + //println!("headers: {:#?}", goose.response.expect("response").headers()); + let response = goose.response.expect("response"); + let cookie: reqwest::cookie::Cookie = response.cookies().next().expect("cookie should be set"); + assert!(cookie.name() == cookie_name); + + Ok(()) +} + +// Verify that the per-user cookie is correct. +pub async fn validate_cookie(user: &mut GooseUser) -> TransactionResult { + // Per-user cookie path. + let cookie_path = format!("{}{}", COOKIE_PATH, user.weighted_users_index); + + // Load COOKIE_PATH, the mock endpoint will validate that the proper Cookie is set. + // Each GooseUser launched has a unique user.weighted_users_index (from 0 to 3), + // and each user has a unique Cookie name which is TestCookie# where # is the index. + // Reqwest doesn't expose the cookie data it tracks, so we set up a per-user path + // and validate the cookie on the mock server side. A 200 will be returned if the + // correct cookie is passed in by the client. A 404 will be returned if not. + let _goose = user.get(&cookie_path).await?; + + Ok(()) +} + // All tests in this file run against common endpoints. fn setup_mock_server_endpoints(server: &MockServer) -> Vec { + let cookie_path_0 = format!("{}0", COOKIE_PATH); + let cookie_path_1 = format!("{}1", COOKIE_PATH); + let cookie_path_2 = format!("{}2", COOKIE_PATH); + let cookie_path_3 = format!("{}3", COOKIE_PATH); vec![ // Set up SESSION_PATH, store in vector at POST_SESSION_KEY. server.mock(|when, then| { @@ -76,13 +142,82 @@ fn setup_mock_server_endpoints(server: &MockServer) -> Vec { when.method(GET).path(SESSION_PATH); then.status(200); }), + // CookiePath0: TestCookie0=foo + server.mock(|when, then| { + when.method(POST).path(&cookie_path_0); + then.status(200) + .header(header::SET_COOKIE.as_str(), "TestCookie0=foo"); + }), + server.mock(|when, then| { + when.method(GET) + .path(cookie_path_0) + .cookie_exists("TestCookie0"); + then.status(200); + }), + // CookiePath1: TestCookie1=foo + server.mock(|when, then| { + when.method(POST).path(&cookie_path_1); + then.status(200) + .header(header::SET_COOKIE.as_str(), "TestCookie1=foo"); + }), + server.mock(|when, then| { + when.method(GET) + .path(cookie_path_1) + .cookie_exists("TestCookie1"); + then.status(200); + }), + // CookiePath2: TestCookie2=foo + server.mock(|when, then| { + when.method(POST).path(&cookie_path_2); + then.status(200) + .header(header::SET_COOKIE.as_str(), "TestCookie2=foo"); + }), + server.mock(|when, then| { + when.method(GET) + .path(cookie_path_2) + .cookie_exists("TestCookie2"); + then.status(200); + }), + // CookiePath3: TestCookie3=foo + server.mock(|when, then| { + when.method(POST).path(&cookie_path_3); + then.status(200) + .header(header::SET_COOKIE.as_str(), "TestCookie3=foo"); + }), + server.mock(|when, then| { + when.method(GET) + .path(cookie_path_3) + .cookie_exists("TestCookie3"); + then.status(200); + }), ] } // Build appropriate configuration for these tests. -fn common_build_configuration(server: &MockServer, custom: &mut Vec<&str>) -> GooseConfiguration { +fn common_build_configuration( + test_type: &TestType, + server: &MockServer, + custom: &mut Vec<&str>, +) -> GooseConfiguration { // Common elements in all our tests. - let mut configuration = vec!["--users", USERS, "--hatch-rate", USERS, "--run-time", "2"]; + let mut configuration = match test_type { + TestType::Session => vec![ + "--users", + SESSION_USERS, + "--hatch-rate", + SESSION_USERS, + "--run-time", + "2", + ], + TestType::Cookie => vec![ + "--users", + COOKIE_USERS, + "--hatch-rate", + COOKIE_USERS, + "--run-time", + "2", + ], + }; // Custom elements in some tests. configuration.append(custom); @@ -92,26 +227,46 @@ fn common_build_configuration(server: &MockServer, custom: &mut Vec<&str>) -> Go } // Helper to confirm all variations generate appropriate results. -fn validate_requests(goose_metrics: &GooseMetrics, mock_endpoints: &[Mock]) { +fn validate_requests(test_type: TestType, goose_metrics: &GooseMetrics, mock_endpoints: &[Mock]) { // Convert USERS to a usize. - let users = USERS.parse::().expect("usize"); - - // Confirm that we loaded the mock endpoints. - assert!(mock_endpoints[POST_SESSION_KEY].hits() == users); - assert!(mock_endpoints[GET_SESSION_KEY].hits() > users); - - // Extract the POST and GET requests out of goose metrics. - let post_metrics = goose_metrics - .requests - .get(&format!("POST {}", SESSION_PATH)) - .unwrap(); - let get_metrics = goose_metrics - .requests - .get(&format!("GET {}", SESSION_PATH)) - .unwrap(); - - // We POST and GET the same path. - assert!(post_metrics.path == get_metrics.path); + let users = match test_type { + TestType::Session => SESSION_USERS.parse::().expect("usize"), + TestType::Cookie => COOKIE_USERS.parse::().expect("usize"), + }; + + match test_type { + TestType::Session => { + // Confirm that each user set a session one and only one time. + assert!(mock_endpoints[POST_SESSION_KEY].hits() == users); + // Confirm that each user validated their session multiple times. + assert!(mock_endpoints[GET_SESSION_KEY].hits() > users); + } + TestType::Cookie => { + // Confirm that each user set a cookie one and only one time. + assert!(mock_endpoints[POST_COOKIE_KEY_0].hits() == 1); + assert!(mock_endpoints[POST_COOKIE_KEY_1].hits() == 1); + assert!(mock_endpoints[POST_COOKIE_KEY_2].hits() == 1); + assert!(mock_endpoints[POST_COOKIE_KEY_3].hits() == 1); + // Confirm that each user validated their cookie multiple times. + assert!(mock_endpoints[GET_COOKIE_KEY_0].hits() > 1); + assert!(mock_endpoints[GET_COOKIE_KEY_1].hits() > 1); + assert!(mock_endpoints[GET_COOKIE_KEY_2].hits() > 1); + assert!(mock_endpoints[GET_COOKIE_KEY_3].hits() > 1); + } + } + + // Extract the POST requests out of goose metrics. + let post_metrics = match test_type { + TestType::Session => goose_metrics.requests.get("POST create session").unwrap(), + TestType::Cookie => goose_metrics.requests.get("POST create cookie").unwrap(), + }; + + // Extract the GET requests out of goose metrics. + let get_metrics = match test_type { + TestType::Session => goose_metrics.requests.get("GET read session").unwrap(), + TestType::Cookie => goose_metrics.requests.get("GET read cookie").unwrap(), + }; + // We made POST requests. assert!(post_metrics.method == GooseMethod::Post); // We made GET requests. @@ -127,16 +282,35 @@ fn validate_requests(goose_metrics: &GooseMetrics, mock_endpoints: &[Mock]) { } // Returns the appropriate scenario needed to build these tests. -fn get_transactions() -> Scenario { - scenario!("LoadTest") - // Set up the sesssion only one time - .register_transaction(transaction!(set_session_data).set_on_start()) - // Validate the session repeateldy. - .register_transaction(transaction!(validate_session_data)) +fn get_scenarios(test_type: &TestType) -> Scenario { + match test_type { + TestType::Session => { + scenario!("Sessions") + // Set up the sesssion only one time + .register_transaction( + transaction!(set_session_data) + .set_on_start() + .set_name("create session"), + ) + // Validate the session repeateldy. + .register_transaction(transaction!(validate_session_data).set_name("read session")) + } + TestType::Cookie => { + scenario!("Cookie") + // Create the cookie only one time + .register_transaction( + transaction!(set_cookie) + .set_on_start() + .set_name("create cookie"), + ) + // Validate the cookie repeateldy. + .register_transaction(transaction!(validate_cookie).set_name("read cookie")) + } + } } // Helper to run all standalone tests. -async fn run_standalone_test() { +async fn run_standalone_test(test_type: TestType) { // Start the mock server. let server = MockServer::start(); @@ -146,21 +320,32 @@ async fn run_standalone_test() { let mut configuration_flags = vec!["--no-reset-metrics"]; // Build common configuration elements. - let configuration = common_build_configuration(&server, &mut configuration_flags); + let configuration = common_build_configuration(&test_type, &server, &mut configuration_flags); // Run the Goose Attack. let goose_metrics = common::run_load_test( - common::build_load_test(configuration.clone(), vec![get_transactions()], None, None), + common::build_load_test( + configuration.clone(), + vec![get_scenarios(&test_type)], + None, + None, + ), None, ) .await; // Confirm that the load test ran correctly. - validate_requests(&goose_metrics, &mock_endpoints); + validate_requests(test_type, &goose_metrics, &mock_endpoints); } #[tokio::test] -// Test a single scenario with multiple weighted transactions. +// Test to confirm sessions are unique per GooseUser and last their lifetime. async fn test_session() { - run_standalone_test().await; + run_standalone_test(TestType::Session).await; +} + +#[tokio::test] +// Test to confirm cookies are unique per GooseUser and last their lifetime. +async fn test_cookie() { + run_standalone_test(TestType::Cookie).await; } From 986440e86df1dac1cb2980f68b9367803cbca0cf Mon Sep 17 00:00:00 2001 From: Jeremy Andrews Date: Wed, 20 Dec 2023 11:18:30 +0100 Subject: [PATCH 3/6] be sure cookies aren't shared between users --- tests/session.rs | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/tests/session.rs b/tests/session.rs index 22eae4d5..0fb2bca7 100644 --- a/tests/session.rs +++ b/tests/session.rs @@ -148,6 +148,28 @@ fn setup_mock_server_endpoints(server: &MockServer) -> Vec { then.status(200) .header(header::SET_COOKIE.as_str(), "TestCookie0=foo"); }), + // Be sure TestCookie1 doesn't exist for user0. + server.mock(|when, then| { + when.method(GET) + .path(&cookie_path_1) + .cookie_exists("TestCookie1"); + then.status(500); + }), + // Be sure TestCookie2 doesn't exist for user0. + server.mock(|when, then| { + when.method(GET) + .path(&cookie_path_1) + .cookie_exists("TestCookie2"); + then.status(500); + }), + // Be sure TestCookie3 doesn't exist for user0. + server.mock(|when, then| { + when.method(GET) + .path(&cookie_path_1) + .cookie_exists("TestCookie3"); + then.status(500); + }), + // TestCookie0 should only exist for user0. server.mock(|when, then| { when.method(GET) .path(cookie_path_0) @@ -160,6 +182,28 @@ fn setup_mock_server_endpoints(server: &MockServer) -> Vec { then.status(200) .header(header::SET_COOKIE.as_str(), "TestCookie1=foo"); }), + // Be sure TestCookie0 doesn't exist for user1. + server.mock(|when, then| { + when.method(GET) + .path(&cookie_path_1) + .cookie_exists("TestCookie0"); + then.status(500); + }), + // Be sure TestCookie2 doesn't exist for user1. + server.mock(|when, then| { + when.method(GET) + .path(&cookie_path_1) + .cookie_exists("TestCookie2"); + then.status(500); + }), + // Be sure TestCookie3 doesn't exist for user1. + server.mock(|when, then| { + when.method(GET) + .path(&cookie_path_1) + .cookie_exists("TestCookie3"); + then.status(500); + }), + // TestCookie1 should only exist for user1. server.mock(|when, then| { when.method(GET) .path(cookie_path_1) @@ -172,6 +216,28 @@ fn setup_mock_server_endpoints(server: &MockServer) -> Vec { then.status(200) .header(header::SET_COOKIE.as_str(), "TestCookie2=foo"); }), + // Be sure TestCookie0 doesn't exist for user2. + server.mock(|when, then| { + when.method(GET) + .path(&cookie_path_2) + .cookie_exists("TestCookie0"); + then.status(500); + }), + // Be sure TestCookie1 doesn't exist for user2. + server.mock(|when, then| { + when.method(GET) + .path(&cookie_path_2) + .cookie_exists("TestCookie1"); + then.status(500); + }), + // Be sure TestCookie3 doesn't exist for user2. + server.mock(|when, then| { + when.method(GET) + .path(&cookie_path_2) + .cookie_exists("TestCookie3"); + then.status(500); + }), + // TestCookie2 should only exist for user0. server.mock(|when, then| { when.method(GET) .path(cookie_path_2) @@ -184,6 +250,28 @@ fn setup_mock_server_endpoints(server: &MockServer) -> Vec { then.status(200) .header(header::SET_COOKIE.as_str(), "TestCookie3=foo"); }), + // Be sure TestCookie0 doesn't exist for user3. + server.mock(|when, then| { + when.method(GET) + .path(&cookie_path_3) + .cookie_exists("TestCookie0"); + then.status(500); + }), + // Be sure TestCookie1 doesn't exist for user3. + server.mock(|when, then| { + when.method(GET) + .path(&cookie_path_3) + .cookie_exists("TestCookie1"); + then.status(500); + }), + // Be sure TestCookie2 doesn't exist for user3. + server.mock(|when, then| { + when.method(GET) + .path(&cookie_path_3) + .cookie_exists("TestCookie2"); + then.status(500); + }), + // TestCookie3 should only exist for user3. server.mock(|when, then| { when.method(GET) .path(cookie_path_3) From f76d73c5a17555a8f99df4e85de4e60922ebc912 Mon Sep 17 00:00:00 2001 From: Jeremy Andrews Date: Wed, 20 Dec 2023 13:09:18 +0100 Subject: [PATCH 4/6] back out startup optimization from #557 --- src/lib.rs | 3 +-- tests/session.rs | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0961e3a8..437655da 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -751,7 +751,6 @@ impl GooseAttack { self.test_plan.total_users() ); - let reqwest_client = goose::create_reqwest_client(&self.configuration)?; let mut weighted_users = Vec::new(); let mut user_count = 0; loop { @@ -772,7 +771,7 @@ impl GooseAttack { base_url, &self.configuration, self.metrics.hash, - Some(reqwest_client.clone()), + Some(goose::create_reqwest_client(&self.configuration)?), )?); user_count += 1; if user_count == total_users { diff --git a/tests/session.rs b/tests/session.rs index 0fb2bca7..ad03614a 100644 --- a/tests/session.rs +++ b/tests/session.rs @@ -20,13 +20,13 @@ const COOKIE_PATH: &str = "/cookie"; const POST_SESSION_KEY: usize = 0; const GET_SESSION_KEY: usize = 1; const POST_COOKIE_KEY_0: usize = 2; -const GET_COOKIE_KEY_0: usize = 3; -const POST_COOKIE_KEY_1: usize = 4; -const GET_COOKIE_KEY_1: usize = 5; -const POST_COOKIE_KEY_2: usize = 6; -const GET_COOKIE_KEY_2: usize = 7; -const POST_COOKIE_KEY_3: usize = 8; -const GET_COOKIE_KEY_3: usize = 9; +const GET_COOKIE_KEY_0: usize = 6; +const POST_COOKIE_KEY_1: usize = 7; +const GET_COOKIE_KEY_1: usize = 11; +const POST_COOKIE_KEY_2: usize = 12; +const GET_COOKIE_KEY_2: usize = 16; +const POST_COOKIE_KEY_3: usize = 17; +const GET_COOKIE_KEY_3: usize = 21; // How many users to simulate, each with their own session. const SESSION_USERS: &str = "10"; @@ -151,21 +151,21 @@ fn setup_mock_server_endpoints(server: &MockServer) -> Vec { // Be sure TestCookie1 doesn't exist for user0. server.mock(|when, then| { when.method(GET) - .path(&cookie_path_1) + .path(&cookie_path_0) .cookie_exists("TestCookie1"); then.status(500); }), // Be sure TestCookie2 doesn't exist for user0. server.mock(|when, then| { when.method(GET) - .path(&cookie_path_1) + .path(&cookie_path_0) .cookie_exists("TestCookie2"); then.status(500); }), // Be sure TestCookie3 doesn't exist for user0. server.mock(|when, then| { when.method(GET) - .path(&cookie_path_1) + .path(&cookie_path_0) .cookie_exists("TestCookie3"); then.status(500); }), From aaf9a6934a54e4f60f9afdb76d8fd6cc3b40b252 Mon Sep 17 00:00:00 2001 From: Jeremy Andrews Date: Wed, 20 Dec 2023 14:02:11 +0100 Subject: [PATCH 5/6] cleanup and document --- CHANGELOG.md | 2 +- tests/session.rs | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 064f9e69..b2a81835 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ - [#565](https://github.com/tag1consulting/goose/pull/565) add `--accept-invalid-certs` to skip validation of https certificates - [#568](https://github.com/tag1consulting/goose/pull/568) don't panic when truncating non utf-8 string - [#574](https://github.com/tag1consulting/goose/pull/574) update [`http`](https://docs.rs/http), [`itertools`](https://docs.rs/itertools) [`nix`](https://docs.rs/nix), [`rustls`](https://docs.rs/rustls/), and [`serial_test`](https://docs.rs/serial_test) - - [#575](https://github.com/tag1consulting/goose/pull/575) add test coverage for sessions + - [#575](https://github.com/tag1consulting/goose/pull/575) add test coverage for sessions and cookies, revert [#557](https://github.com/tag1consulting/goose/pull/557) to avoid sharing the CookieJar between all users ## 0.17.2 August 28, 2023 - [#557](https://github.com/tag1consulting/goose/pull/557) speed up user initialization on Linux diff --git a/tests/session.rs b/tests/session.rs index ad03614a..b0920684 100644 --- a/tests/session.rs +++ b/tests/session.rs @@ -16,7 +16,7 @@ const SESSION_DATA: &str = "This is my session data."; const SESSION_PATH: &str = "/session"; const COOKIE_PATH: &str = "/cookie"; -// Indexes to the above paths, used to validate tests. +// Indexes for valid requests of above paths, used to validate tests. const POST_SESSION_KEY: usize = 0; const GET_SESSION_KEY: usize = 1; const POST_COOKIE_KEY_0: usize = 2; @@ -101,9 +101,8 @@ pub async fn set_cookie(user: &mut GooseUser) -> TransactionResult { .set_request_builder(request_builder) .build(); let goose = user.request(goose_request).await?; - //println!("headers: {:#?}", goose.response.expect("response").headers()); - let response = goose.response.expect("response"); - let cookie: reqwest::cookie::Cookie = response.cookies().next().expect("cookie should be set"); + let response = goose.response.expect("there must be a response"); + let cookie: reqwest::cookie::Cookie = response.cookies().next().expect("cookie must be set"); assert!(cookie.name() == cookie_name); Ok(()) @@ -318,8 +317,8 @@ fn common_build_configuration( fn validate_requests(test_type: TestType, goose_metrics: &GooseMetrics, mock_endpoints: &[Mock]) { // Convert USERS to a usize. let users = match test_type { - TestType::Session => SESSION_USERS.parse::().expect("usize"), - TestType::Cookie => COOKIE_USERS.parse::().expect("usize"), + TestType::Session => SESSION_USERS.parse::().expect("must be a valid usize"), + TestType::Cookie => COOKIE_USERS.parse::().expect("must be a valid usize"), }; match test_type { From 31d88b577af8a66815237cb3537fb54dbdf5e350 Mon Sep 17 00:00:00 2001 From: Jeremy Andrews Date: Wed, 20 Dec 2023 14:05:25 +0100 Subject: [PATCH 6/6] fix formatting --- tests/session.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/session.rs b/tests/session.rs index b0920684..c7dc6d5a 100644 --- a/tests/session.rs +++ b/tests/session.rs @@ -317,8 +317,12 @@ fn common_build_configuration( fn validate_requests(test_type: TestType, goose_metrics: &GooseMetrics, mock_endpoints: &[Mock]) { // Convert USERS to a usize. let users = match test_type { - TestType::Session => SESSION_USERS.parse::().expect("must be a valid usize"), - TestType::Cookie => COOKIE_USERS.parse::().expect("must be a valid usize"), + TestType::Session => SESSION_USERS + .parse::() + .expect("must be a valid usize"), + TestType::Cookie => COOKIE_USERS + .parse::() + .expect("must be a valid usize"), }; match test_type {