This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch var-fail in repository https://gitbox.apache.org/repos/asf/camel.git
commit 055632ddc171ad9fcf3f8fe9a128bbdfd9bf22c2 Author: Claus Ibsen <[email protected]> AuthorDate: Sat Mar 23 09:57:53 2024 +0100 CAMEL-20607: camel-core - Using variableReceive should only set result if exchange was process succesfully --- .../camel/processor/ToVariableErrorTest.java | 291 +++++++++++++++++++++ .../org/apache/camel/support/ExchangeHelper.java | 7 +- 2 files changed, 295 insertions(+), 3 deletions(-) diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/ToVariableErrorTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/ToVariableErrorTest.java new file mode 100644 index 00000000000..f3351a2941d --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/processor/ToVariableErrorTest.java @@ -0,0 +1,291 @@ +/* + * 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.processor; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ToVariableErrorTest extends ContextTestSupport { + + @Override + public boolean isUseRouteBuilder() { + return false; + } + + @Test + public void testThrowException() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:receive") + .toV("direct:foo", null, "bye") + .to("mock:result"); + + from("direct:foo") + .transform().simple("Bye ${body}") + .throwException(new IllegalArgumentException("Forced")); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedMessageCount(0); + Exchange out = template.request("direct:receive", e -> e.getMessage().setBody("World")); + Assertions.assertTrue(out.isFailed()); + Assertions.assertFalse(out.hasVariables()); + // TODO: should this be World or Bye World? + Assertions.assertEquals("Bye World", out.getMessage().getBody()); + assertMockEndpointsSatisfied(); + } + + @Test + public void testTryCatch() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:receive") + .toV("direct:foo", null, "bye") + .to("mock:result"); + + from("direct:foo") + .transform().simple("Bye ${body}") + .doTry() + .throwException(new IllegalArgumentException("Forced")) + .doCatch(Exception.class) + .setBody(simple("Catch: ${body}")) + .end(); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedMessageCount(1); + Exchange out = template.request("direct:receive", e -> e.getMessage().setBody("World")); + Assertions.assertFalse(out.isFailed()); + Assertions.assertTrue(out.hasVariables()); + Assertions.assertEquals("World", out.getMessage().getBody()); + Assertions.assertEquals("Catch: Bye World", out.getVariable("bye")); + assertMockEndpointsSatisfied(); + } + + @Test + public void testOnExceptionHandled() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + onException(Exception.class) + .handled(true) + .setBody(simple("Error: ${body}")); + + from("direct:receive") + .toV("direct:foo", null, "bye") + .to("mock:result"); + + from("direct:foo") + .transform().simple("Bye ${body}") + .throwException(new IllegalArgumentException("Forced")); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedMessageCount(0); + Exchange out = template.request("direct:receive", e -> e.getMessage().setBody("World")); + Assertions.assertFalse(out.isFailed()); + Assertions.assertFalse(out.hasVariables()); + Assertions.assertEquals("Error: Bye World", out.getMessage().getBody()); + assertMockEndpointsSatisfied(); + } + + @Test + public void testOnExceptionNotHandled() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + onException(Exception.class) + .handled(false) + .setBody(simple("Error: ${body}")); + + from("direct:receive") + .toV("direct:foo", null, "bye") + .to("mock:result"); + + from("direct:foo") + .transform().simple("Bye ${body}") + .throwException(new IllegalArgumentException("Forced")); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedMessageCount(0); + Exchange out = template.request("direct:receive", e -> e.getMessage().setBody("World")); + Assertions.assertTrue(out.isFailed()); + Assertions.assertFalse(out.hasVariables()); + Assertions.assertEquals("Error: Bye World", out.getMessage().getBody()); + assertMockEndpointsSatisfied(); + } + + @Test + public void testDeadLetterChannel() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + errorHandler(deadLetterChannel("mock:dead")); + + from("direct:receive") + .toV("direct:foo", null, "bye") + .to("mock:result"); + + from("direct:foo") + .transform().simple("Bye ${body}") + .throwException(new IllegalArgumentException("Forced")); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedMessageCount(0); + getMockEndpoint("mock:dead").expectedMessageCount(1); + Exchange out = template.request("direct:receive", e -> e.getMessage().setBody("World")); + Assertions.assertFalse(out.isFailed()); + Assertions.assertFalse(out.hasVariables()); + Assertions.assertEquals("Bye World", out.getMessage().getBody()); + assertMockEndpointsSatisfied(); + } + + @Test + public void testDefaultErrorHandler() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + errorHandler(defaultErrorHandler()); + + from("direct:receive") + .toV("direct:foo", null, "bye") + .to("mock:result"); + + from("direct:foo") + .transform().simple("Bye ${body}") + .throwException(new IllegalArgumentException("Forced")); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedMessageCount(0); + Exchange out = template.request("direct:receive", e -> e.getMessage().setBody("World")); + Assertions.assertTrue(out.isFailed()); + Assertions.assertFalse(out.hasVariables()); + Assertions.assertEquals("Bye World", out.getMessage().getBody()); + assertMockEndpointsSatisfied(); + } + + @Test + public void testStop() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:receive") + .toV("direct:foo", null, "bye") + .to("mock:result"); + + from("direct:foo") + .transform().simple("Bye ${body}") + .stop(); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedMessageCount(0); + Exchange out = template.request("direct:receive", e -> e.getMessage().setBody("World")); + Assertions.assertFalse(out.isFailed()); + Assertions.assertFalse(out.hasVariables()); + Assertions.assertEquals("Bye World", out.getMessage().getBody()); + assertMockEndpointsSatisfied(); + } + + @Test + public void testRollback() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:receive") + .toV("direct:foo", null, "bye") + .to("mock:result"); + + from("direct:foo") + .transform().simple("Bye ${body}") + .rollback(); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedMessageCount(0); + Exchange out = template.request("direct:receive", e -> e.getMessage().setBody("World")); + Assertions.assertTrue(out.isFailed()); + Assertions.assertFalse(out.hasVariables()); + Assertions.assertEquals("Bye World", out.getMessage().getBody()); + assertMockEndpointsSatisfied(); + } + + @Test + public void testMarkRollbackLast() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:receive") + .toV("direct:foo", null, "bye") + .to("mock:result"); + + from("direct:foo") + .transform().simple("Bye ${body}") + .markRollbackOnly(); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedMessageCount(0); + Exchange out = template.request("direct:receive", e -> e.getMessage().setBody("World")); + Assertions.assertFalse(out.isFailed()); + Assertions.assertFalse(out.hasVariables()); + Assertions.assertEquals("Bye World", out.getMessage().getBody()); + assertMockEndpointsSatisfied(); + } + + @Test + public void testMarkRollbackOnlyLast() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:receive") + .toV("direct:foo", null, "bye") + .to("mock:result"); + + from("direct:foo") + .transform().simple("Bye ${body}") + .markRollbackOnlyLast(); + } + }); + context.start(); + + getMockEndpoint("mock:result").expectedMessageCount(0); + Exchange out = template.request("direct:receive", e -> e.getMessage().setBody("World")); + Assertions.assertFalse(out.isFailed()); + Assertions.assertFalse(out.hasVariables()); + Assertions.assertEquals("Bye World", out.getMessage().getBody()); + assertMockEndpointsSatisfied(); + } + +} diff --git a/core/camel-support/src/main/java/org/apache/camel/support/ExchangeHelper.java b/core/camel-support/src/main/java/org/apache/camel/support/ExchangeHelper.java index faa8470376a..a73db916db9 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/ExchangeHelper.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/ExchangeHelper.java @@ -1168,9 +1168,10 @@ public final class ExchangeHelper { return false; } // same logic as in Pipeline/PipelineHelper - boolean stop = exchange.isFailed() || exchange.isRollbackOnly() || exchange.isRollbackOnlyLast() - || exchange.getExchangeExtension().isErrorHandlerHandledSet() - && exchange.getExchangeExtension().isErrorHandlerHandled(); + boolean stop + = exchange.isRouteStop() || exchange.isFailed() || exchange.isRollbackOnly() || exchange.isRollbackOnlyLast() + || exchange.getExchangeExtension().isErrorHandlerHandledSet() + && exchange.getExchangeExtension().isErrorHandlerHandled(); if (stop) { return false; }
