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 5b2016dfae5ae07a13a396d033aa0ca54714bc2b Author: Christoph Deppisch <[email protected]> AuthorDate: Wed Oct 14 20:04:34 2026 +0200 CAMEL-25378: Address review feedback on camel-test-citrus - Validate operation errors: record failures instead of throwing, reported via assertIsSatisfied() (MockEndpoint pattern) - Receive operation: still throws on validation failure - Add operation validation in CitrusComponent (reject invalid ops) - Add volatile to shared mutable fields for thread safety - Reset counters in expectedMessageCount() - Auto-derive expected count from indexed specs - Add CitrusContext lifecycle management (doStop) - Propagate exchange variables (both directions) between Camel/Citrus - Use Locale.ROOT for case conversions - Switch test dependency to camel-test-junit6 - Update firstVersion to 4.24.0 - Add operation enum constraint - Improve documentation: Maven dependency snippet, path validation API usage, missing spec error behavior, exchange variables - Regenerate catalog and endpoint DSL artifacts Co-Authored-By: Claude Opus 4.6 <[email protected]> --- .../apache/camel/catalog/components/citrus.json | 4 +- .../camel/catalog/docs/citrus-component.adoc | 47 ++++++++++++++++++---- components/camel-test/camel-test-citrus/pom.xml | 10 +---- .../org/apache/camel/component/citrus/citrus.json | 4 +- .../src/main/docs/citrus-component.adoc | 47 ++++++++++++++++++---- .../camel/component/citrus/CitrusComponent.java | 4 ++ .../camel/component/citrus/CitrusEndpoint.java | 28 ++++++++----- .../camel/component/citrus/CitrusProducer.java | 46 ++++++++++++++++----- .../citrus/CitrusMultipleEndpointsTest.java | 2 +- .../camel/component/citrus/CitrusReceiveTest.java | 2 +- .../citrus/CitrusSequentialValidationTest.java | 22 +++++----- .../component/citrus/CitrusValidateJsonTest.java | 12 ++++-- .../citrus/CitrusValidatePlainTextTest.java | 11 +++-- .../component/citrus/CitrusValidateXmlTest.java | 2 +- .../component/citrus/CitrusValidateYamlTest.java | 13 +++--- .../builder/endpoint/StaticEndpointBuilders.java | 6 ++- .../endpoint/dsl/CitrusEndpointBuilderFactory.java | 6 ++- 17 files changed, 189 insertions(+), 77 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 72f7bf646491..ced95b3a80fb 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 @@ -5,7 +5,7 @@ "title": "Citrus", "description": "Citrus message validation component for testing", "deprecated": false, - "firstVersion": "4.23.0", + "firstVersion": "4.24.0", "label": "testing", "javaType": "org.apache.camel.component.citrus.CitrusComponent", "supportLevel": "Preview", @@ -28,7 +28,7 @@ "autowiredEnabled": { "index": 1, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching t [...] }, "properties": { - "operation": { "index": 0, "kind": "path", "displayName": "Operation", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "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." }, + "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": 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." }, "messageType": { "index": 2, "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." }, "lazyStartProducer": { "index": 3, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produc [...] diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/citrus-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/citrus-component.adoc index 2a385b38d6be..280ee52e74a4 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/citrus-component.adoc +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/citrus-component.adoc @@ -3,7 +3,7 @@ :shortname: citrus :artifactid: camel-test-citrus :description: Citrus message validation component for testing -:since: 4.23 +:since: 4.24 :supportlevel: Preview :tabs-sync-option: :component-header: Only producer is supported @@ -19,6 +19,17 @@ modules. This component is intended for use in Camel route unit and integration tests. +== Maven dependency + +[source,xml] +---- +<dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-test-citrus</artifactId> + <scope>test</scope> +</dependency> +---- + == URI format ---- @@ -257,7 +268,9 @@ it replaces `allMessages()` for that exchange entirely (the two are never combin `allMessages()` spec acts as a fallback for exchanges that have no matching indexed spec. If an exchange arrives at an index with no matching indexed spec and no `allMessages()` fallback, -the endpoint fails with an error. +the endpoint records a failure. For the `validate` operation, the failure is collected and reported +when `assertIsSatisfied()` is called (similar to MockEndpoint). For the `receive` operation, the +failure is thrown immediately as an exception. [source,java] ---- @@ -365,14 +378,32 @@ citrus.then().allMessages().respond() citrus.expectedMessageCount(1); ---- -=== Exchange properties as Citrus variables +=== Exchange properties and variables as Citrus variables -All exchange properties are automatically propagated to the Citrus test context as test variables. -This enables the use of Citrus functions and validation matchers in expected message templates. +All exchange properties and exchange variables are automatically propagated to the Citrus test +context as test variables. This enables the use of Citrus variable placeholders (`${variableName}`) +in expected message templates and response bodies. + +Variables extracted by Citrus during validation (e.g., via `@variable('name')@`) are written back +to the exchange as exchange variables, making them available for downstream route processing. === Path validation -Path validation expressions are automatically classified: +Use the `validate()` method on a `MessageValidationSpec` to add Citrus validation context builders +such as JsonPath or XPath expressions. These are provided by the Citrus `DefaultValidations` class: -* Expressions starting with `$` are treated as JsonPath -* Expressions starting with `/` are treated as XPath +[source,java] +---- +CitrusEndpoint citrus = context.getEndpoint("citrus:validate?messageType=json", CitrusEndpoint.class); +citrus.allMessages().validate(new DefaultValidations().jsonPath() + .expression("$.user.name", "John") + .expression("$.user.age", "30")); +---- + +[source,java] +---- +CitrusEndpoint citrus = context.getEndpoint("citrus:validate?messageType=xml", CitrusEndpoint.class); +citrus.allMessages().validate(new DefaultValidations().xpath() + .expression("/order/status", "completed") + .expression("/order/total", "99.99")); +---- diff --git a/components/camel-test/camel-test-citrus/pom.xml b/components/camel-test/camel-test-citrus/pom.xml index 7ce080a3ff84..58ca14a9c68b 100644 --- a/components/camel-test/camel-test-citrus/pom.xml +++ b/components/camel-test/camel-test-citrus/pom.xml @@ -33,7 +33,7 @@ <description>Citrus message validation component for testing</description> <properties> - <firstVersion>4.23.0</firstVersion> + <firstVersion>4.24.0</firstVersion> <label>testing,java</label> <title>Test Citrus</title> </properties> @@ -59,7 +59,7 @@ <!-- Test dependencies --> <dependency> <groupId>org.apache.camel</groupId> - <artifactId>camel-test-junit5</artifactId> + <artifactId>camel-test-junit6</artifactId> <scope>test</scope> </dependency> <dependency> @@ -99,15 +99,9 @@ <scope>test</scope> </dependency> - <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter</artifactId> - <scope>test</scope> - </dependency> <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> - <version>${assertj-version}</version> <scope>test</scope> </dependency> <dependency> 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 72f7bf646491..ced95b3a80fb 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 @@ -5,7 +5,7 @@ "title": "Citrus", "description": "Citrus message validation component for testing", "deprecated": false, - "firstVersion": "4.23.0", + "firstVersion": "4.24.0", "label": "testing", "javaType": "org.apache.camel.component.citrus.CitrusComponent", "supportLevel": "Preview", @@ -28,7 +28,7 @@ "autowiredEnabled": { "index": 1, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching t [...] }, "properties": { - "operation": { "index": 0, "kind": "path", "displayName": "Operation", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "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." }, + "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": 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." }, "messageType": { "index": 2, "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." }, "lazyStartProducer": { "index": 3, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produc [...] diff --git a/components/camel-test/camel-test-citrus/src/main/docs/citrus-component.adoc b/components/camel-test/camel-test-citrus/src/main/docs/citrus-component.adoc index 2a385b38d6be..280ee52e74a4 100644 --- a/components/camel-test/camel-test-citrus/src/main/docs/citrus-component.adoc +++ b/components/camel-test/camel-test-citrus/src/main/docs/citrus-component.adoc @@ -3,7 +3,7 @@ :shortname: citrus :artifactid: camel-test-citrus :description: Citrus message validation component for testing -:since: 4.23 +:since: 4.24 :supportlevel: Preview :tabs-sync-option: :component-header: Only producer is supported @@ -19,6 +19,17 @@ modules. This component is intended for use in Camel route unit and integration tests. +== Maven dependency + +[source,xml] +---- +<dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-test-citrus</artifactId> + <scope>test</scope> +</dependency> +---- + == URI format ---- @@ -257,7 +268,9 @@ it replaces `allMessages()` for that exchange entirely (the two are never combin `allMessages()` spec acts as a fallback for exchanges that have no matching indexed spec. If an exchange arrives at an index with no matching indexed spec and no `allMessages()` fallback, -the endpoint fails with an error. +the endpoint records a failure. For the `validate` operation, the failure is collected and reported +when `assertIsSatisfied()` is called (similar to MockEndpoint). For the `receive` operation, the +failure is thrown immediately as an exception. [source,java] ---- @@ -365,14 +378,32 @@ citrus.then().allMessages().respond() citrus.expectedMessageCount(1); ---- -=== Exchange properties as Citrus variables +=== Exchange properties and variables as Citrus variables -All exchange properties are automatically propagated to the Citrus test context as test variables. -This enables the use of Citrus functions and validation matchers in expected message templates. +All exchange properties and exchange variables are automatically propagated to the Citrus test +context as test variables. This enables the use of Citrus variable placeholders (`${variableName}`) +in expected message templates and response bodies. + +Variables extracted by Citrus during validation (e.g., via `@variable('name')@`) are written back +to the exchange as exchange variables, making them available for downstream route processing. === Path validation -Path validation expressions are automatically classified: +Use the `validate()` method on a `MessageValidationSpec` to add Citrus validation context builders +such as JsonPath or XPath expressions. These are provided by the Citrus `DefaultValidations` class: -* Expressions starting with `$` are treated as JsonPath -* Expressions starting with `/` are treated as XPath +[source,java] +---- +CitrusEndpoint citrus = context.getEndpoint("citrus:validate?messageType=json", CitrusEndpoint.class); +citrus.allMessages().validate(new DefaultValidations().jsonPath() + .expression("$.user.name", "John") + .expression("$.user.age", "30")); +---- + +[source,java] +---- +CitrusEndpoint citrus = context.getEndpoint("citrus:validate?messageType=xml", CitrusEndpoint.class); +citrus.allMessages().validate(new DefaultValidations().xpath() + .expression("/order/status", "completed") + .expression("/order/total", "99.99")); +---- diff --git a/components/camel-test/camel-test-citrus/src/main/java/org/apache/camel/component/citrus/CitrusComponent.java b/components/camel-test/camel-test-citrus/src/main/java/org/apache/camel/component/citrus/CitrusComponent.java index 46930c00acad..57e3d47e1075 100644 --- a/components/camel-test/camel-test-citrus/src/main/java/org/apache/camel/component/citrus/CitrusComponent.java +++ b/components/camel-test/camel-test-citrus/src/main/java/org/apache/camel/component/citrus/CitrusComponent.java @@ -39,6 +39,10 @@ public class CitrusComponent extends DefaultComponent { operation = remaining; } + if (!"validate".equals(operation) && !"receive".equals(operation)) { + throw new IllegalArgumentException( + "Invalid citrus operation: '" + operation + "'. Valid values are: validate, receive"); + } endpoint.setOperation(operation); endpoint.setName(name); setProperties(endpoint, parameters); 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 db8361e85780..b5d5cf59224d 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,7 +39,7 @@ import org.citrusframework.exceptions.ValidationException; import org.citrusframework.message.MessagePayloadBuilder; import org.citrusframework.validation.context.ValidationContext; -@UriEndpoint(firstVersion = "4.23.0", scheme = "citrus", title = "Citrus", syntax = "citrus:operation/name", +@UriEndpoint(firstVersion = "4.24.0", scheme = "citrus", title = "Citrus", syntax = "citrus:operation/name", producerOnly = true, remote = false, category = { Category.TESTING }) public class CitrusEndpoint extends DefaultEndpoint { @@ -51,7 +51,8 @@ public class CitrusEndpoint extends DefaultEndpoint { private volatile CountDownLatch latch; @UriPath(description = "The operation to perform. 'validate' validates exchanges without modifying them." - + " 'receive' validates exchanges and returns a simulated response.") + + " 'receive' validates exchanges and returns a simulated response.", + enums = "validate,receive") @Metadata(required = true) private String operation; @@ -63,15 +64,15 @@ public class CitrusEndpoint extends DefaultEndpoint { + " Supported values: json, xml, yaml, plaintext.") private String messageType; - private MessageValidationSpec allMessagesSpec; + private volatile MessageValidationSpec allMessagesSpec; private final Map<Integer, MessageValidationSpec> indexedSpecs = new LinkedHashMap<>(); - private int nextSpecIndex; + private volatile int nextSpecIndex; - private MessageResponseSpec allMessagesResponseSpec; + private volatile MessageResponseSpec allMessagesResponseSpec; private final Map<Integer, MessageResponseSpec> indexedResponseSpecs = new LinkedHashMap<>(); - private int nextResponseSpecIndex; + private volatile int nextResponseSpecIndex; - private int expectedCount = -1; + private volatile int expectedCount = -1; public CitrusEndpoint(String endpointUri, CitrusComponent component) { super(endpointUri, component); @@ -116,6 +117,8 @@ public class CitrusEndpoint extends DefaultEndpoint { public CitrusEndpoint expectedMessageCount(int count) { this.expectedCount = count; + this.receivedCount.set(0); + this.receivedExchanges.clear(); this.latch = new CountDownLatch(count); return this; } @@ -160,16 +163,21 @@ public class CitrusEndpoint extends DefaultEndpoint { } public void assertIsSatisfied(long timeout, TimeUnit unit) throws InterruptedException { + int effectiveExpected = expectedCount; + if (effectiveExpected < 0 && !indexedSpecs.isEmpty()) { + effectiveExpected = indexedSpecs.size(); + } + if (latch != null && !latch.await(timeout, unit)) { throw new ValidationException( "Timed out waiting for %d messages on endpoint: %s" - .formatted(expectedCount, getEndpointUri())); + .formatted(effectiveExpected, getEndpointUri())); } - if (expectedCount >= 0 && receivedCount.get() != expectedCount) { + if (effectiveExpected >= 0 && receivedCount.get() != effectiveExpected) { throw new ValidationException( "Expected %d messages but received %d on endpoint: %s" - .formatted(expectedCount, receivedCount.get(), getEndpointUri())); + .formatted(effectiveExpected, receivedCount.get(), getEndpointUri())); } if (!failures.isEmpty()) { diff --git a/components/camel-test/camel-test-citrus/src/main/java/org/apache/camel/component/citrus/CitrusProducer.java b/components/camel-test/camel-test-citrus/src/main/java/org/apache/camel/component/citrus/CitrusProducer.java index 407767faebfa..c565db25cba7 100644 --- a/components/camel-test/camel-test-citrus/src/main/java/org/apache/camel/component/citrus/CitrusProducer.java +++ b/components/camel-test/camel-test-citrus/src/main/java/org/apache/camel/component/citrus/CitrusProducer.java @@ -19,6 +19,7 @@ package org.apache.camel.component.citrus; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import org.apache.camel.Exchange; @@ -60,16 +61,25 @@ public class CitrusProducer extends DefaultProducer { citrusContext = CitrusContext.create(); } + @Override + protected void doStop() throws Exception { + super.doStop(); + if (citrusContext != null) { + citrusContext.close(); + citrusContext = null; + } + } + @Override public void process(Exchange exchange) throws Exception { CitrusEndpoint endpoint = getEndpoint(); + int index = endpoint.nextExchangeIndex(); + TestContext testContext = citrusContext.createTestContext(); + propagateExchangeVariables(exchange, testContext); + try { - int index = endpoint.nextExchangeIndex(); MessageValidationSpec spec = endpoint.resolveValidationSpec(index); - TestContext testContext = citrusContext.createTestContext(); - propagateExchangeProperties(exchange, testContext); - if (spec != null) { DefaultMessage receivedMessage = buildReceivedMessage(exchange); DefaultMessage controlMessage = buildControlMessage(spec, testContext); @@ -90,19 +100,35 @@ public class CitrusProducer extends DefaultProducer { } } catch (Exception e) { endpoint.addFailure(e); - throw e; + if ("receive".equals(endpoint.getOperation())) { + throw e; + } } finally { + writeBackExtractedVariables(exchange, testContext); endpoint.onExchangeReceived(exchange); } } - private void propagateExchangeProperties(Exchange exchange, TestContext testContext) { - Map<String, Object> properties = exchange.getProperties(); - for (Map.Entry<String, Object> entry : properties.entrySet()) { + private void propagateExchangeVariables(Exchange exchange, TestContext testContext) { + for (Map.Entry<String, Object> entry : exchange.getProperties().entrySet()) { if (entry.getValue() != null) { testContext.setVariable(entry.getKey(), entry.getValue()); } } + for (Map.Entry<String, Object> entry : exchange.getVariables().entrySet()) { + if (entry.getValue() != null) { + testContext.setVariable(entry.getKey(), entry.getValue()); + } + } + } + + private void writeBackExtractedVariables(Exchange exchange, TestContext testContext) { + for (Map.Entry<String, Object> entry : testContext.getVariables().entrySet()) { + String key = entry.getKey(); + if (!exchange.getProperties().containsKey(key) && !exchange.getVariables().containsKey(key)) { + exchange.setVariable(key, entry.getValue()); + } + } } private DefaultMessage buildReceivedMessage(Exchange exchange) { @@ -137,9 +163,9 @@ public class CitrusProducer extends DefaultProducer { String type = endpoint.getMessageType(); if (type != null) { if (MessageType.knows(type)) { - return MessageType.valueOf(type.toUpperCase()).name(); + return MessageType.valueOf(type.toUpperCase(Locale.ROOT)).name(); } else { - return type.toUpperCase(); + return type.toUpperCase(Locale.ROOT); } } diff --git a/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusMultipleEndpointsTest.java b/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusMultipleEndpointsTest.java index 46e4d762d932..dbac357254af 100644 --- a/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusMultipleEndpointsTest.java +++ b/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusMultipleEndpointsTest.java @@ -18,7 +18,7 @@ package org.apache.camel.component.citrus; import org.apache.camel.RoutesBuilder; import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.test.junit5.CamelTestSupport; +import org.apache.camel.test.junit6.CamelTestSupport; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; diff --git a/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusReceiveTest.java b/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusReceiveTest.java index 101950cedcef..3c0e9a3b2f68 100644 --- a/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusReceiveTest.java +++ b/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusReceiveTest.java @@ -19,7 +19,7 @@ package org.apache.camel.component.citrus; import org.apache.camel.Exchange; import org.apache.camel.RoutesBuilder; import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.test.junit5.CamelTestSupport; +import org.apache.camel.test.junit6.CamelTestSupport; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; diff --git a/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusSequentialValidationTest.java b/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusSequentialValidationTest.java index 07e27a9d7d35..1ce218d5c3c1 100644 --- a/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusSequentialValidationTest.java +++ b/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusSequentialValidationTest.java @@ -16,10 +16,10 @@ */ package org.apache.camel.component.citrus; -import org.apache.camel.CamelExecutionException; import org.apache.camel.RoutesBuilder; import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.test.junit5.CamelTestSupport; +import org.apache.camel.test.junit6.CamelTestSupport; +import org.citrusframework.exceptions.ValidationException; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -73,14 +73,16 @@ class CitrusSequentialValidationTest extends CamelTestSupport { CitrusEndpoint citrus = context.getEndpoint("citrus:validate/test?messageType=json", CitrusEndpoint.class); citrus.message(0).body("{\"event\": \"first\"}"); + citrus.expectedMessageCount(2); template.sendBody("direct:start", "{\"event\": \"first\"}"); + template.sendBody("direct:start", "{\"event\": \"second\"}"); - assertThatThrownBy(() -> template.sendBody("direct:start", "{\"event\": \"second\"}")) - .isInstanceOf(CamelExecutionException.class) - .cause() - .isInstanceOf(IllegalStateException.class) - .hasMessageContaining("No validation specification for exchange at index 1"); + assertThatThrownBy(citrus::assertIsSatisfied) + .isInstanceOf(ValidationException.class) + .satisfies(e -> assertThat(e.getSuppressed()[0]) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("No validation specification for exchange at index 1")); } @Test @@ -121,11 +123,13 @@ class CitrusSequentialValidationTest extends CamelTestSupport { citrus.message(0).body("{\"event\": \"created\"}"); citrus.message(1).body("{\"event\": \"updated\"}"); + citrus.expectedMessageCount(2); template.sendBody("direct:start", "{\"event\": \"created\"}"); + template.sendBody("direct:start", "{\"event\": \"wrong\"}"); - assertThatThrownBy(() -> template.sendBody("direct:start", "{\"event\": \"wrong\"}")) - .isInstanceOf(CamelExecutionException.class); + assertThatThrownBy(citrus::assertIsSatisfied) + .isInstanceOf(ValidationException.class); } @Override diff --git a/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusValidateJsonTest.java b/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusValidateJsonTest.java index def2607d68aa..30241c3e5e81 100644 --- a/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusValidateJsonTest.java +++ b/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusValidateJsonTest.java @@ -18,7 +18,8 @@ package org.apache.camel.component.citrus; import org.apache.camel.RoutesBuilder; import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.test.junit5.CamelTestSupport; +import org.apache.camel.test.junit6.CamelTestSupport; +import org.citrusframework.exceptions.ValidationException; import org.citrusframework.validation.DefaultValidations; import org.junit.jupiter.api.Test; @@ -55,13 +56,16 @@ class CitrusValidateJsonTest extends CamelTestSupport { "greeting": "Hello World!" } """); + citrus.expectedMessageCount(1); - assertThatThrownBy(() -> template.sendBody("direct:start", """ + template.sendBody("direct:start", """ { "greeting": "Goodbye!" } - """)) - .isInstanceOf(org.apache.camel.CamelExecutionException.class); + """); + + assertThatThrownBy(citrus::assertIsSatisfied) + .isInstanceOf(ValidationException.class); } @Test diff --git a/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusValidatePlainTextTest.java b/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusValidatePlainTextTest.java index a603f4ce6e15..f030a5061a85 100644 --- a/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusValidatePlainTextTest.java +++ b/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusValidatePlainTextTest.java @@ -16,10 +16,10 @@ */ package org.apache.camel.component.citrus; -import org.apache.camel.CamelExecutionException; import org.apache.camel.RoutesBuilder; import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.test.junit5.CamelTestSupport; +import org.apache.camel.test.junit6.CamelTestSupport; +import org.citrusframework.exceptions.ValidationException; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -43,9 +43,12 @@ class CitrusValidatePlainTextTest extends CamelTestSupport { void shouldFailOnPlainTextMismatch() { CitrusEndpoint citrus = context.getEndpoint("citrus:validate?messageType=plaintext", CitrusEndpoint.class); citrus.allMessages().body("Hello Camel!"); + citrus.expectedMessageCount(1); + + template.sendBody("direct:start", "Goodbye Camel!"); - assertThatThrownBy(() -> template.sendBody("direct:start", "Goodbye Camel!")) - .isInstanceOf(CamelExecutionException.class); + assertThatThrownBy(citrus::assertIsSatisfied) + .isInstanceOf(ValidationException.class); } @Test diff --git a/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusValidateXmlTest.java b/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusValidateXmlTest.java index 9fff75cc0358..4b734fc3b65a 100644 --- a/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusValidateXmlTest.java +++ b/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusValidateXmlTest.java @@ -18,7 +18,7 @@ package org.apache.camel.component.citrus; import org.apache.camel.RoutesBuilder; import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.test.junit5.CamelTestSupport; +import org.apache.camel.test.junit6.CamelTestSupport; import org.citrusframework.validation.DefaultValidations; import org.junit.jupiter.api.Test; diff --git a/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusValidateYamlTest.java b/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusValidateYamlTest.java index da4906f337ff..58680624f7ce 100644 --- a/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusValidateYamlTest.java +++ b/components/camel-test/camel-test-citrus/src/test/java/org/apache/camel/component/citrus/CitrusValidateYamlTest.java @@ -16,10 +16,10 @@ */ package org.apache.camel.component.citrus; -import org.apache.camel.CamelExecutionException; import org.apache.camel.RoutesBuilder; import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.test.junit5.CamelTestSupport; +import org.apache.camel.test.junit6.CamelTestSupport; +import org.citrusframework.exceptions.ValidationException; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -88,11 +88,14 @@ class CitrusValidateYamlTest extends CamelTestSupport { citrus.allMessages().body(""" greeting: Hello World! """); + citrus.expectedMessageCount(1); - assertThatThrownBy(() -> template.sendBody("direct:start", """ + template.sendBody("direct:start", """ greeting: Goodbye! - """)) - .isInstanceOf(CamelExecutionException.class); + """); + + assertThatThrownBy(citrus::assertIsSatisfied) + .isInstanceOf(ValidationException.class); } @Override 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 e56480791066..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 @@ -3379,7 +3379,7 @@ public class StaticEndpointBuilders { * Citrus message validation component for testing * * Category: testing - * Since: 4.23 + * Since: 4.24 * Maven coordinates: org.apache.camel:camel-test-citrus * * Syntax: <code>citrus:operation/name</code> @@ -3388,6 +3388,7 @@ public class StaticEndpointBuilders { * The operation to perform. 'validate' validates exchanges without * modifying them. 'receive' validates exchanges and returns a simulated * response. + * There are 2 enums and the value can be one of: validate, receive * * Path parameter: name * A unique name to identify this endpoint. Allows multiple Citrus endpoints @@ -3404,7 +3405,7 @@ public class StaticEndpointBuilders { * Citrus message validation component for testing * * Category: testing - * Since: 4.23 + * Since: 4.24 * Maven coordinates: org.apache.camel:camel-test-citrus * * Syntax: <code>citrus:operation/name</code> @@ -3413,6 +3414,7 @@ public class StaticEndpointBuilders { * The operation to perform. 'validate' validates exchanges without * modifying them. 'receive' validates exchanges and returns a simulated * response. + * There are 2 enums and the value can be one of: validate, receive * * Path parameter: name * A unique name to identify this endpoint. Allows multiple Citrus endpoints 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 1cff0c52ed04..8deac9e3c7a7 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 @@ -125,7 +125,7 @@ public interface CitrusEndpointBuilderFactory { * Citrus message validation component for testing * * Category: testing - * Since: 4.23 + * Since: 4.24 * Maven coordinates: org.apache.camel:camel-test-citrus * * Syntax: <code>citrus:operation/name</code> @@ -134,6 +134,7 @@ public interface CitrusEndpointBuilderFactory { * The operation to perform. 'validate' validates exchanges without * modifying them. 'receive' validates exchanges and returns a simulated * response. + * There are 2 enums and the value can be one of: validate, receive * * Path parameter: name * A unique name to identify this endpoint. Allows multiple Citrus @@ -150,7 +151,7 @@ public interface CitrusEndpointBuilderFactory { * Citrus message validation component for testing * * Category: testing - * Since: 4.23 + * Since: 4.24 * Maven coordinates: org.apache.camel:camel-test-citrus * * Syntax: <code>citrus:operation/name</code> @@ -159,6 +160,7 @@ public interface CitrusEndpointBuilderFactory { * The operation to perform. 'validate' validates exchanges without * modifying them. 'receive' validates exchanges and returns a simulated * response. + * There are 2 enums and the value can be one of: validate, receive * * Path parameter: name * A unique name to identify this endpoint. Allows multiple Citrus
