You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kie.apache.org by gi...@apache.org on 2024/10/24 08:28:17 UTC

(incubator-kie-kogito-apps) branch main updated: [incubator-kie-issues#1541] Add “evaluationHitIds” to the response of jitexecutor-dmn’s “/dmnresult” route (#2120)

This is an automated email from the ASF dual-hosted git repository.

gitgabrio pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-kogito-apps.git


The following commit(s) were added to refs/heads/main by this push:
     new 7b582c81f [incubator-kie-issues#1541] Add “evaluationHitIds” to the response of jitexecutor-dmn’s “/dmnresult” route (#2120)
7b582c81f is described below

commit 7b582c81f0608589fbc98f0c013d23d14596ccb3
Author: Gabriele Cardosi <ga...@gmail.com>
AuthorDate: Thu Oct 24 10:28:13 2024 +0200

    [incubator-kie-issues#1541] Add “evaluationHitIds” to the response of jitexecutor-dmn’s “/dmnresult” route (#2120)
    
    * exp_dmn_result_mapped_to_input
    
    * [exp_dmn_result_mapped_to_input] WIP
    
    * [incubator-kie-issues#1541] WIP
    
    * [incubator-kie-issues#1541] Implemented retrieval and population of "evaluationHitIds" field
    
    * [incubator-kie-issues#1541] Fixed tests. Minor refactoring
    
    * [incubator-kie-issues#1541] Fix formatting
    
    * [incubator-kie-issues#1541] Fix as per suggestion
    
    * [incubator-kie-issues#1541] Fix as per suggestion
    
    * kie-issues#1541: Extend test coverage
    
    - test DMN model where a decision table is nested under conditional expression
    - test DMN model where collection data type is used as input and output
    
    * Collections -> MultipleHitRules
    
    * [incubator-kie-issues#1541] Remove duplicated test
    
    * [incubator-kie-issues#1541] Fix imports
    
    ---------
    
    Co-authored-by: Gabriele-Cardosi <ga...@ibm.com>
    Co-authored-by: Jozef Marko <jo...@ibm.com>
---
 .../kie/kogito/jitexecutor/dmn/DMNEvaluator.java   |  17 ++-
 .../kie/kogito/jitexecutor/dmn/JITDMNListener.java |  97 ++++++++++++++
 .../kogito/jitexecutor/dmn/JITDMNServiceImpl.java  |   3 +-
 .../jitexecutor/dmn/responses/JITDMNResult.java    |  17 +++
 .../jitexecutor/dmn/JITDMNServiceImplTest.java     | 141 ++++++++++++++++++++-
 .../jitexecutor/dmn/api/JITDMNResourceTest.java    |  62 ++++++++-
 6 files changed, 325 insertions(+), 12 deletions(-)

diff --git a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/DMNEvaluator.java b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/DMNEvaluator.java
index 979f4159b..92ec93303 100644
--- a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/DMNEvaluator.java
+++ b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/DMNEvaluator.java
@@ -22,7 +22,9 @@ import java.io.StringReader;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
 import org.kie.api.io.Resource;
 import org.kie.dmn.api.core.DMNContext;
@@ -36,6 +38,7 @@ import org.kie.dmn.core.internal.utils.DynamicDMNContextBuilder;
 import org.kie.internal.io.ResourceFactory;
 import org.kie.kogito.jitexecutor.common.requests.MultipleResourcesPayload;
 import org.kie.kogito.jitexecutor.common.requests.ResourceWithURI;
+import org.kie.kogito.jitexecutor.dmn.responses.JITDMNResult;
 import org.kie.kogito.jitexecutor.dmn.utils.ResolveByKey;
 
 public class DMNEvaluator {
@@ -47,6 +50,7 @@ public class DMNEvaluator {
         Resource modelResource = ResourceFactory.newReaderResource(new StringReader(modelXML), "UTF-8");
         DMNRuntime dmnRuntime = DMNRuntimeBuilder.fromDefaults().buildConfiguration()
                 .fromResources(Collections.singletonList(modelResource)).getOrElseThrow(RuntimeException::new);
+        dmnRuntime.addListener(new JITDMNListener());
         DMNModel dmnModel = dmnRuntime.getModels().get(0);
         return new DMNEvaluator(dmnModel, dmnRuntime);
     }
@@ -73,9 +77,16 @@ public class DMNEvaluator {
         return dmnRuntime.getModels();
     }
 
-    public DMNResult evaluate(Map<String, Object> context) {
-        DMNContext dmnContext = new DynamicDMNContextBuilder(dmnRuntime.newContext(), dmnModel).populateContextWith(context);
-        return dmnRuntime.evaluateAll(dmnModel, dmnContext);
+    public JITDMNResult evaluate(Map<String, Object> context) {
+        DMNContext dmnContext =
+                new DynamicDMNContextBuilder(dmnRuntime.newContext(), dmnModel).populateContextWith(context);
+        DMNResult dmnResult = dmnRuntime.evaluateAll(dmnModel, dmnContext);
+        Optional<List<String>> evaluationHitIds = dmnRuntime.getListeners().stream()
+                .filter(JITDMNListener.class::isInstance)
+                .findFirst()
+                .map(JITDMNListener.class::cast)
+                .map(JITDMNListener::getEvaluationHitIds);
+        return new JITDMNResult(getNamespace(), getName(), dmnResult, evaluationHitIds.orElse(Collections.emptyList()));
     }
 
     public static DMNEvaluator fromMultiple(MultipleResourcesPayload payload) {
diff --git a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/JITDMNListener.java b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/JITDMNListener.java
new file mode 100644
index 000000000..9f753e754
--- /dev/null
+++ b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/JITDMNListener.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.kie.kogito.jitexecutor.dmn;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.kie.dmn.api.core.event.AfterConditionalEvaluationEvent;
+import org.kie.dmn.api.core.event.AfterEvaluateAllEvent;
+import org.kie.dmn.api.core.event.AfterEvaluateBKMEvent;
+import org.kie.dmn.api.core.event.AfterEvaluateContextEntryEvent;
+import org.kie.dmn.api.core.event.AfterEvaluateDecisionEvent;
+import org.kie.dmn.api.core.event.AfterEvaluateDecisionServiceEvent;
+import org.kie.dmn.api.core.event.AfterEvaluateDecisionTableEvent;
+import org.kie.dmn.api.core.event.AfterInvokeBKMEvent;
+import org.kie.dmn.api.core.event.DMNEvent;
+import org.kie.dmn.api.core.event.DMNRuntimeEventListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JITDMNListener implements DMNRuntimeEventListener {
+
+    private final List<String> evaluationHitIds = new ArrayList<>();
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(JITDMNListener.class);
+
+    @Override
+    public void afterEvaluateDecisionTable(AfterEvaluateDecisionTableEvent event) {
+        logEvent(event);
+        evaluationHitIds.addAll(event.getSelectedIds());
+    }
+
+    @Override
+    public void afterEvaluateDecision(AfterEvaluateDecisionEvent event) {
+        logEvent(event);
+    }
+
+    @Override
+    public void afterEvaluateBKM(AfterEvaluateBKMEvent event) {
+        logEvent(event);
+    }
+
+    @Override
+    public void afterEvaluateContextEntry(AfterEvaluateContextEntryEvent event) {
+        logEvent(event);
+    }
+
+    @Override
+    public void afterEvaluateDecisionService(AfterEvaluateDecisionServiceEvent event) {
+        logEvent(event);
+    }
+
+    @Override
+    public void afterInvokeBKM(AfterInvokeBKMEvent event) {
+        logEvent(event);
+    }
+
+    @Override
+    public void afterEvaluateAll(AfterEvaluateAllEvent event) {
+        logEvent(event);
+    }
+
+    @Override
+    public void afterConditionalEvaluation(AfterConditionalEvaluationEvent event) {
+        logEvent(event);
+        evaluationHitIds.add(event.getExecutedId());
+    }
+
+    public List<String> getEvaluationHitIds() {
+        return evaluationHitIds;
+    }
+
+    private void logEvent(DMNEvent toLog) {
+        LOGGER.info("{} event {}", toLog.getClass().getSimpleName(), toLog);
+    }
+
+    private void logEvent(AfterConditionalEvaluationEvent toLog) {
+        LOGGER.info("{} event {}", toLog.getClass().getSimpleName(), toLog);
+    }
+
+}
diff --git a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/JITDMNServiceImpl.java b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/JITDMNServiceImpl.java
index 320f1a960..bb0b6513c 100644
--- a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/JITDMNServiceImpl.java
+++ b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/JITDMNServiceImpl.java
@@ -76,8 +76,7 @@ public class JITDMNServiceImpl implements JITDMNService {
     @Override
     public JITDMNResult evaluateModel(String modelXML, Map<String, Object> context) {
         DMNEvaluator dmnEvaluator = DMNEvaluator.fromXML(modelXML);
-        DMNResult dmnResult = dmnEvaluator.evaluate(context);
-        return new JITDMNResult(dmnEvaluator.getNamespace(), dmnEvaluator.getName(), dmnResult);
+        return dmnEvaluator.evaluate(context);
     }
 
     @Override
diff --git a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNResult.java b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNResult.java
index bfaea1642..4f43a123f 100644
--- a/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNResult.java
+++ b/jitexecutor/jitexecutor-dmn/src/main/java/org/kie/kogito/jitexecutor/dmn/responses/JITDMNResult.java
@@ -21,6 +21,7 @@ package org.kie.kogito.jitexecutor.dmn.responses;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -49,16 +50,23 @@ public class JITDMNResult implements Serializable,
 
     private Map<String, JITDMNDecisionResult> decisionResults = new HashMap<>();
 
+    private List<String> evaluationHitIds;
+
     public JITDMNResult() {
         // Intentionally blank.
     }
 
     public JITDMNResult(String namespace, String modelName, org.kie.dmn.api.core.DMNResult dmnResult) {
+        this(namespace, modelName, dmnResult, Collections.emptyList());
+    }
+
+    public JITDMNResult(String namespace, String modelName, org.kie.dmn.api.core.DMNResult dmnResult, List<String> evaluationHitIds) {
         this.namespace = namespace;
         this.modelName = modelName;
         this.setDmnContext(dmnResult.getContext().getAll());
         this.setMessages(dmnResult.getMessages());
         this.setDecisionResults(dmnResult.getDecisionResults());
+        this.evaluationHitIds = evaluationHitIds;
     }
 
     public String getNamespace() {
@@ -102,6 +110,14 @@ public class JITDMNResult implements Serializable,
         }
     }
 
+    public List<String> getEvaluationHitIds() {
+        return evaluationHitIds;
+    }
+
+    public void setEvaluationHitIds(List<String> evaluationHitIds) {
+        this.evaluationHitIds = evaluationHitIds;
+    }
+
     @JsonIgnore
     @Override
     public DMNContext getContext() {
@@ -151,6 +167,7 @@ public class JITDMNResult implements Serializable,
                 .append(", dmnContext=").append(dmnContext)
                 .append(", messages=").append(messages)
                 .append(", decisionResults=").append(decisionResults)
+                .append(", evaluationHitIds=").append(evaluationHitIds)
                 .append("]").toString();
     }
 }
diff --git a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/JITDMNServiceImplTest.java b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/JITDMNServiceImplTest.java
index 3169dce37..e99957ef0 100644
--- a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/JITDMNServiceImplTest.java
+++ b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/JITDMNServiceImplTest.java
@@ -19,8 +19,11 @@
 package org.kie.kogito.jitexecutor.dmn;
 
 import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.junit.jupiter.api.Assertions;
@@ -43,7 +46,7 @@ public class JITDMNServiceImplTest {
     }
 
     @Test
-    public void testModelEvaluation() {
+    void testModelEvaluation() {
         Map<String, Object> context = new HashMap<>();
         context.put("FICO Score", 800);
         context.put("DTI Ratio", .1);
@@ -57,7 +60,141 @@ public class JITDMNServiceImplTest {
     }
 
     @Test
-    public void testExplainability() throws IOException {
+    void testDecisionTableModelEvaluation() throws IOException {
+        String decisionTableModel = getModelFromIoUtils("valid_models/DMNv1_x/LoanEligibility.dmn");
+        Map<String, Object> client = new HashMap<>();
+        client.put("age", 43);
+        client.put("salary", 1950);
+        client.put("existing payments", 100);
+
+        Map<String, Object> loan = new HashMap<>();
+        loan.put("duration", 15);
+        loan.put("installment", 180);
+        Map<String, Object> context = new HashMap<>();
+
+        context.put("Client", client);
+        context.put("Loan", loan);
+        context.put("SupremeDirector", "No");
+        context.put("Bribe", 10);
+        JITDMNResult dmnResult = jitdmnService.evaluateModel(decisionTableModel, context);
+
+        Assertions.assertEquals("LoanEligibility", dmnResult.getModelName());
+        Assertions.assertEquals("https://github.com/kiegroup/kogito-examples/dmn-quarkus-listener-example", dmnResult.getNamespace());
+        Assertions.assertTrue(dmnResult.getMessages().isEmpty());
+        Assertions.assertEquals("Yes", dmnResult.getDecisionResultByName("Eligibility").getResult());
+    }
+
+    @Test
+    void testEvaluationHitIds() throws IOException {
+        final String thenElementId = "_6481FF12-61B5-451C-B775-4143D9B6CD6B";
+        final String elseElementId = "_2CD02CB2-6B56-45C4-B461-405E89D45633";
+        final String ruleId0 = "_1578BD9E-2BF9-4BFC-8956-1A736959C937";
+        final String ruleId1 = "_31CD7AA3-A806-4E7E-B512-821F82043620";
+        final String ruleId3 = "_2545E1A8-93D3-4C8A-A0ED-8AD8B10A58F9";
+        final String ruleId4 = "_510A50DA-D5A4-4F06-B0BE-7F8F2AA83740";
+        String decisionTableModel = getModelFromIoUtils("valid_models/DMNv1_5/RiskScore_Simple.dmn");
+        Map<String, Object> context = new HashMap<>();
+        context.put("Credit Score", "Poor");
+        context.put("DTI", 33);
+        JITDMNResult dmnResult = jitdmnService.evaluateModel(decisionTableModel, context);
+
+        Assertions.assertEquals("DMN_A77074C1-21FE-4F7E-9753-F84661569AFC", dmnResult.getModelName());
+        Assertions.assertTrue(dmnResult.getMessages().isEmpty());
+        Assertions.assertEquals(BigDecimal.valueOf(50), dmnResult.getDecisionResultByName("Risk Score").getResult());
+        List<String> evaluationHitIds = dmnResult.getEvaluationHitIds();
+        Assertions.assertNotNull(evaluationHitIds);
+        Assertions.assertEquals(3, evaluationHitIds.size());
+        Assertions.assertTrue(evaluationHitIds.contains(elseElementId));
+        Assertions.assertTrue(evaluationHitIds.contains(ruleId0));
+        Assertions.assertTrue(evaluationHitIds.contains(ruleId3));
+
+        context = new HashMap<>();
+        context.put("Credit Score", "Excellent");
+        context.put("DTI", 10);
+        dmnResult = jitdmnService.evaluateModel(decisionTableModel, context);
+
+        Assertions.assertTrue(dmnResult.getMessages().isEmpty());
+        Assertions.assertEquals(BigDecimal.valueOf(20), dmnResult.getDecisionResultByName("Risk Score").getResult());
+        evaluationHitIds = dmnResult.getEvaluationHitIds();
+        Assertions.assertNotNull(evaluationHitIds);
+        Assertions.assertEquals(3, evaluationHitIds.size());
+        Assertions.assertTrue(evaluationHitIds.contains(thenElementId));
+        Assertions.assertTrue(evaluationHitIds.contains(ruleId1));
+        Assertions.assertTrue(evaluationHitIds.contains(ruleId4));
+    }
+
+    @Test
+    void testConditionalWithNestedDecisionTableFromRiskScoreEvaluation() throws IOException {
+        final String thenElementId = "_6481FF12-61B5-451C-B775-4143D9B6CD6B";
+        final String thenRuleId0 = "_D1753442-03F0-414B-94F8-6A86182DF6EB";
+        final String thenRuleId4 = "_E787BA51-E31D-449B-A432-50BE7466A15E";
+        final String elseElementId = "_2CD02CB2-6B56-45C4-B461-405E89D45633";
+        final String elseRuleId2 = "_945A5471-9F91-4751-9D96-74978F6FB12B";
+        final String elseRuleId5 = "_654BBFBC-9B84-4BD8-9D0B-13E8DD1B9F5D";
+        String decisionTableModel = getModelFromIoUtils("valid_models/DMNv1_5/RiskScore_Conditional.dmn");
+
+        Map<String, Object> context = new HashMap<>();
+        context.put("Credit Score", "Poor");
+        context.put("DTI", 33);
+        context.put("World Region", "Asia");
+        JITDMNResult dmnResult = jitdmnService.evaluateModel(decisionTableModel, context);
+
+        Assertions.assertTrue(dmnResult.getMessages().isEmpty());
+        Assertions.assertEquals(BigDecimal.valueOf(50), dmnResult.getDecisionResultByName("Risk Score").getResult());
+        List<String> evaluationHitIds = dmnResult.getEvaluationHitIds();
+        Assertions.assertNotNull(evaluationHitIds);
+        Assertions.assertEquals(3, evaluationHitIds.size());
+        Assertions.assertTrue(evaluationHitIds.contains(thenElementId));
+        Assertions.assertTrue(evaluationHitIds.contains(thenRuleId0));
+        Assertions.assertTrue(evaluationHitIds.contains(thenRuleId4));
+
+        context = new HashMap<>();
+        context.put("Credit Score", "Excellent");
+        context.put("DTI", 10);
+        context.put("World Region", "Europe");
+        dmnResult = jitdmnService.evaluateModel(decisionTableModel, context);
+
+        Assertions.assertTrue(dmnResult.getMessages().isEmpty());
+        Assertions.assertEquals(BigDecimal.valueOf(30), dmnResult.getDecisionResultByName("Risk Score").getResult());
+        evaluationHitIds = dmnResult.getEvaluationHitIds();
+        Assertions.assertNotNull(evaluationHitIds);
+        Assertions.assertEquals(3, evaluationHitIds.size());
+        Assertions.assertTrue(evaluationHitIds.contains(elseElementId));
+        Assertions.assertTrue(evaluationHitIds.contains(elseRuleId2));
+        Assertions.assertTrue(evaluationHitIds.contains(elseRuleId5));
+    }
+
+    @Test
+    void testMultipleHitRulesEvaluation() throws IOException {
+        final String rule0 = "_E5C380DA-AF7B-4401-9804-C58296EC09DD";
+        final String rule1 = "_DFD65E8B-5648-4BFD-840F-8C76B8DDBD1A";
+        final String rule2 = "_E80EE7F7-1C0C-4050-B560-F33611F16B05";
+        String decisionTableModel = getModelFromIoUtils("valid_models/DMNv1_5/MultipleHitRules.dmn");
+
+        final List<BigDecimal> numbers = new ArrayList<>();
+        numbers.add(BigDecimal.valueOf(10));
+        numbers.add(BigDecimal.valueOf(2));
+        numbers.add(BigDecimal.valueOf(1));
+        final Map<String, Object> context = new HashMap<>();
+        context.put("Numbers", numbers);
+        final JITDMNResult dmnResult = jitdmnService.evaluateModel(decisionTableModel, context);
+
+        final List<BigDecimal> expectedStatistcs = new ArrayList<>();
+        expectedStatistcs.add(BigDecimal.valueOf(6));
+        expectedStatistcs.add(BigDecimal.valueOf(3));
+        expectedStatistcs.add(BigDecimal.valueOf(1));
+        Assertions.assertTrue(dmnResult.getMessages().isEmpty());
+        Assertions.assertEquals(expectedStatistcs, dmnResult.getDecisionResultByName("Statistics").getResult());
+        final List<String> evaluationHitIds = dmnResult.getEvaluationHitIds();
+        Assertions.assertNotNull(evaluationHitIds);
+        Assertions.assertEquals(6, evaluationHitIds.size());
+        Assertions.assertEquals(3, evaluationHitIds.stream().filter(rule0::equals).count());
+        Assertions.assertEquals(2, evaluationHitIds.stream().filter(rule1::equals).count());
+        Assertions.assertEquals(1, evaluationHitIds.stream().filter(rule2::equals).count());
+    }
+
+    @Test
+    void testExplainability() throws IOException {
         String allTypesModel = getModelFromIoUtils("valid_models/DMNv1_x/allTypes.dmn");
 
         Map<String, Object> context = new HashMap<>();
diff --git a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/JITDMNResourceTest.java b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/JITDMNResourceTest.java
index d728d112c..6c2960308 100644
--- a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/JITDMNResourceTest.java
+++ b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/api/JITDMNResourceTest.java
@@ -22,10 +22,17 @@ import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.kie.kogito.jitexecutor.dmn.requests.JITDMNPayload;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
 import io.quarkus.test.junit.QuarkusTest;
 import io.restassured.http.ContentType;
 
@@ -38,15 +45,25 @@ public class JITDMNResourceTest {
 
     private static String model;
     private static String modelWithExtensionElements;
+    private static String modelWithEvaluationHitIds;
+
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    private static final String EVALUATION_HIT_IDS_FIELD_NAME = "evaluationHitIds";
+
+    static {
+        MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+    }
 
     @BeforeAll
     public static void setup() throws IOException {
         model = getModelFromIoUtils("invalid_models/DMNv1_x/test.dmn");
         modelWithExtensionElements = getModelFromIoUtils("valid_models/DMNv1_x/testWithExtensionElements.dmn");
+        modelWithEvaluationHitIds = getModelFromIoUtils("valid_models/DMNv1_5/RiskScore_Simple.dmn");
     }
 
     @Test
-    public void testjitEndpoint() {
+    void testjitEndpoint() {
         JITDMNPayload jitdmnpayload = new JITDMNPayload(model, buildContext());
         given()
                 .contentType(ContentType.JSON)
@@ -58,7 +75,7 @@ public class JITDMNResourceTest {
     }
 
     @Test
-    public void testjitdmnResultEndpoint() {
+    void testjitdmnResultEndpoint() {
         JITDMNPayload jitdmnpayload = new JITDMNPayload(model, buildContext());
         given()
                 .contentType(ContentType.JSON)
@@ -70,7 +87,34 @@ public class JITDMNResourceTest {
     }
 
     @Test
-    public void testjitExplainabilityEndpoint() {
+    void testjitdmnResultEndpointWithEvaluationHitIds() throws JsonProcessingException {
+        JITDMNPayload jitdmnpayload = new JITDMNPayload(modelWithEvaluationHitIds, buildRiskScoreContext());
+        final String elseElementId = "_2CD02CB2-6B56-45C4-B461-405E89D45633";
+        final String ruleId0 = "_1578BD9E-2BF9-4BFC-8956-1A736959C937";
+        final String ruleId3 = "_2545E1A8-93D3-4C8A-A0ED-8AD8B10A58F9";
+        String response = given().contentType(ContentType.JSON)
+                .body(jitdmnpayload)
+                .when().post("/jitdmn/dmnresult")
+                .then()
+                .statusCode(200)
+                .body(containsString("Risk Score"),
+                        containsString("Loan Pre-Qualification"),
+                        containsString(EVALUATION_HIT_IDS_FIELD_NAME),
+                        containsString(elseElementId),
+                        containsString(ruleId0),
+                        containsString(ruleId3))
+                .extract()
+                .asString();
+        JsonNode retrieved = MAPPER.readTree(response);
+        ArrayNode evaluationHitIdsNode = (ArrayNode) retrieved.get(EVALUATION_HIT_IDS_FIELD_NAME);
+        Assertions.assertThat(evaluationHitIdsNode).hasSize(3)
+                .anyMatch(node -> node.asText().equals(elseElementId))
+                .anyMatch(node -> node.asText().equals(ruleId0))
+                .anyMatch(node -> node.asText().equals(ruleId3));
+    }
+
+    @Test
+    void testjitExplainabilityEndpoint() {
         JITDMNPayload jitdmnpayload = new JITDMNPayload(model, buildContext());
         given()
                 .contentType(ContentType.JSON)
@@ -78,11 +122,12 @@ public class JITDMNResourceTest {
                 .when().post("/jitdmn/evaluateAndExplain")
                 .then()
                 .statusCode(200)
-                .body(containsString("dmnResult"), containsString("saliencies"), containsString("xls2dmn"), containsString("featureName"));
+                .body(containsString("dmnResult"), containsString("saliencies"), containsString("xls2dmn"),
+                        containsString("featureName"));
     }
 
     @Test
-    public void testjitdmnWithExtensionElements() {
+    void testjitdmnWithExtensionElements() {
         Map<String, Object> context = new HashMap<>();
         context.put("m", 1);
         context.put("n", 2);
@@ -97,6 +142,13 @@ public class JITDMNResourceTest {
                 .body(containsString("m"), containsString("n"), containsString("sum"));
     }
 
+    private Map<String, Object> buildRiskScoreContext() {
+        Map<String, Object> context = new HashMap<>();
+        context.put("Credit Score", "Poor");
+        context.put("DTI", 33);
+        return context;
+    }
+
     private Map<String, Object> buildContext() {
         Map<String, Object> context = new HashMap<>();
         context.put("FICO Score", 800);


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@kie.apache.org
For additional commands, e-mail: commits-help@kie.apache.org