Closed wabrit closed 1 year ago
I wonder if this relates to #662 where the nesting didn't work @uglyog ?
I can confirm this is still happening on 12.1.0
I'm really happy! I've spent the last day just understanding Pact architecture (and learning a bit about rust too) and I think I nailed this down to just a single change.
When an arrayContains
operator is used, the flag skip_matchers
is being set to true, causing the inner content not to use the second arrayContains
. See https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_ffi/src/mock_server/bodies.rs#L111
match rule {
MatchingRule::ArrayContains(_) => (obj.get("variants"), true),
_ => (obj.get("value"), false)
}
I'm not gonna submit a PR cause I'm not sure if this flag is set to false
because of a reason, but I can provide the test I created to reproduce the issue and to validate the fix.
In https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_ffi/tests/tests.rs
fn array_contains_matcher() {
let consumer_name = CString::new("array_contains_matcher-consumer").unwrap();
let provider_name = CString::new("array_contains_matcher-provider").unwrap();
let pact_handle = pactffi_new_pact(consumer_name.as_ptr(), provider_name.as_ptr());
let description = CString::new("array_contains_matcher").unwrap();
let interaction = pactffi_new_interaction(pact_handle.clone(), description.as_ptr());
let content_type = CString::new("application/json").unwrap();
let path = CString::new("/book").unwrap();
let json = json!({
"pact:matcher:type": "array-contains",
"variants": [
{
"group": {
"value": "A"
},
"users": {
"pact:matcher:type": "array-contains",
"variants": [
{
"id": {
"value": 1
}
},
{
"id": {
"value": 2
}
},
]
}
},
]
});
let body = CString::new(json.to_string()).unwrap();
let address = CString::new("127.0.0.1:0").unwrap();
let method = CString::new("GET").unwrap();
pactffi_upon_receiving(interaction.clone(), description.as_ptr());
pactffi_with_request(interaction.clone(), method.as_ptr(), path.as_ptr());
pactffi_with_body(interaction.clone(), InteractionPart::Response, content_type.as_ptr(), body.as_ptr());
pactffi_response_status(interaction.clone(), 200);
let port = pactffi_create_mock_server_for_pact(pact_handle.clone(), address.as_ptr(), false);
expect!(port).to(be_greater_than(0));
let client = Client::default();
let result = client.get(format!("http://127.0.0.1:{}/book", port).as_str())
.header("Content-Type", "application/json")
.send();
pactffi_cleanup_mock_server(port);
match result {
Ok(ref res) => {
expect!(res.status()).to(be_eq(200));
},
Err(err) => {
panic!("expected 200 response but request failed: {}", err);
}
};
let json: Value = result.unwrap().json().unwrap();
let users = json.as_array().unwrap().first().unwrap().as_object()
.unwrap().get("users").unwrap();
if users.is_null() {
panic!("'users' field is null in JSON");
}
}
Awesome work Diego - glad you had some fun and learning in the process!
Would you mind raisin an issue, with that reproducible test as part of it here: https://github.com/pact-foundation/pact-reference/issues
We can then link the issues and when the upstream issue is fixed, it will also be fixed here.
The upstream issue was fixed on FFI v0.4.9 https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_ffi/CHANGELOG.md#049---bugfix-release
Thanks! I'll release a new version of the core that uses the FFI today.
Really appreciate your deep dive into this @diestrin! 🙏
Software versions
Expected behaviour
Using arrayContaining matcher should work regardless of nesting level (e.g. arrayContaining including a nested property which is also matched by arrayContaining)
Actual behaviour
An arrayContaining nested inside another arrayContaining causes the mocked server to return null for the inner array.
Steps to reproduce
Sample (GraphQL) query
Sample expectation:
Relevant log files
DEBUG output from consumer test: