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 1afa3af6f48b chore: camel-jbang - the span views and the test scaffold 
read remote and internal from the catalog
1afa3af6f48b is described below

commit 1afa3af6f48b54763b2982726ccb7e29cba93948
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Oct 14 21:51:21 2026 +0200

    chore: camel-jbang - the span views and the test scaffold read remote and 
internal from the catalog
    
    The remote components of a trace (camel get span and the Spans tab of the
    TUI) came from a list of schemes that are not remote (direct, seda, mock,
    log, bean, class), so a timer or an xslt step counted as a remote call.
    They now ask the catalog's remote flag, through ProjectOverview.isRemote.
    
    camel_route_test_scaffold kept a list of trivial schemes that a test does
    not mock (log, direct, seda, mock, controlbus, stub). It now keeps the
    components the catalog marks internal (CAMEL-25652), read from the
    server's own catalog, as an older one loaded for the call has no flag.
    controlbus is mocked now, as it is not internal.
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../modules/ROOT/pages/camel-jbang-mcp.adoc        |  8 +++++---
 .../core/commands/action/CamelSpanAction.java      | 20 +++++++++++++++-----
 .../core/commands/action/CamelSpanActionTest.java  | 14 ++++++++++++++
 .../dsl/jbang/core/commands/mcp/TestInfraData.java | 10 ----------
 .../jbang/core/commands/mcp/TestScaffoldTools.java | 17 +++++++++++++++--
 .../core/commands/mcp/TestScaffoldToolsTest.java   | 22 ++++++++++++++++++++++
 .../dsl/jbang/core/commands/tui/SpansTab.java      | 12 ++++++++----
 .../core/commands/tui/SpansTabRenderTest.java      | 11 +++++++++++
 8 files changed, 90 insertions(+), 24 deletions(-)

diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-mcp.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang-mcp.adoc
index 8e2b9bd1962d..87f24622772d 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-mcp.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-mcp.adoc
@@ -560,9 +560,11 @@ client to the next.
 | Generates a JUnit 5 test skeleton from a Camel route definition (YAML or 
XML). Accepts an optional `format`
   (`yaml` or `xml`, default `yaml`) and `runtime` (`main` or `spring-boot`, 
default `main`). For `main` runtime,
   the generated test extends `CamelTestSupport`; for `spring-boot`, it uses 
`@CamelSpringBootTest` with
-  `@SpringBootTest`. The tool replaces non-trivial producer endpoints with 
mock endpoints, generates
-  `@RegisterExtension` stubs for infrastructure components (Kafka, 
JMS/Artemis, MongoDB, PostgreSQL, Cassandra,
-  Elasticsearch, Redis, RabbitMQ, FTP, Consul, NATS, Pulsar, CouchDB, 
Infinispan, MinIO, Solr), and produces
+  `@SpringBootTest`. The tool replaces producer endpoints with mock endpoints, 
except those of the components
+  the Camel catalog marks internal (`direct:`, `seda:`, `log:`, `mock:` and 
the like), which stay inside the
+  CamelContext. It generates `@RegisterExtension` stubs for infrastructure 
components (Kafka, JMS/Artemis,
+  MongoDB, PostgreSQL, Cassandra, Elasticsearch, Redis, RabbitMQ, FTP, Consul, 
NATS, Pulsar, CouchDB, Infinispan,
+  MinIO, Solr), and produces
   a `NotifyBuilder` pattern for timer-based routes or `template.sendBody()` 
for direct/seda consumers. Returns
   the generated test code, detected components, mock endpoint mappings, 
test-infra services, and required Maven
   test dependencies.
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSpanAction.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSpanAction.java
index 5733ba46a53c..6bc35e6a1c54 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSpanAction.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSpanAction.java
@@ -27,12 +27,16 @@ import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 import com.github.freva.asciitable.AsciiTable;
 import com.github.freva.asciitable.Column;
 import com.github.freva.asciitable.HorizontalAlign;
 import com.github.freva.asciitable.OverflowBehaviour;
+import org.apache.camel.catalog.CamelCatalog;
+import org.apache.camel.catalog.DefaultCamelCatalog;
 import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.dsl.jbang.core.commands.ai.ProjectOverview;
 import org.apache.camel.dsl.jbang.core.common.PathUtils;
 import org.apache.camel.dsl.jbang.core.common.ProcessHelper;
 import org.apache.camel.dsl.jbang.core.common.TerminalWidthHelper;
@@ -663,11 +667,17 @@ public class CamelSpanAction extends ActionBaseCommand {
         return row.attributes != null && 
"EVENT_RECEIVED".equals(row.attributes.get("op"));
     }
 
