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
