diff --git a/guide/src/cli.md b/guide/src/cli.md index 7c8b0eed..0617a09c 100644 --- a/guide/src/cli.md +++ b/guide/src/cli.md @@ -14,8 +14,11 @@ Commands: help Print this message or the help of the given subcommand(s) Options: - -h, --help Prints help information - -V, --version Prints version information + -h, --help Prints help information + -V, --version Prints version information + -l, --loggers Enable loggers defined in the config file + -d, --results-directory Directory to store logs (if enabled with --loggers) + -k, --skipBody Skips request and reponse body from output (try command) ``` As signified in the above help output, there are two subcommands `run` and `try`. @@ -69,6 +72,7 @@ Options: endpoint matching the filter is included in the test -l, --loggers Enable loggers defined in the config file -d, --results-directory Directory to store logs (if enabled with --loggers) + -k, --skipBody Skips request and reponse body from output (try command) -h, --help Prints help information ``` @@ -79,6 +83,8 @@ The `-i`, `--include` parameter allows the filtering of which endpoints are incl The `-l`, `--loggers` flag specifies that any loggers defined in the config file should be enabled. By default, during a try run, loggers are disabled. The `-d`, `--results-directory` parameter will store any log files (if the `--loggers` flag is used) in the specified directory. If the directory does not exist it is created. + +The `-k`, `--skipBody` parameter ensures that during a Try run, the request and response bodies aren't displayed. This can be particularly useful for debugging requests or responses when the body is not crucial for the debugging process.

