diff --git a/rust/pact_matching/Cargo.toml b/rust/pact_matching/Cargo.toml index 920183f48..66e0eea87 100644 --- a/rust/pact_matching/Cargo.toml +++ b/rust/pact_matching/Cargo.toml @@ -26,7 +26,7 @@ ansi_term = "0.12.1" anyhow = "1.0.82" base64 = "0.22.0" bytes = { version = "1.6.0", features = ["serde"] } -chrono = { version = "0.4.38", features = ["std", "clock"], default_features = false, optional = true } +chrono = { version = "0.4.38", features = ["std", "clock"], default-features = false, optional = true } difference = "2.0.0" futures = "0.3.30" hex = "0.4.3" diff --git a/rust/pact_matching/src/lib.rs b/rust/pact_matching/src/lib.rs index 102a73589..48551d7ed 100644 --- a/rust/pact_matching/src/lib.rs +++ b/rust/pact_matching/src/lib.rs @@ -2056,6 +2056,7 @@ pub async fn match_sync_message_response<'a>( /// Generates the request by applying any defined generators // TODO: Need to pass in any plugin data +#[instrument(level = "trace")] pub async fn generate_request(request: &HttpRequest, mode: &GeneratorTestMode, context: &HashMap<&str, Value>) -> HttpRequest { trace!(?request, ?mode, ?context, "generate_request"); let mut request = request.clone(); diff --git a/rust/pact_models/src/generators/mod.rs b/rust/pact_models/src/generators/mod.rs index ca01aeab3..897f4e4a6 100644 --- a/rust/pact_models/src/generators/mod.rs +++ b/rust/pact_models/src/generators/mod.rs @@ -19,7 +19,7 @@ use rand::prelude::*; #[cfg(target_family = "wasm")] use regex::{Captures, Regex}; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; -use tracing::{debug, trace, warn}; +use tracing::{debug, instrument, trace, warn}; use uuid::Uuid; use crate::bodies::OptionalBody; @@ -768,6 +768,7 @@ macro_rules! generators { }}; } +#[instrument(level = "trace")] pub fn generate_value_from_context(expression: &str, context: &HashMap<&str, Value>, data_type: &Option) -> anyhow::Result { let result = if contains_expressions(expression) { parse_expression(expression, &MapValueResolver { context: context.clone() }) diff --git a/rust/pact_verifier/src/lib.rs b/rust/pact_verifier/src/lib.rs index 9b4af63e4..ec32a63c7 100644 --- a/rust/pact_verifier/src/lib.rs +++ b/rust/pact_verifier/src/lib.rs @@ -428,13 +428,22 @@ async fn verify_interaction<'a, F: RequestFilterExecutor, S: ProviderStateExecut let context = execute_provider_states(interaction, provider_state_executor, &client, true) .await .map_err(|e| (e, vec![], start.elapsed()))?; - let provider_states_context = context + let mut provider_states_context = hashmap!{}; + for provider_state in interaction.provider_states() { + for (k, v) in provider_state.params { + provider_states_context.insert(k, v); + } + } + for (k, v) in context { + provider_states_context.insert(k, v); + } + let provider_states_context = provider_states_context .iter() .map(|(k, v)| (k.as_str(), v.clone())) .collect(); info!("Running provider verification for '{}'", interaction.description()); - trace!("Interaction to verify: {:?}", interaction); + trace!(?provider_states_context, "Interaction to verify: {:?}", interaction); #[allow(unused_assignments)] let mut result = Ok((None, vec![])); #[cfg(feature = "plugins")] diff --git a/rust/pact_verifier/src/tests.rs b/rust/pact_verifier/src/tests.rs index 8d969cb06..900eb957f 100644 --- a/rust/pact_verifier/src/tests.rs +++ b/rust/pact_verifier/src/tests.rs @@ -17,7 +17,7 @@ use pact_models::sync_pact::RequestResponsePact; use reqwest::Client; use serde_json::{json, Value}; -use pact_consumer::*; +use pact_consumer::{json_pattern, json_pattern_internal, like}; use pact_consumer::prelude::*; use crate::{NullRequestFilterExecutor, PactSource, ProviderInfo, ProviderStateExecutor, ProviderTransport, publish_result, PublishOptions, VerificationOptions}; @@ -1042,3 +1042,97 @@ async fn fetch_pact_from_dir_filters_by_provider_name() { let (pact, _, _, _) = first_result.unwrap(); expect!(pact.provider().name).to(be_equal_to(provider.name)); } + +// Issue #441 +#[test_log::test(tokio::test)] +async fn support_passing_provider_state_params_to_provider_state_generator() { + let server = PactBuilderAsync::new("RustPactVerifier", "441Provider") + .interaction("a request say hello to John", "", |mut i| async move { + i.request + .path("/api/hello/John"); + i.response + .header("content-type", "application/json") + .json_body(json_pattern!({ + "name": "John" + })); + i + }) + .await + .start_mock_server(None); + + #[allow(deprecated)] + let provider = ProviderInfo { + name: "provider_states_values".to_string(), + host: server.url().host_str().unwrap().to_string(), + port: Some(server.url().port().unwrap()), + transports: vec![ + ProviderTransport { + transport: "HTTP".to_string(), + port: Some(server.url().port().unwrap()), + path: None, + scheme: Some("http".to_string()) + } + ], + .. ProviderInfo::default() + }; + + let verification_options = VerificationOptions:: { + no_pacts_is_error: false, + .. VerificationOptions::default() + }; + let provider_states = Arc::new(DummyProviderStateExecutor{}); + + let pact = RequestResponsePact::from_json("test", &json!({ + "consumer": { + "name": "SomeConsumer" + }, + "interactions": [ + { + "description": "Hello John", + "providerStates": [ + { + "name": "User exists", + "params": { + "name": "John" + } + } + ], + "request": { + "generators": { + "path": { + "dataType": "STRING", + "expression": "/api/hello/${name}", + "type": "ProviderState" + } + }, + "method": "GET", + "path": "/api/hello/James" + }, + "response": { + "body": { + "name": "John" + }, + "headers": { + "Content-Type": "application/json" + }, + "status": 200 + } + } + ], + "metadata": { + "pact-jvm": { + "version": "4.6.7" + }, + "pactSpecification": { + "version": "3.0.0" + } + }, + "provider": { + "name": "SomeProvider" + } + })).unwrap(); + let interaction = pact.interactions.first().unwrap(); + + let result = super::verify_interaction(&provider, interaction, &pact.boxed(), &verification_options, &provider_states).await; + expect!(result).to(be_ok()); +}