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

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new e42df7d3722 CAMEL-21402: Mock endpoints can now use all the standard 
languages more easily in fluent expecation builders and also custom functions 
in Java lined code (#16280)
e42df7d3722 is described below

commit e42df7d37221110667f3d983e48917bfa55c6c33
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Thu Nov 14 18:54:56 2024 +0100

    CAMEL-21402: Mock endpoints can now use all the standard languages more 
easily in fluent expecation builders and also custom functions in Java lined 
code (#16280)
---
 .../camel-mock/src/main/docs/mock-component.adoc   |  19 +++
 .../camel/component/mock/MockValueBuilder.java     | 187 ++++++++++++++++++++-
 .../camel/issues/MockExpectedHeaderCustomTest.java |  58 +++++++
 .../camel/issues/MockExpectedHeaderSimpleTest.java |  66 ++++++++
 .../camel/support/builder/ExpressionBuilder.java   |  38 +++++
 5 files changed, 364 insertions(+), 4 deletions(-)

diff --git a/components/camel-mock/src/main/docs/mock-component.adoc 
b/components/camel-mock/src/main/docs/mock-component.adoc
index 00ea34639a3..5832fae8f43 100644
--- a/components/camel-mock/src/main/docs/mock-component.adoc
+++ b/components/camel-mock/src/main/docs/mock-component.adoc
@@ -288,6 +288,25 @@ By default, the source is the message body, and therefore 
is only needed when yo
 
 To use any of the Camel languages then do as shown previously with the XPath 
example.
 
+==== Using a custom inlined function
+
+You can also use a custom `java.util.Function` as part of mock expectations. 
This allows you full power
+to use Java programming to compute the returned value.
+
+For example, you can write a custom function that takes an int as input and 
return the double value.
+And then use this in mock as follows:
+
+[source,java]
+----
+mock.message(0).header("num").expression(o -> {
+    int num = (int) o;
+    return num * 2;
+}).isLessThan(10);
+----
+
+This example is a bit silly, and in a real use-case you would use custom 
functions
+in advanced testing where you need to do some special coding based on business 
logic and data.
+
 === Mocking existing endpoints
 
 Camel now allows you to automatically mock existing endpoints in your
diff --git 
a/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockValueBuilder.java
 
b/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockValueBuilder.java
index f4b56f9f753..56c4b1f4c08 100644
--- 
a/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockValueBuilder.java
+++ 
b/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockValueBuilder.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
@@ -219,25 +220,203 @@ public class MockValueBuilder implements Expression, 
Predicate {
     // Expression builders
     // 
-------------------------------------------------------------------------
 
-    public MockValueBuilder xpath(String xpath) {
+    /**
+     * Creates an expression using the custom expression
+     *
+     * @param  function the custom function
+     * @return          a builder with the expression
+     */
+    public MockValueBuilder expression(Function<Object, Object> function) {
+        Expression newExp = 
ExpressionBuilder.customExpression(this.expression, function);
+        return onNewValueBuilder(newExp);
+    }
+
+    /**
+     * Creates an expression using the given language
+     *
+     * @param  language the language
+     * @param  value    the expression value
+     * @return          a builder with the expression
+     */
+    public MockValueBuilder language(String language, String value) {
+        Expression newExp = ExpressionBuilder.languageExpression(expression, 
language, value, Object.class);
+        return onNewValueBuilder(newExp);
+    }
+
+    /**
+     * Creates an expression using the simple language
+     *
+     * @param  value the expression value
+     * @return       a builder with the expression
+     */
+    public MockValueBuilder simple(String value) {
+        Expression newExp = ExpressionBuilder.languageExpression(expression, 
"simple", value, Object.class);
+        return onNewValueBuilder(newExp);
+    }
+
+    /**
+     * Creates an expression using the datasonnet language
+     *
+     * @param  value the expression value
+     * @return       a builder with the expression
+     */
+    public MockValueBuilder datasonnet(String value) {
+        Expression newExp = ExpressionBuilder.languageExpression(expression, 
"datasonnet", value, Object.class);
+        return onNewValueBuilder(newExp);
+    }
+
+    /**
+     * Creates an expression using the groovy language
+     *
+     * @param  value the expression value
+     * @return       a builder with the expression
+     */
+    public MockValueBuilder groovy(String value) {
+        Expression newExp = ExpressionBuilder.languageExpression(expression, 
"groovy", value, Object.class);
+        return onNewValueBuilder(newExp);
+    }
+
+    /**
+     * Creates an expression using the javascript language
+     *
+     * @param  value the expression value
+     * @return       a builder with the expression
+     */
+    public MockValueBuilder js(String value) {
+        Expression newExp = ExpressionBuilder.languageExpression(expression, 
"js", value, Object.class);
+        return onNewValueBuilder(newExp);
+    }
+
+    /**
+     * Creates an expression using the jq language
+     *
+     * @param  value the expression value
+     * @return       a builder with the expression
+     */
+    public MockValueBuilder jq(String value) {
+        Expression newExp = ExpressionBuilder.languageExpression(expression, 
"jq", value, Object.class);
+        return onNewValueBuilder(newExp);
+    }
+
+    /**
+     * Creates an expression using the jsonpath language
+     *
+     * @param  value the expression value
+     * @return       a builder with the expression
+     */
+    public MockValueBuilder jsonpath(String value) {
+        Expression newExp = ExpressionBuilder.languageExpression(expression, 
"jsonpath", value, Object.class);
+        return onNewValueBuilder(newExp);
+    }
+
+    /**
+     * Creates an expression using the mvel language
+     *
+     * @param  value the expression value
+     * @return       a builder with the expression
+     */
+    public MockValueBuilder mvel(String value) {
+        Expression newExp = ExpressionBuilder.languageExpression(expression, 
"mvel", value, Object.class);
+        return onNewValueBuilder(newExp);
+    }
+
+    /**
+     * Creates an expression using the ognl language
+     *
+     * @param  value the expression value
+     * @return       a builder with the expression
+     */
+    public MockValueBuilder ognl(String value) {
+        Expression newExp = ExpressionBuilder.languageExpression(expression, 
"ognl", value, Object.class);
+        return onNewValueBuilder(newExp);
+    }
+
+    /**
+     * Creates an expression using the python language
+     *
+     * @param  value the expression value
+     * @return       a builder with the expression
+     */
+    public MockValueBuilder python(String value) {
+        Expression newExp = ExpressionBuilder.languageExpression(expression, 
"python", value, Object.class);
+        return onNewValueBuilder(newExp);
+    }
+
+    /**
+     * Creates an expression using the spel language
+     *
+     * @param  value the expression value
+     * @return       a builder with the expression
+     */
+    public MockValueBuilder spel(String value) {
+        Expression newExp = ExpressionBuilder.languageExpression(expression, 
"spel", value, Object.class);
+        return onNewValueBuilder(newExp);
+    }
+
+    /**
+     * Creates an expression using the xpath language
+     *
+     * @param  value the expression value
+     * @return       a builder with the expression
+     */
+    public MockValueBuilder xpath(String value) {
         // work with string as result as xpath otherwise will use DOM types
-        Expression newExp = ExpressionBuilder.languageExpression(expression, 
"xpath", xpath, String.class);
+        Expression newExp = ExpressionBuilder.languageExpression(expression, 
"xpath", value, String.class);
+        return onNewValueBuilder(newExp);
+    }
+
+    /**
+     * Creates an expression using the xquery language
+     *
+     * @param  value the expression value
+     * @return       a builder with the expression
+     */
+    public MockValueBuilder xquery(String value) {
+        // work with string as result as xquery otherwise will use DOM types
+        Expression newExp = ExpressionBuilder.languageExpression(expression, 
"xquery", value, String.class);
         return onNewValueBuilder(newExp);
     }
 
+    /**
+     * Creates an expression using the tokenize language using new-line as 
tokenizer
+     *
+     * @return a builder with the expression
+     */
     public MockValueBuilder tokenize() {
         return tokenize("\n");
     }
 
+    /**
+     * Creates an expression using the tokenize language
+     *
+     * @param  token the token to use
+     * @return       a builder with the expression
+     */
     public MockValueBuilder tokenize(String token) {
         Expression newExp = ExpressionBuilder.tokenizeExpression(expression, 
token);
         return onNewValueBuilder(newExp);
     }
 
+    /**
+     * Creates an expression using the tokenize language
+     *
+     * @param  token     the token to use
+     * @param  group     number of elements to group
+     * @param  skipFirst whether to skip first element
+     * @return           a builder with the expression
+     */
     public MockValueBuilder tokenize(String token, int group, boolean 
skipFirst) {
         return tokenize(token, Integer.toString(group), skipFirst);
     }
 
+    /**
+     * Creates an expression using the tokenize language
+     *
+     * @param  token     the token to use
+     * @param  group     number of elements to group
+     * @param  skipFirst whether to skip first element
+     * @return           a builder with the expression
+     */
     public MockValueBuilder tokenize(String token, String group, boolean 
skipFirst) {
         Expression newExp = ExpressionBuilder.tokenizeExpression(expression, 
token);
         if (group == null && skipFirst) {
@@ -351,8 +530,8 @@ public class MockValueBuilder implements Expression, 
Predicate {
     }
 
     protected Expression asExpression(Object value) {
-        if (value instanceof Expression expression1) {
-            return expression1;
+        if (value instanceof Expression exp) {
+            return exp;
         } else {
             return ExpressionBuilder.constantExpression(value);
         }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/issues/MockExpectedHeaderCustomTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/issues/MockExpectedHeaderCustomTest.java
new file mode 100644
index 00000000000..57268c8d37b
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/issues/MockExpectedHeaderCustomTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.issues;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.Test;
+
+public class MockExpectedHeaderCustomTest extends ContextTestSupport {
+
+    @Test
+    public void testHeaderCustom() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMessageCount(2);
+
+        // the header(num) becomes input to the custom expression
+        mock.message(0).header("num").expression(o -> {
+            int num = (int) o;
+            return num * 2;
+        }).isLessThan(10);
+
+        // the header(num) becomes input to the simple language as "body"
+        mock.message(1).header("num").expression(o -> {
+            int num = (int) o;
+            return num * 3;
+        }).isGreaterThan(10);
+
+        template.sendBodyAndHeader("direct:test", "message 1", "num", 3);
+        template.sendBodyAndHeader("direct:test", "message 2", "num", 7);
+
+        mock.assertIsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:test").to("mock:result");
+            }
+        };
+    }
+}
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/issues/MockExpectedHeaderSimpleTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/issues/MockExpectedHeaderSimpleTest.java
new file mode 100644
index 00000000000..484c0459d5d
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/issues/MockExpectedHeaderSimpleTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.issues;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.Test;
+
+public class MockExpectedHeaderSimpleTest extends ContextTestSupport {
+
+    @Test
+    public void testSimple() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMessageCount(2);
+
+        mock.message(0).simple("${header.num}").isEqualTo(3);
+        mock.message(0).simple("${header.num}").isLessThan(5);
+        mock.message(1).simple("${header.num}").isEqualTo(7);
+        mock.message(1).simple("${header.num}").isGreaterThan(5);
+
+        template.sendBodyAndHeader("direct:test", "message 1", "num", "3");
+        template.sendBodyAndHeader("direct:test", "message 2", "num", "7");
+
+        mock.assertIsSatisfied();
+    }
+
+    @Test
+    public void testHeaderSimple() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMessageCount(2);
+
+        // the header(num) becomes input to the simple language as "body"
+        mock.message(0).header("num").simple("${body}${body}").isEqualTo("33");
+        mock.message(1).header("num").simple("${body}${body}").isEqualTo("77");
+
+        template.sendBodyAndHeader("direct:test", "message 1", "num", "3");
+        template.sendBodyAndHeader("direct:test", "message 2", "num", "7");
+
+        mock.assertIsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:test").to("mock:result");
+            }
+        };
+    }
+}
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
index 7165644a51d..9d27fc8adac 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
@@ -2445,6 +2445,29 @@ public class ExpressionBuilder {
         };
     }
 
