From f890a36e71f7242e1ddd1a206680ffe48115a826 Mon Sep 17 00:00:00 2001 From: ndr_brt Date: Fri, 5 Apr 2024 09:19:38 +0200 Subject: [PATCH] fix: handle multiple consequences in ODRL duty (#4085) --- DEPENDENCIES | 2 +- .../edc/policy/engine/ScopeFilter.java | 28 ++++----- .../edc/policy/engine/ScopeFilterTest.java | 4 +- .../from/JsonObjectFromPolicyTransformer.java | 7 ++- .../odrl/to/JsonObjectToDutyTransformer.java | 2 +- .../JsonObjectFromPolicyTransformerTest.java | 12 ++-- .../to/JsonObjectToDutyTransformerTest.java | 57 +++++++------------ .../org/eclipse/edc/policy/model/Duty.java | 23 +++++--- .../PolicyDefinitionSerializationTest.java | 22 ++----- .../PolicyDefinitionApiEndToEndTest.java | 26 ++++----- 10 files changed, 83 insertions(+), 100 deletions(-) diff --git a/DEPENDENCIES b/DEPENDENCIES index d66d78a7f3b..faba1599696 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -348,7 +348,7 @@ maven/mavencentral/org.slf4j/slf4j-api/2.0.9, MIT, approved, #5915 maven/mavencentral/org.testcontainers/database-commons/1.19.7, Apache-2.0, approved, #10345 maven/mavencentral/org.testcontainers/jdbc/1.19.7, Apache-2.0, approved, #10348 maven/mavencentral/org.testcontainers/junit-jupiter/1.19.7, MIT, approved, #10344 -maven/mavencentral/org.testcontainers/kafka/1.19.7, None, restricted, #14177 +maven/mavencentral/org.testcontainers/kafka/1.19.7, MIT, approved, #14177 maven/mavencentral/org.testcontainers/postgresql/1.19.7, MIT, approved, #10350 maven/mavencentral/org.testcontainers/testcontainers/1.19.7, Apache-2.0 AND MIT, approved, #10347 maven/mavencentral/org.testcontainers/vault/1.19.7, MIT, approved, #10852 diff --git a/core/common/lib/policy-engine-lib/src/main/java/org/eclipse/edc/policy/engine/ScopeFilter.java b/core/common/lib/policy-engine-lib/src/main/java/org/eclipse/edc/policy/engine/ScopeFilter.java index 534b9a98b73..4df196b6114 100644 --- a/core/common/lib/policy-engine-lib/src/main/java/org/eclipse/edc/policy/engine/ScopeFilter.java +++ b/core/common/lib/policy-engine-lib/src/main/java/org/eclipse/edc/policy/engine/ScopeFilter.java @@ -59,8 +59,7 @@ public Policy applyScope(Policy policy, String scope) { var filteredObligations = policy.getObligations().stream().map(d -> applyScope(d, scope)).filter(Objects::nonNull).collect(toList()); var filteredPermissions = policy.getPermissions().stream().map(p -> applyScope(p, scope)).filter(Objects::nonNull).collect(toList()); var filteredProhibitions = policy.getProhibitions().stream().map(p -> applyScope(p, scope)).filter(Objects::nonNull).collect(toList()); - var policyBuilder = Policy.Builder.newInstance(); - policyBuilder + return Policy.Builder.newInstance() .type(policy.getType()) .assignee(policy.getAssignee()) .assigner(policy.getAssigner()) @@ -69,8 +68,8 @@ public Policy applyScope(Policy policy, String scope) { .duties(filteredObligations) .permissions(filteredPermissions) .prohibitions(filteredProhibitions) - .extensibleProperties(policy.getExtensibleProperties()); - return policyBuilder.build(); + .extensibleProperties(policy.getExtensibleProperties()) + .build(); } @Nullable @@ -79,7 +78,7 @@ Permission applyScope(Permission permission, String scope) { return null; } var filteredConstraints = applyScope(permission.getConstraints(), scope); - var filteredDuties = permission.getDuties().stream().map(d -> applyScope(d, scope)).filter(Objects::nonNull).collect(toList()); + var filteredDuties = permission.getDuties().stream().map(d -> applyScope(d, scope)).filter(Objects::nonNull).toList(); return Permission.Builder.newInstance() .action(permission.getAction()) @@ -93,14 +92,17 @@ Duty applyScope(Duty duty, String scope) { if (actionNotInScope(duty, scope)) { return null; } - var filteredConsequence = duty.getConsequence() != null ? applyScope(duty.getConsequence(), scope) : null; + var filteredConsequences = duty.getConsequences().stream() + .map(consequence -> applyScope(consequence, scope)) + .filter(Objects::nonNull) + .toList(); var filteredConstraints = applyScope(duty.getConstraints(), scope); return Duty.Builder.newInstance() .action(duty.getAction()) .constraints(filteredConstraints) .parentPermission(duty.getParentPermission()) - .consequence(filteredConsequence) + .consequences(filteredConsequences) .build(); } @@ -119,10 +121,10 @@ Prohibition applyScope(Prohibition prohibition, String scope) { @Nullable Constraint applyScope(Constraint rootConstraint, String scope) { - if (rootConstraint instanceof AtomicConstraint) { - return applyScope((AtomicConstraint) rootConstraint, scope); + if (rootConstraint instanceof AtomicConstraint atomicConstraint) { + return applyScope(atomicConstraint, scope); } else if (rootConstraint instanceof MultiplicityConstraint multiplicityConstraint) { - var filteredConstraints = multiplicityConstraint.getConstraints().stream().map(c -> applyScope(c, scope)).filter(Objects::nonNull).collect(toList()); + var filteredConstraints = multiplicityConstraint.getConstraints().stream().map(c -> applyScope(c, scope)).filter(Objects::nonNull).toList(); return filteredConstraints.isEmpty() ? null : multiplicityConstraint.create(filteredConstraints); } return rootConstraint; @@ -133,13 +135,13 @@ private boolean actionNotInScope(Rule rule, String scope) { } private List applyScope(List constraints, String scope) { - return constraints.stream().map(constraint -> applyScope(constraint, scope)).filter(Objects::nonNull).collect(toList()); + return constraints.stream().map(constraint -> applyScope(constraint, scope)).filter(Objects::nonNull).toList(); } @Nullable private Constraint applyScope(AtomicConstraint constraint, String scope) { - if (constraint.getLeftExpression() instanceof LiteralExpression) { - return registry.isInScope(((LiteralExpression) constraint.getLeftExpression()).asString(), scope) ? constraint : null; + if (constraint.getLeftExpression() instanceof LiteralExpression literalExpression) { + return registry.isInScope(literalExpression.asString(), scope) ? constraint : null; } else { return constraint; } diff --git a/core/common/lib/policy-engine-lib/src/test/java/org/eclipse/edc/policy/engine/ScopeFilterTest.java b/core/common/lib/policy-engine-lib/src/test/java/org/eclipse/edc/policy/engine/ScopeFilterTest.java index 5542feba5ce..c3690a291aa 100644 --- a/core/common/lib/policy-engine-lib/src/test/java/org/eclipse/edc/policy/engine/ScopeFilterTest.java +++ b/core/common/lib/policy-engine-lib/src/test/java/org/eclipse/edc/policy/engine/ScopeFilterTest.java @@ -31,6 +31,7 @@ import static org.assertj.core.api.Assertions.assertThat; class ScopeFilterTest { + public static final String BOUND_SCOPE = "scope1"; private static final Action REPORT_ACTION = Action.Builder.newInstance().type("report").build(); private static final Action SUB_ACTION = Action.Builder.newInstance().type("subaction").build(); @@ -80,7 +81,6 @@ void verifyFiltersPolicy() { assertThat(filteredPolicy.getObligations()).isNotEmpty(); assertThat(filteredPolicy.getProhibitions()).isNotEmpty(); assertThat(filteredPolicy.getExtensibleProperties()).isNotEmpty(); - } @Test @@ -163,7 +163,7 @@ void verifyFiltersDutyType() { assertThat(filteredDuty).isNotNull(); assertThat(filteredDuty.getAction()).isNotNull(); - assertThat(filteredDuty.getConsequence()).isNotNull(); + assertThat(filteredDuty.getConsequences()).hasSize(1); assertThat(filteredDuty.getConstraints().size()).isEqualTo(1); // verify that the unbound constraint was removed assertThat(filteredDuty.getConstraints()).contains(BOUND_CONSTRAINT); } diff --git a/core/control-plane/control-plane-transform/src/main/java/org/eclipse/edc/connector/controlplane/transform/odrl/from/JsonObjectFromPolicyTransformer.java b/core/control-plane/control-plane-transform/src/main/java/org/eclipse/edc/connector/controlplane/transform/odrl/from/JsonObjectFromPolicyTransformer.java index a8c3044c4aa..1364bd0b742 100644 --- a/core/control-plane/control-plane-transform/src/main/java/org/eclipse/edc/connector/controlplane/transform/odrl/from/JsonObjectFromPolicyTransformer.java +++ b/core/control-plane/control-plane-transform/src/main/java/org/eclipse/edc/connector/controlplane/transform/odrl/from/JsonObjectFromPolicyTransformer.java @@ -210,9 +210,10 @@ public JsonObject visitProhibition(Prohibition prohibition) { public JsonObject visitDuty(Duty duty) { var obligationBuilder = visitRule(duty); - if (duty.getConsequence() != null) { - var consequence = visitDuty(duty.getConsequence()); - obligationBuilder.add(ODRL_CONSEQUENCE_ATTRIBUTE, consequence); + var consequences = duty.getConsequences(); + if (consequences != null && !consequences.isEmpty()) { + var consequencesJson = consequences.stream().map(this::visitDuty).collect(toJsonArray()); + obligationBuilder.add(ODRL_CONSEQUENCE_ATTRIBUTE, consequencesJson); } return obligationBuilder.build(); diff --git a/core/control-plane/control-plane-transform/src/main/java/org/eclipse/edc/connector/controlplane/transform/odrl/to/JsonObjectToDutyTransformer.java b/core/control-plane/control-plane-transform/src/main/java/org/eclipse/edc/connector/controlplane/transform/odrl/to/JsonObjectToDutyTransformer.java index 5f99391e602..48d5b65841f 100644 --- a/core/control-plane/control-plane-transform/src/main/java/org/eclipse/edc/connector/controlplane/transform/odrl/to/JsonObjectToDutyTransformer.java +++ b/core/control-plane/control-plane-transform/src/main/java/org/eclipse/edc/connector/controlplane/transform/odrl/to/JsonObjectToDutyTransformer.java @@ -43,7 +43,7 @@ public JsonObjectToDutyTransformer() { visitProperties(object, key -> switch (key) { case ODRL_ACTION_ATTRIBUTE -> value -> builder.action(transformObject(value, Action.class, context)); case ODRL_CONSTRAINT_ATTRIBUTE -> value -> builder.constraints(transformArray(value, Constraint.class, context)); - case ODRL_CONSEQUENCE_ATTRIBUTE -> value -> builder.consequence(transformObject(value, Duty.class, context)); + case ODRL_CONSEQUENCE_ATTRIBUTE -> value -> builder.consequences(transformArray(value, Duty.class, context)); default -> doNothing(); }); diff --git a/core/control-plane/control-plane-transform/src/test/java/org/eclipse/edc/connector/controlplane/transform/odrl/from/JsonObjectFromPolicyTransformerTest.java b/core/control-plane/control-plane-transform/src/test/java/org/eclipse/edc/connector/controlplane/transform/odrl/from/JsonObjectFromPolicyTransformerTest.java index daefc67159f..e0ea3f2c02d 100644 --- a/core/control-plane/control-plane-transform/src/test/java/org/eclipse/edc/connector/controlplane/transform/odrl/from/JsonObjectFromPolicyTransformerTest.java +++ b/core/control-plane/control-plane-transform/src/test/java/org/eclipse/edc/connector/controlplane/transform/odrl/from/JsonObjectFromPolicyTransformerTest.java @@ -273,11 +273,13 @@ void transform_prohibitionWithConstraint_returnJsonObject() { void transform_dutyWithConstraintAndConsequence_returnJsonObject() { var constraint = getConstraint(); var action = getAction(); - var consequence = Duty.Builder.newInstance().action(action).build(); + var firstConsequence = Duty.Builder.newInstance().action(action).build(); + var secondConsequence = Duty.Builder.newInstance().action(action).build(); var duty = Duty.Builder.newInstance() .action(action) .constraint(constraint) - .consequence(consequence) + .consequence(firstConsequence) + .consequence(secondConsequence) .build(); var policy = Policy.Builder.newInstance().duty(duty).build(); @@ -294,8 +296,10 @@ void transform_dutyWithConstraintAndConsequence_returnJsonObject() { assertThat(constraintJson.getJsonObject(ODRL_RIGHT_OPERAND_ATTRIBUTE).getJsonString(VALUE).getString()) .isEqualTo(((LiteralExpression) constraint.getRightExpression()).getValue()); - var consequenceJson = dutyJson.getJsonObject(ODRL_CONSEQUENCE_ATTRIBUTE); - assertThat(consequenceJson.getJsonObject(ODRL_ACTION_ATTRIBUTE)).isNotNull(); + var consequencesJson = dutyJson.getJsonArray(ODRL_CONSEQUENCE_ATTRIBUTE); + assertThat(consequencesJson).hasSize(2).map(JsonValue::asJsonObject).allSatisfy(consequenceJson -> { + assertThat(consequenceJson.getJsonObject(ODRL_ACTION_ATTRIBUTE)).isNotNull(); + }); verify(context, never()).reportProblem(anyString()); } diff --git a/core/control-plane/control-plane-transform/src/test/java/org/eclipse/edc/connector/controlplane/transform/odrl/to/JsonObjectToDutyTransformerTest.java b/core/control-plane/control-plane-transform/src/test/java/org/eclipse/edc/connector/controlplane/transform/odrl/to/JsonObjectToDutyTransformerTest.java index 9f1932044b3..172e92f807b 100644 --- a/core/control-plane/control-plane-transform/src/test/java/org/eclipse/edc/connector/controlplane/transform/odrl/to/JsonObjectToDutyTransformerTest.java +++ b/core/control-plane/control-plane-transform/src/test/java/org/eclipse/edc/connector/controlplane/transform/odrl/to/JsonObjectToDutyTransformerTest.java @@ -14,7 +14,6 @@ package org.eclipse.edc.connector.controlplane.transform.odrl.to; -import jakarta.json.Json; import jakarta.json.JsonObject; import org.eclipse.edc.connector.controlplane.transform.TestInput; import org.eclipse.edc.policy.model.Action; @@ -23,12 +22,10 @@ import org.eclipse.edc.policy.model.Duty; import org.eclipse.edc.transform.spi.TransformerContext; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -import java.util.Map; -import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import static jakarta.json.Json.createArrayBuilder; +import static jakarta.json.Json.createObjectBuilder; import static org.assertj.core.api.Assertions.assertThat; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_ACTION_ATTRIBUTE; @@ -47,7 +44,7 @@ class JsonObjectToDutyTransformerTest { private static final String TARGET = "target"; - private final TransformerContext context = mock(TransformerContext.class); + private final TransformerContext context = mock(); private final Action action = Action.Builder.newInstance().type("type").build(); private final Constraint constraint = AtomicConstraint.Builder.newInstance().build(); @@ -64,46 +61,32 @@ void setUp() { when(context.transform(isA(JsonObject.class), eq(Duty.class))).thenReturn(consequence); } - @ParameterizedTest - @MethodSource("jsonSource") - void transform_returnDuty(JsonObject jsonDuty) { + @Test + void transform_returnDuty() { + var actionJson = createObjectBuilder().add(TYPE, "action"); + var constraintJson = createObjectBuilder().add(TYPE, "constraint"); + var consequencesJson = createArrayBuilder() + .add(createObjectBuilder().add(TYPE, "consequence")) + .add(createObjectBuilder().add(TYPE, "consequence")); + var jsonDuty = createObjectBuilder() + .add(ODRL_ACTION_ATTRIBUTE, actionJson) + .add(ODRL_CONSTRAINT_ATTRIBUTE, constraintJson) + .add(ODRL_CONSEQUENCE_ATTRIBUTE, consequencesJson) + .add(ODRL_TARGET_ATTRIBUTE, TARGET) + .build(); + var result = transformer.transform(TestInput.getExpanded(jsonDuty), context); assertThat(result).isNotNull(); assertThat(result.getAction()).isEqualTo(action); assertThat(result.getConstraints()).hasSize(1); assertThat(result.getConstraints().get(0)).isEqualTo(constraint); - assertThat(result.getConsequence()).isEqualTo(consequence); + assertThat(result.getConsequences()).hasSize(2).first().isEqualTo(consequence); verify(context, never()).reportProblem(anyString()); verify(context, times(1)).transform(isA(JsonObject.class), eq(Action.class)); verify(context, times(1)).transform(isA(JsonObject.class), eq(Constraint.class)); - verify(context, times(1)).transform(isA(JsonObject.class), eq(Duty.class)); - } - - static Stream jsonSource() { - var jsonFactory = Json.createBuilderFactory(Map.of()); - var actionJson = jsonFactory.createObjectBuilder().add(TYPE, "action"); - var constraintJson = jsonFactory.createObjectBuilder().add(TYPE, "constraint"); - var consequenceJson = jsonFactory.createObjectBuilder().add(TYPE, "consequence"); - - return Stream.of( - // as object - jsonFactory.createObjectBuilder() - .add(ODRL_ACTION_ATTRIBUTE, actionJson) - .add(ODRL_CONSTRAINT_ATTRIBUTE, constraintJson) - .add(ODRL_CONSEQUENCE_ATTRIBUTE, consequenceJson) - .add(ODRL_TARGET_ATTRIBUTE, TARGET) - .build(), - - // as arrays - jsonFactory.createObjectBuilder() - .add(ODRL_ACTION_ATTRIBUTE, jsonFactory.createArrayBuilder().add(actionJson)) - .add(ODRL_CONSTRAINT_ATTRIBUTE, jsonFactory.createArrayBuilder().add(constraintJson)) - .add(ODRL_CONSEQUENCE_ATTRIBUTE, jsonFactory.createArrayBuilder().add(consequenceJson)) - .add(ODRL_TARGET_ATTRIBUTE, jsonFactory.createArrayBuilder().add(TARGET)) - .build() - ); + verify(context, times(2)).transform(isA(JsonObject.class), eq(Duty.class)); } } diff --git a/spi/common/policy-model/src/main/java/org/eclipse/edc/policy/model/Duty.java b/spi/common/policy-model/src/main/java/org/eclipse/edc/policy/model/Duty.java index 201b2bb78f4..e1754fd9ce2 100644 --- a/spi/common/policy-model/src/main/java/org/eclipse/edc/policy/model/Duty.java +++ b/spi/common/policy-model/src/main/java/org/eclipse/edc/policy/model/Duty.java @@ -21,24 +21,20 @@ import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.List; + import static java.util.stream.Collectors.joining; /** * An obligation that must be performed if all its constraints are satisfied. - * TODO: Do we need to support deserializing the parent permission setting? */ @JsonDeserialize(builder = Duty.Builder.class) @JsonTypeName("dataspaceconnector:duty") public class Duty extends Rule { private Permission parentPermission; - - @Nullable - private Duty consequence; - - public Duty getConsequence() { - return consequence; - } + private final List consequences = new ArrayList<>(); /** * If this duty is part of a permission, returns the parent permission; otherwise returns null. @@ -48,6 +44,10 @@ public Permission getParentPermission() { return parentPermission; } + public List getConsequences() { + return consequences; + } + void setParentPermission(Permission permission) { parentPermission = permission; } @@ -80,7 +80,12 @@ public Builder parentPermission(Permission parentPermission) { } public Builder consequence(Duty consequence) { - rule.consequence = consequence; + rule.consequences.add(consequence); + return this; + } + + public Builder consequences(List consequences) { + rule.consequences.addAll(consequences); return this; } diff --git a/spi/control-plane/policy-spi/src/test/java/org/eclipse/edc/connector/controlplane/policy/spi/PolicyDefinitionSerializationTest.java b/spi/control-plane/policy-spi/src/test/java/org/eclipse/edc/connector/controlplane/policy/spi/PolicyDefinitionSerializationTest.java index 2715f0264bd..1560edf0cd2 100644 --- a/spi/control-plane/policy-spi/src/test/java/org/eclipse/edc/connector/controlplane/policy/spi/PolicyDefinitionSerializationTest.java +++ b/spi/control-plane/policy-spi/src/test/java/org/eclipse/edc/connector/controlplane/policy/spi/PolicyDefinitionSerializationTest.java @@ -31,7 +31,6 @@ class PolicyDefinitionSerializationTest { private final TypeManager typeManager = new TypeManager(); - @Test void verifySerialization() { var policyDef = PolicyDefinition.Builder.newInstance() @@ -42,9 +41,7 @@ void verifySerialization() { .build(); var json = typeManager.writeValueAsString(policyDef); - assertThat(json).isNotNull(); - assertThat(json).contains("createdAt"); - assertThat(json).contains("sampleInheritsFrom"); + assertThat(json).isNotNull().contains("createdAt").contains("sampleInheritsFrom"); var deserialized = typeManager.readValue(json, PolicyDefinition.class); assertThat(deserialized).usingRecursiveComparison().isEqualTo(policyDef); @@ -52,21 +49,14 @@ void verifySerialization() { } private Policy createPolicy() { - var permission = Permission.Builder.newInstance().build(); - - var prohibition = Prohibition.Builder.newInstance().build(); - - var duty = Duty.Builder.newInstance().build(); - - var p = Policy.Builder.newInstance() - .permission(permission) - .prohibition(prohibition) - .duties(List.of(duty)) + return Policy.Builder.newInstance() + .permission(Permission.Builder.newInstance().build()) + .prohibition(Prohibition.Builder.newInstance().build()) + .duties(List.of(Duty.Builder.newInstance().build())) .inheritsFrom("sampleInheritsFrom") .assigner("sampleAssigner") .assignee("sampleAssignee") .target("sampleTarget") - .type(PolicyType.SET); - return p.build(); + .type(PolicyType.SET).build(); } } diff --git a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/PolicyDefinitionApiEndToEndTest.java b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/PolicyDefinitionApiEndToEndTest.java index 82b230d989f..e20fc51db44 100644 --- a/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/PolicyDefinitionApiEndToEndTest.java +++ b/system-tests/management-api/management-api-test-runner/src/test/java/org/eclipse/edc/test/e2e/managementapi/PolicyDefinitionApiEndToEndTest.java @@ -20,11 +20,7 @@ import org.eclipse.edc.junit.annotations.EndToEndTest; import org.eclipse.edc.junit.annotations.PostgresqlIntegrationTest; import org.eclipse.edc.junit.extensions.EdcRuntimeExtension; -import org.eclipse.edc.policy.model.Action; -import org.eclipse.edc.policy.model.Duty; import org.eclipse.edc.policy.model.Policy; -import org.eclipse.edc.policy.model.Prohibition; -import org.eclipse.edc.policy.model.Rule; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.BeforeAllCallback; @@ -38,7 +34,6 @@ import static jakarta.json.Json.createObjectBuilder; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.InstanceOfAssertFactories.MAP; -import static org.assertj.core.api.InstanceOfAssertFactories.list; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.CONTEXT; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; @@ -108,14 +103,6 @@ void shouldStorePolicyDefinition() { .contentType(JSON) .extract().jsonPath().getString(ID); - assertThat(store().findById(id)).isNotNull() - .extracting(PolicyDefinition::getPolicy).isNotNull().satisfies(policy -> { - assertThat(policy.getPermissions()).hasSize(1); - assertThat(policy.getProhibitions()).hasSize(1).first() - .extracting(Prohibition::getRemedies).asInstanceOf(list(Duty.class)).first() - .extracting(Rule::getAction).extracting(Action::getType).isEqualTo(ODRL_SCHEMA + "anonymize"); - }); - baseRequest() .get("/v2/policydefinitions/" + id) .then() @@ -126,7 +113,8 @@ void shouldStorePolicyDefinition() { .body(CONTEXT, hasEntry(EDC_PREFIX, EDC_NAMESPACE)) .body(CONTEXT, hasEntry(ODRL_PREFIX, ODRL_SCHEMA)) .body("policy.'odrl:permission'.'odrl:constraint'.'odrl:operator'.@id", is("odrl:eq")) - .body("policy.'odrl:prohibition'.'odrl:remedy'.'odrl:action'.'odrl:type'", is(ODRL_SCHEMA + "anonymize")); + .body("policy.'odrl:prohibition'.'odrl:remedy'.'odrl:action'.'odrl:type'", is(ODRL_SCHEMA + "anonymize")) + .body("policy.'odrl:obligation'.'odrl:consequence'.size()", is(2)); } @Test @@ -346,6 +334,16 @@ private JsonObject sampleOdrlPolicy() { .add("remedy", createObjectBuilder() .add("action", "anonymize")) )) + .add("obligation", createArrayBuilder() + .add(createObjectBuilder() + .add("target", "http://example.com/data:77") + .add("action", "use") + .add("consequence", createArrayBuilder() + .add(createObjectBuilder().add("action", "use")) + .add(createObjectBuilder().add("action", "anonymize")) + ) + ) + ) .build(); }