-    private static boolean isRemoteScheme(String scheme) {
-        return scheme != null
-                && !"direct".equals(scheme) && !"seda".equals(scheme)
-                && !"mock".equals(scheme) && !"log".equals(scheme)
-                && !"bean".equals(scheme) && !"class".equals(scheme);
+    // whether the component of a span talks to a remote system, as the 
catalog says (a scheme it does not know counts as
+    // remote); remembered per scheme, as watch builds the trace summaries 
again and again
+    private static final Map<String, Boolean> REMOTE_SCHEMES = new 
ConcurrentHashMap<>();
+
+    static boolean isRemoteScheme(String scheme) {
+        return scheme != null && REMOTE_SCHEMES.computeIfAbsent(scheme, s -> 
ProjectOverview.isRemote(s, OwnCatalog.CATALOG));
+    }
+
+    /** The catalog of the CLI's own Camel version, created on first use. */
+    private static final class OwnCatalog {
+        static final CamelCatalog CATALOG = new DefaultCamelCatalog();
     }
 
     private static String spanLabel(Row row) {
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSpanActionTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSpanActionTest.java
index e3b3b4930b4b..b355dbe8da99 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSpanActionTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSpanActionTest.java
@@ -24,6 +24,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.junit.jupiter.MockitoExtension;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
@@ -86,4 +87,17 @@ class CamelSpanActionTest extends ActionCommandTestSupport {
         response.put("spans", spans);
         return response;
     }
+
+    @Test
+    void remoteComponentsComeFromTheCatalog() {
+        // as the catalog marks them; a scheme it does not know counts as 
remote
+        assertTrue(CamelSpanAction.isRemoteScheme("kafka"));
+        assertTrue(CamelSpanAction.isRemoteScheme("acme"));
+        assertFalse(CamelSpanAction.isRemoteScheme("direct"));
+        assertFalse(CamelSpanAction.isRemoteScheme("bean"));
+        // not in the list the check used to keep: a timer or an xslt step is 
not a remote call
+        assertFalse(CamelSpanAction.isRemoteScheme("timer"));
+        assertFalse(CamelSpanAction.isRemoteScheme("xslt"));
+        assertFalse(CamelSpanAction.isRemoteScheme(null));
+    }
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TestInfraData.java
 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TestInfraData.java
index a5d542b26c85..45976aa34105 100644
--- 
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TestInfraData.java
+++ 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TestInfraData.java
@@ -36,9 +36,6 @@ import jakarta.enterprise.context.ApplicationScoped;
 @ApplicationScoped
 public class TestInfraData {
 
-    /** Component schemes that are trivial and should not be replaced with 
mocks. */
-    private static final Set<String> TRIVIAL_SCHEMES = Set.of("log", "direct", 
"seda", "mock", "controlbus", "stub");
-
     /** Component schemes that are internally triggered (user can send 
messages to them). */
     private static final Set<String> SENDABLE_SCHEMES = Set.of("direct", 
"seda");
 
@@ -169,13 +166,6 @@ public class TestInfraData {
         return List.copyOf(TEST_INFRA_MAP.keySet());
     }
 
-    /**
-     * Get the set of trivial component schemes that should not be replaced 
with mocks.
-     */
-    public Set<String> getTrivialSchemes() {
-        return TRIVIAL_SCHEMES;
-    }
-
     /**
      * Get the set of component schemes that are internally triggered (user 
can send messages to them).
      */
diff --git 
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TestScaffoldTools.java
 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TestScaffoldTools.java
index af5620e544fc..b140bf47e319 100644
--- 
a/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TestScaffoldTools.java
+++ 
b/dsl/camel-jbang/camel-jbang-mcp/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/TestScaffoldTools.java
@@ -110,11 +110,14 @@ public class TestScaffoldTools {
             // Collect all unique component schemes
             List<String> allSchemes = collectSchemes(fromEndpoints, 
toEndpoints);
 
-            // Determine which to endpoints need mock replacements
+            // Determine which to endpoints need mock replacements: all but 
those of the components the catalog marks
+            // internal (direct, seda, log, mock and the like), which stay 
inside the CamelContext. The server's own
+            // catalog has the flag; an older one loaded for this call would 
not.
+            CamelCatalog ownCatalog = catalogService.getDefaultCatalog();
             List<String> mockEndpoints = toEndpoints.stream()
                     .filter(uri -> {
                         String scheme = extractScheme(uri);
-                        return scheme != null && 
!testInfraData.getTrivialSchemes().contains(scheme);
+                        return scheme != null && !isInternal(ownCatalog, 
scheme);
                     })
                     .toList();
 
@@ -183,6 +186,16 @@ public class TestScaffoldTools {
 
     // ---- Scheme extraction and mock naming ----
 
+    /** Whether the catalog marks the component internal: it stays inside the 
CamelContext, so a test keeps it real. */
+    static boolean isInternal(CamelCatalog catalog, String scheme) {
+        try {
+            ComponentModel model = catalog.componentModel(scheme);
+            return model != null && model.isInternal();
+        } catch (RuntimeException e) {
+            return false;
+        }
+    }
+
     String extractScheme(String uri) {
         if (uri == null || uri.isEmpty()) {
             return null;
diff --git 
a/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/TestScaffoldToolsTest.java
 
b/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/TestScaffoldToolsTest.java
index da5d5760779e..1c96273bbdef 100644
--- 
a/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/TestScaffoldToolsTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-mcp/src/test/java/org/apache/camel/dsl/jbang/core/commands/mcp/TestScaffoldToolsTest.java
@@ -265,6 +265,28 @@ class TestScaffoldToolsTest {
         assertThat(mocks).isEmpty();
     }
 
+    @Test
+    void mocksWhatLeavesTheCamelContextButNotInternalComponents() throws 
Exception {
+        String route = """
+                - route:
+                    from:
+                      uri: direct:start
+                      steps:
+                        - to: caffeine-cache:orders
+                        - to: disruptor:work
+                        - to: controlbus:route?routeId=other&action=stop
+                        - to: kafka:orders
+                """;
+
+        String json = tools.camel_route_test_scaffold(route, "yaml", "main", 
null, null);
+        JsonObject result = (JsonObject) Jsoner.deserialize(json);
+
+        // the components the catalog marks internal stay real; controlbus is 
not internal, it can evaluate an expression
+        JsonArray mocks = result.getCollection("mockEndpoints");
+        assertThat(mocks).extracting(m -> ((JsonObject) 
m).getString("originalUri"))
+                .containsExactly("controlbus:route?routeId=other&action=stop", 
"kafka:orders");
+    }
+
     // ---- Spring Boot runtime test generation ----
 
     @Test
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SpansTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SpansTab.java
index 6c96fa755631..d308ff38e5a9 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SpansTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SpansTab.java
@@ -25,6 +25,7 @@ import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicReference;
 
 import dev.tamboui.layout.Constraint;
@@ -49,6 +50,7 @@ import dev.tamboui.widgets.table.Cell;
 import dev.tamboui.widgets.table.Row;
 import dev.tamboui.widgets.table.Table;
 import dev.tamboui.widgets.table.TableState;
+import org.apache.camel.dsl.jbang.core.commands.ai.ProjectOverview;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
 
@@ -905,11 +907,13 @@ class SpansTab extends AbstractTab {
         return span.name();
     }
 
-    private static boolean isRemoteScheme(String scheme) {
+    // whether the component of a span talks to a remote system, as the 
catalog says (a scheme it does not know counts as
+    // remote); remembered per scheme, as the trace summaries are built on 
every refresh
+    private static final Map<String, Boolean> REMOTE_SCHEMES = new 
ConcurrentHashMap<>();
+
+    static boolean isRemoteScheme(String scheme) {
         return scheme != null
-                && !"direct".equals(scheme) && !"seda".equals(scheme)
-                && !"mock".equals(scheme) && !"log".equals(scheme)
-                && !"bean".equals(scheme) && !"class".equals(scheme);
+                && REMOTE_SCHEMES.computeIfAbsent(scheme, s -> 
ProjectOverview.isRemote(s, ProjectOverviewAssist.catalog()));
     }
 
     private static int compareNullable(String a, String b) {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SpansTabRenderTest.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SpansTabRenderTest.java
index 88d5e1dd603b..f0afae119cda 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SpansTabRenderTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SpansTabRenderTest.java
@@ -29,6 +29,7 @@ import dev.tamboui.text.Span;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
@@ -160,4 +161,14 @@ class SpansTabRenderTest {
                 "route1", null, "camel", Map.of());
     }
 
+    @Test
+    void remoteComponentsComeFromTheCatalog() {
+        // as the catalog marks them; a scheme it does not know counts as 
remote
+        assertThat(SpansTab.isRemoteScheme("kafka")).isTrue();
+        assertThat(SpansTab.isRemoteScheme("acme")).isTrue();
+        assertThat(SpansTab.isRemoteScheme("log")).isFalse();
+        // not in the list the check used to keep: a timer or an xslt step is 
not a remote call
+        assertThat(SpansTab.isRemoteScheme("timer")).isFalse();
+        assertThat(SpansTab.isRemoteScheme("xslt")).isFalse();
+    }
 }

Reply via email to