Skip to content

Commit

Permalink
feat(verifier): Add the client language to the verification results i…
Browse files Browse the repository at this point in the history
…f set #307
  • Loading branch information
rholshausen committed Feb 18, 2024
1 parent 6975203 commit 2b5148b
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 33 deletions.
9 changes: 6 additions & 3 deletions rust/pact_verifier/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1074,7 +1074,7 @@ pub async fn verify_provider_async<F: RequestFilterExecutor, S: ProviderStateExe
verification_result.interaction_results.extend_from_slice(results.as_slice());

if let Some(publish) = publish_options {
publish_result(results.as_slice(), &pact_source, &publish).await;
publish_result(results.as_slice(), &pact_source, &publish, metrics_data.as_ref()).await;

if !errors.is_empty() || !pending_errors.is_empty() {
process_notices(&context, VERIFICATION_NOTICE_AFTER_ERROR_RESULT_AND_PUBLISH, &mut verification_result);
Expand Down Expand Up @@ -1566,17 +1566,18 @@ async fn publish_result(
results: &[VerificationInteractionResult],
source: &PactSource,
options: &PublishOptions,
metrics_data: Option<&VerificationMetrics>
) {
let publish_result = match source {
PactSource::BrokerUrl(_, broker_url, auth, links) => {
publish_to_broker(results, source, &options.build_url, &options.provider_tags,
&options.provider_branch, &options.provider_version, links.clone(), broker_url.clone(),
auth.clone()
auth.clone(), metrics_data
).await
}
PactSource::BrokerWithDynamicConfiguration { broker_url, auth, links, provider_branch, provider_tags, .. } => {
publish_to_broker(results, source, &options.build_url, &provider_tags, &provider_branch,
&options.provider_version, links.clone(), broker_url.clone(), auth.clone()
&options.provider_version, links.clone(), broker_url.clone(), auth.clone(), metrics_data
).await
}
_ => {
Expand All @@ -1600,6 +1601,7 @@ async fn publish_to_broker(
links: Vec<Link>,
broker_url: String,
auth: Option<HttpAuth>,
metrics_data: Option<&VerificationMetrics>
) -> Result<Value, pact_broker::PactBrokerError> {
info!("Publishing verification results back to the Pact Broker");
let result = if results.iter().all(|r| r.result.is_ok()) {
Expand All @@ -1622,6 +1624,7 @@ async fn publish_to_broker(
build_url.clone(),
provider_tags.clone(),
provider_branch.clone(),
metrics_data
).await
}

Expand Down
1 change: 1 addition & 0 deletions rust/pact_verifier/src/metrics.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Structs for collecting metrics for verification
/// Metrics data to send after running a verification
#[derive(Clone, Debug)]
pub struct VerificationMetrics {
/// test framework used to run the tests
pub test_framework: String,
Expand Down
66 changes: 54 additions & 12 deletions rust/pact_verifier/src/pact_broker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use tracing::{debug, error, info, trace, warn};
use pact_matching::Mismatch;

use crate::{MismatchResult, VERIFIER_VERSION};
use crate::metrics::VerificationMetrics;
use crate::utils::with_retries;

fn is_true(object: &serde_json::Map<String, Value>, field: &str) -> bool {
Expand Down Expand Up @@ -790,7 +791,8 @@ pub async fn publish_verification_results(
version: String,
build_url: Option<String>,
provider_tags: Vec<String>,
branch: Option<String>
branch: Option<String>,
metrics_data: Option<&VerificationMetrics>
) -> Result<serde_json::Value, PactBrokerError> {
let hal_client = HALClient::with_url(broker_url, auth.clone());

Expand All @@ -810,11 +812,16 @@ pub async fn publish_verification_results(
"Response from the pact broker has no 'pb:publish-verification-results' link".into()
))?;

let json = build_payload(result, version, build_url);
let json = build_payload(result, version, build_url, metrics_data);
hal_client.post_json(publish_link.href.unwrap_or_default().as_str(), json.to_string().as_str()).await
}

fn build_payload(result: TestResult, version: String, build_url: Option<String>) -> serde_json::Value {
fn build_payload(
result: TestResult,
version: String,
build_url: Option<String>,
metrics_data: Option<&VerificationMetrics>
) -> serde_json::Value {
let mut json = json!({
"success": result.to_bool(),
"providerApplicationVersion": version,
Expand All @@ -825,8 +832,16 @@ fn build_payload(result: TestResult, version: String, build_url: Option<String>)
});
let json_obj = json.as_object_mut().unwrap();

if build_url.is_some() {
json_obj.insert("buildUrl".into(), json!(build_url.unwrap()));
if let Some(build_url) = build_url {
json_obj.insert("buildUrl".into(), build_url.into());
}

if let Some(metrics_data) = metrics_data {
json_obj.get_mut("verifiedBy").unwrap()["clientLanguage"] = json!({
"testFramework": metrics_data.test_framework,
"name": metrics_data.app_name,
"version": metrics_data.app_version
});
}

match result {
Expand Down Expand Up @@ -1082,6 +1097,7 @@ mod tests {
use pact_models::{Consumer, PactSpecification, Provider};
use pact_models::prelude::RequestResponsePact;
use pact_models::sync_interaction::RequestResponseInteraction;
use pretty_assertions::assert_eq;

use pact_consumer::*;
use pact_consumer::prelude::*;
Expand Down Expand Up @@ -2018,7 +2034,7 @@ mod tests {
#[test]
fn test_build_payload_with_success() {
let result = TestResult::Ok(vec![]);
let payload = super::build_payload(result, "1".to_string(), None);
let payload = super::build_payload(result, "1".to_string(), None, None);
expect!(payload).to(be_equal_to(json!({
"providerApplicationVersion": "1",
"success": true,
Expand All @@ -2033,7 +2049,7 @@ mod tests {
#[test]
fn test_build_payload_adds_the_build_url_if_provided() {
let result = TestResult::Ok(vec![]);
let payload = super::build_payload(result, "1".to_string(), Some("http://build-url".to_string()));
let payload = super::build_payload(result, "1".to_string(), Some("http://build-url".to_string()), None);
expect!(payload).to(be_equal_to(json!({
"providerApplicationVersion": "1",
"success": true,
Expand All @@ -2049,7 +2065,7 @@ mod tests {
#[test]
fn test_build_payload_adds_a_result_for_each_interaction() {
let result = TestResult::Ok(vec![Some("1".to_string()), Some("2".to_string()), Some("3".to_string()), None]);
let payload = super::build_payload(result, "1".to_string(), Some("http://build-url".to_string()));
let payload = super::build_payload(result, "1".to_string(), Some("http://build-url".to_string()), None);
expect!(payload).to(be_equal_to(json!({
"providerApplicationVersion": "1",
"success": true,
Expand All @@ -2069,7 +2085,7 @@ mod tests {
#[test]
fn test_build_payload_with_failure() {
let result = TestResult::Failed(vec![]);
let payload = super::build_payload(result, "1".to_string(), None);
let payload = super::build_payload(result, "1".to_string(), None, None);
expect!(payload).to(be_equal_to(json!({
"providerApplicationVersion": "1",
"success": false,
Expand All @@ -2093,7 +2109,7 @@ mod tests {
interaction_id: Some("1234abc".to_string())
}))
]);
let payload = super::build_payload(result, "1".to_string(), None);
let payload = super::build_payload(result, "1".to_string(), None, None);
expect!(payload).to(be_equal_to(json!({
"providerApplicationVersion": "1",
"success": false,
Expand All @@ -2120,7 +2136,7 @@ mod tests {
let result = TestResult::Failed(vec![
(Some("1234abc".to_string()), Some(MismatchResult::Error("Bang".to_string(), Some("1234abc".to_string()))))
]);
let payload = super::build_payload(result, "1".to_string(), None);
let payload = super::build_payload(result, "1".to_string(), None, None);
expect!(payload).to(be_equal_to(json!({
"providerApplicationVersion": "1",
"success": false,
Expand Down Expand Up @@ -2156,7 +2172,7 @@ mod tests {
(Some("12345678".to_string()), Some(MismatchResult::Error("Bang".to_string(), Some("1234abc".to_string())))),
(Some("abc123".to_string()), None)
]);
let payload = super::build_payload(result, "1".to_string(), None);
let payload = super::build_payload(result, "1".to_string(), None, None);
expect!(payload).to(be_equal_to(json!({
"providerApplicationVersion": "1",
"success": false,
Expand Down Expand Up @@ -2191,6 +2207,32 @@ mod tests {
})));
}

#[test]
fn test_build_payload_adds_client_language_version_if_provided() {
let result = TestResult::Ok(vec![]);
let metrics = VerificationMetrics {
test_framework: "TEST".to_string(),
app_name: "TESTER".to_string(),
app_version: "1.2.3".to_string()
};
let payload = super::build_payload(result, "1".to_string(), Some("http://build-url".to_string()), Some(&metrics));
assert_eq!(payload, json!({
"providerApplicationVersion": "1",
"success": true,
"buildUrl": "http://build-url",
"testResults": [],
"verifiedBy": {
"implementation": "Pact-Rust",
"version": VERIFIER_VERSION,
"clientLanguage": {
"testFramework": "TEST",
"name": "TESTER",
"version": "1.2.3"
}
}
}));
}

#[test]
fn build_link_from_json() {
let json = json!({
Expand Down
38 changes: 20 additions & 18 deletions rust/pact_verifier/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ fn publish_result_does_nothing_if_not_from_broker() {
provider_tags: vec![],
.. super::PublishOptions::default()
};
super::publish_result(&vec![], &PactSource::File("/tmp/test".into()), &options).await;
super::publish_result(&vec![], &PactSource::File("/tmp/test".into()), &options, None).await;
})
});
expect!(server_response).to(be_err());
Expand Down Expand Up @@ -318,14 +318,15 @@ async fn publish_successful_result_to_broker() {

let source = PactSource::BrokerUrl("Test".to_string(), server.url().to_string(), None, links.clone());
publish_result(&[VerificationInteractionResult {
interaction_id: Some("1".to_string()),
interaction_key: None,
description: "".to_string(),
interaction_description: "".to_string(),
result: Ok(()),
pending: false,
duration: Default::default(),
}], &source, &options).await;
interaction_id: Some("1".to_string()),
interaction_key: None,
description: "".to_string(),
interaction_description: "".to_string(),
result: Ok(()),
pending: false,
duration: Default::default(),
}], &source, &options, None
).await;

// Same publish but with dynamic configuration as pact source:
let source = PactSource::BrokerWithDynamicConfiguration {
Expand All @@ -340,14 +341,15 @@ async fn publish_successful_result_to_broker() {
links
};
super::publish_result(&[VerificationInteractionResult {
interaction_id: Some("1".to_string()),
interaction_key: None,
description: "".to_string(),
interaction_description: "".to_string(),
result: Ok(()),
pending: false,
duration: Default::default(),
}], &source, &options).await;
interaction_id: Some("1".to_string()),
interaction_key: None,
description: "".to_string(),
interaction_description: "".to_string(),
result: Ok(()),
pending: false,
duration: Default::default(),
}], &source, &options, None
).await;
}

#[test]
Expand Down Expand Up @@ -1023,7 +1025,7 @@ async fn test_publish_results_from_url_source_with_provider_branch() {
};
let verification_result = vec![];

publish_result(&verification_result, &source, &options).await;
publish_result(&verification_result, &source, &options, None).await;
}

#[test_log::test(tokio::test)]
Expand Down

0 comments on commit 2b5148b

Please sign in to comment.