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

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

commit 51013863a91a7e89ebe9592f6a66cc100e0015d6
Author: Christoph Deppisch <[email protected]>
AuthorDate: Thu Oct 15 10:44:19 2026 +0200

    CAMEL-25378: Address davsclaus review feedback
    
    - Override @UriPath name with Citrus-specific description to prevent
      inheriting MockEndpoint's metadata
    - Inject Supplier<TestContext> into CitrusValidationProcessor so specs
      configured before doStart() (e.g. isUseAdviceWith tests) work correctly
    - Indexed specs imply a minimum expected message count when the test
      has not set one explicitly
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
 .../org/apache/camel/catalog/components/citrus.json     |  2 +-
 .../component/citrus/CitrusEndpointUriFactory.java      |  2 +-
 .../org/apache/camel/component/citrus/citrus.json       |  2 +-
 .../apache/camel/component/citrus/CitrusEndpoint.java   | 17 +++++++++++++++--
 .../component/citrus/CitrusValidationProcessor.java     | 14 +++++++-------
 .../camel/builder/endpoint/StaticEndpointBuilders.java  | 10 ++++++----
 .../endpoint/dsl/CitrusEndpointBuilderFactory.java      | 10 ++++++----
 7 files changed, 37 insertions(+), 20 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/citrus.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/citrus.json
