diff --git a/kie-dmn/kie-dmn-core/pom.xml b/kie-dmn/kie-dmn-core/pom.xml
index ab4f01aae28..cfa0dea7c8b 100644
--- a/kie-dmn/kie-dmn-core/pom.xml
+++ b/kie-dmn/kie-dmn-core/pom.xml
@@ -276,5 +276,35 @@
true
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ unpack
+ generate-test-resources
+
+ unpack
+
+
+
+
+ org.kie
+ kie-dmn-test-resources
+ ${project.version}
+ jar
+ tests
+ true
+ ${project.build.directory}/test-classes/org/kie/dmn/core
+ **/*.dmn
+
+
+
+
+
+
+
diff --git a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNRuntimeImpl.java b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNRuntimeImpl.java
index 203c44f32af..b335f3a7fd1 100644
--- a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNRuntimeImpl.java
+++ b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/impl/DMNRuntimeImpl.java
@@ -18,7 +18,9 @@
*/
package org.kie.dmn.core.impl;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -30,6 +32,7 @@
import javax.xml.namespace.QName;
import org.drools.kiesession.rulebase.InternalKnowledgeBase;
+import org.kie.api.builder.Message;
import org.kie.dmn.api.core.DMNContext;
import org.kie.dmn.api.core.DMNDecisionResult;
import org.kie.dmn.api.core.DMNMessage;
@@ -111,6 +114,7 @@ public DMNResult evaluateAll(DMNModel model, DMNContext context) {
Objects.requireNonNull(model, () -> MsgUtil.createMessage(Msg.PARAM_CANNOT_BE_NULL, "model"));
Objects.requireNonNull(context, () -> MsgUtil.createMessage(Msg.PARAM_CANNOT_BE_NULL, "context"));
boolean performRuntimeTypeCheck = performRuntimeTypeCheck(model);
+ identifyDecisionErrors(model);
DMNResultImpl result = createResult( model, context );
DMNRuntimeEventManagerUtils.fireBeforeEvaluateAll( eventManager, model, result );
// the engine should evaluate all Decisions belonging to the "local" model namespace, not imported decision explicitly.
@@ -148,6 +152,7 @@ public DMNResult evaluateByName( DMNModel model, DMNContext context, String... d
if (decisionNames.length == 0) {
throw new IllegalArgumentException(MsgUtil.createMessage(Msg.PARAM_CANNOT_BE_EMPTY, "decisionNames"));
}
+ identifyDecisionErrors(model, decisionNames);
final DMNResultImpl result = createResult( model, context );
for (String name : decisionNames) {
evaluateByNameInternal( model, context, result, name );
@@ -184,6 +189,7 @@ public DMNResult evaluateById( DMNModel model, DMNContext context, String... dec
if (decisionIds.length == 0) {
throw new IllegalArgumentException(MsgUtil.createMessage(Msg.PARAM_CANNOT_BE_EMPTY, "decisionIds"));
}
+ identifyDecisionErrors(model, decisionIds);
final DMNResultImpl result = createResult( model, context );
for ( String id : decisionIds ) {
evaluateByIdInternal( model, context, result, id );
@@ -754,6 +760,15 @@ private static String getDependencyIdentifier(DMNNode callerNode, DMNNode node)
}
+ private static void identifyDecisionErrors(DMNModel model, String... decisions) {
+ List errorMessages = model.getMessages(DMNMessage.Severity.ERROR);
+ List identifiedErrors = errorMessages.stream().map(Message::getText)
+ .filter(messages -> decisions.length == 0 || Arrays.stream(decisions).anyMatch(messages::contains)).collect(Collectors.toList());
+ if (!identifiedErrors.isEmpty()) {
+ throw new IllegalStateException(String.join(", ", identifiedErrors));
+ }
+ }
+
public boolean performRuntimeTypeCheck(DMNModel model) {
Objects.requireNonNull(model, () -> MsgUtil.createMessage(Msg.PARAM_CANNOT_BE_NULL, "model"));
return overrideRuntimeTypeCheck || ((DMNModelImpl) model).isRuntimeTypeCheck();
diff --git a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/internal/utils/DMNRuntimeBuilderTest.java b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/internal/utils/DMNRuntimeBuilderTest.java
index f10cec99ede..1ed6dc20f8e 100644
--- a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/internal/utils/DMNRuntimeBuilderTest.java
+++ b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/internal/utils/DMNRuntimeBuilderTest.java
@@ -18,13 +18,23 @@
*/
package org.kie.dmn.core.internal.utils;
+import java.io.File;
import java.util.Collections;
+import org.drools.util.FileUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.kie.api.io.Resource;
+import org.kie.dmn.api.core.DMNContext;
+import org.kie.dmn.api.core.DMNModel;
+import org.kie.dmn.api.core.DMNResult;
+import org.kie.dmn.api.core.DMNRuntime;
+import org.kie.dmn.core.api.DMNFactory;
import org.kie.dmn.core.impl.DMNRuntimeImpl;
+import org.kie.internal.io.ResourceFactory;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
class DMNRuntimeBuilderTest {
@@ -43,4 +53,198 @@ void buildFromConfiguration() {
.fromResources(Collections.emptyList()).getOrElseThrow(RuntimeException::new);
assertThat(retrieved).isNotNull();
}
+
+ @Test
+ void fromDefaultsMultipleDecisionWithoutInputDataReference() {
+ File modelFile = FileUtils.getFile("Invalid_decisions_model.dmn");
+ assertThat(modelFile).isNotNull().exists();
+ Resource modelResource = ResourceFactory.newFileResource(modelFile);
+ DMNRuntime dmnRuntime = DMNRuntimeBuilder.fromDefaults().buildConfiguration()
+ .fromResources(Collections.singletonList(modelResource)).getOrElseThrow(RuntimeException::new);
+ assertThat(dmnRuntime).isNotNull();
+ String nameSpace = "https://kie.org/dmn/_BDC29BCF-B5DC-4AD7-8A5F-43DC08780F97";
+
+ final DMNModel dmnModel = dmnRuntime.getModel(
+ nameSpace,
+ "DMN_1A4BD262-7672-4887-9F25-986EE5277D16");
+ assertThat(dmnModel).isNotNull();
+ DMNContext context = DMNFactory.newContext();
+ context.set( "Person Age", 24 );
+ String errorMessage = "DMN: Error compiling FEEL expression 'Person Age >= 18' for name 'Can Drive?' on node 'Can Drive?': syntax error near 'Age' (DMN id: _563E78C7-EFD1-4109-9F30-B14922EF68DF, Error compiling the referenced FEEL expression) ";
+ assertThatIllegalStateException().isThrownBy(() -> {
+ dmnRuntime.evaluateAll(dmnModel, context);
+ }).withMessage(errorMessage);
+ }
+
+ @Test
+ void evaluateMultipleDecisionModel() {
+ File modelFile = FileUtils.getFile("MultipleDecision.dmn");
+ assertThat(modelFile).isNotNull().exists();
+ Resource modelResource = ResourceFactory.newFileResource(modelFile);
+ DMNRuntime dmnRuntime = DMNRuntimeBuilder.fromDefaults().buildConfiguration()
+ .fromResources(Collections.singletonList(modelResource)).getOrElseThrow(RuntimeException::new);
+ assertThat(dmnRuntime).isNotNull();
+ String nameSpace = "https://kie.org/dmn/_CADD03FC-4ABD-46D2-B631-E7FDE384D6D7";
+
+ final DMNModel dmnModel = dmnRuntime.getModel(
+ nameSpace,
+ "DMN_54AA2CFA-2374-4FCE-8F16-B594DFF87EBE");
+ assertThat(dmnModel).isNotNull();
+ DMNContext context = DMNFactory.newContext();
+ context.set( "Person Age", 24 );
+ DMNResult dmnResult = dmnRuntime.evaluateAll(dmnModel, context);
+ assertThat(dmnResult).isNotNull();
+ }
+
+ @Test
+ void evaluateWrongDecisionWithoutInputDataReferencesByName() {
+ File modelFile = FileUtils.getFile("Invalid_decisions_model.dmn");
+ assertThat(modelFile).isNotNull().exists();
+ Resource modelResource = ResourceFactory.newFileResource(modelFile);
+ DMNRuntime dmnRuntime = DMNRuntimeBuilder.fromDefaults().buildConfiguration()
+ .fromResources(Collections.singletonList(modelResource)).getOrElseThrow(RuntimeException::new);
+ assertThat(dmnRuntime).isNotNull();
+ String nameSpace = "https://kie.org/dmn/_BDC29BCF-B5DC-4AD7-8A5F-43DC08780F97";
+
+ final DMNModel dmnModel = dmnRuntime.getModel(
+ nameSpace,
+ "DMN_1A4BD262-7672-4887-9F25-986EE5277D16");
+ assertThat(dmnModel).isNotNull();
+ DMNContext context = DMNFactory.newContext();
+ context.set( "Person Age", 24 );
+ String errorMessage = "DMN: Error compiling FEEL expression 'Person Age >= 18' for name 'Can Drive?' on node 'Can Drive?': syntax error near 'Age' (DMN id: _563E78C7-EFD1-4109-9F30-B14922EF68DF, Error compiling the referenced FEEL expression) ";
+ assertThatIllegalStateException().isThrownBy(() -> {
+ dmnRuntime.evaluateByName(dmnModel, context, "Can Drive");
+ }).withMessage(errorMessage);
+ }
+
+ @Test
+ void evaluateRightDecisionWithoutInputDataReferencesByName() {
+ File modelFile = FileUtils.getFile("Invalid_decisions_model.dmn");
+ assertThat(modelFile).isNotNull().exists();
+ Resource modelResource = ResourceFactory.newFileResource(modelFile);
+ DMNRuntime dmnRuntime = DMNRuntimeBuilder.fromDefaults().buildConfiguration()
+ .fromResources(Collections.singletonList(modelResource)).getOrElseThrow(RuntimeException::new);
+ assertThat(dmnRuntime).isNotNull();
+ String nameSpace = "https://kie.org/dmn/_BDC29BCF-B5DC-4AD7-8A5F-43DC08780F97";
+
+ final DMNModel dmnModel = dmnRuntime.getModel(
+ nameSpace,
+ "DMN_1A4BD262-7672-4887-9F25-986EE5277D16");
+ assertThat(dmnModel).isNotNull();
+ DMNContext context = DMNFactory.newContext();
+ context.set( "Person Age", 24 );
+ DMNResult dmnResult = dmnRuntime.evaluateByName(dmnModel, context, "Can Vote?");
+ assertThat(dmnResult).isNotNull();
+ }
+
+ @Test
+ void evaluateWrongDecisionWithoutInputDataReferencesById() {
+ File modelFile = FileUtils.getFile("Invalid_decisions_model.dmn");
+ assertThat(modelFile).isNotNull().exists();
+ Resource modelResource = ResourceFactory.newFileResource(modelFile);
+ DMNRuntime dmnRuntime = DMNRuntimeBuilder.fromDefaults().buildConfiguration()
+ .fromResources(Collections.singletonList(modelResource)).getOrElseThrow(RuntimeException::new);
+ assertThat(dmnRuntime).isNotNull();
+ String nameSpace = "https://kie.org/dmn/_BDC29BCF-B5DC-4AD7-8A5F-43DC08780F97";
+
+ final DMNModel dmnModel = dmnRuntime.getModel(
+ nameSpace,
+ "DMN_1A4BD262-7672-4887-9F25-986EE5277D16");
+ assertThat(dmnModel).isNotNull();
+ DMNContext context = DMNFactory.newContext();
+ context.set( "Person Age", 24 );
+ String errorMessage = "DMN: Error compiling FEEL expression 'Person Age >= 18' for name 'Can Drive?' on node 'Can Drive?': syntax error near 'Age' (DMN id: _563E78C7-EFD1-4109-9F30-B14922EF68DF, Error compiling the referenced FEEL expression) ";
+ assertThatIllegalStateException().isThrownBy(() -> {
+ dmnRuntime.evaluateById(dmnModel, context, "_563E78C7-EFD1-4109-9F30-B14922EF68DF");
+ }).withMessage(errorMessage);
+ }
+
+ @Test
+ void evaluateRightDecisionWithoutInputDataReferencesById() {
+ File modelFile = FileUtils.getFile("Invalid_decisions_model.dmn");
+ assertThat(modelFile).isNotNull().exists();
+ Resource modelResource = ResourceFactory.newFileResource(modelFile);
+ DMNRuntime dmnRuntime = DMNRuntimeBuilder.fromDefaults().buildConfiguration()
+ .fromResources(Collections.singletonList(modelResource)).getOrElseThrow(RuntimeException::new);
+ assertThat(dmnRuntime).isNotNull();
+ String nameSpace = "https://kie.org/dmn/_BDC29BCF-B5DC-4AD7-8A5F-43DC08780F97";
+
+ final DMNModel dmnModel = dmnRuntime.getModel(
+ nameSpace,
+ "DMN_1A4BD262-7672-4887-9F25-986EE5277D16");
+ assertThat(dmnModel).isNotNull();
+ DMNContext context = DMNFactory.newContext();
+ context.set( "Person Age", 24 );
+ DMNResult dmnResult = dmnRuntime.evaluateById(dmnModel, context, "_7ACCB8BC-A382-4530-B8EE-AD32D187FD8B");
+ assertThat(dmnResult).isNotNull();
+ }
+
+ @Test
+ void evaluateDecisionWithInvalidFeelError() {
+ File modelFile = FileUtils.getFile("InvalidFeel.dmn");
+ assertThat(modelFile).isNotNull().exists();
+ Resource modelResource = ResourceFactory.newFileResource(modelFile);
+ DMNRuntime dmnRuntime = DMNRuntimeBuilder.fromDefaults().buildConfiguration()
+ .fromResources(Collections.singletonList(modelResource)).getOrElseThrow(RuntimeException::new);
+ assertThat(dmnRuntime).isNotNull();
+ String nameSpace = "https://kie.org/dmn/_9DF86C49-C80A-4744-9F50-BCE65A89C98C";
+
+ final DMNModel dmnModel = dmnRuntime.getModel(
+ nameSpace,
+ "DMN_33900B8B-73DD-4D1E-87E9-F6C3FE534B43");
+ assertThat(dmnModel).isNotNull();
+ DMNContext context = DMNFactory.newContext();
+ context.set("Person Age", 24);
+ String errorMessage = "DMN: Error compiling FEEL expression 'Person Age >?= 18' for name 'Can Drive' on node 'Can Drive': Unknown variable '?' (DMN id: _F477B6E0-C617-4087-9648-DE25A711C5F9, Error compiling the referenced FEEL expression) ";
+ assertThatIllegalStateException().isThrownBy(() -> {
+ dmnRuntime.evaluateByName(dmnModel, context, "Can Drive");
+ }).withMessage(errorMessage);
+
+ }
+
+ @Test
+ void evaluateMultipleErrorDecision() {
+ File modelFile = FileUtils.getFile("MultipleErrorDecision.dmn");
+ assertThat(modelFile).isNotNull().exists();
+ Resource modelResource = ResourceFactory.newFileResource(modelFile);
+ DMNRuntime dmnRuntime = DMNRuntimeBuilder.fromDefaults().buildConfiguration()
+ .fromResources(Collections.singletonList(modelResource)).getOrElseThrow(RuntimeException::new);
+ assertThat(dmnRuntime).isNotNull();
+ String nameSpace = "https://kie.org/dmn/_36ADF828-4BE5-41E1-8808-6245D13C6AB4";
+
+ final DMNModel dmnModel = dmnRuntime.getModel(
+ nameSpace,
+ "DMN_45A15AF7-9910-4EAD-B249-8AE218B3BF43");
+ assertThat(dmnModel).isNotNull();
+ DMNContext context = DMNFactory.newContext();
+ context.set( "Person Age", 24 );
+ String errorMessage = "DMN: Error compiling FEEL expression 'Age + 20.?>' for name 'ContextEntry-1' on node 'Can Vote?': syntax error near '+' (DMN id: _B7D17199-0568-40EE-94D0-FDFAB0E97868, Error compiling the referenced FEEL expression) , DMN: Error compiling FEEL expression 'if Age > 25 \"YES\" elsesss \"NO\"' for name 'Can Vote?' on node 'Can Vote?': syntax error near '\"YES\"' (DMN id: _59E71393-14B3-405D-A0B4-3C1E6562823F, Error compiling the referenced FEEL expression) ";
+ assertThatIllegalStateException().isThrownBy(() -> {
+ dmnRuntime.evaluateByName(dmnModel, context, "Can Vote");
+ }).withMessage(errorMessage);
+ }
+
+ @Test
+ void evaluateMultipleErrorModel() {
+ File modelFile = FileUtils.getFile("MultipleError.dmn");
+ assertThat(modelFile).isNotNull().exists();
+ Resource modelResource = ResourceFactory.newFileResource(modelFile);
+ DMNRuntime dmnRuntime = DMNRuntimeBuilder.fromDefaults().buildConfiguration()
+ .fromResources(Collections.singletonList(modelResource)).getOrElseThrow(RuntimeException::new);
+ assertThat(dmnRuntime).isNotNull();
+ String nameSpace = "https://kie.org/dmn/_231A34DE-33C6-4787-A51F-228C910D5EAF";
+
+ final DMNModel dmnModel = dmnRuntime.getModel(
+ nameSpace,
+ "DMN_DC99A8C4-4524-407D-B3D1-577442AED995");
+ assertThat(dmnModel).isNotNull();
+ DMNContext context = DMNFactory.newContext();
+ context.set( "Person Age", 24 );
+ String errorMessage = "DMN: Error compiling FEEL expression 'Person Age >= 18' for name 'Can Vote?' on node 'Can Vote?': syntax error near 'Age' (DMN id: _E3EF0CCA-0F1E-42B1-8C65-124D77C07E38, Error compiling the referenced FEEL expression) , DMN: Error compiling FEEL expression 'Person Age >=18' for name 'Can Drive?' on node 'Can Drive?': syntax error near 'Age' (DMN id: _B2F31CDD-29D1-4C20-93B8-8FB8E11E1FFC, Error compiling the referenced FEEL expression) ";
+ assertThatIllegalStateException().isThrownBy(() -> {
+ dmnRuntime.evaluateByName(dmnModel, context, "Can Vote?", "Can Drive?");
+ }).withMessage(errorMessage);
+ }
+
}
\ No newline at end of file
diff --git a/kie-dmn/kie-dmn-test-resources/src/test/resources/invalid_models/DMNv1_5/InvalidFeel.dmn b/kie-dmn/kie-dmn-test-resources/src/test/resources/invalid_models/DMNv1_5/InvalidFeel.dmn
new file mode 100644
index 00000000000..b7b58f6ae11
--- /dev/null
+++ b/kie-dmn/kie-dmn-test-resources/src/test/resources/invalid_models/DMNv1_5/InvalidFeel.dmn
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Person Age >?= 18
+
+
+
+
+
+
+
+ 190
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/kie-dmn/kie-dmn-test-resources/src/test/resources/invalid_models/DMNv1_5/Invalid_decisions_model.dmn b/kie-dmn/kie-dmn-test-resources/src/test/resources/invalid_models/DMNv1_5/Invalid_decisions_model.dmn
new file mode 100644
index 00000000000..75383661572
--- /dev/null
+++ b/kie-dmn/kie-dmn-test-resources/src/test/resources/invalid_models/DMNv1_5/Invalid_decisions_model.dmn
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+ Can Drive
+
+ Person Age >= 18
+
+
+ Person Age >= 18
+
+
+
+
+
+
+
+
+ Person Age>=18
+
+
+
+
+
+
+
+ 190
+
+
+ 190
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/kie-dmn/kie-dmn-test-resources/src/test/resources/invalid_models/DMNv1_5/MultipleError.dmn b/kie-dmn/kie-dmn-test-resources/src/test/resources/invalid_models/DMNv1_5/MultipleError.dmn
new file mode 100644
index 00000000000..caef1591de9
--- /dev/null
+++ b/kie-dmn/kie-dmn-test-resources/src/test/resources/invalid_models/DMNv1_5/MultipleError.dmn
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+ Person Age >= 18
+
+
+
+
+
+ Person Age >=18
+
+
+
+
+
+
+
+ 190
+
+
+ 190
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/kie-dmn/kie-dmn-test-resources/src/test/resources/invalid_models/DMNv1_5/MultipleErrorDecision.dmn b/kie-dmn/kie-dmn-test-resources/src/test/resources/invalid_models/DMNv1_5/MultipleErrorDecision.dmn
new file mode 100644
index 00000000000..bfe20aedbc7
--- /dev/null
+++ b/kie-dmn/kie-dmn-test-resources/src/test/resources/invalid_models/DMNv1_5/MultipleErrorDecision.dmn
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Age + 20.?>
+
+
+
+
+ if Age > 25 "YES" elsesss "NO"
+
+
+
+
+
+
+
+
+
+ 120
+
+
+ 190
+
+
+ 190
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/kie-dmn/kie-dmn-test-resources/src/test/resources/valid_models/DMNv1_5/MultipleDecision.dmn b/kie-dmn/kie-dmn-test-resources/src/test/resources/valid_models/DMNv1_5/MultipleDecision.dmn
new file mode 100644
index 00000000000..c85554c46d7
--- /dev/null
+++ b/kie-dmn/kie-dmn-test-resources/src/test/resources/valid_models/DMNv1_5/MultipleDecision.dmn
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Person Age >= 18
+
+
+
+
+
+
+
+
+ Person Age>=18
+
+
+
+
+
+
+
+ 190
+
+
+ 190
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+