diff --git a/extensions/common/api/management-api-json-ld-context/src/main/resources/document/management-context-v1.jsonld b/extensions/common/api/management-api-json-ld-context/src/main/resources/document/management-context-v1.jsonld index 18b0efdf7f6..d8227fe8b7d 100644 --- a/extensions/common/api/management-api-json-ld-context/src/main/resources/document/management-context-v1.jsonld +++ b/extensions/common/api/management-api-json-ld-context/src/main/resources/document/management-context-v1.jsonld @@ -36,6 +36,16 @@ "SuspendTransfer": "edc:SuspendTransfer", "Secret": "edc:Secret", "EndpointDataReferenceEntry": "edc:EndpointDataReferenceEntry", + "PolicyValidationResult": "edc:PolicyValidationResult", + "PolicyEvaluationPlanRequest": "edc:PolicyEvaluationPlanRequest", + "PolicyEvaluationPlan": "edc:PolicyEvaluationPlan", + "PermissionStep": "edc:PermissionStep", + "ProhibitionStep": "edc:ProhibitionStep", + "DutyStep": "edc:DutyStep", + "OrConstraintStep": "edc:OrConstraintStep", + "AndConstraintStep": "edc:AndConstraintStep", + "XoneConstraintStep": "edc:XoneConstraintStep", + "AtomicConstraintStep": "edc:AtomicConstraintStep", "properties": { "@id": "edc:properties", "@context": { @@ -111,6 +121,54 @@ "transferProcessId": "edc:transferProcessId", "contractNegotiationId": "edc:contractNegotiationId", "agreementId": "edc:agreementId", - "inForceDate": "edc:inForceDate" + "inForceDate": "edc:inForceDate", + "isValid": "edc:isValid", + "errors": { + "@id": "edc:errors", + "@container": "@set" + }, + "policyScope": "edc:policyScope", + "preValidators": { + "@id": "edc:preValidators", + "@container": "@set" + }, + "postValidators": { + "@id": "edc:postValidators", + "@container": "@set" + }, + "permissionSteps": { + "@id": "edc:permissionSteps", + "@container": "@set" + }, + "prohibitionSteps": { + "@id": "edc:prohibitionSteps", + "@container": "@set" + }, + "obligationSteps": { + "@id": "edc:obligationSteps", + "@container": "@set" + }, + "constraintSteps": { + "@id": "edc:constraintSteps", + "@container": "@set" + }, + "filteringReasons": { + "@id": "edc:filteringReasons", + "@container": "@set" + }, + "isFiltered": "edc:isFiltered", + "functionName": "edc:functionName", + "functionParams": { + "@id": "edc:functionParams", + "@container": "@set" + }, + "dutySteps": { + "@id": "edc:dutySteps", + "@container": "@set" + }, + "ruleFunctions": { + "@id": "edc:ruleFunctions", + "@container": "@set" + } } } \ No newline at end of file diff --git a/extensions/common/api/management-api-json-ld-context/src/test/java/org/eclipse/edc/connector/api/management/jsonld/serde/SerdeIntegrationTest.java b/extensions/common/api/management-api-json-ld-context/src/test/java/org/eclipse/edc/connector/api/management/jsonld/serde/SerdeIntegrationTest.java index a187248bde6..446349fe0f3 100644 --- a/extensions/common/api/management-api-json-ld-context/src/test/java/org/eclipse/edc/connector/api/management/jsonld/serde/SerdeIntegrationTest.java +++ b/extensions/common/api/management-api-json-ld-context/src/test/java/org/eclipse/edc/connector/api/management/jsonld/serde/SerdeIntegrationTest.java @@ -17,7 +17,10 @@ import jakarta.json.Json; import jakarta.json.JsonObject; import jakarta.json.JsonString; +import jakarta.json.JsonValue; import org.eclipse.edc.connector.controlplane.api.management.contractnegotiation.model.NegotiationState; +import org.eclipse.edc.connector.controlplane.api.management.policy.model.PolicyEvaluationPlanRequest; +import org.eclipse.edc.connector.controlplane.api.management.policy.model.PolicyValidationResult; import org.eclipse.edc.connector.controlplane.api.management.transferprocess.model.SuspendTransfer; import org.eclipse.edc.connector.controlplane.api.management.transferprocess.model.TerminateTransfer; import org.eclipse.edc.connector.controlplane.api.management.transferprocess.model.TransferState; @@ -54,8 +57,11 @@ import org.junit.jupiter.params.provider.ArgumentsProvider; import org.junit.jupiter.params.provider.ArgumentsSource; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -69,9 +75,11 @@ import static org.eclipse.edc.connector.api.management.jsonld.serde.TestFunctions.createContractAgreement; import static org.eclipse.edc.connector.api.management.jsonld.serde.TestFunctions.createContractNegotiation; import static org.eclipse.edc.connector.api.management.jsonld.serde.TestFunctions.createEdrEntry; +import static org.eclipse.edc.connector.api.management.jsonld.serde.TestFunctions.createPolicyEvaluationPlan; import static org.eclipse.edc.connector.api.management.jsonld.serde.TestFunctions.createTransferProcess; import static org.eclipse.edc.connector.api.management.jsonld.serde.TestFunctions.inForceDatePermission; import static org.eclipse.edc.connector.api.management.jsonld.serde.TestFunctions.policyDefinitionObject; +import static org.eclipse.edc.connector.api.management.jsonld.serde.TestFunctions.policyEvaluationPlanRequest; import static org.eclipse.edc.connector.api.management.jsonld.serde.TestFunctions.querySpecObject; import static org.eclipse.edc.connector.api.management.jsonld.serde.TestFunctions.secretObject; import static org.eclipse.edc.connector.api.management.jsonld.serde.TestFunctions.suspendTransferObject; @@ -208,6 +216,62 @@ void ser_TransferState() { } + @Test + void ser_PolicyValidationResult() { + var result = new PolicyValidationResult(false, List.of("error1", "error2")); + var compactResult = serialize(result); + + assertThat(compactResult).isNotNull(); + assertThat(compactResult.getString(TYPE)).isEqualTo("PolicyValidationResult"); + assertThat(compactResult.getBoolean("isValid")).isEqualTo(false); + assertThat(compactResult.getJsonArray("errors")).contains(Json.createValue("error1"), Json.createValue("error2")); + + } + + @Test + void ser_PolicyEvaluationPlan() { + var plan = createPolicyEvaluationPlan(); + var compactResult = serialize(plan); + + assertThat(compactResult).isNotNull(); + assertThat(compactResult.getString(TYPE)).isEqualTo("PolicyEvaluationPlan"); + assertThat(compactResult.getJsonArray("preValidators")).hasSize(1); + assertThat(compactResult.getJsonArray("postValidators")).hasSize(1); + + + BiFunction> ruleAsser = (ruleType, multiplicityType) -> (ruleValue) -> { + var rule = ruleValue.asJsonObject(); + assertThat(rule.getString(TYPE)).isEqualTo(ruleType); + assertThat(rule.getJsonArray("ruleFunctions")).hasSize(0); + assertThat(rule.getJsonArray("constraintSteps")).hasSize(1); + + var constraint = rule.getJsonArray("constraintSteps").get(0).asJsonObject(); + assertThat(constraint.getString(TYPE)).isEqualTo(multiplicityType); + assertThat(constraint.getJsonArray("constraintSteps")).hasSize(2) + .allSatisfy(value -> { + var atomicConstraint = value.asJsonObject(); + assertThat(atomicConstraint.getString(TYPE)).isEqualTo("AtomicConstraintStep"); + assertThat(atomicConstraint.getJsonArray("filteringReasons")).hasSize(1); + assertThat(atomicConstraint.getBoolean("isFiltered")).isTrue(); + assertThat(atomicConstraint.getString("functionName")).isEqualTo("AtomicConstraintFunction"); + assertThat(atomicConstraint.getJsonArray("functionParams")).hasSize(3); + }); + }; + + assertThat(compactResult.getJsonArray("permissionSteps")).hasSize(1) + .first() + .satisfies(ruleAsser.apply("PermissionStep", "OrConstraintStep")); + + assertThat(compactResult.getJsonArray("prohibitionSteps")).hasSize(1) + .first() + .satisfies(ruleAsser.apply("ProhibitionStep", "AndConstraintStep")); + + assertThat(compactResult.getJsonArray("obligationSteps")).hasSize(1) + .first() + .satisfies(ruleAsser.apply("DutyStep", "XoneConstraintStep")); + + } + @Test void de_ContractRequest() { var inputObject = contractRequestObject(); @@ -293,6 +357,16 @@ void de_PolicyDefinition_withInForceDate() { } + @Test + void de_PolicyEvaluationPlanRequest() { + var inputObject = policyEvaluationPlanRequest(); + var terminateTransfer = deserialize(inputObject, PolicyEvaluationPlanRequest.class); + + assertThat(terminateTransfer).isNotNull(); + assertThat(terminateTransfer.policyScope()).isEqualTo(inputObject.getString("policyScope")); + + } + /** * Tests for entities that supports transformation from/to JsonObject */ diff --git a/extensions/common/api/management-api-json-ld-context/src/test/java/org/eclipse/edc/connector/api/management/jsonld/serde/TestFunctions.java b/extensions/common/api/management-api-json-ld-context/src/test/java/org/eclipse/edc/connector/api/management/jsonld/serde/TestFunctions.java index 34a15529612..d9d75fbb1a7 100644 --- a/extensions/common/api/management-api-json-ld-context/src/test/java/org/eclipse/edc/connector/api/management/jsonld/serde/TestFunctions.java +++ b/extensions/common/api/management-api-json-ld-context/src/test/java/org/eclipse/edc/connector/api/management/jsonld/serde/TestFunctions.java @@ -22,7 +22,21 @@ import org.eclipse.edc.connector.controlplane.contract.spi.types.negotiation.ContractNegotiation; import org.eclipse.edc.connector.controlplane.transfer.spi.types.TransferProcess; import org.eclipse.edc.edr.spi.types.EndpointDataReferenceEntry; +import org.eclipse.edc.policy.engine.spi.AtomicConstraintFunction; +import org.eclipse.edc.policy.engine.spi.plan.PolicyEvaluationPlan; +import org.eclipse.edc.policy.engine.spi.plan.step.AndConstraintStep; +import org.eclipse.edc.policy.engine.spi.plan.step.AtomicConstraintStep; +import org.eclipse.edc.policy.engine.spi.plan.step.ConstraintStep; +import org.eclipse.edc.policy.engine.spi.plan.step.DutyStep; +import org.eclipse.edc.policy.engine.spi.plan.step.OrConstraintStep; +import org.eclipse.edc.policy.engine.spi.plan.step.PermissionStep; +import org.eclipse.edc.policy.engine.spi.plan.step.ProhibitionStep; +import org.eclipse.edc.policy.engine.spi.plan.step.ValidatorStep; +import org.eclipse.edc.policy.engine.spi.plan.step.XoneConstraintStep; +import org.eclipse.edc.policy.model.AtomicConstraint; +import org.eclipse.edc.policy.model.LiteralExpression; import org.eclipse.edc.policy.model.Policy; +import org.eclipse.edc.policy.model.Rule; import org.eclipse.edc.spi.types.domain.DataAddress; import org.eclipse.edc.spi.types.domain.callback.CallbackAddress; @@ -42,10 +56,13 @@ import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; import static org.eclipse.edc.policy.model.OdrlNamespace.ODRL_SCHEMA; +import static org.eclipse.edc.policy.model.Operator.EQ; import static org.eclipse.edc.spi.constants.CoreConstants.EDC_NAMESPACE; import static org.eclipse.edc.spi.types.domain.callback.CallbackAddress.EVENTS; import static org.eclipse.edc.spi.types.domain.callback.CallbackAddress.IS_TRANSACTIONAL; import static org.eclipse.edc.spi.types.domain.callback.CallbackAddress.URI; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class TestFunctions { @@ -225,6 +242,30 @@ public static EndpointDataReferenceEntry createEdrEntry() { .build(); } + public static PolicyEvaluationPlan createPolicyEvaluationPlan() { + + var firstConstraint = atomicConstraintStep(atomicConstraint("foo", "bar")); + var secondConstraint = atomicConstraintStep(atomicConstraint("baz", "bar")); + + List constraints = List.of(firstConstraint, secondConstraint); + + var orConstraintStep = new OrConstraintStep(constraints, mock()); + var andConstraintStep = new AndConstraintStep(constraints, mock()); + var xoneConstraintStep = new XoneConstraintStep(constraints, mock()); + + var permission = PermissionStep.Builder.newInstance().constraint(orConstraintStep).rule(mock()).build(); + var duty = DutyStep.Builder.newInstance().constraint(xoneConstraintStep).rule(mock()).build(); + var prohibition = ProhibitionStep.Builder.newInstance().constraint(andConstraintStep).rule(mock()).build(); + + return PolicyEvaluationPlan.Builder.newInstance() + .postValidator(new ValidatorStep(mock())) + .prohibition(prohibition) + .permission(permission) + .duty(duty) + .preValidator(new ValidatorStep(mock())) + .build(); + } + public static JsonObject policyDefinitionObject() { return createObjectBuilder() .add(CONTEXT, createContextBuilder().build()) @@ -312,4 +353,28 @@ public static JsonObject inForceDatePermission(String operatorStart, Object star .build()) .build(); } + + public static JsonObject policyEvaluationPlanRequest() { + return Json.createObjectBuilder() + .add(CONTEXT, createContextBuilder().build()) + .add(TYPE, "PolicyEvaluationPlanRequest") + .add("policyScope", "catalog") + .build(); + } + + private static AtomicConstraintStep atomicConstraintStep(AtomicConstraint atomicConstraint) { + AtomicConstraintFunction function = mock(); + when(function.name()).thenReturn("AtomicConstraintFunction"); + return new AtomicConstraintStep(atomicConstraint, List.of("filtered constraint"), mock(), function); + } + + private static AtomicConstraint atomicConstraint(String key, String value) { + var left = new LiteralExpression(key); + var right = new LiteralExpression(value); + return AtomicConstraint.Builder.newInstance() + .leftExpression(left) + .operator(EQ) + .rightExpression(right) + .build(); + } }