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

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


The following commit(s) were added to refs/heads/main by this push:
     new ad9645a6237a CAMEL-25908: camel-knative-http - a consumer started 
again receives the requests of its path again (#28432)
ad9645a6237a is described below

commit ad9645a6237a793788b3791c8751370e099b8ba1
Author: allthingssecurity <[email protected]>
AuthorDate: Sun Oct 25 13:01:31 2026 +0530

    CAMEL-25908: camel-knative-http - a consumer started again receives the 
requests of its path again (#28432)
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../knative/http/KnativeHttpConsumer.java          |  2 +
 .../component/knative/http/KnativeHttpTest.java    | 82 ++++++++++++++++++++++
 2 files changed, 84 insertions(+)

diff --git 
a/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsumer.java
 
b/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsumer.java
index 651207e928eb..0608e48c438c 100644
--- 
a/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsumer.java
+++ 
b/components/camel-knative/camel-knative-http/src/main/java/org/apache/camel/component/knative/http/KnativeHttpConsumer.java
@@ -193,7 +193,9 @@ public class KnativeHttpConsumer extends DefaultConsumer {
     @Override
     protected void doStop() throws Exception {
         if (route != null) {
+            // a removed route cannot be added to the router again, so a start 
creates a new one
             route.remove();
+            route = null;
         }
 
         super.doStop();
diff --git 
a/components/camel-knative/camel-knative-http/src/test/java/org/apache/camel/component/knative/http/KnativeHttpTest.java
 
b/components/camel-knative/camel-knative-http/src/test/java/org/apache/camel/component/knative/http/KnativeHttpTest.java
index 1c63aede2ac0..50dcb5a6f757 100644
--- 
a/components/camel-knative/camel-knative-http/src/test/java/org/apache/camel/component/knative/http/KnativeHttpTest.java
+++ 
b/components/camel-knative/camel-knative-http/src/test/java/org/apache/camel/component/knative/http/KnativeHttpTest.java
@@ -31,6 +31,7 @@ import io.vertx.core.http.HttpServerRequest;
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelException;
 import org.apache.camel.CamelExecutionException;
+import org.apache.camel.Consumer;
 import org.apache.camel.Exchange;
 import org.apache.camel.FailedToStartRouteException;
 import org.apache.camel.ProducerTemplate;
@@ -44,9 +45,11 @@ import org.apache.camel.component.knative.spi.Knative;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.http.base.HttpOperationFailedException;
 import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.support.PropertyBindingSupport;
 import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.test.AvailablePortFinder;
+import org.apache.camel.throttling.ThrottlingExceptionRoutePolicy;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.StringHelper;
 import org.assertj.core.api.Assertions;
@@ -66,6 +69,7 @@ import static 
org.apache.camel.component.knative.http.KnativeHttpTestSupport.con
 import static 
org.apache.camel.component.knative.http.KnativeHttpTestSupport.httpAttribute;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.awaitility.Awaitility.await;
 import static org.hamcrest.Matchers.emptyOrNullString;
 import static org.hamcrest.Matchers.is;
 
@@ -986,6 +990,84 @@ public class KnativeHttpTest {
         });
     }
 
+    @ParameterizedTest
+    @EnumSource(CloudEvents.class)
+    void testConsumerStoppedAndStartedAgain(CloudEvent ce) throws Exception {
+        configureTwoConsumersAndStart(ce, r2 -> {
+        });
+
+        // the consumer is not Suspendable, so a route policy that suspends 
and resumes it stops and starts it again
+        Consumer consumer = context.getRoute("r2").getConsumer();
+        ServiceHelper.stopService(consumer);
+        assertThat(template.request("direct:start", e -> 
e.getMessage().setBody("h2"))).satisfies(e -> {
+            assertThat(e.isFailed()).isTrue();
+            
assertThat(e.getException()).isInstanceOf(HttpOperationFailedException.class);
+        });
+
+        ServiceHelper.startService(consumer);
+
+        assertThat(template.requestBody("direct:start", "h2", 
String.class)).isEqualTo("r2");
+    }
+
+    @ParameterizedTest
+    @EnumSource(CloudEvents.class)
+    void testConsumerStartedAgainByCircuitBreakerRoutePolicy(CloudEvent ce) 
throws Exception {
+        ThrottlingExceptionRoutePolicy policy = new 
ThrottlingExceptionRoutePolicy(1, 60000, 1000, null);
+        AtomicBoolean fail = new AtomicBoolean(true);
+        configureTwoConsumersAndStart(ce, r2 -> 
r2.routePolicy(policy).process(e -> {
+            if (fail.get()) {
+                throw new IllegalStateException("Forced");
+            }
+        }));
+        Consumer consumer = context.getRoute("r2").getConsumer();
+
+        // the failure opens the circuit, which stops the consumer as it is 
not Suspendable
+        assertThat(template.request("direct:start", e -> 
e.getMessage().setBody("h2")).isFailed()).isTrue();
+        await().atMost(20, TimeUnit.SECONDS).until(() -> 
ServiceHelper.isStopped(consumer));
+        fail.set(false);
+
+        // after halfOpenAfter the circuit is half open: the consumer is 
started again to let a request through
+        await().atMost(20, TimeUnit.SECONDS).until(() -> 
ServiceHelper.isStarted(consumer));
+
+        assertThat(template.requestBody("direct:start", "h2", 
String.class)).isEqualTo("r2");
+    }
+
+    private void configureTwoConsumersAndStart(CloudEvent ce, 
java.util.function.Consumer<RouteDefinition> r2)
+            throws Exception {
+        configureKnativeComponent(
+                context,
+                ce,
+                sourceEndpoint(
+                        "ep1",
+                        Map.of(
+                                Knative.KNATIVE_CLOUD_EVENT_TYPE, 
"org.apache.camel.event",
+                                Knative.CONTENT_TYPE, "text/plain",
+                                Knative.KNATIVE_FILTER_PREFIX + "h", "h1")),
+                sourceEndpoint(
+                        "ep2",
+                        Map.of(
+                                Knative.KNATIVE_CLOUD_EVENT_TYPE, 
"org.apache.camel.event",
+                                Knative.CONTENT_TYPE, "text/plain",
+                                Knative.KNATIVE_FILTER_PREFIX + "h", "h2")));
+
+        RouteBuilder.addRoutes(context, b -> {
+            b.from("knative:endpoint/ep1")
+                    .routeId("r1")
+                    .setBody().simple("${routeId}");
+            RouteDefinition route = b.from("knative:endpoint/ep2")
+                    .routeId("r2");
+            r2.accept(route);
+            route.setBody().simple("${routeId}");
+        });
+        RouteBuilder.addRoutes(context, b -> {
+            b.from("direct:start")
+                    .setHeader("h").body()
+                    .toF("http://localhost:%d";, platformHttpPort);
+        });
+
+        context.start();
+    }
+
     @ParameterizedTest
     @EnumSource(CloudEvents.class)
     void testAddConsumer(CloudEvent ce) throws Exception {

Reply via email to