+    public static Expression beanExpression(final Class<?> bean, final String 
method) {
+        return new ExpressionAdapter() {
+            private Language language;
+
+            @Override
+            public Object evaluate(Exchange exchange) {
+                Expression exp = language.createExpression(null, new Object[] 
{ null, null, method, bean });
+                exp.init(exchange.getContext());
+                return exp.evaluate(exchange, Object.class);
+            }
+
+            @Override
+            public void init(CamelContext context) {
+                super.init(context);
+                this.language = context.resolveLanguage("bean");
+            }
+
+            public String toString() {
+                return "bean(" + bean + ", " + method + ")";
+            }
+        };
+    }
+
     public static Expression propertiesComponentExpression(final String key, 
final String defaultValue) {
         return new ExpressionAdapter() {
             private Expression exp;
@@ -2567,6 +2590,21 @@ public class ExpressionBuilder {
         };
     }
 
+    public static Expression customExpression(final Expression expression, 
final Function<Object, Object> function) {
+        return new ExpressionAdapter() {
+
+            @Override
+            public Object evaluate(Exchange exchange) {
+                Object input = expression.evaluate(exchange, Object.class);
+                return function.apply(input);
+            }
+
+            public String toString() {
+                return "custom(" + expression + ")";
+            }
+        };
+    }
+
     /**
      * Returns the expression for the message body as a one-line string
      */

Reply via email to