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

commit 03ee8ca50b310f428ba3010fac2f3cbcce761f0f
Author: Adriano Machado <[email protected]>
AuthorDate: Tue Jun 23 01:18:17 2026 -0400

    CAMEL-23688: camel-jbang - add unit tests for action reader CLI commands
    
    Adds unit tests for the request/response reader action commands in
    camel-jbang-core: route-dump, bean, thread-dump, top-processors,
    route-controller, and gc. A new callWithResponse helper in
    ActionCommandTestSupport simulates the running Camel writing output
    via a background responder thread synchronized with Awaitility.
    
    Closes #24189
    
    Co-Authored-By: Claude Opus 4.8 <[email protected]>
---
 .../commands/action/ActionCommandTestSupport.java  | 34 ++++++++
 .../core/commands/action/CamelBeanDumpTest.java    | 92 ++++++++++++++++++++++
 .../core/commands/action/CamelGCActionTest.java    | 59 ++++++++++++++
 .../commands/action/CamelRouteDumpActionTest.java  | 91 +++++++++++++++++++++
 .../core/commands/action/CamelSourceTopTest.java   | 87 ++++++++++++++++++++
 .../core/commands/action/CamelThreadDumpTest.java  | 91 +++++++++++++++++++++
 .../commands/action/RouteControllerActionTest.java | 84 ++++++++++++++++++++
 7 files changed, 538 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 9a31d872dd30..0fc4e4423194 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
@@ -17,11 +17,13 @@
 package org.apache.camel.dsl.jbang.core.commands.action;
 
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.time.Instant;
 import java.util.Comparator;
 import java.util.Optional;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Stream;
 
 import org.apache.camel.dsl.jbang.core.commands.CamelCommand;
@@ -33,6 +35,7 @@ import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.mockito.MockedStatic;
 
+import static org.awaitility.Awaitility.await;
 import static org.mockito.Mockito.lenient;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.mockStatic;
@@ -117,6 +120,37 @@ abstract class ActionCommandTestSupport extends 
CamelCommandBaseTestSupport {
         }
     }
 
