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 aa1aea55b8a5 CAMEL-23688: camel-jbang - add unit tests for more action 
reader CLI commands
aa1aea55b8a5 is described below

commit aa1aea55b8a5c679075dda4784993fecd88cb6bc
Author: Adriano Machado <[email protected]>
AuthorDate: Tue Jun 23 12:23:38 2026 -0400

    CAMEL-23688: camel-jbang - add unit tests for more action reader CLI 
commands
    
    Add Batch C of regression test coverage for camel-jbang CLI action
    commands. Tests cover output.json round-trip readers (browse, span,
    route-topology, load, stub), named-pid request path (send, receive,
    route-structure), and message-history reader (history). Test-only
    change, no production code modified.
    
    Closes #24199
    Co-Authored-By: Claude Code <[email protected]>
---
 .../commands/action/ActionCommandTestSupport.java  |  10 ++
 .../commands/action/CamelBrowseActionTest.java     |  83 +++++++++++++++++
 .../commands/action/CamelHistoryActionTest.java    | 103 +++++++++++++++++++++
 .../core/commands/action/CamelLoadActionTest.java  |  89 ++++++++++++++++++
 .../commands/action/CamelReceiveActionTest.java    |  71 ++++++++++++++
 .../action/CamelRouteStructureActionTest.java      |  80 ++++++++++++++++
 .../action/CamelRouteTopologyActionTest.java       |  82 ++++++++++++++++
 .../core/commands/action/CamelSendActionTest.java  |  81 ++++++++++++++++
 .../core/commands/action/CamelSpanActionTest.java  |  89 ++++++++++++++++++
 .../core/commands/action/CamelStubActionTest.java  |  81 ++++++++++++++++
 10 files changed, 769 insertions(+)

diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/ActionCommandTestSupport.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/ActionCommandTestSupport.java
index 0fc4e4423194..7ba3806afeb4 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/ActionCommandTestSupport.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/ActionCommandTestSupport.java
@@ -92,6 +92,16 @@ abstract class ActionCommandTestSupport extends 
CamelCommandBaseTestSupport {
         Files.writeString(f, root.toJson());
     }
 
