From ec6dec91a30737b0c58c0ddceafbaae4d43e2754 Mon Sep 17 00:00:00 2001 From: oflatt Date: Thu, 29 Aug 2024 13:40:44 -0600 Subject: [PATCH] integration testing should test entity manifest Signed-off-by: oflatt --- cedar-testing/Cargo.toml | 1 + cedar-testing/src/integration_testing.rs | 95 ++++++++++++++++-------- 2 files changed, 65 insertions(+), 31 deletions(-) diff --git a/cedar-testing/Cargo.toml b/cedar-testing/Cargo.toml index 1ac371adb..c9b704a28 100644 --- a/cedar-testing/Cargo.toml +++ b/cedar-testing/Cargo.toml @@ -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" diff --git a/cedar-testing/src/integration_testing.rs b/cedar-testing/src/integration_testing.rs index ad6d9d5ad..49c02ab4c 100644 --- a/cedar-testing/src/integration_testing.rs +++ b/cedar-testing/src/integration_testing.rs @@ -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::{ @@ -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 = 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 = 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 @@ -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 = 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 = 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, ); } }