index 76941d15c7f3..058471240c86 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/citrus.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/citrus.json
@@ -31,7 +31,7 @@
   },
   "properties": {
     "operation": { "index": 0, "kind": "path", "displayName": "Operation", 
"group": "producer", "label": "", "required": true, "type": "enum", "javaType": 
"java.lang.String", "enum": [ "validate", "receive" ], "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
operation to perform. 'validate' validates exchanges without modifying them. 
'receive' validates exchanges and returns a simulated response." },
-    "name": { "index": 1, "kind": "path", "displayName": "Name", "group": 
"producer", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Name of mock endpoint" },
+    "name": { "index": 1, "kind": "path", "displayName": "Name", "group": 
"producer", "label": "", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"description": "A unique name to identify this endpoint. Allows multiple Citrus 
endpoints with different validation expectations in the same route." },
     "assertPeriod": { "index": 2, "kind": "parameter", "displayName": "Assert 
Period", "group": "producer", "label": "producer", "required": false, "type": 
"duration", "javaType": "long", "deprecated": false, "autowired": false, 
"secret": false, "description": "Sets a grace period after which the mock will 
re-assert to ensure the preliminary assertion is still valid. This is used, for 
example, to assert that exactly a number of messages arrive. For example, if 
the expected count was set  [...]
     "expectedCount": { "index": 3, "kind": "parameter", "displayName": 
"Expected Count", "group": "producer", "label": "producer", "required": false, 
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": -1, "description": "Specifies the expected 
number of message exchanges that should be received by this mock. Beware: If 
you want to expect that 0 messages, then take extra care, as 0 matches when the 
tests starts, so you need to s [...]
     "messageType": { "index": 4, "kind": "parameter", "displayName": "Message 
Type", "group": "producer", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "description": "The message type for validation. Determines 
which Citrus validation module is used. Supported values: json, xml, yaml, 
plaintext." },
diff --git 
a/components/camel-test/camel-test-citrus/src/generated/java/org/apache/camel/component/citrus/CitrusEndpointUriFactory.java
 
b/components/camel-test/camel-test-citrus/src/generated/java/org/apache/camel/component/citrus/CitrusEndpointUriFactory.java
index 64ff55b2ec76..54ed2323f209 100644
--- 
a/components/camel-test/camel-test-citrus/src/generated/java/org/apache/camel/component/citrus/CitrusEndpointUriFactory.java
+++ 
b/components/camel-test/camel-test-citrus/src/generated/java/org/apache/camel/component/citrus/CitrusEndpointUriFactory.java
@@ -60,7 +60,7 @@ public class CitrusEndpointUriFactory extends 
org.apache.camel.support.component
         Map<String, Object> copy = copyParameters(properties);
 
         uri = buildPathParameter(syntax, uri, "operation", null, true, copy);
-        uri = buildPathParameter(syntax, uri, "name", null, true, copy);
+        uri = buildPathParameter(syntax, uri, "name", null, false, copy);
         uri = buildQueryParameters(uri, copy, encode);
         return uri;
     }
diff --git 
a/components/camel-test/camel-test-citrus/src/generated/resources/META-INF/org/apache/camel/component/citrus/citrus.json
 
b/components/camel-test/camel-test-citrus/src/generated/resources/META-INF/org/apache/camel/component/citrus/citrus.json
index 76941d15c7f3..058471240c86 100644
--- 
a/components/camel-test/camel-test-citrus/src/generated/resources/META-INF/org/apache/camel/component/citrus/citrus.json
+++ 
b/components/camel-test/camel-test-citrus/src/generated/resources/META-INF/org/apache/camel/component/citrus/citrus.json
@@ -31,7 +31,7 @@
   },
   "properties": {
     "operation": { "index": 0, "kind": "path", "displayName": "Operation", 
"group": "producer", "label": "", "required": true, "type": "enum", "javaType": 
"java.lang.String", "enum": [ "validate", "receive" ], "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
operation to perform. 'validate' validates exchanges without modifying them. 
'receive' validates exchanges and returns a simulated response." },
-    "name": { "index": 1, "kind": "path", "displayName": "Name", "group": 
"producer", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Name of mock endpoint" },
+    "name": { "index": 1, "kind": "path", "displayName": "Name", "group": 
"producer", "label": "", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"description": "A unique name to identify this endpoint. Allows multiple Citrus 
endpoints with different validation expectations in the same route." },
     "assertPeriod": { "index": 2, "kind": "parameter", "displayName": "Assert 
Period", "group": "producer", "label": "producer", "required": false, "type": 
"duration", "javaType": "long", "deprecated": false, "autowired": false, 
"secret": false, "description": "Sets a grace period after which the mock will 
re-assert to ensure the preliminary assertion is still valid. This is used, for 
example, to assert that exactly a number of messages arrive. For example, if 
the expected count was set  [...]
     "expectedCount": { "index": 3, "kind": "parameter", "displayName": 
"Expected Count", "group": "producer", "label": "producer", "required": false, 
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": -1, "description": "Specifies the expected 
number of message exchanges that should be received by this mock. Beware: If 
you want to expect that 0 messages, then take extra care, as 0 matches when the 
tests starts, so you need to s [...]
     "messageType": { "index": 4, "kind": "parameter", "displayName": "Message 
Type", "group": "producer", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "description": "The message type for validation. Determines 
which Citrus validation module is used. Supported values: json, xml, yaml, 
plaintext." },
diff --git 
a/components/camel-test/camel-test-citrus/src/main/java/org/apache/camel/component/citrus/CitrusEndpoint.java
 
b/components/camel-test/camel-test-citrus/src/main/java/org/apache/camel/component/citrus/CitrusEndpoint.java
index a1d6cb58f32a..04f33ae3e931 100644
--- 
a/components/camel-test/camel-test-citrus/src/main/java/org/apache/camel/component/citrus/CitrusEndpoint.java
+++ 
b/components/camel-test/camel-test-citrus/src/main/java/org/apache/camel/component/citrus/CitrusEndpoint.java
@@ -39,6 +39,10 @@ public class CitrusEndpoint extends MockEndpoint {
     @Metadata(required = true)
     private String operation;
 
+    @UriPath(description = "A unique name to identify this endpoint. Allows 
multiple Citrus endpoints"
+                           + " with different validation expectations in the 
same route.")
+    private String name;
+
     @UriParam(description = "The message type for validation. Determines which 
Citrus validation module is used."
                             + " Supported values: json, xml, yaml, plaintext.")
     private String messageType;
@@ -82,17 +86,19 @@ public class CitrusEndpoint extends MockEndpoint {
     public MessageValidationSpec validate(int index) {
         MessageValidationSpec messageValidationSpec = new 
MessageValidationSpec();
         whenExchangeReceived(index, createProcessor(messageValidationSpec));
+        applyImpliedMinimumCount(index);
         return messageValidationSpec;
     }
 
     private CitrusValidationProcessor createProcessor(MessageValidationSpec 
validationSpec) {
-        return new CitrusValidationProcessor(citrusContext, messageType, 
validationSpec);
+        return new CitrusValidationProcessor(() -> 
citrusContext.createTestContext(), messageType, validationSpec);
     }
 
     private CitrusValidationProcessor createProcessor(
             MessageValidationSpec validationSpec,
             MessageResponseSpec responseSpec) {
-        return new CitrusValidationProcessor(citrusContext, messageType, 
validationSpec, responseSpec);
+        return new CitrusValidationProcessor(
+                () -> citrusContext.createTestContext(), messageType, 
validationSpec, responseSpec);
     }
 
     // --- Gherkin-style API (for 'receive' operation) ---
@@ -101,6 +107,12 @@ public class CitrusEndpoint extends MockEndpoint {
         return new WhenSpec();
     }
 
+    private void applyImpliedMinimumCount(int index) {
+        if (getExpectedCount() < 0 && getExpectedMinimumCount() < index) {
+            expectedMinimumMessageCount(index);
+        }
+    }
+
     @Override
     public void reset() {
         super.reset();
@@ -157,6 +169,7 @@ public class CitrusEndpoint extends MockEndpoint {
         public WhenMessageValidationSpec receive(int index) {
             WhenMessageValidationSpec messageValidationSpec = new 
WhenMessageValidationSpec(index);
             whenExchangeReceived(index, 
createProcessor(messageValidationSpec));
+            applyImpliedMinimumCount(index);
             return messageValidationSpec;
         }
 
diff --git 
a/components/camel-test/camel-test-citrus/src/main/java/org/apache/camel/component/citrus/CitrusValidationProcessor.java
 
b/components/camel-test/camel-test-citrus/src/main/java/org/apache/camel/component/citrus/CitrusValidationProcessor.java
index 092944def606..c9e139140c6e 100644
--- 
a/components/camel-test/camel-test-citrus/src/main/java/org/apache/camel/component/citrus/CitrusValidationProcessor.java
+++ 
b/components/camel-test/camel-test-citrus/src/main/java/org/apache/camel/component/citrus/CitrusValidationProcessor.java
@@ -21,11 +21,11 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.function.Supplier;
 
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.StreamCache;
-import org.citrusframework.CitrusContext;
 import org.citrusframework.context.TestContext;
 import org.citrusframework.message.DefaultMessage;
 import org.citrusframework.message.MessagePayloadBuilder;
@@ -43,20 +43,20 @@ class CitrusValidationProcessor implements Processor {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(CitrusValidationProcessor.class);
 
-    private final CitrusContext citrusContext;
+    private final Supplier<TestContext> testContextSupplier;
     private final String messageType;
     private final MessageValidationSpec spec;
     private final MessageResponseSpec responseSpec;
 
-    CitrusValidationProcessor(CitrusContext citrusContext, String messageType,
+    CitrusValidationProcessor(Supplier<TestContext> testContextSupplier, 
String messageType,
                               MessageValidationSpec validationSpec) {
-        this(citrusContext, messageType, validationSpec, null);
+        this(testContextSupplier, messageType, validationSpec, null);
     }
 
-    CitrusValidationProcessor(CitrusContext citrusContext, String messageType,
+    CitrusValidationProcessor(Supplier<TestContext> testContextSupplier, 
String messageType,
                               MessageValidationSpec validationSpec,
                               MessageResponseSpec responseSpec) {
-        this.citrusContext = citrusContext;
+        this.testContextSupplier = testContextSupplier;
         this.messageType = messageType;
         this.spec = validationSpec;
         this.responseSpec = responseSpec;
@@ -64,7 +64,7 @@ class CitrusValidationProcessor implements Processor {
 
     @Override
     public void process(Exchange exchange) throws Exception {
-        TestContext testContext = citrusContext.createTestContext();
+        TestContext testContext = testContextSupplier.get();
         propagateExchangeVariables(exchange, testContext);
 
         try {
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
index 9d1bf697ccc6..bef527f62ada 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
@@ -3390,8 +3390,9 @@ public class StaticEndpointBuilders {
      * response.
      * There are 2 enums and the value can be one of: validate, receive
      * 
-     * Path parameter: name (required)
-     * Name of mock endpoint
+     * Path parameter: name
+     * A unique name to identify this endpoint. Allows multiple Citrus 
endpoints
+     * with different validation expectations in the same route.
      * 
      * @param path operation/name
      * @return the dsl builder
@@ -3415,8 +3416,9 @@ public class StaticEndpointBuilders {
      * response.
      * There are 2 enums and the value can be one of: validate, receive
      * 
-     * Path parameter: name (required)
-     * Name of mock endpoint
+     * Path parameter: name
+     * A unique name to identify this endpoint. Allows multiple Citrus 
endpoints
+     * with different validation expectations in the same route.
      * 
      * @param componentName to use a custom component name for the endpoint
      * instead of the default name
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/CitrusEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/CitrusEndpointBuilderFactory.java
index 5c1bcbe5036b..57bbadf83f6b 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/CitrusEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/CitrusEndpointBuilderFactory.java
@@ -592,8 +592,9 @@ public interface CitrusEndpointBuilderFactory {
          * response.
          * There are 2 enums and the value can be one of: validate, receive
          * 
-         * Path parameter: name (required)
-         * Name of mock endpoint
+         * Path parameter: name
+         * A unique name to identify this endpoint. Allows multiple Citrus
+         * endpoints with different validation expectations in the same route.
          * 
          * @param path operation/name
          * @return the dsl builder
@@ -617,8 +618,9 @@ public interface CitrusEndpointBuilderFactory {
          * response.
          * There are 2 enums and the value can be one of: validate, receive
          * 
-         * Path parameter: name (required)
-         * Name of mock endpoint
+         * Path parameter: name
+         * A unique name to identify this endpoint. Allows multiple Citrus
+         * endpoints with different validation expectations in the same route.
          * 
          * @param componentName to use a custom component name for the endpoint
          * instead of the default name

Reply via email to