You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by pp...@apache.org on 2022/03/31 09:48:13 UTC
[camel-quarkus] 41/43: Improve MicroProfile Fault Tolerance extension test coverage
This is an automated email from the ASF dual-hosted git repository.
ppalaga pushed a commit to branch 2.7.x
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
commit 1d3928ccec604e49fed09c0c4f4a6ee4409565e0
Author: James Netherton <ja...@gmail.com>
AuthorDate: Tue Mar 29 14:54:38 2022 +0100
Improve MicroProfile Fault Tolerance extension test coverage
Fixes #3677
---
integration-tests/microprofile/pom.xml | 44 ++++++++--
.../it/faulttolerance/GreetingBean.java | 65 +++++++++++++++
....java => MicroProfileFaultToleranceHelper.java} | 26 +++---
.../MicroProfileFaultToleranceRoutes.java | 93 ++++++++++++++++++++--
.../MicroprofileFaultToleranceResource.java | 39 ++++++++-
.../MicroprofileFaultToleranceTest.java | 60 +++++++++-----
6 files changed, 276 insertions(+), 51 deletions(-)
diff --git a/integration-tests/microprofile/pom.xml b/integration-tests/microprofile/pom.xml
index 0cbf0f9..e8984f8 100644
--- a/integration-tests/microprofile/pom.xml
+++ b/integration-tests/microprofile/pom.xml
@@ -33,23 +33,31 @@
<dependencies>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
- <artifactId>camel-quarkus-microprofile-fault-tolerance</artifactId>
+ <artifactId>camel-quarkus-bean</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
- <artifactId>camel-quarkus-microprofile-health</artifactId>
+ <artifactId>camel-quarkus-direct</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
- <artifactId>camel-quarkus-microprofile-metrics</artifactId>
+ <artifactId>camel-quarkus-log</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
- <artifactId>camel-quarkus-direct</artifactId>
+ <artifactId>camel-quarkus-microprofile-fault-tolerance</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
- <artifactId>camel-quarkus-log</artifactId>
+ <artifactId>camel-quarkus-microprofile-health</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-microprofile-metrics</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-mock</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
@@ -120,6 +128,19 @@
<!-- The following dependencies guarantee that this module is built after them. You can update them by running `mvn process-resources -Pformat -N` from the source tree root directory -->
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-bean-deployment</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>*</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-direct-deployment</artifactId>
<version>${project.version}</version>
<type>pom</type>
@@ -183,6 +204,19 @@
</exclusion>
</exclusions>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-mock-deployment</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>*</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
</dependencies>
</profile>
</profiles>
diff --git a/integration-tests/microprofile/src/main/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/GreetingBean.java b/integration-tests/microprofile/src/main/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/GreetingBean.java
new file mode 100644
index 0000000..3053a27
--- /dev/null
+++ b/integration-tests/microprofile/src/main/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/GreetingBean.java
@@ -0,0 +1,65 @@
+/*
+ * 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.quarkus.component.microprofile.it.faulttolerance;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.enterprise.context.ApplicationScoped;
+
+import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
+import org.eclipse.microprofile.faulttolerance.Fallback;
+import org.eclipse.microprofile.faulttolerance.Timeout;
+
+import static org.apache.camel.quarkus.component.microprofile.it.faulttolerance.MicroProfileFaultToleranceRoutes.EXCEPTION_MESSAGE;
+import static org.apache.camel.quarkus.component.microprofile.it.faulttolerance.MicroProfileFaultToleranceRoutes.FALLBACK_RESULT;
+import static org.apache.camel.quarkus.component.microprofile.it.faulttolerance.MicroProfileFaultToleranceRoutes.RESULT;
+
+@ApplicationScoped
+public class GreetingBean {
+
+ @Fallback(fallbackMethod = "fallbackGreeting")
+ public String greetWithFallback() {
+ AtomicInteger counter = MicroProfileFaultToleranceHelper.getCounter("beanFallback");
+ if (counter.incrementAndGet() == 1) {
+ throw new IllegalStateException(EXCEPTION_MESSAGE);
+ }
+ return RESULT;
+ }
+
+ @Timeout(250)
+ public String greetWithDelay() throws InterruptedException {
+ AtomicInteger counter = MicroProfileFaultToleranceHelper.getCounter("beanTimeout");
+ if (counter.incrementAndGet() == 1) {
+ Thread.sleep(500);
+ return "Nothing to see here, method invocation timed out!";
+ }
+ return RESULT;
+ }
+
+ @CircuitBreaker(failureRatio = 1.0, requestVolumeThreshold = 1, delay = 0)
+ public String greetWithCircuitBreaker() {
+ AtomicInteger counter = MicroProfileFaultToleranceHelper.getCounter("beanThreshold");
+ if (counter.incrementAndGet() == 1) {
+ throw new IllegalStateException(EXCEPTION_MESSAGE);
+ }
+ return RESULT;
+ }
+
+ public String fallbackGreeting() {
+ return FALLBACK_RESULT;
+ }
+}
diff --git a/integration-tests/microprofile/src/main/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/MicroprofileFaultToleranceResource.java b/integration-tests/microprofile/src/main/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/MicroProfileFaultToleranceHelper.java
similarity index 59%
copy from integration-tests/microprofile/src/main/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/MicroprofileFaultToleranceResource.java
copy to integration-tests/microprofile/src/main/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/MicroProfileFaultToleranceHelper.java
index 348a870..63071b4 100644
--- a/integration-tests/microprofile/src/main/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/MicroprofileFaultToleranceResource.java
+++ b/integration-tests/microprofile/src/main/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/MicroProfileFaultToleranceHelper.java
@@ -16,25 +16,19 @@
*/
package org.apache.camel.quarkus.component.microprofile.it.faulttolerance;
-import javax.inject.Inject;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
-import org.apache.camel.ProducerTemplate;
+public class MicroProfileFaultToleranceHelper {
-@Path("/microprofile-fault-tolerance")
-public class MicroprofileFaultToleranceResource {
+ private static final Map<String, AtomicInteger> COUNTERS = new ConcurrentHashMap();
- @Inject
- ProducerTemplate producerTemplate;
+ private MicroProfileFaultToleranceHelper() {
+ // Utility class
+ }
- @Path("/route/{route}")
- @POST
- @Produces(MediaType.TEXT_PLAIN)
- public String triggerFaultToleranceRoute(String body, @PathParam("route") String route) {
- return producerTemplate.requestBody("direct:" + route, body, String.class);
+ public static AtomicInteger getCounter(String name) {
+ return COUNTERS.computeIfAbsent(name, key -> new AtomicInteger());
}
}
diff --git a/integration-tests/microprofile/src/main/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/MicroProfileFaultToleranceRoutes.java b/integration-tests/microprofile/src/main/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/MicroProfileFaultToleranceRoutes.java
index 3dca95a..4096b1c 100644
--- a/integration-tests/microprofile/src/main/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/MicroProfileFaultToleranceRoutes.java
+++ b/integration-tests/microprofile/src/main/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/MicroProfileFaultToleranceRoutes.java
@@ -16,23 +16,47 @@
*/
package org.apache.camel.quarkus.component.microprofile.it.faulttolerance;
+import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicInteger;
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.inject.Named;
+
import org.apache.camel.builder.RouteBuilder;
+import org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException;
+@ApplicationScoped
public class MicroProfileFaultToleranceRoutes extends RouteBuilder {
+ public static final String EXCEPTION_MESSAGE = "Simulated Exception";
public static final String FALLBACK_RESULT = "Fallback response";
public static final String RESULT = "Hello Camel Quarkus MicroProfile Fault Tolerance";
- private static final AtomicInteger COUNTER = new AtomicInteger();
- private static final AtomicInteger TIMEOUT_COUNTER = new AtomicInteger();
+
+ @Inject
+ GreetingBean greetingBean;
@Override
public void configure() throws Exception {
- from("direct:faultTolerance")
+ from("direct:faultToleranceWithBulkhead")
.circuitBreaker()
+ .faultToleranceConfiguration().bulkheadEnabled(true).end()
.process(exchange -> {
- if (COUNTER.incrementAndGet() == 1) {
+ AtomicInteger counter = MicroProfileFaultToleranceHelper.getCounter("bulkhead");
+ if (counter.incrementAndGet() == 1) {
+ throw new IllegalStateException(EXCEPTION_MESSAGE);
+ }
+ exchange.getMessage().setBody(RESULT);
+ })
+ .onFallback()
+ .setBody().constant(FALLBACK_RESULT)
+ .end();
+
+ from("direct:faultToleranceWithFallback")
+ .circuitBreaker()
+ .process(exchange -> {
+ AtomicInteger counter = MicroProfileFaultToleranceHelper.getCounter("fallback");
+ if (counter.incrementAndGet() == 1) {
throw new IllegalStateException("Simulated Exception");
}
exchange.getMessage().setBody(RESULT);
@@ -41,18 +65,73 @@ public class MicroProfileFaultToleranceRoutes extends RouteBuilder {
.setBody().constant(FALLBACK_RESULT)
.end();
+ from("direct:faultToleranceWithThreshold")
+ .circuitBreaker()
+ .faultToleranceConfiguration().failureRatio(100).successThreshold(1).requestVolumeThreshold(1).delay(0).end()
+ .process(exchange -> {
+ AtomicInteger counter = MicroProfileFaultToleranceHelper.getCounter("threshold");
+ if (counter.incrementAndGet() == 1) {
+ throw new IllegalStateException("Simulated Exception");
+ }
+ exchange.getMessage().setBody("Nothing to see here. Circuit breaker is open...");
+ })
+ .end()
+ .setBody().simple(RESULT);
+
from("direct:faultToleranceWithTimeout")
.circuitBreaker()
.faultToleranceConfiguration().timeoutEnabled(true).timeoutDuration(500).end()
.process(exchange -> {
- if (TIMEOUT_COUNTER.incrementAndGet() == 1) {
+ AtomicInteger counter = MicroProfileFaultToleranceHelper.getCounter("timeout");
+ if (counter.incrementAndGet() == 1) {
Thread.sleep(1000);
}
- exchange.getMessage().setBody("Regular hi " + exchange.getMessage().getBody(String.class));
+ exchange.getMessage().setBody(RESULT);
})
.onFallback()
- .setBody().simple("Sorry ${body}, had to fallback!")
+ .setBody().simple(FALLBACK_RESULT)
.end();
+ // Unavailable on Camel 3.14.2
+ // from("direct:faultToleranceWithTimeoutCustomExecutor")
+ // .circuitBreaker()
+ // .faultToleranceConfiguration().timeoutEnabled(true).timeoutScheduledExecutorService("myThreadPool")
+ // .timeoutDuration(500).end()
+ // .process(exchange -> {
+ // AtomicInteger counter = MicroProfileFaultToleranceHelper.getCounter("timeoutCustomExecutor");
+ // if (counter.incrementAndGet() == 1) {
+ // Thread.sleep(1000);
+ // }
+ // exchange.getMessage().setBody(RESULT);
+ // })
+ // .onFallback()
+ // .setBody().simple(FALLBACK_RESULT)
+ // .end();
+
+ from("direct:inheritErrorHandler")
+ .errorHandler(deadLetterChannel("mock:dead").maximumRedeliveries(3).redeliveryDelay(0))
+ .circuitBreaker().inheritErrorHandler(true)
+ .to("mock:start")
+ .throwException(new IllegalArgumentException(EXCEPTION_MESSAGE)).end()
+ .to("mock:end");
+
+ from("direct:circuitBreakerBean")
+ .bean(greetingBean, "greetWithCircuitBreaker");
+
+ from("direct:fallbackBean")
+ .bean(greetingBean, "greetWithFallback");
+
+ from("direct:timeoutBean")
+ .doTry()
+ .bean(greetingBean, "greetWithDelay")
+ .doCatch(TimeoutException.class)
+ .setBody().constant(FALLBACK_RESULT)
+ .end();
+ }
+
+ @Named("myThreadPool")
+ public ScheduledExecutorService myThreadPool() {
+ return getCamelContext().getExecutorServiceManager()
+ .newScheduledThreadPool(this, "myThreadPool", 2);
}
}
diff --git a/integration-tests/microprofile/src/main/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/MicroprofileFaultToleranceResource.java b/integration-tests/microprofile/src/main/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/MicroprofileFaultToleranceResource.java
index 348a870..3193d54 100644
--- a/integration-tests/microprofile/src/main/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/MicroprofileFaultToleranceResource.java
+++ b/integration-tests/microprofile/src/main/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/MicroprofileFaultToleranceResource.java
@@ -23,7 +23,9 @@ import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
+import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
+import org.apache.camel.component.mock.MockEndpoint;
@Path("/microprofile-fault-tolerance")
public class MicroprofileFaultToleranceResource {
@@ -31,10 +33,43 @@ public class MicroprofileFaultToleranceResource {
@Inject
ProducerTemplate producerTemplate;
+ @Inject
+ CamelContext context;
+
@Path("/route/{route}")
@POST
@Produces(MediaType.TEXT_PLAIN)
- public String triggerFaultToleranceRoute(String body, @PathParam("route") String route) {
- return producerTemplate.requestBody("direct:" + route, body, String.class);
+ public String triggerFaultToleranceRoute(@PathParam("route") String route) {
+ return producerTemplate.requestBody("direct:" + route, null, String.class);
+ }
+
+ @Path("/faultToleranceWithThreshold/{route}")
+ @POST
+ @Produces(MediaType.TEXT_PLAIN)
+ public String faultToleranceWithThreshold(@PathParam("route") String route) {
+ try {
+ return producerTemplate.requestBody("direct:" + route, null, String.class);
+ } catch (Exception e) {
+ return e.getCause().getMessage();
+ }
+ }
+
+ @Path("/inheritErrorHandler")
+ @POST
+ public void inheritErrorHandler() throws Exception {
+ MockEndpoint start = context.getEndpoint("mock:start", MockEndpoint.class);
+ start.expectedMessageCount(4);
+
+ MockEndpoint end = context.getEndpoint("mock:end", MockEndpoint.class);
+ end.expectedMessageCount(0);
+
+ MockEndpoint dead = context.getEndpoint("mock:dead", MockEndpoint.class);
+ dead.expectedMessageCount(1);
+
+ producerTemplate.requestBody("direct:inheritErrorHandler", null, String.class);
+
+ start.assertIsSatisfied(5000);
+ end.assertIsSatisfied(5000);
+ dead.assertIsSatisfied(5000);
}
}
diff --git a/integration-tests/microprofile/src/test/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/MicroprofileFaultToleranceTest.java b/integration-tests/microprofile/src/test/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/MicroprofileFaultToleranceTest.java
index ff610c2..4733608 100644
--- a/integration-tests/microprofile/src/test/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/MicroprofileFaultToleranceTest.java
+++ b/integration-tests/microprofile/src/test/java/org/apache/camel/quarkus/component/microprofile/it/faulttolerance/MicroprofileFaultToleranceTest.java
@@ -18,46 +18,64 @@ package org.apache.camel.quarkus.component.microprofile.it.faulttolerance;
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.RestAssured;
-import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static org.apache.camel.quarkus.component.microprofile.it.faulttolerance.MicroProfileFaultToleranceRoutes.EXCEPTION_MESSAGE;
+import static org.hamcrest.Matchers.is;
@QuarkusTest
class MicroprofileFaultToleranceTest {
- @Test
- public void testCamelMicroProfileFaultToleranceFallback() {
-
+ @ParameterizedTest
+ @MethodSource("routeUris")
+ public void testCamelMicroProfileFaultTolerance(String route) {
// First request should trigger the fallback response
- RestAssured.post("/microprofile-fault-tolerance/route/faultTolerance")
+ RestAssured.post("/microprofile-fault-tolerance/route/" + route)
.then()
.statusCode(200)
- .body(Matchers.is(MicroProfileFaultToleranceRoutes.FALLBACK_RESULT));
+ .body(is(MicroProfileFaultToleranceRoutes.FALLBACK_RESULT));
// Next request(s) should trigger the expected response
- RestAssured.post("/microprofile-fault-tolerance/route/faultTolerance")
+ RestAssured.post("/microprofile-fault-tolerance/route/" + route)
.then()
.statusCode(200)
- .body(Matchers.is(MicroProfileFaultToleranceRoutes.RESULT));
+ .body(is(MicroProfileFaultToleranceRoutes.RESULT));
}
- @Test
- public void testCamelMicroProfileFaultToleranceFallbackWithTimeout() {
-
- // First request should trigger the fallback response
- RestAssured.given()
- .body("Joe")
- .post("/microprofile-fault-tolerance/route/faultToleranceWithTimeout")
+ @ParameterizedTest
+ @ValueSource(strings = { "faultToleranceWithThreshold", "circuitBreakerBean" })
+ public void testCamelMicroProfileFaultToleranceWithThreshold(String route) {
+ // First request should trigger an exception and open the circuit breaker
+ RestAssured.post("/microprofile-fault-tolerance/faultToleranceWithThreshold/" + route)
.then()
.statusCode(200)
- .body(Matchers.is("Sorry Joe, had to fallback!"));
+ .body(is(EXCEPTION_MESSAGE));
- // Next request(s) should trigger the expected response
- RestAssured.given()
- .body("Mary")
- .post("/microprofile-fault-tolerance/route/faultToleranceWithTimeout")
+ // Next request(s) should close the circuit breaker and trigger the expected response
+ RestAssured.post("/microprofile-fault-tolerance/faultToleranceWithThreshold/" + route)
.then()
.statusCode(200)
- .body(Matchers.is("Regular hi Mary"));
+ .body(is(MicroProfileFaultToleranceRoutes.RESULT));
+ }
+
+ @Test
+ public void testCamelMicroProfileFaultToleranceInheritErrorHandler() {
+ RestAssured.post("/microprofile-fault-tolerance/inheritErrorHandler")
+ .then()
+ .statusCode(204);
}
+ public static String[] routeUris() {
+ return new String[] {
+ "faultToleranceWithFallback",
+ "faultToleranceWithBulkhead",
+ "faultToleranceWithTimeout",
+ // unavailable on Camel 3.14.2 "faultToleranceWithTimeoutCustomExecutor",
+ "fallbackBean",
+ "timeoutBean",
+ };
+ }
}