From 6a89d308ae20a3e5497f0119f9369e322278df55 Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Thu, 6 Jun 2024 22:21:14 +0100 Subject: [PATCH 1/3] chore: point to pact_models 1.2.1 --- compatibility-suite/Cargo.toml | 2 +- rust/Cargo.lock | 55 +++++-------------------------- rust/Cargo.toml | 1 + rust/pact_cli/Cargo.toml | 2 +- rust/pact_consumer/Cargo.toml | 2 +- rust/pact_ffi/Cargo.toml | 2 +- rust/pact_matching/Cargo.toml | 2 +- rust/pact_verifier/Cargo.toml | 2 +- rust/pact_verifier_cli/Cargo.toml | 2 +- rust/pact_wasm/Cargo.toml | 2 +- 10 files changed, 17 insertions(+), 55 deletions(-) diff --git a/compatibility-suite/Cargo.toml b/compatibility-suite/Cargo.toml index bd4408e2f..7b60d1a3a 100644 --- a/compatibility-suite/Cargo.toml +++ b/compatibility-suite/Cargo.toml @@ -13,7 +13,7 @@ futures = "0.3.29" itertools = "0.12.1" lazy_static = "1.4.0" maplit = "1.0.2" -pact_models = { version = "~1.2.0" } +pact_models = { version = "~1.2.1", path = "../rust/pact_models" } pact_matching = { version = "1.2.3", path = "../rust/pact_matching" } pact_mock_server = { version = "1.2.8" } pact_verifier = { version = "1.2.1", path = "../rust/pact_verifier" } diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 9861bbc23..acde54479 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1881,7 +1881,7 @@ dependencies = [ "maplit", "md5", "os_info", - "pact_models 1.2.0", + "pact_models", "prost", "prost-types", "regex", @@ -1918,7 +1918,7 @@ dependencies = [ "pact-plugin-driver", "pact_matching 1.2.4", "pact_mock_server", - "pact_models 1.2.0", + "pact_models", "pretty_assertions", "quickcheck", "rand", @@ -1962,7 +1962,7 @@ dependencies = [ "pact-plugin-driver", "pact_matching 1.2.4", "pact_mock_server", - "pact_models 1.2.0", + "pact_models", "pact_verifier", "panic-message", "pretty_assertions", @@ -2015,7 +2015,7 @@ dependencies = [ "nom", "onig", "pact-plugin-driver", - "pact_models 1.2.0", + "pact_models", "rand", "reqwest 0.12.4", "semver", @@ -2058,7 +2058,7 @@ dependencies = [ "ntest", "onig", "pact-plugin-driver", - "pact_models 1.2.0", + "pact_models", "pretty_assertions", "quickcheck", "rand", @@ -2094,7 +2094,7 @@ dependencies = [ "maplit", "pact-plugin-driver", "pact_matching 1.2.3", - "pact_models 1.2.0", + "pact_models", "rustls 0.21.12", "rustls-pemfile 1.0.4", "serde", @@ -2108,45 +2108,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "pact_models" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf3bf784d5fc22d0332041fa8f9dd9992e0ce2b22236462847ca1b1377297e10" -dependencies = [ - "anyhow", - "ariadne", - "base64 0.21.7", - "bytes", - "chrono", - "chrono-tz 0.8.6", - "fs2", - "gregorian", - "hashers", - "hex", - "indextree", - "itertools 0.10.5", - "lazy_static", - "lenient_semver", - "logos", - "maplit", - "mime", - "nom", - "onig", - "parse-zoneinfo", - "rand", - "rand_regex", - "regex", - "regex-syntax 0.6.29", - "reqwest 0.11.27", - "semver", - "serde", - "serde_json", - "sxd-document", - "tracing", - "uuid", -] - [[package]] name = "pact_models" version = "1.2.1" @@ -2217,7 +2178,7 @@ dependencies = [ "pact-plugin-driver", "pact_consumer", "pact_matching 1.2.4", - "pact_models 1.2.0", + "pact_models", "pretty_assertions", "quickcheck", "regex", @@ -2247,7 +2208,7 @@ dependencies = [ "junit-report", "log", "maplit", - "pact_models 1.2.0", + "pact_models", "pact_verifier", "regex", "reqwest 0.12.4", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 6b307a417..ebe00edf4 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -12,3 +12,4 @@ resolver = "2" [patch.crates-io] onig = { git = "https://github.com/rust-onig/rust-onig", default-features = false } +pact_models = { version = "~1.2.1", path = "./pact_models" } \ No newline at end of file diff --git a/rust/pact_cli/Cargo.toml b/rust/pact_cli/Cargo.toml index 184b0b838..39ca6a4f5 100644 --- a/rust/pact_cli/Cargo.toml +++ b/rust/pact_cli/Cargo.toml @@ -17,7 +17,7 @@ exclude = [ clap = "2.31.2" serde_json = "1.0" serde = "1.0" -pact_models = { version = "~1.2.0", path = "../pact_models" } +pact_models = { version = "~1.2.1", path = "../pact_models" } pact_matching = { version = "~1.1.10", path = "../pact_matching" } anyhow = "1.0.40" log = "0.4.14" diff --git a/rust/pact_consumer/Cargo.toml b/rust/pact_consumer/Cargo.toml index 7cf19cde1..ccfc000ce 100644 --- a/rust/pact_consumer/Cargo.toml +++ b/rust/pact_consumer/Cargo.toml @@ -31,7 +31,7 @@ lazy_static = "1.4.0" maplit = "1.0.2" pact_matching = { version = "~1.2.3", path = "../pact_matching", default-features = false } pact_mock_server = { version = "~1.2.8", default-features = false } -pact_models = { version = "~1.2.0", default-features = false } +pact_models = { version = "~1.2.1", default-features = false } pact-plugin-driver = { version = "~0.6.1", optional = true, default-features = false } regex = "1.10.4" serde_json = "1.0.115" diff --git a/rust/pact_ffi/Cargo.toml b/rust/pact_ffi/Cargo.toml index e3b0ce8c5..c0c64aad2 100644 --- a/rust/pact_ffi/Cargo.toml +++ b/rust/pact_ffi/Cargo.toml @@ -32,7 +32,7 @@ multipart = { version = "0.18.0", default-features = false, features = ["client" onig = { version = "6.4.0", default-features = false } pact_matching = { version = "~1.2.3", path = "../pact_matching" } pact_mock_server = { version = "~1.2.8" } -pact_models = { version = "~1.2.0" } +pact_models = { version = "~1.2.1" } pact-plugin-driver = { version = "~0.6.1" } pact_verifier = { version = "~1.2.1", path = "../pact_verifier" } panic-message = "0.3.0" diff --git a/rust/pact_matching/Cargo.toml b/rust/pact_matching/Cargo.toml index 7dcf3e445..0994bdebe 100644 --- a/rust/pact_matching/Cargo.toml +++ b/rust/pact_matching/Cargo.toml @@ -41,7 +41,7 @@ mime = "0.3.17" multer = { version = "3.0.0", features = ["all"], optional = true } nom = "7.1.3" onig = { version = "6.4.0", default-features = false } -pact_models = { version = "~1.2.0", default-features = false } +pact_models = { version = "~1.2.1", default-features = false } pact-plugin-driver = { version = "~0.6.1", optional = true, default-features = false } rand = "0.8.5" reqwest = { version = "0.12.3", default-features = false, features = ["rustls-tls-native-roots", "json"] } diff --git a/rust/pact_verifier/Cargo.toml b/rust/pact_verifier/Cargo.toml index 42c6b1b53..536b56a6f 100644 --- a/rust/pact_verifier/Cargo.toml +++ b/rust/pact_verifier/Cargo.toml @@ -36,7 +36,7 @@ lazy_static = "1.4.0" maplit = "1.0.2" mime = "0.3.17" pact_matching = { version = "~1.2.3", path = "../pact_matching", default-features = false } -pact_models = { version = "~1.2.0", default-features = false } +pact_models = { version = "~1.2.1", default-features = false } pact-plugin-driver = { version = "~0.6.1", optional = true, default-features = false } regex = "1.10.4" reqwest = { version = "0.12.3", default-features = false, features = ["rustls-tls-native-roots", "blocking", "json"] } diff --git a/rust/pact_verifier_cli/Cargo.toml b/rust/pact_verifier_cli/Cargo.toml index 81e8657ad..e6161b3b0 100644 --- a/rust/pact_verifier_cli/Cargo.toml +++ b/rust/pact_verifier_cli/Cargo.toml @@ -29,7 +29,7 @@ env_logger = "0.11.2" junit-report = { version = "0.8.3", optional = true } log = "0.4.20" maplit = "1.0.2" -pact_models = { version = "~1.2.0", default-features = false } +pact_models = { version = "~1.2.1", default-features = false } pact_verifier = { version = "~1.2.1", path = "../pact_verifier", default-features = false } regex = "1.10.2" reqwest = { version = "0.12.4", default-features = false, features = ["rustls-tls-native-roots", "blocking", "json"] } diff --git a/rust/pact_wasm/Cargo.toml b/rust/pact_wasm/Cargo.toml index 12cf27727..26f67c27c 100644 --- a/rust/pact_wasm/Cargo.toml +++ b/rust/pact_wasm/Cargo.toml @@ -18,7 +18,7 @@ exclude = [ crate-type = ["cdylib", "rlib"] [dependencies] -pact_models = { version = "~1.2.0", path = "../pact_models" } +pact_models = { version = "~1.2.1", path = "../pact_models" } wasm-bindgen = "0.2.79" console_error_panic_hook = "0.1.7" console_log = { version = "0.2.0", features = ["color"] } From 5f3362e6446f1bf23033c43458093b02589120f5 Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Thu, 6 Jun 2024 22:22:08 +0100 Subject: [PATCH 2/3] fix: pact merging creating dupes without provider states and type matchings with multi interactions in one file --- rust/pact_models/src/message_pact.rs | 2 +- rust/pact_models/src/pact.rs | 83 +++++++++++++++++++++- rust/pact_models/src/v4/pact.rs | 102 +++++++++++++++++++++++++-- 3 files changed, 179 insertions(+), 8 deletions(-) diff --git a/rust/pact_models/src/message_pact.rs b/rust/pact_models/src/message_pact.rs index 579547a1b..a7e75bc0b 100644 --- a/rust/pact_models/src/message_pact.rs +++ b/rust/pact_models/src/message_pact.rs @@ -308,7 +308,7 @@ impl ReadWritePact for MessagePact { let messages: Vec> = self.messages.iter() .merge_join_by(pact.interactions().iter(), |a, b| { let cmp = Ord::cmp(&a.description, &b.description()); - if cmp == Ordering::Equal { + if cmp == Ordering::Equal && ! &a.provider_states().is_empty(){ Ord::cmp(&a.provider_states.iter().map(|p| p.name.clone()).collect::>(), &b.provider_states().iter().map(|p| p.name.clone()).collect::>()) } else { diff --git a/rust/pact_models/src/pact.rs b/rust/pact_models/src/pact.rs index 0ad19e1bc..6ca6af9f3 100644 --- a/rust/pact_models/src/pact.rs +++ b/rust/pact_models/src/pact.rs @@ -232,8 +232,12 @@ pub fn write_pact( warn!("Note: Existing pact is an older specification version ({:?}), and will be upgraded", existing_pact.specification_version()); } - + // println!("existing pact: {}",serde_json::to_string_pretty(&existing_pact.to_json(pact_spec)?)?); + // println!("new pact: {}",serde_json::to_string_pretty(&pact.to_json(pact_spec)?)?); + // println!("merging pacts"); + let merged_pact = pact.merge(existing_pact.deref())?; + // println!("merged pact json: {}",serde_json::to_string_pretty(&merged_pact.to_json(pact_spec)?)?); let pact_json = serde_json::to_string_pretty(&merged_pact.to_json(pact_spec)?)?; with_write_lock(path, &mut f, 3, &mut |f| { @@ -1010,6 +1014,83 @@ mod tests { }}"#, PACT_RUST_VERSION.unwrap()))); } + #[test] + fn write_pact_test_should_merge_duplicate_pacts() { + let pact = RequestResponsePact { consumer: Consumer { name: "dupe_consumer".to_string() }, + provider: Provider { name: "dupe_provider".to_string() }, + interactions: vec![ + RequestResponseInteraction { + description: "Test Interaction".to_string(), + request: Request { headers: Some(hashmap!{ + "Accept".to_string()=>vec!["application/json".to_string()] + }), .. Request::default() }, + .. RequestResponseInteraction::default() + } + ], + metadata: btreemap!{}, + specification_version: PactSpecification::V3 + }; + let pact2 = RequestResponsePact { consumer: Consumer { name: "dupe_consumer".to_string() }, + provider: Provider { name: "dupe_provider".to_string() }, + interactions: vec![ + RequestResponseInteraction { + description: "Test Interaction".to_string(), + request: Request { headers: Some(hashmap!{ + "Accept".to_string()=>vec!["application/json".to_string()] + }), .. Request::default() }, + .. RequestResponseInteraction::default() + } + ], + metadata: btreemap!{}, + specification_version: PactSpecification::V3 + }; + let mut dir = env::temp_dir(); + let x = rand::random::(); + dir.push(format!("pact_test_{}", x)); + dir.push(pact.default_file_name()); + + let result = write_pact(pact.boxed(), dir.as_path(), PactSpecification::V3, false); + let result2 = write_pact(pact2.boxed(), dir.as_path(), PactSpecification::V3, false); + + let pact_file: String = read_pact_file(dir.as_path().to_str().unwrap()).unwrap_or("".to_string()); + fs::remove_dir_all(dir.parent().unwrap()).unwrap_or(()); + + expect!(result).to(be_ok()); + expect!(result2).to(be_ok()); + expect!(pact_file).to(be_equal_to(format!(r#"{{ + "consumer": {{ + "name": "dupe_consumer" + }}, + "interactions": [ + {{ + "description": "Test Interaction", + "request": {{ + "headers": {{ + "Accept": "application/json" + }}, + "method": "GET", + "path": "/" + }}, + "response": {{ + "status": 200 + }} + }} + ], + "metadata": {{ + "pactRust": {{ + "models": "{}" + }}, + "pactSpecification": {{ + "version": "3.0.0" + }} + }}, + "provider": {{ + "name": "dupe_provider" + }} +}}"#, PACT_RUST_VERSION.unwrap()))); + } + + #[test] fn write_pact_test_should_not_merge_pacts_with_conflicts() { let pact = RequestResponsePact { consumer: Consumer { name: "write_pact_test_consumer".to_string() }, diff --git a/rust/pact_models/src/v4/pact.rs b/rust/pact_models/src/v4/pact.rs index f3f0c3be1..c80b33eec 100644 --- a/rust/pact_models/src/v4/pact.rs +++ b/rust/pact_models/src/v4/pact.rs @@ -367,16 +367,25 @@ impl ReadWritePact for V4Pact { (_, _) => { let type_a = a.type_of(); let type_b = b.type_of(); - let cmp = Ord::cmp(&type_a, &type_b); - if cmp == Ordering::Equal { + // println!("a.type: {}",type_a); + // println!("b.type: {}",type_b); + let cmp = Ord::cmp(&a.description(), &b.description()); + // println!("a.description: {}",&a.description()); + // println!("b.description: {}",&b.description()); + if cmp == Ordering::Equal && !a.provider_states().is_empty() { let cmp = Ord::cmp(&a.provider_states().iter().map(|p| p.name.clone()).collect::>(), - &b.provider_states().iter().map(|p| p.name.clone()).collect::>()); + &b.provider_states().iter().map(|p| p.name.clone()).collect::>()); if cmp == Ordering::Equal { - Ord::cmp(&a.description(), &b.description()) - } else { + Ord::cmp(&type_a, &type_b) + } else + { cmp } - } else { + } + else if cmp == Ordering::Equal && a.provider_states().is_empty() { + Ord::cmp(&type_a, &type_b) + } + else { cmp } } @@ -957,6 +966,87 @@ mod tests { "name": "write_pact_test_provider" }} }}"#, PACT_RUST_VERSION.unwrap()))); + + } + #[test] + fn write_pact_test_should_merge_duplicate_pacts() { + let pact = V4Pact { + consumer: Consumer { name: "write_pact_test_consumer".into() }, + provider: Provider { name: "write_pact_test_provider".into() }, + interactions: vec![ + Box::new(SynchronousHttp { + description: "Test Interaction".into(), + request: HttpRequest { headers: Some(hashmap!{ + "Accept".to_string()=>vec!["application/json".to_string()] + }), .. HttpRequest::default() }, + .. SynchronousHttp::default() + }) + ], + metadata: btreemap!{}, + plugin_data: vec![] + }; + let pact2 = V4Pact { + consumer: Consumer { name: "write_pact_test_consumer".into() }, + provider: Provider { name: "write_pact_test_provider".into() }, + interactions: vec![ + Box::new(SynchronousHttp { + description: "Test Interaction".into(), + request: HttpRequest { headers: Some(hashmap!{ + "Accept".to_string()=>vec!["application/json".to_string()] + }), .. HttpRequest::default() }, + .. SynchronousHttp::default() + }) + ], + metadata: btreemap!{}, + plugin_data: vec![] + }; + let mut dir = env::temp_dir(); + let x = rand::random::(); + dir.push(format!("pact_test_{}", x)); + dir.push(pact.default_file_name()); + + let result = write_pact(pact.boxed(), dir.as_path(), PactSpecification::V4, false); + let result2: Result<(), anyhow::Error> = write_pact(pact2.boxed(), dir.as_path(), PactSpecification::V4, false); + let pact_file = read_pact_file(dir.as_path().to_str().unwrap()).unwrap_or_default(); + fs::remove_dir_all(dir.parent().unwrap()).unwrap_or(()); + + expect!(result).to(be_ok()); + expect!(result2).to(be_ok()); + expect!(pact_file).to(be_equal_to(format!(r#"{{ + "consumer": {{ + "name": "write_pact_test_consumer" + }}, + "interactions": [ + {{ + "description": "Test Interaction", + "pending": false, + "request": {{ + "headers": {{ + "Accept": [ + "application/json" + ] + }}, + "method": "GET", + "path": "/" + }}, + "response": {{ + "status": 200 + }}, + "type": "Synchronous/HTTP" + }} + ], + "metadata": {{ + "pactRust": {{ + "models": "{}" + }}, + "pactSpecification": {{ + "version": "4.0" + }} + }}, + "provider": {{ + "name": "write_pact_test_provider" + }} +}}"#, PACT_RUST_VERSION.unwrap()))); } #[test] From 51cf97c62c51d019ebe9119f7644fdc7e36efd04 Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Thu, 6 Jun 2024 22:26:53 +0100 Subject: [PATCH 3/3] chore: updates pact_models to 1.2.1 (compat suite) --- compatibility-suite/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/compatibility-suite/Cargo.toml b/compatibility-suite/Cargo.toml index 7b60d1a3a..a1a46a745 100644 --- a/compatibility-suite/Cargo.toml +++ b/compatibility-suite/Cargo.toml @@ -64,3 +64,4 @@ harness = false [patch.crates-io] pact_matching = { path = "../rust/pact_matching" } +pact_models = { path = "../rust/pact_models" }