This is an automated email from the ASF dual-hosted git repository. gitgabrio pushed a commit to branch incubator-kie-issues#908 in repository https://gitbox.apache.org/repos/asf/incubator-kie-kogito-apps.git
commit c8c3ecba83df9a4e0cfa52f24081fe5ebf56a298 Author: Gabriele-Cardosi <[email protected]> AuthorDate: Thu Mar 14 11:47:50 2024 +0100 [incubator-kie-issues#908] Testing DMN 1.5 features inside jitexecutor --- jitexecutor/jitexecutor-dmn/pom.xml | 13 ++ .../org/kie/kogito/jitexecutor/dmn/DMN15Test.java | 234 +++++++++++++++++++++ 2 files changed, 247 insertions(+) diff --git a/jitexecutor/jitexecutor-dmn/pom.xml b/jitexecutor/jitexecutor-dmn/pom.xml index 80a29975a..b0972e9a2 100644 --- a/jitexecutor/jitexecutor-dmn/pom.xml +++ b/jitexecutor/jitexecutor-dmn/pom.xml @@ -43,6 +43,13 @@ <type>pom</type> <scope>import</scope> </dependency> + <dependency> + <groupId>org.kie</groupId> + <artifactId>kie-dmn-test-resources</artifactId> + <version>${project.version}</version> + <classifier>tests</classifier> + <scope>test</scope> + </dependency> </dependencies> </dependencyManagement> @@ -92,6 +99,12 @@ <artifactId>trusty-storage-api</artifactId> </dependency> + <dependency> + <groupId>org.kie</groupId> + <artifactId>kie-dmn-test-resources</artifactId> + <classifier>tests</classifier> + <scope>test</scope> + </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-junit5</artifactId> diff --git a/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/DMN15Test.java b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/DMN15Test.java new file mode 100644 index 000000000..ea0e1c73f --- /dev/null +++ b/jitexecutor/jitexecutor-dmn/src/test/java/org/kie/kogito/jitexecutor/dmn/DMN15Test.java @@ -0,0 +1,234 @@ +/* + * 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.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.type.CollectionType; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.RestAssured; +import io.restassured.http.ContentType; +import io.restassured.response.ValidatableResponse; +import org.drools.util.IoUtils; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.kie.dmn.api.core.DMNDecisionResult; +import org.kie.dmn.api.core.DMNMessage; +import org.kie.dmn.api.core.DMNResult; +import org.kie.kogito.jitexecutor.common.requests.MultipleResourcesPayload; +import org.kie.kogito.jitexecutor.common.requests.ResourceWithURI; +import org.kie.kogito.jitexecutor.dmn.requests.JITDMNPayload; +import org.kie.kogito.jitexecutor.dmn.responses.JITDMNDecisionResult; +import org.kie.kogito.jitexecutor.dmn.responses.JITDMNMessage; +import org.kie.kogito.jitexecutor.dmn.responses.JITDMNResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@QuarkusTest +class DMN15Test { + + private static final Logger LOG = LoggerFactory.getLogger(DMN15Test.class); + private static final ObjectMapper MAPPER; + + static { + final var jitModule = new SimpleModule().addAbstractTypeMapping(DMNResult.class, JITDMNResult.class) + .addAbstractTypeMapping(DMNDecisionResult.class, JITDMNDecisionResult.class) + .addAbstractTypeMapping(DMNMessage.class, JITDMNMessage.class); + + MAPPER = new ObjectMapper() + .registerModule(new Jdk8Module()) + .registerModule(jitModule); + MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + private static final CollectionType LIST_OF_MSGS = MAPPER.getTypeFactory() + .constructCollectionType(List.class, + JITDMNMessage.class); + + @BeforeAll + public static void setup() { + RestAssured.enableLoggingOfRequestAndResponseIfValidationFails(); + } + + @Test + void unnamedImport() throws IOException { + String URI1 = "Importing_EmptyNamed_Model.dmn"; + String URI2 = "Imported_Model_Unamed.dmn"; + ResourceWithURI model1 = new ResourceWithURI(URI1, getModelFromIoUtils(URI1)); + ResourceWithURI model2 = new ResourceWithURI(URI2, getModelFromIoUtils(URI2)); + + JITDMNPayload jitdmnpayload = new JITDMNPayload(URI1, List.of(model1, model2), Collections.EMPTY_MAP); + given() + .contentType(ContentType.JSON) + .body(jitdmnpayload) + .when().post("/jitdmn") + .then() + .statusCode(200) + .body("'Local Hello'", is("function Local Hello( Person )")) + .body("'Say Hello'", is("function Say Hello( Person )")); + + String response = given() + .contentType(ContentType.JSON) + .body(new MultipleResourcesPayload(URI1, List.of(model1, model2))) + .when() + .post("/jitdmn/validate") + .then() + .statusCode(200) + .extract() + .asString(); + LOG.info("Validate response: {}", response); + List<JITDMNMessage> messages = MAPPER.readValue(response, LIST_OF_MSGS); + assertEquals(0, messages.size()); + + Map<String, Object> context = + Map.of("A Person", Map.of("name", "John", "age", 47)); + jitdmnpayload = new JITDMNPayload(URI1, List.of(model1, model2), context); + given() + .contentType(ContentType.JSON) + .body(jitdmnpayload) + .when() + .post("/jitdmn/dmnresult") + .then() + .statusCode(200) + .body("decisionResults.result[0]", is("Hello John!")) + .body("decisionResults.result[1]", is("Local Hello John!")); + } + + @Test + void forLoopDatesEvaluate() throws IOException { + String modelFileName = "ForLoopDatesEvaluate.dmn"; + validate(getModelFromIoUtils(modelFileName)); + String model = getModel(modelFileName); + Map<String, Object> expectedValues = Map.of("forloopdates[0]", "2021-01-02", + "forloopdates[1]", "2021-01-03", + "forloopdates[2]", "2021-01-04"); + endpoint(model, expectedValues); + expectedValues = Map.of("decisionResults.result[0][0]", "2021-01-02", + "decisionResults.result[0][1]", "2021-01-03", + "decisionResults.result[0][2]", "2021-01-04"); + result(model, expectedValues); + } + + @Test + void listReplaceEvaluate() throws IOException { + String modelFileName = "ListReplaceEvaluate.dmn"; + validate(getModelFromIoUtils(modelFileName)); + String model = getModel(modelFileName); + Map<String, Object> expectedValues = Map.of("listreplacenumbers[0]", 2, + "listreplacenumbers[1]", 4, + "listreplacenumbers[2]", 6, + "listreplacenumbers[3]", 8); + endpoint(model, expectedValues); + expectedValues = Map.of("decisionResults.result[0][0]", 2, + "decisionResults.result[0][1]", 4, + "decisionResults.result[0][2]", 6, + "decisionResults.result[0][3]", 8); + result(model, expectedValues); + } + + @Test + void negationOfDurationEvaluate() throws IOException { + String modelFileName = "NegationOfDurationEvaluate.dmn"; + validate(getModelFromIoUtils(modelFileName)); + String model = getModel(modelFileName); + Map<String, Object> expectedValues = Map.of("durationnegation", true); + endpoint(model, expectedValues); + expectedValues = Map.of("decisionResults.result[0]", true); + result(model, expectedValues); + } + + @Test + void dateToDateTimeFunction() throws IOException { + String modelFileName = "DateToDateTimeFunction.dmn"; + validate(getModelFromIoUtils(modelFileName)); + String model = getModel(modelFileName); + Map<String, Object> expectedValues = Map.of("normal", "function normal( a, b )", + "usingNormal", "2021-05-31T00:00:00Z"); + endpoint(model, expectedValues); + result(model, Map.of("decisionResults.result[0]", "2021-05-31T00:00:00Z")); + } + + private void result(String model, Map<String, Object> expectedValues) { + String payload = "{ \"model\": " + model + ", \"context\": {\n" + + "}}"; + ValidatableResponse validatableResponse = given() + .contentType(ContentType.JSON) + .body(payload) + .when() + .post("/jitdmn/dmnresult") + .then() + .statusCode(200); + expectedValues.forEach((key, value) -> validatableResponse.body(key, is(value))); + } + + private void endpoint(String model, Map<String, Object> expectedValues) { + String payload = "{ \"model\": " + model + ", \"context\": {\n" + + "}}"; + ValidatableResponse validatableResponse = given() + .contentType(ContentType.JSON) + .accept(ContentType.JSON) + .body(payload) + .post("/jitdmn") + .then() + .statusCode(200); + expectedValues.forEach((key, value) -> validatableResponse.body(key, is(value))); + } + + private void validate(String model) throws IOException { + String response = given() + .contentType(ContentType.XML) + .body(model) + .when() + .post("/jitdmn/validate") + .then() + .statusCode(200) + .extract() + .asString(); + LOG.info("Validate response: {}", response); + List<JITDMNMessage> messages = MAPPER.readValue(response, LIST_OF_MSGS); + assertEquals(0, messages.size()); + } + + private String getModelFromIoUtils(String modelFileName) throws IOException { + return new String(IoUtils.readBytesFromInputStream(Thread.currentThread().getContextClassLoader().getResourceAsStream(modelFileName))); + } + + private String getModel(String modelFileName) throws IOException { + URL resource = Thread.currentThread().getContextClassLoader().getResource(modelFileName); + assertNotNull(resource); + try (InputStream is = resource.openStream()) { + return MAPPER.writeValueAsString(new String(is.readAllBytes(), StandardCharsets.UTF_8)); + } + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