+    /**
+     * Writes a message-history file for the given pid. Unlike the 
action/output round trip, {@code CamelHistoryAction}
+     * reads this pre-existing {@code <pid>-history.json} file (one JSON 
object per line) directly, so no responder
+     * thread is needed: write the fixture, then run with {@link 
#callWithSingleProcess}.
+     */
+    protected static void writeMessageHistoryFile(long pid, JsonObject line) 
throws Exception {
+        Path f = CommandLineHelper.getCamelDir().resolve(pid + 
"-history.json");
+        Files.writeString(f, line.toJson());
+    }
+
     /**
      * Reads back the action file an action command wrote for the given pid.
      *
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelBrowseActionTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelBrowseActionTest.java
new file mode 100644
index 000000000000..037016d073aa
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelBrowseActionTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.commands.action;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+import org.junit.jupiter.api.Test;
+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.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@ExtendWith(MockitoExtension.class)
+class CamelBrowseActionTest extends ActionCommandTestSupport {
+
+    @Test
+    void testRequestsBrowseAndRendersEndpoints() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelBrowseAction command = new CamelBrowseAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "myApp";
+        // options are normally defaulted by picocli; set them as we construct 
the command directly
+        command.sort = "uri";
+        command.limit = 100;
+
+        int exit = callWithResponse(command, singleEndpointResponse());
+
+        assertEquals(0, exit);
+
+        JsonObject action = readActionFile(TEST_PID);
+        assertNotNull(action, "action file should be written for the matched 
process");
+        assertEquals("browse", action.getString("action"));
+
+        String out = printer.getOutput();
+        assertTrue(out.contains("seda://foo"), "should print the browsed 
endpoint uri, was: " + out);
+    }
+
+    @Test
+    void testReturnsErrorWhenNameDoesNotMatch() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelBrowseAction command = new CamelBrowseAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "doesNotExist";
+
+        int exit = callWithSingleProcess(command);
+
+        assertEquals(1, exit);
+        assertTrue(printer.getOutput().isEmpty(), "nothing should be rendered 
when no process matches");
+    }
+
+    private static JsonObject singleEndpointResponse() {
+        JsonObject endpoint = new JsonObject();
+        endpoint.put("endpointUri", "seda://foo");
+        endpoint.put("queueSize", 1);
+        endpoint.put("limit", 100);
+        endpoint.put("position", 0);
+        endpoint.put("firstTimestamp", 0);
+        endpoint.put("lastTimestamp", 0);
+        JsonArray browse = new JsonArray();
+        browse.add(endpoint);
+
+        JsonObject response = new JsonObject();
+        response.put("browse", browse);
+        return response;
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelHistoryActionTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelHistoryActionTest.java
new file mode 100644
index 000000000000..a137f72ff99d
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelHistoryActionTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.commands.action;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+import org.junit.jupiter.api.Test;
+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.assertTrue;
+
+@ExtendWith(MockitoExtension.class)
+class CamelHistoryActionTest extends ActionCommandTestSupport {
+
+    private static final long FIXED_TIMESTAMP = 1_700_000_000_000L;
+
+    @Test
+    void testRendersMessageHistoryFromHistoryFile() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+        // CamelHistoryAction reads a pre-existing <pid>-history.json, not the 
action/output round trip
+        writeMessageHistoryFile(TEST_PID, singleTraceLine());
+
+        CamelHistoryAction command = new CamelHistoryAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "myApp";
+        // options are normally defaulted by picocli; set them as we construct 
the command directly
+        // depth defaults to 9 in picocli; without it depth=0 filters down to 
only level-1 created/completed nodes
+        command.depth = 9;
+        command.loggingColor = false;
+
+        int exit = callWithSingleProcess(command);
+
+        assertEquals(0, exit);
+
+        String out = printer.getOutput();
+        assertTrue(out.contains("Message History of last completed"),
+                "should print the message history header, was: " + out);
+        assertTrue(out.contains("myApp"), "should print the integration name, 
was: " + out);
+        assertTrue(out.contains("ABCDEFGH-0001"), "should print the exchange 
id, was: " + out);
+    }
+
+    @Test
+    void testRendersNothingWhenNameDoesNotMatch() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+        writeMessageHistoryFile(TEST_PID, singleTraceLine());
+
+        CamelHistoryAction command = new CamelHistoryAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "doesNotExist";
+        command.loggingColor = false;
+
+        int exit = callWithSingleProcess(command);
+
+        assertEquals(0, exit);
+        assertTrue(printer.getOutput().isEmpty(), "nothing should be rendered 
when no process matches");
+    }
+
+    private static JsonObject singleTraceLine() {
+        JsonObject message = new JsonObject();
+        message.put("exchangePattern", "InOnly");
+        message.put("exchangeId", "ABCDEFGH-0001");
+        message.put("body", new JsonObject());
+
+        JsonObject trace = new JsonObject();
+        trace.put("uid", 1);
+        trace.put("first", true);
+        trace.put("last", true);
+        trace.put("routeId", "myRoute");
+        trace.put("fromRouteId", "myRoute");
+        trace.put("nodeId", "to1");
+        trace.put("nodeShortName", "to");
+        trace.put("nodeLabel", "to[mock://out]");
+        trace.put("timestamp", FIXED_TIMESTAMP);
+        trace.put("elapsed", 5);
+        trace.put("failed", false);
+        trace.put("done", true);
+        trace.put("threadName", "main");
+        trace.put("exchangeId", "ABCDEFGH-0001");
+        trace.put("message", message);
+        JsonArray traces = new JsonArray();
+        traces.add(trace);
+
+        JsonObject line = new JsonObject();
+        line.put("name", "myApp");
+        line.put("traces", traces);
+        return line;
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLoadActionTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLoadActionTest.java
new file mode 100644
index 000000000000..c1ecc63af580
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLoadActionTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.commands.action;
+
+import java.util.List;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.util.json.JsonObject;
+import org.junit.jupiter.api.Test;
+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.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@ExtendWith(MockitoExtension.class)
+class CamelLoadActionTest extends ActionCommandTestSupport {
+
+    @Test
+    void testRequestsLoadAndReportsSuccess() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelLoadAction command = new CamelLoadAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "myApp";
+        command.source = List.of("myRoute.yaml");
+
+        int exit = callWithResponse(command, successResponse());
+
+        assertEquals(0, exit);
+
+        JsonObject action = readActionFile(TEST_PID);
+        assertNotNull(action, "action file should be written for the matched 
process");
+        assertEquals("load", action.getString("action"));
+
+        String out = printer.getOutput();
+        assertTrue(out.contains("Successfully loaded 1 source files"),
+                "should report the loaded source files, was: " + out);
+    }
+
+    @Test
+    void testReturnsErrorWhenNoSourceProvided() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelLoadAction command = new CamelLoadAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "myApp";
+
+        // the command rejects the missing --source before resolving any 
process, so no ProcessHandle mock is needed
+        int exit = command.doCall();
+
+        assertEquals(1, exit);
+        assertTrue(printer.getOutput().contains("No source files provided"),
+                "should report the missing source option, was: " + 
printer.getOutput());
+    }
+
+    @Test
+    void testReturnsErrorWhenNameDoesNotMatch() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelLoadAction command = new CamelLoadAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "doesNotExist";
+        command.source = List.of("myRoute.yaml");
+
+        int exit = callWithSingleProcess(command);
+
+        assertEquals(1, exit);
+        assertTrue(printer.getOutput().isEmpty(), "nothing should be rendered 
when no process matches");
+    }
+
+    private static JsonObject successResponse() {
+        JsonObject response = new JsonObject();
+        response.put("status", "success");
+        return response;
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelReceiveActionTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelReceiveActionTest.java
new file mode 100644
index 000000000000..26b80af8c988
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelReceiveActionTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.commands.action;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.util.json.JsonObject;
+import org.junit.jupiter.api.Test;
+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.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@ExtendWith(MockitoExtension.class)
+class CamelReceiveActionTest extends ActionCommandTestSupport {
+
+    @Test
+    void testStartsReceivingFromNamedIntegration() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelReceiveAction command = new CamelReceiveAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "myApp";
+        // request the start sub-action against the running integration (no 
--endpoint, so no auto-dump/spawn)
+        command.action = "start";
+        command.loggingColor = false;
+
+        int exit = callWithResponse(command, new JsonObject());
+
+        assertEquals(0, exit);
+
+        JsonObject action = readActionFile(TEST_PID);
+        assertNotNull(action, "action file should be written for the matched 
process");
+        assertEquals("receive", action.getString("action"));
+        assertEquals("true", action.getString("enabled"));
+        assertEquals("*", action.getString("endpoint"));
+
+        String out = printer.getOutput();
+        assertTrue(out.contains("Starting to receive messages from existing 
Camel: myApp"),
+                "should report connecting to the running integration, was: " + 
out);
+    }
+
+    @Test
+    void testRendersNothingWhenNameDoesNotMatch() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelReceiveAction command = new CamelReceiveAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "doesNotExist";
+        command.action = "start";
+        command.loggingColor = false;
+
+        int exit = callWithSingleProcess(command);
+
+        assertEquals(0, exit);
+        assertTrue(printer.getOutput().isEmpty(), "nothing should be rendered 
when no process matches");
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelRouteStructureActionTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelRouteStructureActionTest.java
new file mode 100644
index 000000000000..f28fc350cd1f
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelRouteStructureActionTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.commands.action;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+import org.junit.jupiter.api.Test;
+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.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@ExtendWith(MockitoExtension.class)
+class CamelRouteStructureActionTest extends ActionCommandTestSupport {
+
+    @Test
+    void testRequestsRouteStructureFromNamedIntegrationAndRendersSource() 
throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelRouteStructureAction command = new CamelRouteStructureAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "myApp";
+        // options are normally defaulted by picocli; set them as we construct 
the command directly
+        command.sort = "name";
+
+        int exit = callWithResponse(command, singleRouteResponse());
+
+        assertEquals(0, exit);
+
+        JsonObject action = readActionFile(TEST_PID);
+        assertNotNull(action, "action file should be written for the matched 
process");
+        assertEquals("route-structure", action.getString("action"));
+
+        String out = printer.getOutput();
+        assertTrue(out.contains("Source: myroute.yaml"), "should print the 
source filename, was: " + out);
+        assertTrue(out.contains("from[timer://foo]"), "should print the route 
structure code, was: " + out);
+    }
+
+    // Note: there is no no-match test here. When no pid matches, the command 
falls back to doCallSource, which
+    // spawns a background Camel via Run to compile source files. That spawn 
path is out of scope for this batch
+    // (it cannot be exercised deterministically in a unit test), so only the 
named-pid round-trip branch is covered.
+
+    private static JsonObject singleRouteResponse() {
+        JsonObject code = new JsonObject();
+        code.put("line", 1);
+        code.put("type", "from");
+        code.put("id", "from1");
+        code.put("level", 0);
+        code.put("code", "from[timer://foo]");
+        JsonArray codeLines = new JsonArray();
+        codeLines.add(code);
+
+        JsonObject route = new JsonObject();
+        route.put("source", "myroute.yaml");
+        route.put("routeId", "myRoute");
+        route.put("code", codeLines);
+        JsonArray routes = new JsonArray();
+        routes.add(route);
+
+        JsonObject response = new JsonObject();
+        response.put("routes", routes);
+        return response;
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelRouteTopologyActionTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelRouteTopologyActionTest.java
new file mode 100644
index 000000000000..f2ce53604391
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelRouteTopologyActionTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.commands.action;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+import org.junit.jupiter.api.Test;
+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.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@ExtendWith(MockitoExtension.class)
+class CamelRouteTopologyActionTest extends ActionCommandTestSupport {
+
+    @Test
+    void testRequestsTopologyAndRendersNodes() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelRouteTopologyAction command = new CamelRouteTopologyAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "myApp";
+
+        int exit = callWithResponse(command, singleNodeResponse());
+
+        assertEquals(0, exit);
+
+        JsonObject action = readActionFile(TEST_PID);
+        assertNotNull(action, "action file should be written for the matched 
process");
+        assertEquals("route-topology", action.getString("action"));
+
+        String out = printer.getOutput();
+        assertTrue(out.contains("Route Topology (1 routes, 0 connections)"),
+                "should print the topology summary header, was: " + out);
+        assertTrue(out.contains("myRoute"), "should print the route id, was: " 
+ out);
+        assertTrue(out.contains("timer://foo"), "should print the route 
source, was: " + out);
+    }
+
+    @Test
+    void testReturnsErrorWhenNameDoesNotMatch() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelRouteTopologyAction command = new CamelRouteTopologyAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "doesNotExist";
+
+        int exit = callWithSingleProcess(command);
+
+        assertEquals(1, exit);
+        assertTrue(printer.getOutput().contains("No running Camel integration 
found"),
+                "should report no running integration, was: " + 
printer.getOutput());
+    }
+
+    private static JsonObject singleNodeResponse() {
+        JsonObject node = new JsonObject();
+        node.put("routeId", "myRoute");
+        node.put("from", "timer://foo");
+        node.put("nodeType", "route");
+        JsonArray nodes = new JsonArray();
+        nodes.add(node);
+
+        JsonObject response = new JsonObject();
+        response.put("nodes", nodes);
+        response.put("edges", new JsonArray());
+        return response;
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSendActionTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSendActionTest.java
new file mode 100644
index 000000000000..1dd087b67b1b
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSendActionTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.commands.action;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.util.json.JsonObject;
+import org.junit.jupiter.api.Test;
+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.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@ExtendWith(MockitoExtension.class)
+class CamelSendActionTest extends ActionCommandTestSupport {
+
+    private static final long FIXED_TIMESTAMP = 1_700_000_000_000L;
+
+    @Test
+    void testSendsToNamedIntegrationAndRendersStatus() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelSendAction command = new CamelSendAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "myApp";
+        command.endpoint = "seda://foo";
+        // route the status line to the captured printer instead of AnsiConsole
+        command.loggingColor = false;
+
+        int exit = callWithResponse(command, sentResponse());
+
+        assertEquals(0, exit);
+
+        JsonObject action = readActionFile(TEST_PID);
+        assertNotNull(action, "action file should be written for the matched 
process");
+        assertEquals("send", action.getString("action"));
+        assertEquals("seda://foo", action.getString("endpoint"));
+
+        String out = printer.getOutput();
+        assertTrue(out.contains("seda://foo"), "should print the target 
endpoint, was: " + out);
+        assertTrue(out.contains("Sent (success)"), "should print the send 
status, was: " + out);
+    }
+
+    @Test
+    void testReturnsErrorWhenNameDoesNotMatch() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelSendAction command = new CamelSendAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "doesNotExist";
+        command.endpoint = "seda://foo";
+
+        int exit = callWithSingleProcess(command);
+
+        assertEquals(1, exit);
+        assertTrue(printer.getOutput().contains("matches 0 running Camel 
integrations"),
+                "should report no matching integration, was: " + 
printer.getOutput());
+    }
+
+    private static JsonObject sentResponse() {
+        JsonObject response = new JsonObject();
+        response.put("timestamp", FIXED_TIMESTAMP);
+        response.put("endpoint", "seda://foo");
+        response.put("elapsed", 5);
+        response.put("exchangeId", "E1");
+        return response;
+    }
+}
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
new file mode 100644
index 000000000000..e3b3b4930b4b
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSpanActionTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.commands.action;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+import org.junit.jupiter.api.Test;
+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.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@ExtendWith(MockitoExtension.class)
+class CamelSpanActionTest extends ActionCommandTestSupport {
+
+    @Test
+    void testRequestsSpansAndRendersTrace() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelSpanAction command = new CamelSpanAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "myApp";
+        // options are normally defaulted by picocli; set them as we construct 
the command directly
+        command.limit = 500;
+
+        int exit = callWithResponse(command, singleSpanResponse());
+
+        assertEquals(0, exit);
+
+        JsonObject action = readActionFile(TEST_PID);
+        assertNotNull(action, "action file should be written for the matched 
process");
+        assertEquals("span", action.getString("action"));
+
+        String out = printer.getOutput();
+        assertTrue(out.contains("myRoute"), "should print the route id of the 
captured span, was: " + out);
+    }
+
+    @Test
+    void testReturnsErrorWhenNameDoesNotMatch() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelSpanAction command = new CamelSpanAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "doesNotExist";
+
+        int exit = callWithSingleProcess(command);
+
+        assertEquals(1, exit);
+        assertTrue(printer.getOutput().isEmpty(), "nothing should be rendered 
when no process matches");
+    }
+
+    private static JsonObject singleSpanResponse() {
+        JsonObject span = new JsonObject();
+        span.put("traceId", "abcdef0123456789");
+        span.put("spanId", "span-1");
+        span.put("parentSpanId", "");
+        span.put("name", "timer://foo");
+        span.put("kind", "INTERNAL");
+        span.put("status", "OK");
+        span.put("durationMs", 5);
+        span.put("routeId", "myRoute");
+        span.put("processorId", "to1");
+        span.put("startEpochNanos", 1_000_000L);
+        span.put("endEpochNanos", 6_000_000L);
+        span.put("attributes", new JsonObject());
+        JsonArray spans = new JsonArray();
+        spans.add(span);
+
+        JsonObject response = new JsonObject();
+        response.put("enabled", true);
+        response.put("spans", spans);
+        return response;
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelStubActionTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelStubActionTest.java
new file mode 100644
index 000000000000..7427c4f07a9f
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelStubActionTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.commands.action;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+import org.junit.jupiter.api.Test;
+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.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@ExtendWith(MockitoExtension.class)
+class CamelStubActionTest extends ActionCommandTestSupport {
+
+    @Test
+    void testRequestsStubAndRendersQueues() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelStubAction command = new CamelStubAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "myApp";
+        // options are normally defaulted by picocli; set them as we construct 
the command directly
+        command.sort = "name";
+        command.limit = 10;
+
+        int exit = callWithResponse(command, singleQueueResponse());
+
+        assertEquals(0, exit);
+
+        JsonObject action = readActionFile(TEST_PID);
+        assertNotNull(action, "action file should be written for the matched 
process");
+        assertEquals("stub", action.getString("action"));
+
+        String out = printer.getOutput();
+        assertTrue(out.contains("myStub"), "should print the stub queue name, 
was: " + out);
+    }
+
+    @Test
+    void testReturnsErrorWhenNameDoesNotMatch() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelStubAction command = new CamelStubAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "doesNotExist";
+
+        int exit = callWithSingleProcess(command);
+
+        assertEquals(1, exit);
+        assertTrue(printer.getOutput().isEmpty(), "nothing should be rendered 
when no process matches");
+    }
+
+    private static JsonObject singleQueueResponse() {
+        JsonObject queue = new JsonObject();
+        queue.put("name", "myStub");
+        queue.put("max", 100);
+        queue.put("size", 1);
+        queue.put("endpointUri", "stub://foo");
+        JsonArray queues = new JsonArray();
+        queues.add(queue);
+
+        JsonObject response = new JsonObject();
+        response.put("queues", queues);
+        return response;
+    }
+}


Reply via email to