diff --git a/.github/workflows/postman-collection-runner.yml b/.github/workflows/postman-collection-runner.yml index 6b0911d1b456..3291755b56cf 100644 --- a/.github/workflows/postman-collection-runner.yml +++ b/.github/workflows/postman-collection-runner.yml @@ -143,7 +143,7 @@ jobs: for i in $(echo "$CONNECTORS" | tr "," "\n"); do echo $i - if ! cargo run --bin test_utils -- --connector_name="$i" --base_url="$BASE_URL" --admin_api_key="$ADMIN_API_KEY"; then + if ! cargo run --bin test_utils -- --connector-name="$i" --base-url="$BASE_URL" --admin-api-key="$ADMIN_API_KEY"; then failed_connectors+=("$i") fi done diff --git a/crates/test_utils/README.md b/crates/test_utils/README.md index 1e92174b3337..2edbc7104c25 100644 --- a/crates/test_utils/README.md +++ b/crates/test_utils/README.md @@ -28,9 +28,16 @@ Required fields: Optional fields: +- `--delay` -- To add a delay between requests in milliseconds. + - Maximum delay is 4294967295 milliseconds or 4294967.295 seconds or 71616 minutes or 1193.6 hours or 49.733 days + - Example: `--delay 1000` (for 1 second delay) - `--folder` -- To run individual folders in the collection - Use double quotes to specify folder name. If you wish to run multiple folders, separate them with a comma (`,`) - Example: `--folder "QuickStart"` or `--folder "Health check,QuickStart"` +- `--header` -- If you wish to add custom headers to the requests, you can pass them as a string + - Example: `--header "key:value"` + - If you want to pass multiple custom headers, you can pass multiple `--header` flags + - Example: `--header "key1:value1" --header "key2:value2"` - `--verbose` -- A boolean to print detailed logs (requests and responses) **Note:** Passing `--verbose` will also print the connector as well as admin API keys in the logs. So, make sure you don't push the commands with `--verbose` to any public repository. diff --git a/crates/test_utils/src/main.rs b/crates/test_utils/src/main.rs index 637122e468e6..22c91e063d8f 100644 --- a/crates/test_utils/src/main.rs +++ b/crates/test_utils/src/main.rs @@ -3,10 +3,10 @@ use std::process::{exit, Command}; use test_utils::newman_runner; fn main() { - let mut newman_command: Command = newman_runner::command_generate(); + let mut runner = newman_runner::generate_newman_command(); // Execute the newman command - let output = newman_command.spawn(); + let output = runner.newman_command.spawn(); let mut child = match output { Ok(child) => child, Err(err) => { @@ -16,6 +16,30 @@ fn main() { }; let status = child.wait(); + if runner.file_modified_flag { + let git_status = Command::new("git") + .args([ + "restore", + format!("{}/event.prerequest.js", runner.collection_path).as_str(), + ]) + .output(); + + match git_status { + Ok(output) => { + if output.status.success() { + let stdout_str = String::from_utf8_lossy(&output.stdout); + println!("Git command executed successfully: {stdout_str}"); + } else { + let stderr_str = String::from_utf8_lossy(&output.stderr); + eprintln!("Git command failed with error: {stderr_str}"); + } + } + Err(e) => { + eprintln!("Error running Git: {e}"); + } + } + } + let exit_code = match status { Ok(exit_status) => { if exit_status.success() { diff --git a/crates/test_utils/src/newman_runner.rs b/crates/test_utils/src/newman_runner.rs index c51556f8f255..af7fb5592813 100644 --- a/crates/test_utils/src/newman_runner.rs +++ b/crates/test_utils/src/newman_runner.rs @@ -1,22 +1,34 @@ -use std::{env, process::Command}; +use std::{ + env, + fs::OpenOptions, + io::{self, Write}, + path::Path, + process::Command, +}; use clap::{arg, command, Parser}; use masking::PeekInterface; use crate::connector_auth::{ConnectorAuthType, ConnectorAuthenticationMap}; - #[derive(Parser)] #[command(version, about = "Postman collection runner using newman!", long_about = None)] struct Args { /// Admin API Key of the environment - #[arg(short, long = "admin_api_key")] + #[arg(short, long)] admin_api_key: String, /// Base URL of the Hyperswitch environment - #[arg(short, long = "base_url")] + #[arg(short, long)] base_url: String, /// Name of the connector - #[arg(short, long = "connector_name")] + #[arg(short, long)] connector_name: String, + /// Custom headers + #[arg(short = 'H', long = "header")] + custom_headers: Option>, + /// Minimum delay in milliseconds to be added before sending a request + /// By default, 7 milliseconds will be the delay + #[arg(short, long, default_value_t = 7)] + delay_request: u32, /// Folder name of specific tests #[arg(short, long = "folder")] folders: Option, @@ -25,6 +37,12 @@ struct Args { verbose: bool, } +pub struct ReturnArgs { + pub newman_command: Command, + pub file_modified_flag: bool, + pub collection_path: String, +} + // Just by the name of the connector, this function generates the name of the collection dir // Example: CONNECTOR_NAME="stripe" -> OUTPUT: postman/collection-dir/stripe #[inline] @@ -32,7 +50,29 @@ fn get_path(name: impl AsRef) -> String { format!("postman/collection-dir/{}", name.as_ref()) } -pub fn command_generate() -> Command { +// This function currently allows you to add only custom headers. +// In future, as we scale, this can be modified based on the need +fn insert_content(dir: T, content_to_insert: U) -> io::Result<()> +where + T: AsRef + std::fmt::Debug, + U: AsRef + std::fmt::Debug, +{ + let file_name = "event.prerequest.js"; + let file_path = dir.as_ref().join(file_name); + + // Open the file in write mode or create it if it doesn't exist + let mut file = OpenOptions::new() + .write(true) + .append(true) + .create(true) + .open(file_path)?; + + write!(file, "\n{:#?}", content_to_insert)?; + + Ok(()) +} + +pub fn generate_newman_command() -> ReturnArgs { let args = Args::parse(); let connector_name = args.connector_name; @@ -129,7 +169,10 @@ pub fn command_generate() -> Command { ]); } - newman_command.arg("--delay-request").arg("7"); // 7 milli seconds delay + newman_command.args([ + "--delay-request", + format!("{}", &args.delay_request).as_str(), + ]); newman_command.arg("--color").arg("on"); @@ -151,5 +194,24 @@ pub fn command_generate() -> Command { newman_command.arg("--verbose"); } - newman_command + let mut modified = false; + if let Some(headers) = &args.custom_headers { + for header in headers { + if let Some((key, value)) = header.split_once(':') { + let content_to_insert = + format!(r#"pm.request.headers.add({{key: "{key}", value: "{value}"}});"#); + if insert_content(&collection_path, &content_to_insert).is_ok() { + modified = true; + } + } else { + eprintln!("Invalid header format: {}", header); + } + } + } + + ReturnArgs { + newman_command, + file_modified_flag: modified, + collection_path, + } }