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;
+ }
+}