In both the `run` and `try` subcommands a [config file](./config.md) is required. diff --git a/lib/config/src/configv2/endpoints.rs b/lib/config/src/configv2/endpoints.rs index 28cd264c..852a7ac3 100644 --- a/lib/config/src/configv2/endpoints.rs +++ b/lib/config/src/configv2/endpoints.rs @@ -81,10 +81,9 @@ impl Endpoint { .chain( self.body .as_ref() - .map_or(BTreeSet::new(), |b| b.get_required_providers()) - .into_iter(), + .map_or(BTreeSet::new(), |b| b.get_required_providers()), ) - .chain(self.url.get_required_providers().into_iter()) + .chain(self.url.get_required_providers()) // need to figure this out; removing it can mess up the peak load detection, // but with it, extra values can be taken from providers that are only used // in declare. @@ -220,8 +219,8 @@ impl EndPointBody { .flat_map(|(_, s)| { s.headers .iter() - .flat_map(|(_, h)| h.get_required_providers().into_iter()) - .chain(s.body.get_required_providers().into_iter()) + .flat_map(|(_, h)| h.get_required_providers()) + .chain(s.body.get_required_providers()) }) .collect(), } @@ -422,7 +421,9 @@ mod tests { } ); - let EndPointBody::::File(FileBody { path: file, .. }) = from_yaml("!file body.txt").unwrap() else { + let EndPointBody::::File(FileBody { path: file, .. }) = + from_yaml("!file body.txt").unwrap() + else { panic!("was not file variant") }; assert_eq!( @@ -443,8 +444,8 @@ mod tests { body: !str some text"#; let EndPointBody::::Multipart(multipart) = from_yaml(TEST).unwrap() else { - panic!("was not multipart variant") - }; + panic!("was not multipart variant") + }; assert_eq!(multipart.len(), 2); assert_eq!(multipart[0].0, "foo"); assert_eq!( diff --git a/lib/config/src/configv2/load_pattern.rs b/lib/config/src/configv2/load_pattern.rs index 93560b71..a846556b 100644 --- a/lib/config/src/configv2/load_pattern.rs +++ b/lib/config/src/configv2/load_pattern.rs @@ -138,7 +138,7 @@ impl From> for LoadPattern { over: Template::new_literal("1s".parse().unwrap()), }] .into_iter() - .chain(value.into_iter()) + .chain(value) .tuple_windows() .map(|(prev, curr)| match curr { // if `curr` has no `from` defined, take the `to` value of `prev` diff --git a/lib/config/src/configv2/providers.rs b/lib/config/src/configv2/providers.rs index ebcb18dc..4d4c01b8 100644 --- a/lib/config/src/configv2/providers.rs +++ b/lib/config/src/configv2/providers.rs @@ -181,11 +181,12 @@ mod tests { fn test_provider_type_response() { static TEST1: &str = "!response"; - let ProviderType::::Response( ResponseProvider { + let ProviderType::::Response(ResponseProvider { auto_return, buffer, unique, - }) = from_yaml(TEST1).unwrap() else { + }) = from_yaml(TEST1).unwrap() + else { panic!("was not response") }; assert_eq!(auto_return, None); @@ -203,7 +204,8 @@ mod tests { auto_return, buffer, unique, - }) = from_yaml(TEST2).unwrap() else { + }) = from_yaml(TEST2).unwrap() + else { panic!("was not response") }; assert_eq!(auto_return, Some(ProviderSend::Block)); diff --git a/lib/config/src/configv2/providers/file.rs b/lib/config/src/configv2/providers/file.rs index fb1ccbb4..346bb9c1 100644 --- a/lib/config/src/configv2/providers/file.rs +++ b/lib/config/src/configv2/providers/file.rs @@ -179,15 +179,18 @@ mod tests { fn test_file_read_format_csv() { // defaults let frf = from_yaml::("!csv").unwrap(); - let FileReadFormat::Csv ( - CsvParams {comment, + let FileReadFormat::Csv(CsvParams { + comment, delimiter, double_quote, escape, headers, terminator, quote, - }) = frf else { panic!("was not csv") }; + }) = frf + else { + panic!("was not csv") + }; assert_eq!(comment, None); assert_eq!(delimiter, None); assert_eq!(double_quote, true); @@ -210,7 +213,7 @@ mod tests { "##, ) .unwrap(); - let FileReadFormat::Csv (CsvParams{ + let FileReadFormat::Csv(CsvParams { comment, delimiter, double_quote, @@ -218,7 +221,10 @@ mod tests { headers, terminator, quote, - }) = frf else { panic!("was not csv") }; + }) = frf + else { + panic!("was not csv") + }; assert_eq!(comment, Some(CharByte(b'$'))); assert_eq!(delimiter, Some(CharByte(b';'))); assert_eq!(double_quote, false); @@ -245,7 +251,10 @@ mod tests { headers, terminator, quote, - }) = frf else { panic!("was not csv") }; + }) = frf + else { + panic!("was not csv") + }; assert_eq!(comment, None); assert_eq!(delimiter, None); assert_eq!(double_quote, true); @@ -351,7 +360,10 @@ format: !csv headers, terminator, quote, - }) = format else { panic!("was not csv") }; + }) = format + else { + panic!("was not csv") + }; assert_eq!(comment, None); assert_eq!(delimiter, None); assert_eq!(double_quote, true); diff --git a/lib/config/src/shared.rs b/lib/config/src/shared.rs index bc414014..85ffdc08 100644 --- a/lib/config/src/shared.rs +++ b/lib/config/src/shared.rs @@ -30,7 +30,8 @@ pub fn duration_from_string(dur: &str) -> Option { // unless a value greater then u64::MAX is used let [n, unit] = (1..=2) .map(|i| captures.get(i).expect("should have capture group").as_str()) - .collect::>()[..] else { + .collect::>()[..] + else { unreachable!() }; n.parse::().unwrap() @@ -60,10 +61,11 @@ pub(crate) fn get_hits_per(s: &str) -> Option<(f64, Per)> { let captures = REGEX.captures(s)?; // None of this should ever panic due to how the regex is formed. let [n, tag] = (1..=2) - .map(|i| captures.get(i).unwrap().as_str()) - .collect::>()[..] else { - unreachable!() - }; + .map(|i| captures.get(i).unwrap().as_str()) + .collect::>()[..] + else { + unreachable!() + }; let n: f64 = n.parse().unwrap(); Some(( diff --git a/src/bin/pewpew.rs b/src/bin/pewpew.rs index 1d0855db..a8083281 100644 --- a/src/bin/pewpew.rs +++ b/src/bin/pewpew.rs @@ -151,11 +151,15 @@ mod args { /// Directory to store logs (if enabled with --loggers) #[arg(short = 'd', long = "results-directory", value_name = "DIRECTORY")] results_dir: Option, + /// Skips request and reponse body from output + #[arg(short = 'k', long = "skipBody")] + skip_body_on: bool, } impl From for TryConfig { fn from(value: TryConfigTmp) -> Self { let loggers_on = value.loggers_on; + let skip_body_on = value.skip_body_on; let results_dir = value.results_dir.filter(|_| loggers_on); if let Some(d) = &results_dir { create_dir_all(d).unwrap(); @@ -168,6 +172,7 @@ mod args { filters: value.filters, file: value.file, format: value.format, + skip_body_on, } } } @@ -265,8 +270,9 @@ mod tests { let stats_regex = Regex::new(r"^stats-integration-\d+\.json$").unwrap(); let cli_config: ExecConfig = args::try_parse_from(["myprog", RUN_COMMAND, YAML_FILE]).unwrap(); - let ExecConfig::Run(run_config) = cli_config else { panic!("subcommand was not `run`") }; - + let ExecConfig::Run(run_config) = cli_config else { + panic!("subcommand was not `run`") + }; assert_eq!(run_config.config_file.to_str().unwrap(), YAML_FILE); assert!(matches!(run_config.output_format, RunOutputFormat::Human)); assert!(run_config.results_dir.is_none()); @@ -298,8 +304,9 @@ mod tests { YAML_FILE, ]) .unwrap(); - let ExecConfig::Run(run_config) = cli_config else { panic!() }; - + let ExecConfig::Run(run_config) = cli_config else { + panic!() + }; assert_eq!(run_config.config_file.to_str().unwrap(), YAML_FILE); assert!(matches!(run_config.output_format, RunOutputFormat::Json)); assert!(run_config.results_dir.is_some()); @@ -336,8 +343,9 @@ mod tests { YAML_FILE, ]) .unwrap(); - let ExecConfig::Run(run_config) = cli_config else { panic!() }; - + let ExecConfig::Run(run_config) = cli_config else { + panic!() + }; assert_eq!(run_config.config_file.to_str().unwrap(), YAML_FILE); assert!(matches!(run_config.output_format, RunOutputFormat::Json)); assert!(run_config.results_dir.is_some()); @@ -359,8 +367,9 @@ mod tests { fn cli_run_format_json() { let cli_config = args::try_parse_from(["myprog", RUN_COMMAND, "-f", "json", YAML_FILE]).unwrap(); - let ExecConfig::Run(run_config) = cli_config else { panic!() }; - + let ExecConfig::Run(run_config) = cli_config else { + panic!() + }; assert!(matches!(run_config.output_format, RunOutputFormat::Json)); assert!(!run_config.output_format.is_human()); } @@ -369,8 +378,9 @@ mod tests { fn cli_run_format_human() { let cli_config = args::try_parse_from(["myprog", RUN_COMMAND, "-f", "human", YAML_FILE]).unwrap(); - let ExecConfig::Run(run_config) = cli_config else { panic!() }; - + let ExecConfig::Run(run_config) = cli_config else { + panic!() + }; assert!(matches!(run_config.output_format, RunOutputFormat::Human)); assert!(run_config.output_format.is_human()); } @@ -387,8 +397,9 @@ mod tests { YAML_FILE, ]) .unwrap(); - let ExecConfig::Run(run_config) = cli_config else { panic!() }; - + let ExecConfig::Run(run_config) = cli_config else { + panic!() + }; assert_eq!(run_config.config_file.to_str().unwrap(), YAML_FILE); assert!(run_config.results_dir.is_some()); assert_eq!(run_config.results_dir.unwrap().to_str().unwrap(), TEST_DIR); @@ -401,13 +412,15 @@ mod tests { #[test] fn cli_try_simple() { let cli_config = args::try_parse_from(["myprog", TRY_COMMAND, YAML_FILE]).unwrap(); - let ExecConfig::Try(try_config) = cli_config else { panic!() }; - + let ExecConfig::Try(try_config) = cli_config else { + panic!() + }; assert_eq!(try_config.config_file.to_str().unwrap(), YAML_FILE); assert!(try_config.file.is_none()); assert!(try_config.filters.is_none()); assert!(matches!(try_config.format, TryRunFormat::Human)); assert!(!try_config.loggers_on); + assert!(!try_config.skip_body_on); assert!(try_config.results_dir.is_none()); } @@ -423,13 +436,15 @@ mod tests { "-i", "_id=0", "-l", + "-k", "-o", STATS_FILE, YAML_FILE, ]) .unwrap(); - let ExecConfig::Try(try_config) = cli_config else { panic!() }; - + let ExecConfig::Try(try_config) = cli_config else { + panic!() + }; assert_eq!(try_config.config_file.to_str().unwrap(), YAML_FILE); assert!(try_config.file.is_some()); assert_eq!(try_config.file.unwrap(), STATS_FILE); @@ -445,6 +460,7 @@ mod tests { } assert!(matches!(try_config.format, TryRunFormat::Json)); assert!(try_config.loggers_on); + assert!(try_config.skip_body_on); assert!(try_config.results_dir.is_some()); assert_eq!(try_config.results_dir.unwrap().to_str().unwrap(), TEST_DIR); } @@ -461,13 +477,15 @@ mod tests { "--include", "_id=0", "--loggers", + "--skipBody", "--file", STATS_FILE, YAML_FILE, ]) .unwrap(); - let ExecConfig::Try(try_config) = cli_config else { panic!() }; - + let ExecConfig::Try(try_config) = cli_config else { + panic!() + }; assert_eq!(try_config.config_file.to_str().unwrap(), YAML_FILE); assert!(try_config.file.is_some()); assert_eq!(try_config.file.unwrap(), STATS_FILE); @@ -483,6 +501,7 @@ mod tests { } assert!(matches!(try_config.format, TryRunFormat::Json)); assert!(try_config.loggers_on); + assert!(try_config.skip_body_on); assert!(try_config.results_dir.is_some()); assert_eq!(try_config.results_dir.unwrap().to_str().unwrap(), TEST_DIR); } @@ -501,8 +520,9 @@ mod tests { YAML_FILE2, ]) .unwrap(); - let ExecConfig::Try(try_config) = cli_config else { panic!() }; - + let ExecConfig::Try(try_config) = cli_config else { + panic!() + }; assert_eq!(try_config.config_file.to_str().unwrap(), YAML_FILE2); assert!(try_config.filters.is_some()); let filters = try_config.filters.unwrap(); @@ -535,8 +555,9 @@ mod tests { "_id=1", ]) .unwrap(); - let ExecConfig::Try(try_config) = cli_config else { panic!() }; - + let ExecConfig::Try(try_config) = cli_config else { + panic!() + }; assert_eq!(try_config.config_file.to_str().unwrap(), YAML_FILE2); assert!(try_config.filters.is_some()); let filters = try_config.filters.unwrap(); @@ -569,8 +590,9 @@ mod tests { YAML_FILE2, ]) .unwrap(); - let ExecConfig::Try(try_config) = cli_config else { panic!() }; - + let ExecConfig::Try(try_config) = cli_config else { + panic!() + }; assert_eq!(try_config.config_file.to_str().unwrap(), YAML_FILE2); assert!(try_config.filters.is_some()); let filters = try_config.filters.unwrap(); @@ -622,8 +644,9 @@ mod tests { let cli_config = args::try_parse_from(["myprog", TRY_COMMAND, "-f", "json", YAML_FILE]).unwrap(); - let ExecConfig::Try(try_config) = cli_config else { panic!() }; - + let ExecConfig::Try(try_config) = cli_config else { + panic!() + }; assert!(matches!(try_config.format, TryRunFormat::Json)); assert!(!try_config.format.is_human()); } @@ -632,8 +655,9 @@ mod tests { fn cli_try_format_human() { let cli_config = args::try_parse_from(["myprog", TRY_COMMAND, "-f", "human", YAML_FILE]).unwrap(); - let ExecConfig::Try(try_config) = cli_config else { panic!() }; - + let ExecConfig::Try(try_config) = cli_config else { + panic!() + }; assert!(matches!(try_config.format, TryRunFormat::Human)); assert!(try_config.format.is_human()); } @@ -643,8 +667,9 @@ mod tests { // -d is only enabled with -l let cli_config = args::try_parse_from(["myprog", TRY_COMMAND, "-d", TEST_DIR, YAML_FILE]).unwrap(); - let ExecConfig::Try(try_config) = cli_config else { panic!() }; - + let ExecConfig::Try(try_config) = cli_config else { + panic!() + }; assert_eq!(try_config.config_file.to_str().unwrap(), YAML_FILE); assert!(!try_config.loggers_on); assert!(try_config.results_dir.is_none()); @@ -655,8 +680,9 @@ mod tests { // -d is only enabled with -l let cli_config = args::try_parse_from(["myprog", TRY_COMMAND, "-l", "-d", TEST_DIR, YAML_FILE]).unwrap(); - let ExecConfig::Try(try_config) = cli_config else { panic!() }; - + let ExecConfig::Try(try_config) = cli_config else { + panic!() + }; assert_eq!(try_config.config_file.to_str().unwrap(), YAML_FILE); assert!(try_config.loggers_on); assert!(try_config.results_dir.is_some()); diff --git a/src/lib.rs b/src/lib.rs index 27b7ef79..660a8d7d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -337,6 +337,9 @@ pub struct TryConfig { /// Directory to store logs (if enabled with --loggers) #[arg(short = 'd', long = "results-directory", value_name = "DIRECTORY")] pub results_dir: Option, + /// Skips request and reponse body from output (try command) + #[arg(short = 's', long = "skipBody")] + pub skip_body_on: bool, } impl fmt::Display for TryConfig { @@ -878,41 +881,60 @@ fn create_try_run_future( debug!("create_try_run_future start"); // create a logger for the try run // request.headers only logs single Accept Headers due to JSON requirements. Use headers_all instead + let request_body_template = if try_config.skip_body_on { + "" + } else if matches!(try_config.format, TryRunFormat::Human) { + "\n${if(request.body != '', '${request.body}', '')}\n\n" + } else { + r#""body": "request.body""# + }; + let response_body_template = if try_config.skip_body_on { + "" + } else if matches!(try_config.format, TryRunFormat::Human) { + "\n${if(response.body != '', '${response.body}', '')}\n\n" + } else { + r#""body": "response.body""# + }; let select = if matches!(try_config.format, TryRunFormat::Human) { Query::simple( - r#"`\ -Request\n\ -========================================\n\ -${request['start-line']}\n\ -${join(request['headers_all'], '\n', ': ')}\n\ -${request.body != '' ? request.body : ''}\n\ - -Response (RTT: ${stats.rtt}ms)\n\ -========================================\n\ -${response['start-line']}\n\ -${join(response.headers_all, '\n', ': ')}\n\ -${response.body != '' ? JSON.stringify(response.body) : ''}\n\n`"# - .to_string(), + format!( + r#""`\n\ + Request\n\ + ========================================\n\ + ${{request['start-line']}}\n\ + ${{join(request.headers_all, '\n', ': ')}}\n\ + {} + Response (RTT: ${{stats.rtt}}ms)\n\ + ========================================\n\ + ${{response['start-line']}}\n\ + ${{join(response.headers_all, '\n', ': ')}}\n\ + {}`""#, + request_body_template, response_body_template + ), vec![], None, ) } else { Query::from_json( - r#"{ - "request": { - "start-line": "request['start-line']", - "headers": "request.headers_all", - "body": "request.body" - }, - "response": { - "start-line": "response['start-line']", - "headers": "response.headers_all", - "body": "response.body" - }, - "stats": { - "RTT": "stats.rtt" - } - }"#, + format!( + r#"{{ + "request": {{ + "start-line": "request['start-line']", + "headers": "request.headers_all", + {} + }}, + "response": {{ + "start-line": "response['start-line']", + "headers": "response.headers_all", + {} + }}, + "stats": {{ + "RTT": "stats.rtt" + }} + }}"#, + request_body_template, response_body_template + ) + .as_str(), ) }; let to = try_config.file.map_or(LogTo::Stdout, |path| {