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 85b924c1859f CAMEL-26804: camel-jbang - a chaos experiment that feeds 
a broker run by camel infra does not warn about a real system (#29557)
85b924c1859f is described below

commit 85b924c1859f122251493909e71f250cb5419c96
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Nov 10 13:10:24 2026 +0100

    CAMEL-26804: camel-jbang - a chaos experiment that feeds a broker run by 
camel infra does not warn about a real system (#29557)
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../modules/ROOT/pages/camel-jbang-managing.adoc   |  11 +-
 .../action/CamelChaosExperimentAction.java         |   7 +-
 .../core/commands/ai/ChaosExplorePlaybook.java     |   3 +-
 .../dsl/jbang/core/common/ChaosExperimentRun.java  |  39 +++++-
 .../camel/dsl/jbang/core/common/InfraServices.java | 150 +++++++++++++++++++++
 .../jbang/core/common/ChaosExperimentRunTest.java  |  41 +++++-
 .../dsl/jbang/core/common/InfraServicesTest.java   |  67 +++++++++
 7 files changed, 305 insertions(+), 13 deletions(-)

diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-managing.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang-managing.adoc
index 8a1fbac0b265..ade32cf767bd 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-managing.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-managing.adoc
@@ -973,7 +973,16 @@ polls, named so the route takes it: `chaos-<time>.json`, 
numbered as `chaos-<tim
 repeated, with the extension of its `include` or `antInclude` filter, else of 
the body. A `CamelFileName` in `--header` names the files instead.
 
 A feed to a remote system that is not stubbed, such as a Kafka broker, has a 
warning, as the messages go to that system:
-use a local one (`camel infra run kafka`), or stub it.
+use a local one (`camel infra run kafka`), or stub it. A broker that `camel 
infra run` started on this machine is such a
+local one: when the input of the route is on it (its address, as the 
integration reports it, is on a port of a service
+that `camel infra ps` lists), there is no warning, and the traffic says so:
+
+[source,text]
+----
+  traffic: 6 messages sent to 
kafka://refunds?brokers=localhost:9092&groupId=shop (the local kafka from camel 
infra) in 199ms
+----
+
+A real broker tests what a stub cannot, such as a consumer that reads a failed 
message again or goes on without it.
 
 `camel cmd chaos-explore` lets the AI of `camel ask` do it all: let there be 
chaos. It starts the exploration with the
 budget, and the AI reads the suggestions, runs one experiment per call, reads 
each verdict, and goes on while there is
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelChaosExperimentAction.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelChaosExperimentAction.java
index 08fe673bce9b..0167a45180e0 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelChaosExperimentAction.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelChaosExperimentAction.java
@@ -235,6 +235,8 @@ public class CamelChaosExperimentAction extends 
CamelChaosAction {
             long failed = traffic.getLongOrDefault("failed", 0);
             StringBuilder sb = new StringBuilder();
             sb.append(sent).append(sent == 1 ? " message" : " 
messages").append(" sent to ").append(endpoint)
+                    .append(traffic.containsKey("localInfra")
+                            ? " (the local " + traffic.getString("localInfra") 
+ " from camel infra)" : "")
                     .append(failed > 0 ? " (" + failed + " failed)" : 
"").append(" in ")
                     .append(time(traffic.getLongOrDefault("elapsed", 0)));
             // the status codes the clients of an HTTP feed got (CAMEL-26793)
@@ -250,7 +252,10 @@ public class CamelChaosExperimentAction extends 
CamelChaosAction {
             return sb.toString();
         }
         // a single message: the answer of the send
-        return "1 message sent to " + endpoint + 
("success".equals(traffic.getString("status")) ? "" : " (failed)");
+        return "1 message sent to " + endpoint
+               + (traffic.containsKey("localInfra")
+                       ? " (the local " + traffic.getString("localInfra") + " 
from camel infra)" : "")
+               + ("success".equals(traffic.getString("status")) ? "" : " 
(failed)");
     }
 
     // a time under a second in millis, as a send of a few messages takes
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/ChaosExplorePlaybook.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/ChaosExplorePlaybook.java
index e4f809384651..f95c5b51a110 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/ChaosExplorePlaybook.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/ChaosExplorePlaybook.java
@@ -95,7 +95,8 @@ public final class ChaosExplorePlaybook {
                 to call when its path has a parameter (such as POST 
/orders/42); the traffic counts the status codes \
                 the clients got. A route of kind file is fed with its id too: 
each message is written as a file the \
                 route takes. An experiment refuses a feed that cannot reach 
its route, with the reason and \
-                what to do instead, and warns when the feed goes to a real 
system that is not stubbed
+                what to do instead, and warns when the feed goes to a real 
system that is not stubbed (a local \
+                broker from camel infra is not one)
                    - a rule at=dlq fails the dead letter channel, so it fires 
only when a message goes there: use \
                 the combined suggestions, which add the fault that sends 
messages there too. A message the \
                 dead letter channel did not deliver is handled there, so it 
does not fail in its route: the \
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/ChaosExperimentRun.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/ChaosExperimentRun.java
index f7e9b75a7bdd..3dfee88cdaf8 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/ChaosExperimentRun.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/ChaosExperimentRun.java
@@ -215,8 +215,11 @@ public final class ChaosExperimentRun {
         if (ruleWarnings != null) {
             warnings.addAll(ruleWarnings);
         }
+        // a broker that camel infra runs on this machine is a local one, not 
a real system (CAMEL-26804)
+        List<InfraServices.Service> infra = feed != null ? 
InfraServices.running() : List.of();
+        InfraServices.Service local = feed != null ? localInfra(status, 
feed.endpoint(), infra) : null;
         if (feed != null) {
-            String real = feedWarning(status, feed.endpoint());
+            String real = feedWarning(status, feed.endpoint(), infra);
             if (real != null) {
                 warnings.add(real);
             }
@@ -264,6 +267,9 @@ public final class ChaosExperimentRun {
         }
         JsonObject answer = new JsonObject(begun);
         if (traffic != null) {
+            if (local != null) {
+                traffic.put("localInfra", local.name());
+            }
             answer.put("traffic", traffic);
         }
         answer.put("waited", waited);
@@ -426,7 +432,7 @@ public final class ChaosExperimentRun {
      * A warning when the feed goes to a real remote system, as the route it 
reaches starts from one that is not stubbed
      * (a Kafka broker, a JMS queue), or null. Such a feed is fine for a local 
broker (camel infra run).
      */
-    public static String feedWarning(JsonObject status, String feed) {
+    public static String feedWarning(JsonObject status, String feed, 
List<InfraServices.Service> infra) {
         List<Object> routes = status != null ? status.getCollection("routes") 
: null;
         JsonObject route = routes != null && !feed.endsWith("*") ? 
route(routes, feed) : null;
         String from = route != null ? route.getString("from") : null;
@@ -438,7 +444,7 @@ public final class ChaosExperimentRun {
         }
         String id = route.getString("routeId");
         Boolean stubbed = stubbed(status, id);
-        if (stubbed == null || stubbed) {
+        if (stubbed == null || stubbed || localInfra(status, feed, infra) != 
null) {
             return null;
         }
         String scheme = model.getScheme();
@@ -447,6 +453,33 @@ public final class ChaosExperimentRun {
                + " with --stub=" + scheme + " so no real system gets them";
     }
 
+    /**
+     * The service camel infra runs on this machine that the input of the 
route the feed reaches is on (CAMEL-26804):
+     * the addresses of its input (the services of the status, such as the 
brokers of Kafka, and the URI it starts from)
+     * are all local, on ports of that service. Null when the route is not 
known, or its input is elsewhere.
+     */
+    static InfraServices.Service localInfra(JsonObject status, String feed, 
List<InfraServices.Service> infra) {
+        List<Object> routes = status != null ? status.getCollection("routes") 
: null;
+        JsonObject route = routes != null && !infra.isEmpty() && 
!feed.endsWith("*") ? route(routes, feed) : null;
+        if (route == null) {
+            return null;
+        }
+        String id = route.getString("routeId");
+        List<String> addresses = new ArrayList<>();
+        if (route.getString("from") != null) {
+            addresses.add(route.getString("from"));
+        }
+        if (status.get("services") instanceof JsonObject services && 
services.getCollection("services") != null) {
+            for (Object o : services.getCollection("services")) {
+                if (o instanceof JsonObject service && 
id.equals(service.getString("routeId"))
+                        && service.getString("serviceUrl") != null) {
+                    addresses.add(service.getString("serviceUrl"));
+                }
+            }
+        }
+        return InfraServices.serving(addresses, infra);
+    }
+
     /** The route the feed reaches: by its id, or by the endpoint it starts 
from; null when none. */
     private static JsonObject route(List<Object> routes, String feed) {
         String endpoint = normalize(feed);
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/InfraServices.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/InfraServices.java
new file mode 100644
index 000000000000..a9a7322609b6
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/InfraServices.java
@@ -0,0 +1,150 @@
+/*
+ * 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.dsl.jbang.core.common;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.function.LongPredicate;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+import org.apache.camel.util.json.Jsoner;
+
+/**
+ * The services that {@code camel infra run} started on this machine, from 
their pid files in the Camel directory
+ * ({@code infra-<service>-<pid>.json}, which hold what the service tells 
about itself, such as its brokers), with the
+ * ports they listen on. A chaos experiment uses it to know that a broker is a 
local one from camel infra, not a real
+ * system (CAMEL-26804).
+ */
+public final class InfraServices {
+
+    // host:port, as in localhost:9092, PLAINTEXT://localhost:9092 or 
tcp://127.0.0.1:61616
+    private static final Pattern HOST_PORT = 
Pattern.compile("([A-Za-z0-9._-]+|\\[[0-9A-Fa-f:]+\\]):(\\d{1,5})(?!\\d)");
+    private static final Set<String> LOCAL_HOSTS = Set.of("localhost", 
"127.0.0.1", "0.0.0.0", "::1", "[::1]");
+
+    /** A service camel infra runs: its name (such as kafka), its pid, and the 
ports it listens on. */
+    public record Service(String name, long pid, Set<Integer> ports) {
+    }
+
+    private InfraServices() {
+    }
+
+    /** The services camel infra runs now, whose process is alive. */
+    public static List<Service> running() {
+        return running(CommandLineHelper.getCamelDir(),
+                pid -> 
ProcessHandle.of(pid).map(ProcessHandle::isAlive).orElse(false));
+    }
+
+    static List<Service> running(Path camelDir, LongPredicate alive) {
+        List<Service> answer = new ArrayList<>();
+        try (Stream<Path> files = Files.list(camelDir)) {
+            for (Path file : files.toList()) {
+                String name = file.getFileName().toString();
+                if (!name.startsWith("infra-") || !name.endsWith(".json") || 
name.lastIndexOf('-') <= 6) {
+                    continue;
+                }
+                long pid;
+                try {
+                    pid = Long.parseLong(name.substring(name.lastIndexOf('-') 
+ 1, name.length() - 5));
+                } catch (NumberFormatException e) {
+                    continue;
+                }
+                if (!alive.test(pid)) {
+                    continue;
+                }
+                Set<Integer> ports = new TreeSet<>();
+                try {
+                    ports(Jsoner.deserialize(Files.readString(file)), null, 
ports);
+                } catch (Exception e) {
+                    // a pid file being written, or not ours: no ports known
+                }
+                answer.add(new Service(name.substring(6, 
name.lastIndexOf('-')), pid, ports));
+            }
+        } catch (IOException e) {
+            // no Camel directory yet: nothing runs
+        }
+        
answer.sort(Comparator.comparing(Service::name).thenComparingLong(Service::pid));
+        return answer;
+    }
+
+    /** The ports in the data of a service: a field whose name has port in it, 
and the port of each host:port. */
+    private static void ports(Object value, String key, Set<Integer> ports) {
+        if (value instanceof JsonObject jo) {
+            jo.forEach((k, v) -> ports(v, k, ports));
+        } else if (value instanceof JsonArray ja) {
+            ja.forEach(v -> ports(v, key, ports));
+        } else if (value instanceof Number n && key != null && 
key.toLowerCase(Locale.ROOT).contains("port")) {
+            ports.add(n.intValue());
+        } else if (value instanceof String s) {
+            if (key != null && key.toLowerCase(Locale.ROOT).contains("port") 
&& s.matches("\\d{1,5}")) {
+                ports.add(Integer.parseInt(s));
+            }
+            addresses(s).forEach((host, port) -> ports.add(port));
+        }
+    }
+
+    /** The host:port addresses in a text, such as the brokers of Kafka or the 
URL of a broker. */
+    static Map<String, Integer> addresses(String text) {
+        Map<String, Integer> answer = new LinkedHashMap<>();
+        if (text == null) {
+            return answer;
+        }
+        Matcher m = HOST_PORT.matcher(text);
+        while (m.find()) {
+            int port = Integer.parseInt(m.group(2));
+            if (port > 0 && port <= 65535) {
+                answer.put(m.group(1).toLowerCase(Locale.ROOT) + ":" + port, 
port);
+            }
+        }
+        return answer;
+    }
+
+    /**
+     * The service camel infra runs that the addresses are all on, such as 
{@code kafka} for localhost:9092 when camel
+     * infra runs Kafka on that port; null when one of them is on another host 
or another port, or there are none.
+     */
+    public static Service serving(List<String> texts, List<Service> services) {
+        Service found = null;
+        boolean any = false;
+        for (String text : texts) {
+            for (String address : addresses(text).keySet()) {
+                any = true;
+                String host = address.substring(0, address.lastIndexOf(':'));
+                int port = 
Integer.parseInt(address.substring(address.lastIndexOf(':') + 1));
+                Service service = LOCAL_HOSTS.contains(host)
+                        ? services.stream().filter(s -> 
s.ports().contains(port)).findFirst().orElse(null) : null;
+                if (service == null) {
+                    return null;
+                }
+                found = found == null ? service : found;
+            }
+        }
+        return any ? found : null;
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/common/ChaosExperimentRunTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/common/ChaosExperimentRunTest.java
index bd7a3e007a03..90816f647e5e 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/common/ChaosExperimentRunTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/common/ChaosExperimentRunTest.java
@@ -22,6 +22,7 @@ import java.util.Collections;
 import java.util.Deque;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
@@ -428,18 +429,44 @@ class ChaosExperimentRunTest {
                         "chaos", new JsonObject(Map.of("report", report))));
 
         // not stubbed: the messages go to the broker (CAMEL-26792)
-        assertThat(ChaosExperimentRun.feedWarning(status, 
"refunds")).isEqualTo(
+        assertThat(ChaosExperimentRun.feedWarning(status, "refunds", 
List.of())).isEqualTo(
                 "The feed goes to kafka://refunds?brokers=localhost:9092, 
where route refunds starts, and it is not"
-                                                                               
 + " stubbed: the messages go to the real kafka. Use a local one (camel infra"
-                                                                               
 + " run kafka), or run the integration with --stub=kafka so no real system"
-                                                                               
 + " gets them");
+                                                                               
            + " stubbed: the messages go to the real kafka. Use a local one 
(camel infra"
+                                                                               
            + " run kafka), or run the integration with --stub=kafka so no real 
system"
+                                                                               
            + " gets them");
         // stubbed, a file, or a report that does not tell: no warning
-        assertThat(ChaosExperimentRun.feedWarning(status, "returns")).isNull();
-        assertThat(ChaosExperimentRun.feedWarning(status, "inbox")).isNull();
-        assertThat(ChaosExperimentRun.feedWarning(new 
JsonObject(Map.of("routes", status.get("routes"))), "refunds"))
+        assertThat(ChaosExperimentRun.feedWarning(status, "returns", 
List.of())).isNull();
+        assertThat(ChaosExperimentRun.feedWarning(status, "inbox", 
List.of())).isNull();
+        assertThat(ChaosExperimentRun.feedWarning(new 
JsonObject(Map.of("routes", status.get("routes"))), "refunds", List.of()))
                 .isNull();
     }
 
+    @Test
+    void aFeedToABrokerOfCamelInfraIsNotWarned() {
+        JsonObject report
+                = new JsonObject(Map.of("routes", new JsonArray(List.of(new 
JsonObject(Map.of("route", "refunds"))))));
+        // the brokers of Kafka come from the services of the status, as they 
are often configured on the component
+        JsonObject services = new JsonObject(
+                Map.of("services", new JsonArray(
+                        List.of(new JsonObject(
+                                Map.of("component", "kafka", "direction", 
"in", "routeId", "refunds", "serviceUrl",
+                                        "localhost:32775"))))));
+        JsonObject status = new JsonObject(
+                Map.of(
+                        "routes",
+                        new JsonArray(List.of(new JsonObject(Map.of("routeId", 
"refunds", "from", "kafka://refunds")))),
+                        "services", services, "chaos", new 
JsonObject(Map.of("report", report))));
+        List<InfraServices.Service> infra = List.of(new 
InfraServices.Service("kafka", 42, Set.of(32775)));
+
+        // camel infra runs Kafka there: a local broker, not a real system 
(CAMEL-26804)
+        assertThat(ChaosExperimentRun.feedWarning(status, "refunds", 
infra)).isNull();
+        assertThat(ChaosExperimentRun.localInfra(status, "refunds", 
infra).name()).isEqualTo("kafka");
+        // camel infra runs Kafka on another port, or nothing: the broker may 
be a real one
+        List<InfraServices.Service> other = List.of(new 
InfraServices.Service("kafka", 42, Set.of(9092)));
+        assertThat(ChaosExperimentRun.feedWarning(status, "refunds", 
other)).startsWith("The feed goes to kafka://refunds");
+        assertThat(ChaosExperimentRun.feedWarning(status, "refunds", 
List.of())).startsWith("The feed goes to kafka://refunds");
+    }
+
     @Test
     void aRuleThatMatchesNothingComesWithItsWarning() throws Exception {
         integration.shows("PENDING", true);
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/common/InfraServicesTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/common/InfraServicesTest.java
new file mode 100644
index 000000000000..0875ad85d73b
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/common/InfraServicesTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.dsl.jbang.core.common;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class InfraServicesTest {
+
+    @TempDir
+    Path camelDir;
+
+    @Test
+    void theServicesOfCamelInfraWithTheirPorts() throws Exception {
+        // the pid files of camel infra run hold what the service tells about 
itself
+        Files.writeString(camelDir.resolve("infra-kafka-101.json"),
+                
"{\"brokers\":\"localhost:32775\",\"getBootstrapServers\":\"PLAINTEXT://localhost:32775\"}");
+        Files.writeString(camelDir.resolve("infra-artemis-102.json"),
+                
"{\"serviceAddress\":\"tcp://127.0.0.1:61616\",\"port\":61616,\"webPort\":\"8161\"}");
+        // a service whose process is gone, and a file that is not a pid file
+        Files.writeString(camelDir.resolve("infra-mosquitto-103.json"), 
"{\"port\":1883}");
+        Files.writeString(camelDir.resolve("infra-notes.json"), "{}");
+
+        List<InfraServices.Service> services = InfraServices.running(camelDir, 
pid -> pid != 103);
+
+        assertThat(services).containsExactly(
+                new InfraServices.Service("artemis", 102, Set.of(61616, 8161)),
+                new InfraServices.Service("kafka", 101, Set.of(32775)));
+    }
+
+    @Test
+    void addressesAllOnAServiceOfCamelInfra() {
+        List<InfraServices.Service> services = List.of(
+                new InfraServices.Service("kafka", 101, Set.of(32775)),
+                new InfraServices.Service("artemis", 102, Set.of(61616)));
+
+        assertThat(InfraServices.serving(List.of("localhost:32775"), 
services).name()).isEqualTo("kafka");
+        assertThat(InfraServices.serving(List.of("jms:queue:orders", 
"tcp://127.0.0.1:61616"), services).name())
+                .isEqualTo("artemis");
+        // another host, another port, one broker of two elsewhere, or no 
address at all: not known to be local
+        assertThat(InfraServices.serving(List.of("kafka.example.com:32775"), 
services)).isNull();
+        assertThat(InfraServices.serving(List.of("localhost:9092"), 
services)).isNull();
+        
assertThat(InfraServices.serving(List.of("localhost:32775,localhost:9092"), 
services)).isNull();
+        assertThat(InfraServices.serving(List.of("kafka://refunds"), 
services)).isNull();
+    }
+}

Reply via email to