diff --git a/.github/secrets/connector_auth.toml.gpg b/.github/secrets/connector_auth.toml.gpg index 0038228e65..9f1e13ea89 100644 Binary files a/.github/secrets/connector_auth.toml.gpg and b/.github/secrets/connector_auth.toml.gpg differ diff --git a/.github/workflows/postman-collection-runner.yml b/.github/workflows/postman-collection-runner.yml index b8f074757a..4552cc793d 100644 --- a/.github/workflows/postman-collection-runner.yml +++ b/.github/workflows/postman-collection-runner.yml @@ -1,9 +1,9 @@ -name: Postman Collection API test +name: Postman Collection Runner on: workflow_dispatch: schedule: - - cron: '30 0,12 * * *' # Run workflow at 6 AM and 6 PM IST + - cron: "30 0,12 * * *" # Run workflow at 6 AM and 6 PM IST concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -33,7 +33,14 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v3 - + + - name: Install Rust + uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + + - uses: Swatinem/rust-cache@v2.4.0 + - name: Decrypt connector auth file env: CONNECTOR_AUTH_PASSPHRASE: ${{ secrets.CONNECTOR_AUTH_PASSPHRASE }} @@ -48,13 +55,14 @@ jobs: env: ADMIN_API_KEY: ${{ secrets.INTEG_ADMIN_API_KEY }} BASE_URL: ${{ secrets.INTEG_BASE_URL }} - CONNECTOR_CONFIG_PATH: ${{ env.CONNECTOR_CONFIG_PATH }} + CONNECTOR_AUTH_FILE_PATH: ${{ env.CONNECTOR_CONFIG_PATH }} GATEWAY_MERCHANT_ID: ${{ secrets.STRIPE_GATEWAY_MERCHANT_ID }} GPAY_CERTIFICATE: ${{ secrets.STRIPE_GPAY_CERTIFICATE }} GPAY_CERTIFICATE_KEYS: ${{ secrets.STRIPE_GPAY_CERTIFICATE_KEYS }} uses: nick-fields/retry@v2 with: - timeout_minutes: 6 + timeout_minutes: 30 max_attempts: 3 retry_on: error - command: ./scripts/postman_test_automation.sh ${{ matrix.connector }} + command: | + cargo run --package test_utils --bin test_utils -- --connector_name=${{ matrix.connector }} --base_url=$BASE_URL --admin_api_key=$ADMIN_API_KEY diff --git a/Cargo.lock b/Cargo.lock index d6310a82ea..0a197af7e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1312,6 +1312,7 @@ dependencies = [ "anstyle", "bitflags 1.3.2", "clap_lex", + "once_cell", ] [[package]] @@ -3819,6 +3820,7 @@ dependencies = [ "signal-hook-tokio", "storage_models", "strum", + "test_utils", "thirtyfour", "thiserror", "time 0.3.22", @@ -4531,6 +4533,20 @@ dependencies = [ "test-case-core", ] +[[package]] +name = "test_utils" +version = "0.1.0" +dependencies = [ + "api_models", + "clap", + "masking", + "router", + "serde", + "serde_json", + "serde_path_to_error", + "toml 0.7.4", +] + [[package]] name = "thirtyfour" version = "0.31.0" diff --git a/connector-template/test.rs b/connector-template/test.rs index b97470baea..8dfc7c9743 100644 --- a/connector-template/test.rs +++ b/connector-template/test.rs @@ -2,10 +2,8 @@ use std::str::FromStr; use masking::Secret; use router::types::{self, api, storage::enums}; -use crate::{ - connector_auth, - utils::{self, ConnectorActions}, -}; +use crate::utils::{self, ConnectorActions}; +use test_utils::connector_auth; #[derive(Clone, Copy)] struct {{project-name | downcase | pascal_case}}Test; diff --git a/connector_auth.toml.gpg b/connector_auth.toml.gpg deleted file mode 100644 index b7bc002bce..0000000000 Binary files a/connector_auth.toml.gpg and /dev/null differ diff --git a/crates/common_utils/Cargo.toml b/crates/common_utils/Cargo.toml index 145a06573e..166f597392 100644 --- a/crates/common_utils/Cargo.toml +++ b/crates/common_utils/Cargo.toml @@ -33,7 +33,7 @@ signal-hook = { version = "0.3.15", optional = true } thiserror = "1.0.40" time = { version = "0.3.21", features = ["serde", "serde-well-known", "std"] } tokio = { version = "1.28.2", features = ["macros", "rt-multi-thread"], optional = true } -phonenumber = "0.3.2+8.13.9" +phonenumber = "0.3.2" # First party crates masking = { version = "0.1.0", path = "../masking" } diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml index 6584eb2fe5..4f0be43b96 100644 --- a/crates/router/Cargo.toml +++ b/crates/router/Cargo.toml @@ -114,6 +114,9 @@ tokio = "1.28.2" toml = "0.7.4" wiremock = "0.5" +# First party dev-dependencies +test_utils = { version = "0.1.0", path = "../test_utils" } + [[bin]] name = "router" path = "src/bin/router.rs" diff --git a/crates/router/tests/connectors/connector_auth.rs b/crates/router/tests/connectors/connector_auth.rs deleted file mode 100644 index 4e2e8901bb..0000000000 --- a/crates/router/tests/connectors/connector_auth.rs +++ /dev/null @@ -1,149 +0,0 @@ -use std::env; - -use router::types::ConnectorAuthType; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct ConnectorAuthentication { - pub aci: Option, - pub adyen: Option, - pub adyen_uk: Option, - pub airwallex: Option, - pub authorizedotnet: Option, - pub bambora: Option, - pub bitpay: Option, - pub bluesnap: Option, - pub cashtocode: Option, - pub checkout: Option, - pub coinbase: Option, - pub cryptopay: Option, - pub cybersource: Option, - pub dlocal: Option, - #[cfg(feature = "dummy_connector")] - pub dummyconnector: Option, - pub fiserv: Option, - pub forte: Option, - pub globalpay: Option, - pub globepay: Option, - pub iatapay: Option, - pub mollie: Option, - pub multisafepay: Option, - pub nexinets: Option, - pub noon: Option, - pub nmi: Option, - pub nuvei: Option, - pub opayo: Option, - pub opennode: Option, - pub payeezy: Option, - pub payme: Option, - pub paypal: Option, - pub payu: Option, - pub powertranz: Option, - pub rapyd: Option, - pub shift4: Option, - pub stripe: Option, - pub stripe_au: Option, - pub stripe_uk: Option, - pub trustpay: Option, - pub worldpay: Option, - pub worldline: Option, - pub zen: Option, - pub automation_configs: Option, -} - -impl ConnectorAuthentication { - #[allow(clippy::expect_used)] - pub(crate) fn new() -> Self { - // before running tests - let path = env::var("CONNECTOR_AUTH_FILE_PATH") - .expect("connector authentication file path not set"); - toml::from_str( - &std::fs::read_to_string(path).expect("connector authentication config file not found"), - ) - .expect("Failed to read connector authentication config file") - } -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct HeaderKey { - pub api_key: String, -} - -impl From for ConnectorAuthType { - fn from(key: HeaderKey) -> Self { - Self::HeaderKey { - api_key: key.api_key, - } - } -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct BodyKey { - pub api_key: String, - pub key1: String, -} - -impl From for ConnectorAuthType { - fn from(key: BodyKey) -> Self { - Self::BodyKey { - api_key: key.api_key, - key1: key.key1, - } - } -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct SignatureKey { - pub api_key: String, - pub key1: String, - pub api_secret: String, -} - -impl From for ConnectorAuthType { - fn from(key: SignatureKey) -> Self { - Self::SignatureKey { - api_key: key.api_key, - key1: key.key1, - api_secret: key.api_secret, - } - } -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct MultiAuthKey { - pub api_key: String, - pub key1: String, - pub api_secret: String, - pub key2: String, -} - -impl From for ConnectorAuthType { - fn from(key: MultiAuthKey) -> Self { - Self::MultiAuthKey { - api_key: key.api_key, - key1: key.key1, - api_secret: key.api_secret, - key2: key.key2, - } - } -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct AutomationConfigs { - pub hs_base_url: Option, - pub hs_api_key: Option, - pub hs_test_browser: Option, - pub chrome_profile_path: Option, - pub firefox_profile_path: Option, - pub pypl_email: Option, - pub pypl_pass: Option, - pub gmail_email: Option, - pub gmail_pass: Option, - pub configs_url: Option, - pub stripe_pub_key: Option, - pub testcases_path: Option, - pub bluesnap_gateway_merchant_id: Option, - pub globalpay_gateway_merchant_id: Option, - pub run_minimum_steps: Option, - pub airwallex_merchant_name: Option, -} diff --git a/crates/router/tests/connectors/dummyconnector.rs b/crates/router/tests/connectors/dummyconnector.rs index c8a9d1acb8..35e68e99f8 100644 --- a/crates/router/tests/connectors/dummyconnector.rs +++ b/crates/router/tests/connectors/dummyconnector.rs @@ -3,11 +3,9 @@ use std::str::FromStr; use cards::CardNumber; use masking::Secret; use router::types::{self, api, storage::enums}; +use test_utils::connector_auth; -use crate::{ - connector_auth, - utils::{self, ConnectorActions}, -}; +use crate::utils::{self, ConnectorActions}; #[derive(Clone, Copy)] struct DummyConnectorTest; diff --git a/crates/router/tests/connectors/main.rs b/crates/router/tests/connectors/main.rs index 64ce4ad14f..690e8f1dc0 100644 --- a/crates/router/tests/connectors/main.rs +++ b/crates/router/tests/connectors/main.rs @@ -4,6 +4,7 @@ clippy::unwrap_in_result, clippy::unwrap_used )] +use test_utils::connector_auth; mod aci; mod adyen; @@ -20,7 +21,6 @@ mod cashtocode; mod checkout; mod checkout_ui; mod coinbase; -mod connector_auth; mod cryptopay; mod cybersource; mod dlocal; diff --git a/crates/router/tests/integration_demo.rs b/crates/router/tests/integration_demo.rs index 1fc675ffa9..16e7ead0a3 100644 --- a/crates/router/tests/integration_demo.rs +++ b/crates/router/tests/integration_demo.rs @@ -1,13 +1,8 @@ #![allow(clippy::unwrap_used)] mod utils; - -#[allow(dead_code)] -mod auth { - include!("connectors/connector_auth.rs"); -} - -use auth::ConnectorAuthentication; +use masking::PeekInterface; +use test_utils::connector_auth::ConnectorAuthentication; use utils::{mk_service, ApiKey, AppClient, MerchantId, PaymentId, Status}; /// Example of unit test @@ -77,7 +72,7 @@ async fn partial_refund() { &server, &merchant_id, "stripe", - &authentication.checkout.unwrap().api_key, + authentication.checkout.unwrap().api_key.peek(), ) .await; @@ -143,7 +138,7 @@ async fn exceed_refund() { &server, &merchant_id, "stripe", - &authentication.checkout.unwrap().api_key, + authentication.checkout.unwrap().api_key.peek(), ) .await; diff --git a/crates/test_utils/Cargo.toml b/crates/test_utils/Cargo.toml new file mode 100644 index 0000000000..920cdc1405 --- /dev/null +++ b/crates/test_utils/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "test_utils" +description = "Postman collection runner and utility" +version = "0.1.0" +edition.workspace = true +rust-version.workspace = true +readme = "README.md" +license.workspace = true + +[features] +default = ["dummy_connector"] +dummy_connector = ["api_models/dummy_connector"] + + +[dependencies] +clap = { version = "4.3.2", default-features = false, features = ["std", "derive", "help", "usage", "cargo"] } +serde = { version = "1.0.163", features = ["derive"] } +serde_json = "1.0.96" +serde_path_to_error = "0.1.11" +toml = "0.7.4" + +# First party crates +router = { version = "0.2.0", path = "../router" } +api_models = { version = "0.1.0", path = "../api_models", features = ["errors"] } +masking = { version = "0.1.0", path = "../masking" } diff --git a/crates/test_utils/README.md b/crates/test_utils/README.md new file mode 100644 index 0000000000..5a7f913a96 --- /dev/null +++ b/crates/test_utils/README.md @@ -0,0 +1,13 @@ +# Test Runner + +The main part of running tests through `newman`. + +# Usage + +- Make sure you that you've the postman collection for the connector available in the `postman` dir with the name `.postman_collection.json` +- Add the connector credentials to the `connector_auth.toml` / `auth.toml` +- In terminal, execute: + ```zsh + export CONNECTOR_AUTH_FILE_PATH=/path/to/auth.toml + cargo run --package test_utils --bin test_utils -- --connector_name= --base_url= --admin_api_key= + ``` diff --git a/crates/test_utils/src/connector_auth.rs b/crates/test_utils/src/connector_auth.rs new file mode 100644 index 0000000000..4c4a5f023a --- /dev/null +++ b/crates/test_utils/src/connector_auth.rs @@ -0,0 +1,258 @@ +use std::{collections::HashMap, env}; + +use masking::{PeekInterface, Secret}; +use router::types::ConnectorAuthType; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct ConnectorAuthentication { + pub aci: Option, + pub adyen: Option, + pub adyen_uk: Option, + pub airwallex: Option, + pub authorizedotnet: Option, + pub bambora: Option, + pub bitpay: Option, + pub bluesnap: Option, + pub cashtocode: Option, + pub checkout: Option, + pub coinbase: Option, + pub cryptopay: Option, + pub cybersource: Option, + pub dlocal: Option, + #[cfg(feature = "dummy_connector")] + pub dummyconnector: Option, + pub fiserv: Option, + pub forte: Option, + pub globalpay: Option, + pub globepay: Option, + pub iatapay: Option, + pub mollie: Option, + pub multisafepay: Option, + pub nexinets: Option, + pub noon: Option, + pub nmi: Option, + pub nuvei: Option, + pub opayo: Option, + pub opennode: Option, + pub payeezy: Option, + pub payme: Option, + pub paypal: Option, + pub payu: Option, + pub powertranz: Option, + pub rapyd: Option, + pub shift4: Option, + pub stripe: Option, + pub stripe_au: Option, + pub stripe_uk: Option, + pub trustpay: Option, + pub worldpay: Option, + pub worldline: Option, + pub zen: Option, + pub automation_configs: Option, +} + +impl Default for ConnectorAuthentication { + fn default() -> Self { + Self::new() + } +} + +#[allow(dead_code)] +impl ConnectorAuthentication { + #[allow(clippy::expect_used)] + pub fn new() -> Self { + // Do `export CONNECTOR_AUTH_FILE_PATH="/hyperswitch/crates/router/tests/connectors/sample_auth.toml"` + // before running tests in shell + let path = env::var("CONNECTOR_AUTH_FILE_PATH") + .expect("Connector authentication file path not set"); + toml::from_str( + &std::fs::read_to_string(path).expect("connector authentication config file not found"), + ) + .expect("Failed to read connector authentication config file") + } +} + +#[derive(Clone, Debug, Deserialize)] +pub struct ConnectorAuthenticationMap(HashMap); + +impl Default for ConnectorAuthenticationMap { + fn default() -> Self { + Self::new() + } +} + +// This is a temporary solution to avoid rust compiler from complaining about unused function +#[allow(dead_code)] +impl ConnectorAuthenticationMap { + pub fn inner(&self) -> &HashMap { + &self.0 + } + + #[allow(clippy::expect_used)] + pub fn new() -> Self { + // Do `export CONNECTOR_AUTH_FILE_PATH="/hyperswitch/crates/router/tests/connectors/sample_auth.toml"` + // before running tests in shell + let path = env::var("CONNECTOR_AUTH_FILE_PATH") + .expect("connector authentication file path not set"); + + // Read the file contents to a JsonString + let contents = + &std::fs::read_to_string(path).expect("Failed to read connector authentication file"); + + // Deserialize the JsonString to a HashMap + let auth_config: HashMap = + toml::from_str(contents).expect("Failed to deserialize TOML file"); + + // auth_config contains the data in below given format: + // { + // "connector_name": Table( + // { + // "api_key": String( + // "API_Key", + // ), + // "api_secret": String( + // "Secret key", + // ), + // "key1": String( + // "key1", + // ), + // "key2": String( + // "key2", + // ), + // }, + // ), + // "connector_name": Table( + // ... + // } + + // auth_map refines and extracts required information + let auth_map = auth_config + .into_iter() + .map(|(connector_name, config)| { + let auth_type = match config { + toml::Value::Table(table) => { + match ( + table.get("api_key"), + table.get("key1"), + table.get("api_secret"), + table.get("key2"), + ) { + (Some(api_key), None, None, None) => ConnectorAuthType::HeaderKey { + api_key: api_key.as_str().unwrap_or_default().to_string(), + }, + (Some(api_key), Some(key1), None, None) => ConnectorAuthType::BodyKey { + api_key: api_key.as_str().unwrap_or_default().to_string(), + key1: key1.as_str().unwrap_or_default().to_string(), + }, + (Some(api_key), Some(key1), Some(api_secret), None) => { + ConnectorAuthType::SignatureKey { + api_key: api_key.as_str().unwrap_or_default().to_string(), + key1: key1.as_str().unwrap_or_default().to_string(), + api_secret: api_secret.as_str().unwrap_or_default().to_string(), + } + } + (Some(api_key), Some(key1), Some(api_secret), Some(key2)) => { + ConnectorAuthType::MultiAuthKey { + api_key: api_key.as_str().unwrap_or_default().to_string(), + key1: key1.as_str().unwrap_or_default().to_string(), + api_secret: api_secret.as_str().unwrap_or_default().to_string(), + key2: key2.as_str().unwrap_or_default().to_string(), + } + } + _ => ConnectorAuthType::NoKey, + } + } + _ => ConnectorAuthType::NoKey, + }; + (connector_name, auth_type) + }) + .collect(); + + Self(auth_map) + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct HeaderKey { + pub api_key: Secret, +} + +impl From for ConnectorAuthType { + fn from(key: HeaderKey) -> Self { + Self::HeaderKey { + api_key: key.api_key.peek().to_string(), + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct BodyKey { + pub api_key: Secret, + pub key1: Secret, +} + +impl From for ConnectorAuthType { + fn from(key: BodyKey) -> Self { + Self::BodyKey { + api_key: key.api_key.peek().to_string(), + key1: key.key1.peek().to_string(), + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct SignatureKey { + pub api_key: Secret, + pub key1: Secret, + pub api_secret: Secret, +} + +impl From for ConnectorAuthType { + fn from(key: SignatureKey) -> Self { + Self::SignatureKey { + api_key: key.api_key.peek().to_string(), + key1: key.key1.peek().to_string(), + api_secret: key.api_secret.peek().to_string(), + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct MultiAuthKey { + pub api_key: Secret, + pub key1: Secret, + pub api_secret: Secret, + pub key2: Secret, +} + +impl From for ConnectorAuthType { + fn from(key: MultiAuthKey) -> Self { + Self::MultiAuthKey { + api_key: key.api_key.peek().to_string(), + key1: key.key1.peek().to_string(), + api_secret: key.api_secret.peek().to_string(), + key2: key.key2.peek().to_string(), + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct AutomationConfigs { + pub hs_base_url: Option, + pub hs_api_key: Option, + pub hs_test_browser: Option, + pub chrome_profile_path: Option, + pub firefox_profile_path: Option, + pub pypl_email: Option, + pub pypl_pass: Option, + pub gmail_email: Option, + pub gmail_pass: Option, + pub configs_url: Option, + pub stripe_pub_key: Option, + pub testcases_path: Option, + pub bluesnap_gateway_merchant_id: Option, + pub globalpay_gateway_merchant_id: Option, + pub run_minimum_steps: Option, + pub airwallex_merchant_name: Option, +} diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs new file mode 100644 index 0000000000..82b4addfb9 --- /dev/null +++ b/crates/test_utils/src/lib.rs @@ -0,0 +1 @@ +pub mod connector_auth; diff --git a/crates/test_utils/src/main.rs b/crates/test_utils/src/main.rs new file mode 100644 index 0000000000..650ba6cd29 --- /dev/null +++ b/crates/test_utils/src/main.rs @@ -0,0 +1,156 @@ +use std::{ + env, + process::{exit, Command as cmd}, +}; + +use clap::{arg, command, Parser}; +use router::types::ConnectorAuthType; +use test_utils::connector_auth::ConnectorAuthenticationMap; + +// Just by the name of the connector, this function generates the name of the collection +// Example: CONNECTOR_NAME="stripe" -> OUTPUT: postman/stripe.postman_collection.json +#[inline] +fn path_generation(name: impl AsRef) -> String { + format!("postman/{}.postman_collection.json", name.as_ref()) +} + +#[derive(Parser)] +#[command(version, about = "Postman collection runner using newman!", long_about = None)] +struct Args { + /// Name of the connector + #[arg(short, long = "connector_name")] + connector_name: String, + /// Base URL of the Hyperswitch environment + #[arg(short, long = "base_url")] + base_url: String, + /// Admin API Key of the environment + #[arg(short, long = "admin_api_key")] + admin_api_key: String, +} + +fn main() { + let args = Args::parse(); + + let connector_name = args.connector_name; + let base_url = args.base_url; + let admin_api_key = args.admin_api_key; + + let collection_path = path_generation(&connector_name); + let auth_map = ConnectorAuthenticationMap::new(); + + let inner_map = auth_map.inner(); + + // Newman runner + // Depending on the conditions satisfied, variables are added. Since certificates of stripe have already + // been added to the postman collection, those conditions are set to true and collections that have + // variables set up for certificate, will consider those variables and will fail. + + let mut newman_command = cmd::new("newman"); + + newman_command.args(["run", &collection_path]); + newman_command.args(["--env-var", &format!("admin_api_key={admin_api_key}")]); + newman_command.args(["--env-var", &format!("baseUrl={base_url}")]); + + if let Some(auth_type) = inner_map.get(&connector_name) { + match auth_type { + ConnectorAuthType::HeaderKey { api_key } => { + newman_command.args(["--env-var", &format!("connector_api_key={api_key}")]); + } + ConnectorAuthType::BodyKey { api_key, key1 } => { + newman_command.args([ + "--env-var", + &format!("connector_api_key={api_key}"), + "--env-var", + &format!("connector_key1={key1}"), + ]); + } + ConnectorAuthType::SignatureKey { + api_key, + key1, + api_secret, + } => { + newman_command.args([ + "--env-var", + &format!("connector_api_key={api_key}"), + "--env-var", + &format!("connector_key1={key1}"), + "--env-var", + &format!("connector_api_secret={api_secret}"), + ]); + } + ConnectorAuthType::MultiAuthKey { + api_key, + key1, + key2, + api_secret, + } => { + newman_command.args([ + "--env-var", + &format!("connector_api_key={api_key}"), + "--env-var", + &format!("connector_key1={key1}"), + "--env-var", + &format!("connector_key1={key2}"), + "--env-var", + &format!("connector_api_secret={api_secret}"), + ]); + } + // Handle other ConnectorAuthType variants + _ => { + eprintln!("Invalid authentication type."); + } + } + } else { + eprintln!("Connector not found."); + } + + // Add additional environment variables if present + if let Ok(gateway_merchant_id) = env::var("GATEWAY_MERCHANT_ID") { + newman_command.args([ + "--env-var", + &format!("gateway_merchant_id={gateway_merchant_id}"), + ]); + } + + if let Ok(gpay_certificate) = env::var("GPAY_CERTIFICATE") { + newman_command.args(["--env-var", &format!("certificate={gpay_certificate}")]); + } + + if let Ok(gpay_certificate_keys) = env::var("GPAY_CERTIFICATE_KEYS") { + newman_command.args([ + "--env-var", + &format!("certificate_keys={gpay_certificate_keys}"), + ]); + } + + newman_command.arg("--delay-request").arg("5"); + + // Execute the newman command + let output = newman_command.spawn(); + let mut child = match output { + Ok(child) => child, + Err(err) => { + eprintln!("Failed to execute command: {err}"); + exit(1); + } + }; + let status = child.wait(); + + let exit_code = match status { + Ok(exit_status) => { + if exit_status.success() { + println!("Command executed successfully!"); + exit_status.code().unwrap_or(0) + } else { + eprintln!("Command failed with exit code: {:?}", exit_status.code()); + exit_status.code().unwrap_or(1) + } + } + Err(err) => { + eprintln!("Failed to wait for command execution: {}", err); + exit(1); + } + }; + + exit(exit_code); +} diff --git a/scripts/postman_test_automation.sh b/scripts/postman_test_automation.sh deleted file mode 100755 index 575e113bfc..0000000000 --- a/scripts/postman_test_automation.sh +++ /dev/null @@ -1,66 +0,0 @@ -#! /usr/bin/env bash -set -euo pipefail - -# Just by the name of the connector, this function generates the name of the collection -# Example: CONNECTOR_NAME="stripe" -> OUTPUT: postman/stripe.postman_collection.json -path_generation() { - local name="${1}" - local collection_name="postman/${name}.postman_collection.json" - echo "${collection_name}" -} - -# This function gets the api keys from the connector_auth.toml file -# Also determines the type of key (HeaderKey, BodyKey, SignatureKey) for the connector -get_api_keys() { - local input="${1}" - # We get $CONNECTOR_CONFIG_PATH from the GITHUB_ENV - result=$(awk -v name="${input}" -F ' // ' 'BEGIN{ flag=0 } /^\[.*\]/{ if ($1 == "["name"]") { flag=1 } else { flag=0 } } flag==1 && /^[^#]/ { print $0 }' "${CONNECTOR_CONFIG_PATH}") - # OUTPUT of result for `` that has `HeaderKey`: - # [] - # api_key = "HeadKey of " - - # Keys are set as variables since some API Keys for connectors such as ACI - # are Base64 encoded and require "Bearer" to be prefixed such as "Bearer Skst45645gey5r#&$==". - # This effectively stops the shell from interpreting the value of the variable as a command. - API_KEY=$(echo "${result}" | awk -F ' = ' '$1 == "api_key" { gsub(/"/, "", $2); print $2 }') - KEY1=$(echo "${result}" | awk -F ' = ' '$1 == "key1" { gsub(/"/, "", $2); print $2 }') - KEY2=$(echo "${result}" | awk -F ' = ' '$1 == "key2" { gsub(/"/, "", $2); print $2 }') - API_SECRET=$(echo "${result}" | awk -F ' = ' '$1 == "api_secret" { gsub(/"/, "", $2); print $2 }') - - # Determine the type of key - if [[ -n "${API_KEY}" && -z "${KEY1}" && -z "${API_SECRET}" ]]; then - KEY_TYPE="HeaderKey" - elif [[ -n "${API_KEY}" && -n "${KEY1}" && -z "${API_SECRET}" ]]; then - KEY_TYPE="BodyKey" - elif [[ -n "${API_KEY}" && -n "${KEY1}" && -n "${API_SECRET}" ]]; then - KEY_TYPE="SignatureKey" - elif [[ -n "${API_KEY}" && -n "${KEY1}" && -n "${KEY2}" && -n "${API_SECRET}" ]]; then - KEY_TYPE="MultiAuthKey" - else - KEY_TYPE="Invalid" - fi -} - -# [ MAIN ] -CONNECTOR_NAME="${1}" -KEY_TYPE="" - -# Function call -COLLECTION_PATH=$(path_generation "${CONNECTOR_NAME}") -get_api_keys "${CONNECTOR_NAME}" - -# Newman runner -# Depending on the conditions satisfied, variables are added. Since certificates of stripe have already -# been added to the postman collection, those conditions are set to true and collections that have -# variables set up for certificate, will consider those variables and will fail. -newman run "${COLLECTION_PATH}" \ - --env-var "admin_api_key=${ADMIN_API_KEY}" \ - --env-var "baseUrl=${BASE_URL}" \ - --env-var "connector_api_key=${API_KEY}" \ - $(if [[ "${KEY_TYPE}" == BodyKey ]]; then echo --env-var "connector_key1=${KEY1}"; fi) \ - $(if [[ "${KEY_TYPE}" == SignatureKey ]]; then echo --env-var "connector_key1=${KEY1}" --env-var "connector_api_secret=${API_SECRET}"; fi) \ - $(if [[ "${KEY_TYPE}" == MultiAuthKey ]]; then echo --env-var "connector_key1=${KEY1}" --env-var "connector_key2=${KEY2}" --env-var "connector_api_secret=${API_SECRET}"; fi) \ - $(if [[ -n "${GATEWAY_MERCHANT_ID}" ]]; then echo --env-var "gateway_merchant_id=${GATEWAY_MERCHANT_ID}"; fi) \ - $(if [[ -n "${GPAY_CERTIFICATE}" ]]; then echo --env-var "certificate=${GPAY_CERTIFICATE}"; fi) \ - $(if [[ -n "${GPAY_CERTIFICATE_KEYS}" ]]; then echo --env-var "certificate_keys=${GPAY_CERTIFICATE_KEYS}"; fi) \ - --delay-request 5