+    /**
+     * Runs a request/response reader command end to end. Mocks a single 
discoverable process (TEST_PID) and, in a
+     * background thread, simulates the running Camel writing {@code response} 
to its output file once the command has
+     * written its action request.
+     * <p>
+     * The reader commands delete any stale output file <em>before</em> 
writing the action file and only then poll for
+     * the output, so the responder waits for the action file to appear: that 
guarantees the response lands after the
+     * command's own delete and cannot be wiped out. No {@code Thread.sleep} 
is used; the wait is driven by Awaitility.
+     *
+     * @return the command exit code; rendered output can be asserted 
afterwards via {@code printer.getOutput()}
+     */
+    protected int callWithResponse(CamelCommand command, JsonObject response) 
throws Exception {
+        Path actionFile = CommandLineHelper.getCamelDir().resolve(TEST_PID + 
"-action.json");
+        Path outputFile = CommandLineHelper.getCamelDir().resolve(TEST_PID + 
"-output.json");
+        Thread responder = new Thread(() -> {
+            await().atMost(5, TimeUnit.SECONDS).until(() -> 
Files.exists(actionFile));
+            try {
+                Files.writeString(outputFile, response.toJson());
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        }, "test-camel-responder");
+        responder.setDaemon(true);
+        responder.start();
+        try {
+            return callWithSingleProcess(command);
+        } finally {
+            responder.join(TimeUnit.SECONDS.toMillis(10));
+        }
+    }
+
     /**
      * Creates a mock ProcessHandle for the test process. Info is 
pre-configured with empty commandLine and a fixed
      * start instant so extractName falls through to context.name.
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelBeanDumpTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelBeanDumpTest.java
new file mode 100644
index 000000000000..8f25e546ed58
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelBeanDumpTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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 CamelBeanDumpTest extends ActionCommandTestSupport {
+
+    @Test
+    void testRequestsBeanDumpAndRendersBeans() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelBeanDump command = new CamelBeanDump(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "myApp";
+        // options are normally defaulted by picocli; set them as we construct 
the command directly
+        command.filter = "all";
+        command.sort = "name";
+        command.properties = true;
+
+        int exit = callWithResponse(command, singleBeanResponse());
+
+        assertEquals(0, exit);
+
+        JsonObject action = readActionFile(TEST_PID);
+        assertNotNull(action, "action file should be written for the matched 
process");
+        assertEquals("bean", action.getString("action"));
+
+        String out = printer.getOutput();
+        assertTrue(out.contains("BEAN: myBean"), "should print the bean name, 
was: " + out);
+        assertTrue(out.contains("com.foo.MyBean"), "should print the bean 
type, was: " + out);
+        assertTrue(out.contains("greeting"), "should print the bean property 
name, was: " + out);
+        assertTrue(out.contains("helloWorld"), "should print the bean property 
value, was: " + out);
+    }
+
+    @Test
+    void testReturnsErrorWhenNameDoesNotMatch() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelBeanDump command = new CamelBeanDump(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 singleBeanResponse() {
+        JsonObject property = new JsonObject();
+        property.put("name", "greeting");
+        property.put("type", "java.lang.String");
+        property.put("value", "helloWorld");
+        JsonArray properties = new JsonArray();
+        properties.add(property);
+
+        JsonObject bean = new JsonObject();
+        bean.put("name", "myBean");
+        bean.put("type", "com.foo.MyBean");
+        bean.put("properties", properties);
+
+        JsonObject beans = new JsonObject();
+        beans.put("myBean", bean);
+
+        JsonObject response = new JsonObject();
+        response.put("beans", beans);
+        return response;
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelGCActionTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelGCActionTest.java
new file mode 100644
index 000000000000..c723910ca967
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelGCActionTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.assertNull;
+
+@ExtendWith(MockitoExtension.class)
+class CamelGCActionTest extends ActionCommandTestSupport {
+
+    @Test
+    void testWritesGcActionForMatchingName() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelGCAction command = new CamelGCAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "myApp";
+
+        int exit = callWithSingleProcess(command);
+
+        assertEquals(0, exit);
+        JsonObject action = readActionFile(TEST_PID);
+        assertNotNull(action, "action file should be written for the matched 
process");
+        assertEquals("gc", action.getString("action"));
+    }
+
+    @Test
+    void testNoActionWhenNameDoesNotMatch() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelGCAction command = new CamelGCAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "doesNotExist";
+
+        int exit = callWithSingleProcess(command);
+
+        assertEquals(0, exit);
+        assertNull(readActionFile(TEST_PID), "no action file should be written 
when no process matches");
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelRouteDumpActionTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelRouteDumpActionTest.java
new file mode 100644
index 000000000000..7e09e0a0b286
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelRouteDumpActionTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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 CamelRouteDumpActionTest extends ActionCommandTestSupport {
+
+    @Test
+    void testRequestsRouteDumpAndRendersSource() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelRouteDumpAction command = new CamelRouteDumpAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "myApp";
+        // options are normally defaulted by picocli; set them as we construct 
the command directly
+        command.format = "yaml";
+        command.sort = "name";
+
+        int exit = callWithResponse(command, singleRouteResponse());
+
+        assertEquals(0, exit);
+
+        // the command must request a route-dump with the default yaml format
+        JsonObject action = readActionFile(TEST_PID);
+        assertNotNull(action, "action file should be written for the matched 
process");
+        assertEquals("route-dump", action.getString("action"));
+        assertEquals("yaml", action.getString("format"));
+
+        // the simulated response must be rendered as source code
+        String out = printer.getOutput();
+        assertTrue(out.contains("Source: myroute.yaml"), "should print the 
source filename, was: " + out);
+        assertTrue(out.contains("from uri: timer:foo"), "should print the 
route code, was: " + out);
+    }
+
+    @Test
+    void testReturnsErrorWhenNameDoesNotMatch() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelRouteDumpAction command = new CamelRouteDumpAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "doesNotExist";
+
+        // no process matches, so the command returns before requesting any 
output
+        int exit = callWithSingleProcess(command);
+
+        assertEquals(1, exit);
+        assertTrue(printer.getOutput().isEmpty(), "nothing should be rendered 
when no process matches");
+    }
+
+    private static JsonObject singleRouteResponse() {
+        JsonObject code = new JsonObject();
+        code.put("line", 1);
+        code.put("code", "from uri: 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/CamelSourceTopTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSourceTopTest.java
new file mode 100644
index 000000000000..37341bc382d8
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSourceTopTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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 CamelSourceTopTest extends ActionCommandTestSupport {
+
+    @Test
+    void testRequestsTopProcessorsAndRendersRows() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelSourceTop command = new CamelSourceTop(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "myApp";
+
+        int exit = callWithResponse(command, singleProcessorResponse());
+
+        assertEquals(0, exit);
+
+        JsonObject action = readActionFile(TEST_PID);
+        assertNotNull(action, "action file should be written for the matched 
process");
+        assertEquals("top-processors", action.getString("action"));
+
+        String out = printer.getOutput();
+        assertTrue(out.contains("Route: myRoute"), "should print the route id, 
was: " + out);
+        assertTrue(out.contains("Total: 5"), "should print the processor 
statistics, was: " + out);
+    }
+
+    @Test
+    void testReturnsErrorWhenNameDoesNotMatch() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelSourceTop command = new CamelSourceTop(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 singleProcessorResponse() {
+        JsonObject stats = new JsonObject();
+        stats.put("exchangesTotal", 5);
+        stats.put("meanProcessingTime", 2);
+        stats.put("maxProcessingTime", 3);
+        stats.put("minProcessingTime", 1);
+        stats.put("lastProcessingTime", 2);
+
+        JsonObject processor = new JsonObject();
+        processor.put("processorId", "myProcessor");
+        processor.put("routeId", "myRoute");
+        processor.put("location", "myroute.yaml");
+        processor.put("statistics", stats);
+
+        JsonArray processors = new JsonArray();
+        processors.add(processor);
+
+        JsonObject response = new JsonObject();
+        response.put("processors", processors);
+        return response;
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDumpTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDumpTest.java
new file mode 100644
index 000000000000..b76fb160994f
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/CamelThreadDumpTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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 CamelThreadDumpTest extends ActionCommandTestSupport {
+
+    @Test
+    void testRequestsThreadDumpAndRendersThreads() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelThreadDump command = new CamelThreadDump(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "myApp";
+        // options are normally defaulted by picocli; set them as we construct 
the command directly
+        command.filters = new String[] { "all" };
+        command.sort = "id";
+        command.depth = 1;
+
+        int exit = callWithResponse(command, singleThreadResponse());
+
+        assertEquals(0, exit);
+
+        JsonObject action = readActionFile(TEST_PID);
+        assertNotNull(action, "action file should be written for the matched 
process");
+        assertEquals("thread-dump", action.getString("action"));
+
+        String out = printer.getOutput();
+        assertTrue(out.contains("PID: " + TEST_PID), "should print the pid 
header, was: " + out);
+        assertTrue(out.contains("Camel-thread-1"), "should print the thread 
name, was: " + out);
+        assertTrue(out.contains("RUNNABLE"), "should print the thread state, 
was: " + out);
+    }
+
+    @Test
+    void testReturnsErrorWhenNameDoesNotMatch() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        CamelThreadDump command = new CamelThreadDump(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 singleThreadResponse() {
+        JsonObject thread = new JsonObject();
+        thread.put("id", 1);
+        thread.put("name", "Camel-thread-1");
+        thread.put("state", "RUNNABLE");
+        thread.put("waitedCount", 0);
+        thread.put("waitedTime", 0);
+        thread.put("blockedCount", 0);
+        thread.put("blockedTime", 0);
+        thread.put("stackTrace", new JsonArray());
+
+        JsonArray threads = new JsonArray();
+        threads.add(thread);
+
+        JsonObject response = new JsonObject();
+        response.put("threadCount", 1);
+        response.put("peakThreadCount", 2);
+        response.put("threads", threads);
+        return response;
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/RouteControllerActionTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/RouteControllerActionTest.java
new file mode 100644
index 000000000000..3e3f6b715e1e
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/action/RouteControllerActionTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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 RouteControllerActionTest extends ActionCommandTestSupport {
+
+    @Test
+    void testRequestsRouteControllerAndRendersRoutes() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        RouteControllerAction command = new RouteControllerAction(new 
CamelJBangMain().withPrinter(printer));
+        command.name = "myApp";
+        // options are normally defaulted by picocli; set them as we construct 
the command directly
+        command.sort = "id";
+        command.header = true;
+
+        int exit = callWithResponse(command, defaultControllerResponse());
+
+        assertEquals(0, exit);
+
+        JsonObject action = readActionFile(TEST_PID);
+        assertNotNull(action, "action file should be written for the matched 
process");
+        assertEquals("route-controller", action.getString("action"));
+
+        String out = printer.getOutput();
+        assertTrue(out.contains("Default Route Controller"), "should print the 
controller header, was: " + out);
+        assertTrue(out.contains("myRoute"), "should print the route id, was: " 
+ out);
+    }
+
+    @Test
+    void testReturnsErrorWhenNameDoesNotMatch() throws Exception {
+        writeStatusFile(TEST_PID, "myApp");
+
+        RouteControllerAction command = new RouteControllerAction(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 defaultControllerResponse() {
+        JsonObject route = new JsonObject();
+        route.put("routeId", "myRoute");
+        route.put("uri", "timer://foo");
+        route.put("status", "Started");
+        JsonArray routes = new JsonArray();
+        routes.add(route);
+
+        JsonObject response = new JsonObject();
+        response.put("controller", "DefaultRouteController");
+        response.put("startingRoutes", false);
+        response.put("totalRoutes", 1);
+        response.put("routes", routes);
+        return response;
+    }
+}

Reply via email to