Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Entity slicing integration testing #1156

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cedar-testing/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ default = ["ipaddr", "decimal"]
decimal = ["cedar-policy/decimal"]
ipaddr = ["cedar-policy/ipaddr"]
integration-testing = []
entity-manifest = ["cedar-policy/entity-manifest"]

[dev-dependencies]
assert_cmd = "2.0"
Expand Down
95 changes: 64 additions & 31 deletions cedar-testing/src/integration_testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ use cedar_policy_core::ast::{EntityUID, PolicySet, Request};
use cedar_policy_core::entities::{self, json::err::JsonDeserializationErrorContext, Entities};
use cedar_policy_core::extensions::Extensions;
use cedar_policy_core::{jsonvalue::JsonValueWithNoDuplicateKeys, parser};
#[cfg(feature = "entity-manifest")]
use cedar_policy_validator::entity_manifest::compute_entity_manifest;
use cedar_policy_validator::ValidatorSchema;
use serde::{Deserialize, Serialize};
use std::{
Expand Down Expand Up @@ -252,6 +254,47 @@ pub fn parse_request_from_test(
})
}

/// Asserts that the test response matches the json request,
/// including errors when the error comparison mode is enabled.
fn check_matches_json(
response: TestResponse,
json_request: &JsonRequest,
error_comparison_mode: ErrorComparisonMode,
test_name: &str,
) {
// check decision
assert_eq!(
response.response.decision(),
json_request.decision,
"test {test_name} failed for request \"{}\": unexpected decision",
&json_request.description
);
// check reason
let reason: HashSet<PolicyId> = response.response.diagnostics().reason().cloned().collect();
assert_eq!(
reason,
json_request.reason.iter().cloned().collect(),
"test {test_name} failed for request \"{}\": unexpected reason",
&json_request.description
);
// check errors, if applicable
// for now, the integration tests only support the `PolicyIds` comparison mode
if matches!(error_comparison_mode, ErrorComparisonMode::PolicyIds) {
let errors: HashSet<PolicyId> = response
.response
.diagnostics()
.errors()
.map(|err| err.policy_id.clone())
.collect();
assert_eq!(
errors,
json_request.errors.iter().cloned().collect(),
"test {test_name} failed for request \"{}\": unexpected errors",
&json_request.description
);
}
}

/// Run an integration test starting from a pre-parsed `JsonTest`.
///
/// # Panics
Expand Down Expand Up @@ -294,38 +337,28 @@ pub fn perform_integration_test(
let response = test_impl
.is_authorized(&request, &policies, &entities)
.expect("Authorization failed");
// check decision
assert_eq!(
response.response.decision(),
json_request.decision,
"test {test_name} failed for request \"{}\": unexpected decision",
&json_request.description
);
// check reason
let reason: HashSet<PolicyId> = response.response.diagnostics().reason().cloned().collect();
assert_eq!(
reason,
json_request.reason.into_iter().collect(),
"test {test_name} failed for request \"{}\": unexpected reason",
&json_request.description
);
// check errors, if applicable
// for now, the integration tests only support the `PolicyIds` comparison mode
if matches!(
check_matches_json(
response,
&json_request,
test_impl.error_comparison_mode(),
ErrorComparisonMode::PolicyIds
) {
let errors: HashSet<PolicyId> = response
.response
.diagnostics()
.errors()
.map(|err| err.policy_id.clone())
.collect();
assert_eq!(
errors,
json_request.errors.into_iter().collect(),
"test {test_name} failed for request \"{}\": unexpected errors",
&json_request.description
test_name,
);

// now check that entity slicing arrives at the same decision
#[cfg(feature = "entity-manifest")]
if should_validate {
let entity_manifest = compute_entity_manifest(&schema, &policies).expect("test failed");
let entity_slice = entity_manifest
.slice_entities(&entities, &request)
.expect("test failed");
let slice_response = test_impl
.is_authorized(&request, &policies, &entity_slice)
.expect("Authorization failed");
check_matches_json(
slice_response,
&json_request,
test_impl.error_comparison_mode(),
test_name,
);
}
}
Expand Down
Loading