Skip to content

Commit

Permalink
fix(FFI): creating a new interaction with the same description as an …
Browse files Browse the repository at this point in the history
…existiong one will now replace it #389
  • Loading branch information
rholshausen committed Feb 17, 2024
1 parent 8b35aab commit 5dad90c
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 7 deletions.
40 changes: 33 additions & 7 deletions rust/pact_ffi/src/mock_server/handles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,15 @@ ffi_fn! {
}
}

/// Creates a new HTTP Interaction and returns a handle to it.
fn find_interaction_with_description(pact: &V4Pact, description: &str) -> Option<usize> {
pact.interactions.iter().find_position(|i| {
i.description() == description
}).map(|(index, _)| index)
}

/// Creates a new HTTP Interaction and returns a handle to it. Calling this function with the
/// same description as an existing interaction will result in that interaction being replaced
/// with the new one.
///
/// * `description` - The interaction description. It needs to be unique for each interaction.
///
Expand All @@ -441,8 +449,14 @@ pub extern fn pactffi_new_interaction(pact: PactHandle, description: *const c_ch
description: description.to_string(),
..SynchronousHttp::default()
};
inner.pact.interactions.push(interaction.boxed_v4());
InteractionHandle::new(pact, inner.pact.interactions.len() as u16)
if let Some(index) = find_interaction_with_description(&inner.pact, description) {
warn!("There is an existing interaction with description '{}', it will be replaced", description);
inner.pact.interactions[index] = interaction.boxed_v4();
InteractionHandle::new(pact, (index + 1) as u16)
} else {
inner.pact.interactions.push(interaction.boxed_v4());
InteractionHandle::new(pact, inner.pact.interactions.len() as u16)
}
}).unwrap_or_else(|| InteractionHandle::new(pact, 0))
} else {
InteractionHandle::new(pact, 0)
Expand All @@ -461,8 +475,14 @@ pub extern fn pactffi_new_message_interaction(pact: PactHandle, description: *co
description: description.to_string(),
..AsynchronousMessage::default()
};
inner.pact.interactions.push(interaction.boxed_v4());
InteractionHandle::new(pact, inner.pact.interactions.len() as u16)
if let Some(index) = find_interaction_with_description(&inner.pact, description) {
warn!("There is an existing interaction with description '{}', it will be replaced", description);
inner.pact.interactions[index] = interaction.boxed_v4();
InteractionHandle::new(pact, (index + 1) as u16)
} else {
inner.pact.interactions.push(interaction.boxed_v4());
InteractionHandle::new(pact, inner.pact.interactions.len() as u16)
}
}).unwrap_or_else(|| InteractionHandle::new(pact, 0))
} else {
InteractionHandle::new(pact, 0)
Expand All @@ -481,8 +501,14 @@ pub extern fn pactffi_new_sync_message_interaction(pact: PactHandle, description
description: description.to_string(),
..SynchronousMessage::default()
};
inner.pact.interactions.push(interaction.boxed_v4());
InteractionHandle::new(pact, inner.pact.interactions.len() as u16)
if let Some(index) = find_interaction_with_description(&inner.pact, description) {
warn!("There is an existing interaction with description '{}', it will be replaced", description);
inner.pact.interactions[index] = interaction.boxed_v4();
InteractionHandle::new(pact, (index + 1) as u16)
} else {
inner.pact.interactions.push(interaction.boxed_v4());
InteractionHandle::new(pact, inner.pact.interactions.len() as u16)
}
}).unwrap_or_else(|| InteractionHandle::new(pact, 0))
} else {
InteractionHandle::new(pact, 0)
Expand Down
73 changes: 73 additions & 0 deletions rust/pact_ffi/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -930,3 +930,76 @@ fn merging_pact_file() {
}"#
);
}

// Issue #389
#[test_log::test]
fn repeated_interaction() {
let pact_handle = PactHandle::new("MergingPactC2", "MergingPactP2");
pactffi_with_specification(pact_handle, PactSpecification::V4);

let description = CString::new("a request for an order with an unknown ID").unwrap();
let path = CString::new("/api/orders/404").unwrap();
let method = CString::new("GET").unwrap();
let accept = CString::new("Accept").unwrap();
let header = CString::new("application/json").unwrap();

let i_handle = pactffi_new_interaction(pact_handle, description.as_ptr());
pactffi_with_request(i_handle, method.as_ptr(), path.as_ptr());
pactffi_with_header_v2(i_handle, InteractionPart::Request, accept.as_ptr(), 0, header.as_ptr());
pactffi_response_status(i_handle, 200);

let i_handle = pactffi_new_interaction(pact_handle, description.as_ptr());
pactffi_with_request(i_handle, method.as_ptr(), path.as_ptr());
pactffi_with_header_v2(i_handle, InteractionPart::Request, accept.as_ptr(), 0, header.as_ptr());
pactffi_response_status(i_handle, 200);

let i_handle = pactffi_new_interaction(pact_handle, description.as_ptr());
pactffi_with_request(i_handle, method.as_ptr(), path.as_ptr());
pactffi_with_header_v2(i_handle, InteractionPart::Request, accept.as_ptr(), 0, header.as_ptr());
pactffi_response_status(i_handle, 200);

let tmp = tempfile::tempdir().unwrap();
let tmp_dir = CString::new(tmp.path().to_string_lossy().as_bytes().to_vec()).unwrap();
let result = pactffi_pact_handle_write_file(pact_handle, tmp_dir.as_ptr(), false);

let pact_file = pact_default_file_name(&pact_handle);
pactffi_free_pact_handle(pact_handle);

expect!(result).to(be_equal_to(0));

let pact_path = tmp.path().join(pact_file.unwrap());
let f= File::open(pact_path).unwrap();

let mut json: Value = serde_json::from_reader(f).unwrap();
json["metadata"] = Value::Null;
assert_eq!(serde_json::to_string_pretty(&json).unwrap(),
r#"{
"consumer": {
"name": "MergingPactC2"
},
"interactions": [
{
"description": "a request for an order with an unknown ID",
"pending": false,
"request": {
"headers": {
"Accept": [
"application/json"
]
},
"method": "GET",
"path": "/api/orders/404"
},
"response": {
"status": 200
},
"type": "Synchronous/HTTP"
}
],
"metadata": null,
"provider": {
"name": "MergingPactP2"
}
}"#
);
}

0 comments on commit 5dad90c

Please sign in to comment.