This is an automated email from the ASF dual-hosted git repository. jamesnetherton pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
The following commit(s) were added to refs/heads/main by this push: new 64bd7d8db2 Groovy: extend test coverage 64bd7d8db2 is described below commit 64bd7d8db280cd2caaa13d2714d452de26b7e8dc Author: Jiri Ondrusek <ondrusek.j...@gmail.com> AuthorDate: Wed Mar 12 08:25:52 2025 +0100 Groovy: extend test coverage --- .../ROOT/pages/reference/extensions/groovy.adoc | 6 ++ .../groovy/runtime/src/main/doc/limitations.adoc | 6 ++ .../component/groovy/it/GroovyProducers.java | 44 +++++++++++ .../component/groovy/it/GroovyResource.java | 39 ++++++---- .../quarkus/component/groovy/it/GroovyRoutes.java | 71 ++++++++++++++++++ .../src/main/resources/application.properties | 17 +++++ .../groovy/src/main/resources/mygroovy.groovy | 17 +++++ .../quarkus/component/groovy/it/GroovyTest.java | 86 +++++++++++++++++++++- 8 files changed, 268 insertions(+), 18 deletions(-) diff --git a/docs/modules/ROOT/pages/reference/extensions/groovy.adoc b/docs/modules/ROOT/pages/reference/extensions/groovy.adoc index 49ec755be1..8a8fe60be2 100644 --- a/docs/modules/ROOT/pages/reference/extensions/groovy.adoc +++ b/docs/modules/ROOT/pages/reference/extensions/groovy.adoc @@ -52,3 +52,9 @@ Due to some limitations in GraalVM that prevent to execute even basic scripts in Groovy expressions is made with the static compilation enabled which means that the types used in your expression must be known at compile time. Please refer to the https://docs.groovy-lang.org/latest/html/documentation/core-semantics.html#static-type-checking[Groovy documentation for more details]. +This primarily impacts the customization of the Groovy Shell and the handling of exchange information. +In native mode, customizing the Groovy Shell and accessing the following exchange variables will not function as expected. +``` +header, variable, variables, exchangeProperty, exchangeProperties, log, attachment +``` + diff --git a/extensions/groovy/runtime/src/main/doc/limitations.adoc b/extensions/groovy/runtime/src/main/doc/limitations.adoc index 5aa4300809..1681d0d654 100644 --- a/extensions/groovy/runtime/src/main/doc/limitations.adoc +++ b/extensions/groovy/runtime/src/main/doc/limitations.adoc @@ -1,3 +1,9 @@ Due to some limitations in GraalVM that prevent to execute even basic scripts in native mode, the compilation of the Groovy expressions is made with the static compilation enabled which means that the types used in your expression must be known at compile time. Please refer to the https://docs.groovy-lang.org/latest/html/documentation/core-semantics.html#static-type-checking[Groovy documentation for more details]. + +This primarily impacts the customization of the Groovy Shell and the handling of exchange information. +In native mode, customizing the Groovy Shell and accessing the following exchange variables will not function as expected. +``` +header, variable, variables, exchangeProperty, exchangeProperties, log, attachment +``` \ No newline at end of file diff --git a/integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyProducers.java b/integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyProducers.java new file mode 100644 index 0000000000..f70ae2d167 --- /dev/null +++ b/integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyProducers.java @@ -0,0 +1,44 @@ +/* + * 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.apache.camel.quarkus.component.groovy.it; + +import java.util.Collections; +import java.util.Map; + +import groovy.lang.GroovyShell; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Named; +import org.apache.camel.Exchange; +import org.apache.camel.language.groovy.GroovyShellFactory; +import org.codehaus.groovy.control.CompilerConfiguration; + +@ApplicationScoped +public class GroovyProducers { + + @Named("customShell") + public GroovyShellFactory createCustomShell() { + return new GroovyShellFactory() { + public GroovyShell createGroovyShell(Exchange exchange) { + return new GroovyShell(new CompilerConfiguration()); + } + + public Map<String, Object> getVariables(Exchange exchange) { + return Collections.singletonMap("hello", (Object) "Ahoj"); + } + }; + } +} diff --git a/integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyResource.java b/integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyResource.java index 2732e8ccc1..222bcc0b0b 100644 --- a/integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyResource.java +++ b/integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyResource.java @@ -40,22 +40,6 @@ public class GroovyResource { @Inject ProducerTemplate producerTemplate; - @POST - @Path("/hello") - @Consumes(MediaType.TEXT_PLAIN) - @Produces(MediaType.TEXT_PLAIN) - public String hello(String message) { - return producerTemplate.requestBody("direct:groovyHello", message, String.class); - } - - @POST - @Path("/hi") - @Consumes(MediaType.TEXT_PLAIN) - @Produces(MediaType.TEXT_PLAIN) - public String hi(String message) { - return producerTemplate.requestBody("direct:groovyHi", message, String.class); - } - @POST @Path("/predicate") @Consumes(MediaType.TEXT_PLAIN) @@ -75,4 +59,27 @@ public class GroovyResource { return producerTemplate.requestBodyAndHeaders("direct:" + route, statement, headers, String.class); } + @POST + @Path("/direct/{id}") + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.APPLICATION_JSON) + public String direct(@PathParam("id") String id, String message) { + return producerTemplate.requestBody("direct:" + id, message, String.class); + } + + @Path("/contextValidation") + @POST + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.APPLICATION_JSON) + public String route() { + final Map<String, Object> headers = Map.of("header1", (Object) "value_of_header1"); + return producerTemplate.requestBodyAndHeaders("direct:contextValidation", "body", headers, String.class); + } + + @Path("results/validateExchangeProperties") + @POST + @Produces(MediaType.TEXT_PLAIN) + public Object getMessagesOfWithoutSsl() throws InterruptedException { + return producerTemplate.requestBody("direct:validateExchangeProperty", "body", String.class); + } } diff --git a/integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyRoutes.java b/integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyRoutes.java index 4fd526812b..ad6edd6d3f 100644 --- a/integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyRoutes.java +++ b/integration-tests/groovy/src/main/java/org/apache/camel/quarkus/component/groovy/it/GroovyRoutes.java @@ -16,13 +16,21 @@ */ package org.apache.camel.quarkus.component.groovy.it; +import java.util.Optional; + +import jakarta.activation.DataHandler; +import jakarta.activation.FileDataSource; +import org.apache.camel.attachment.AttachmentMessage; import org.apache.camel.builder.RouteBuilder; +import org.eclipse.microprofile.config.ConfigProvider; public class GroovyRoutes extends RouteBuilder { @Override public void configure() { + Optional<Boolean> inNative = ConfigProvider.getConfig().getOptionalValue("quarkus.native.enabled", Boolean.class); + routeTemplate("whereTo") .templateParameter("bar") .templateBean("myBar", "groovy", "resource:classpath:bean.txt") @@ -34,6 +42,11 @@ public class GroovyRoutes extends RouteBuilder { from("direct:groovyHello") .transform().groovy("\"Hello \" + body + \" from Groovy!\""); + + from("direct:filter") + .filter().groovy("!(request.body as String).contains('Hi')") + .transform().groovy("\"Received unknown request: \" + body"); + from("direct:predicate") .choice() .when().groovy("((int) body) / 2 > 10") @@ -45,5 +58,63 @@ public class GroovyRoutes extends RouteBuilder { .script() .groovy("exchange.getMessage().setBody('Hello ' + exchange.getMessage().getBody(String.class) + ' from Groovy!')"); + from("direct:multiStatement") + .transform().groovy(""" + def a = "Hello A" + def b = "Hello B" + //other statements + def result = "Hello C" + """); + + from("direct:scriptFromResource") + .setHeader("myHeader").groovy("resource:classpath:mygroovy.groovy") + .setBody(simple("${header.myHeader}")); + + from("direct:validateContext") + .setHeader("myHeader", constant("myHeaderValue")) + .setVariable("myVariable", constant("myVariableValue")) + .setProperty("myProperty", constant("myPropertyValue")) + .process(exchange -> { + AttachmentMessage attMsg = exchange.getIn(AttachmentMessage.class); + attMsg.addAttachment("mygroovy.groovy", new DataHandler(new FileDataSource("mygroovy.groovy"))); + }) + .transform().groovy("return " + getContextVariables(false)) + .log("${body}"); + + //routes only for jvm + if (inNative.isEmpty() || !inNative.get()) { + from("direct:customizedHi") + .transform().groovy("hello + \" \" + body + \" from Groovy!\""); + + from("direct:validateContextInJvm") + .setHeader("myHeader", constant("myHeaderValue")) + .setVariable("myVariable", constant("myVariableValue")) + .setProperty("myProperty", constant("myPropertyValue")) + .process(exchange -> { + AttachmentMessage attMsg = exchange.getIn(AttachmentMessage.class); + attMsg.addAttachment("mygroovy.groovy", new DataHandler(new FileDataSource("mygroovy.groovy"))); + }) + .transform().groovy("return " + getContextVariables(true)) + .log("${body}"); + } + } + + private static String getContextVariables(boolean jvm) { + String contextVariables = "\"headers: \" + headers + " + + "\", exchange: \" + exchange + " + + "\", camelContext: \" + camelContext + " + + "\", request: \" + request"; + + if (jvm) { + // following properties are not working in the native mode + contextVariables += " + \", exchangeProperties: \" + exchangeProperties + " + + "\", exchangeProperty: \" + exchangeProperty + " + + "\", variable: \" + variable + " + + "\", variables: \" + variables + " + + "\", header: \" + header + " + + "\", attachments: \" + attachments + " + + "\", log: \" + log"; + } + return contextVariables; } } diff --git a/integration-tests/groovy/src/main/resources/application.properties b/integration-tests/groovy/src/main/resources/application.properties new file mode 100644 index 0000000000..14d5d5f7bf --- /dev/null +++ b/integration-tests/groovy/src/main/resources/application.properties @@ -0,0 +1,17 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- +quarkus.native.resources.includes=*.groovy diff --git a/integration-tests/groovy/src/main/resources/mygroovy.groovy b/integration-tests/groovy/src/main/resources/mygroovy.groovy new file mode 100644 index 0000000000..8baf968ea4 --- /dev/null +++ b/integration-tests/groovy/src/main/resources/mygroovy.groovy @@ -0,0 +1,17 @@ +/* + * 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. + */ +return "Hello " + body + " from resources!" \ No newline at end of file diff --git a/integration-tests/groovy/src/test/java/org/apache/camel/quarkus/component/groovy/it/GroovyTest.java b/integration-tests/groovy/src/test/java/org/apache/camel/quarkus/component/groovy/it/GroovyTest.java index 1a4dc1a3a1..defd9f688f 100644 --- a/integration-tests/groovy/src/test/java/org/apache/camel/quarkus/component/groovy/it/GroovyTest.java +++ b/integration-tests/groovy/src/test/java/org/apache/camel/quarkus/component/groovy/it/GroovyTest.java @@ -16,6 +16,7 @@ */ package org.apache.camel.quarkus.component.groovy.it; +import io.quarkus.test.junit.DisabledOnIntegrationTest; import io.quarkus.test.junit.QuarkusTest; import io.restassured.RestAssured; import io.restassured.http.ContentType; @@ -30,7 +31,7 @@ class GroovyTest { void groovyHello() { RestAssured.given() .body("Will Smith") - .post("/groovy/hello") + .post("/groovy/direct/groovyHello") .then() .statusCode(200) .body(CoreMatchers.is("Hello Will Smith from Groovy!")); @@ -40,7 +41,7 @@ class GroovyTest { void groovyHi() { RestAssured.given() .body("Jack") - .post("/groovy/hi") + .post("/groovy/direct/groovyHi") .then() .statusCode(200) .body(CoreMatchers.is("Hi Jack we are going to Shamrock")); @@ -77,4 +78,85 @@ class GroovyTest { .body(Matchers.is("Hello world from Groovy!")); } + @Test + void groovyFilter() { + //hi is not changed + RestAssured.given() + .body("Hi") + .post("/groovy/direct/filter") + .then() + .statusCode(200) + .body(CoreMatchers.is("Hi")); + //hello is changed + RestAssured.given() + .body("Hello") + .post("/groovy/direct/filter") + .then() + .statusCode(200) + .body(CoreMatchers.is("Received unknown request: Hello")); + } + + @Test + void groovyMultiStatement() { + //hi is not changed + RestAssured.given() + .body("Hi") + .post("/groovy/direct/multiStatement") + .then() + .statusCode(200) + .body(CoreMatchers.is("Hello C")); + } + + @Test + void groovyScriptFromResource() { + RestAssured.given() + .body("Sheldon") + .post("/groovy/direct/scriptFromResource") + .then() + .statusCode(200) + .body(CoreMatchers.is("Hello Sheldon from resources!")); + } + + @Test + void contextValidation() { + RestAssured.given() + .body("") + .post("/groovy/direct/validateContext") + .then() + .statusCode(200) + .body(Matchers.containsString("camelContext: CamelContext(")) + .body(Matchers.containsString("request: Message")) + .body(Matchers.containsString("headers: [myHeader:myHeaderValue")); + } + + //following tests don't work in the native mode (see extension doc) + + @DisabledOnIntegrationTest + @Test + void contextValidationInJVMMode() { + //JVM mode allows to use more variables + RestAssured.given() + .body("") + .post("/groovy/direct/validateContextInJvm") + .then() + .statusCode(200) + .body(Matchers.containsString("exchangeProperties: [myProperty:myPropertyValue")) + .body(Matchers.containsString("exchangeProperty: [myProperty:myPropertyValue")) + .body(Matchers.containsString("variable: [myVariable:myVariableValue]")) + .body(Matchers.containsString("variable: [myVariable:myVariableValue]")) + .body(Matchers.containsString("header: [myHeader:myHeaderValue]")) + .body(Matchers.containsString("attachments: [mygroovy.groovy")) + .body(Matchers.containsString("log: org.slf4j.impl")); + } + + @DisabledOnIntegrationTest + @Test + void groovyCustomizedShellHi() { + RestAssured.given() + .body("Jack") + .post("/groovy/direct/customizedHi") + .then() + .statusCode(200) + .body(CoreMatchers.is("Ahoj Jack from Groovy!")); + } }