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 f246c1e735cc CAMEL-23817: camel-jbang - Fix test init command
f246c1e735cc is described below
commit f246c1e735cc40b831d5cccfc83c46679e412ec3
Author: Christoph Deppisch <[email protected]>
AuthorDate: Fri Jun 26 07:47:36 2026 +0200
CAMEL-23817: camel-jbang - Fix test init command
Move custom init logic from CitrusExecutionStrategy into a dedicated
TestInit command class. Fix isCitrusCommand to use instanceof instead
of fragile string-based class name check. Add unit tests for the test
plugin covering init, run, inspect and list commands.
Closes #24256
---
.gitignore | 3 +-
.../dsl/jbang/core/commands/test/TestInit.java | 126 +++++++++++++++++++
.../dsl/jbang/core/commands/test/TestPlugin.java | 74 +----------
.../jbang/core/commands/test/TestPluginTest.java | 138 +++++++++++++++++++++
.../src/test/resources/my-sample.citrus.it.yaml | 27 ++++
5 files changed, 298 insertions(+), 70 deletions(-)
diff --git a/.gitignore b/.gitignore
index 6a653dcd0b9f..7c7295bcf5b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,7 +30,8 @@ node_modules/
mvnd.zip*
.camel-jbang
.camel-jbang-run
+.citrus-jbang
.mvn/.develocity/develocity-workspace-id
backlog
.claude
-.omc
\ No newline at end of file
+.omc
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-test/src/main/java/org/apache/camel/dsl/jbang/core/commands/test/TestInit.java
b/dsl/camel-jbang/camel-jbang-plugin-test/src/main/java/org/apache/camel/dsl/jbang/core/commands/test/TestInit.java
new file mode 100644
index 000000000000..8d8eea6fd034
--- /dev/null
+++
b/dsl/camel-jbang/camel-jbang-plugin-test/src/main/java/org/apache/camel/dsl/jbang/core/commands/test/TestInit.java
@@ -0,0 +1,126 @@
+/*
+ * 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.test;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Stack;
+
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.catalog.VersionHelper;
+import org.apache.camel.dsl.jbang.core.commands.ExportHelper;
+import org.apache.camel.util.IOHelper;
+import org.citrusframework.CitrusSettings;
+import org.citrusframework.CitrusVersion;
+import org.citrusframework.jbang.CitrusJBangMain;
+import org.citrusframework.jbang.commands.CitrusCommand;
+import org.citrusframework.util.ClassLoaderHelper;
+import org.citrusframework.util.FileUtils;
+import picocli.CommandLine;
+
+import static java.nio.file.Files.writeString;
+
+/**
+ * Automatically uses test subfolder as a working directory for creating new
tests. Automatically adds a
+ * citrus-application.properties configuration if not present.
+ */
[email protected](name = "init", description = "Creates a new Citrus test")
+public class TestInit extends CitrusCommand {
+
+ @CommandLine.Parameters(description = "Name of test file (or a github
link)", arity = "1",
+ paramLabel = "<file>", parameterConsumer =
TestInit.FileConsumer.class)
+ private Path filePath; // Defined only for file path completion; the field
never used
+
+ private String file;
+
+ @CommandLine.Option(names = { "--directory" },
+ description = "Directory where the files will be
created", defaultValue = TestPlugin.TEST_DIR)
+ private String directory;
+
+ public TestInit(CitrusJBangMain citrus) {
+ super(citrus);
+ }
+
+ @Override
+ public Integer call() throws Exception {
+ String ext = FileUtils.getFileExtension(file);
+ String name = FileUtils.getBaseName(file);
+ String content;
+ try (InputStream is =
ClassLoaderHelper.getClassLoader().getResourceAsStream("templates/" + ext +
".tmpl")) {
+ if (is == null) {
+ printer().println("Error: Unsupported file type: " + ext);
+ return 1;
+ }
+ content = FileUtils.readToString(is, StandardCharsets.UTF_8);
+ }
+
+ Path currentDir = Paths.get(".");
+ Path workingDir;
+ if (directory.equals(currentDir.getFileName().toString())) {
+ // current directory is already the target subfolder
+ workingDir = currentDir;
+ } else if (currentDir.resolve(directory).toFile().exists()) {
+ // navigate to existing target subfolder
+ workingDir = currentDir.resolve(directory);
+ System.setProperty(CitrusSettings.RESOURCES_WORKDIR_PROPERTY,
workingDir.toString());
+ } else if (currentDir.resolve(directory).toFile().mkdirs()) {
+ // create target subfolder and navigate to it
+ workingDir = currentDir.resolve(directory);
+ System.setProperty(CitrusSettings.RESOURCES_WORKDIR_PROPERTY,
workingDir.toString());
+ } else {
+ throw new RuntimeCamelException("Failed to create working
directory in: " + currentDir);
+ }
+
+ File target = workingDir.resolve(file).toFile();
+ content = content.replaceFirst("\\{\\{ \\.Name }}", name);
+
+ writeString(target.toPath(), content);
+
+ // Create Citrus application properties if not present
+ if
(!workingDir.resolve(CitrusSettings.getApplicationPropertiesFile()).toFile().exists())
{
+ Path citrusApplicationProperties =
workingDir.resolve(CitrusSettings.getApplicationPropertiesFile());
+ try (InputStream is
+ = TestPlugin.class.getClassLoader()
+
.getResourceAsStream("templates/citrus-application-properties.tmpl")) {
+ String context = IOHelper.loadText(is);
+
+ context = context.replaceAll("\\{\\{ \\.CitrusVersion }}",
CitrusVersion.version());
+ context = context.replaceAll("\\{\\{ \\.CamelVersion }}", new
VersionHelper().getVersion());
+
+ ExportHelper.safeCopy(new
ByteArrayInputStream(context.getBytes(StandardCharsets.UTF_8)),
+ citrusApplicationProperties);
+ } catch (Exception e) {
+ getMain().getOut().println("Failed to create %s for tests in:
%s"
+
.formatted(CitrusSettings.getApplicationPropertiesFile(),
citrusApplicationProperties));
+ }
+ }
+
+ return 0;
+ }
+
+ static class FileConsumer extends ParameterConsumer<TestInit> {
+ @Override
+ protected void doConsumeParameters(Stack<String> args, TestInit cmd) {
+ cmd.file = args.pop();
+ }
+ }
+}
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-test/src/main/java/org/apache/camel/dsl/jbang/core/commands/test/TestPlugin.java
b/dsl/camel-jbang/camel-jbang-plugin-test/src/main/java/org/apache/camel/dsl/jbang/core/commands/test/TestPlugin.java
index 59a860268e7d..19d70e68b6bc 100644
---
a/dsl/camel-jbang/camel-jbang-plugin-test/src/main/java/org/apache/camel/dsl/jbang/core/commands/test/TestPlugin.java
+++
b/dsl/camel-jbang/camel-jbang-plugin-test/src/main/java/org/apache/camel/dsl/jbang/core/commands/test/TestPlugin.java
@@ -16,30 +16,21 @@
*/
package org.apache.camel.dsl.jbang.core.commands.test;
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.Optional;
-import org.apache.camel.RuntimeCamelException;
import org.apache.camel.catalog.VersionHelper;
import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
-import org.apache.camel.dsl.jbang.core.commands.ExportHelper;
import org.apache.camel.dsl.jbang.core.common.CamelJBangPlugin;
import org.apache.camel.dsl.jbang.core.common.Plugin;
import org.apache.camel.dsl.jbang.core.common.PluginExporter;
import org.apache.camel.dsl.jbang.core.common.Printer;
-import org.apache.camel.util.IOHelper;
-import org.citrusframework.CitrusSettings;
import org.citrusframework.CitrusVersion;
import org.citrusframework.jbang.CitrusJBangMain;
import org.citrusframework.jbang.commands.Agent;
import org.citrusframework.jbang.commands.AgentRun;
import org.citrusframework.jbang.commands.AgentStart;
import org.citrusframework.jbang.commands.AgentStop;
-import org.citrusframework.jbang.commands.Init;
+import org.citrusframework.jbang.commands.CitrusCommand;
import org.citrusframework.jbang.commands.Inspect;
import org.citrusframework.jbang.commands.ListTests;
import org.citrusframework.jbang.commands.Run;
@@ -48,13 +39,15 @@ import picocli.CommandLine;
@CamelJBangPlugin(name = "camel-jbang-plugin-test", firstVersion = "4.14.0")
public class TestPlugin implements Plugin {
+ public static final String TEST_DIR = "test";
+
@Override
public void customize(CommandLine commandLine, CamelJBangMain main) {
CitrusJBangMain citrus = new CitrusJBangMain();
citrus.withPrinter(new PipedPrinter(main.getOut()));
var cmd = new CommandLine(new TestCommand(main))
- .addSubcommand("init", new CommandLine(new Init(citrus)))
+ .addSubcommand("init", new CommandLine(new TestInit(citrus)))
.addSubcommand("inspect", new CommandLine(new Inspect(citrus)))
.addSubcommand("run", new CommandLine(new Run(citrus)))
.addSubcommand("ps", new CommandLine(new ListTests(citrus)),
"ls")
@@ -78,8 +71,6 @@ public class TestPlugin implements Plugin {
*/
private record CitrusExecutionStrategy(CamelJBangMain main) implements
CommandLine.IExecutionStrategy {
- public static final String TEST_DIR = "test";
-
@Override
public int execute(CommandLine.ParseResult parseResult)
throws CommandLine.ExecutionException,
CommandLine.ParameterException {
@@ -90,21 +81,9 @@ public class TestPlugin implements Plugin {
}
if (isCitrusCommand(parseResult)) {
- String command = "";
- if (parseResult.originalArgs().size() > 2) {
- command = parseResult.originalArgs().get(1);
- } else if (parseResult.originalArgs().size() == 2) {
- command = parseResult.originalArgs().get(1);
- }
-
System.setProperty("citrus.jbang.version",
CitrusVersion.version());
System.setProperty("citrus.camel.jbang.version", new
VersionHelper().getVersion());
- // Prepare commands
- if ("init".equals(command)) {
- prepareInitCommand();
- }
-
if (!isCamelLauncherRuntime()) {
var tccLoader =
Thread.currentThread().getContextClassLoader();
try {
@@ -122,49 +101,6 @@ public class TestPlugin implements Plugin {
return new CommandLine.RunLast().execute(parseResult);
}
- /**
- * Prepare init command. Automatically uses test subfolder as a
working directory for creating new tests.
- * Automatically adds a citrus-application.properties configuration if
not present.
- */
- private void prepareInitCommand() {
- Path currentDir = Paths.get(".");
- Path workingDir;
- // Automatically set test subfolder as a working directory
- if (TEST_DIR.equals(currentDir.getFileName().toString())) {
- // current directory is already the test subfolder
- workingDir = currentDir;
- } else if (currentDir.resolve(TEST_DIR).toFile().exists()) {
- // navigate to existing test subfolder
- workingDir = currentDir.resolve(TEST_DIR);
- System.setProperty(CitrusSettings.RESOURCES_WORKDIR_PROPERTY,
workingDir.toString());
- } else if (currentDir.resolve(TEST_DIR).toFile().mkdirs()) {
- // create test subfolder and navigate to it
- workingDir = currentDir.resolve(TEST_DIR);
- System.setProperty(CitrusSettings.RESOURCES_WORKDIR_PROPERTY,
workingDir.toString());
- } else {
- throw new RuntimeCamelException("Cannot create test working
directory in: " + currentDir);
- }
-
- // Create Citrus application properties if not present
- if
(!workingDir.resolve(CitrusSettings.getApplicationPropertiesFile()).toFile().exists())
{
- Path citrusApplicationProperties =
workingDir.resolve(CitrusSettings.getApplicationPropertiesFile());
- try (InputStream is
- = TestPlugin.class.getClassLoader()
-
.getResourceAsStream("templates/citrus-application-properties.tmpl")) {
- String context = IOHelper.loadText(is);
-
- context = context.replaceAll("\\{\\{ \\.CitrusVersion }}",
CitrusVersion.version());
- context = context.replaceAll("\\{\\{ \\.CamelVersion }}",
new VersionHelper().getVersion());
-
- ExportHelper.safeCopy(new
ByteArrayInputStream(context.getBytes(StandardCharsets.UTF_8)),
- citrusApplicationProperties);
- } catch (Exception e) {
- main.getOut().println("Failed to create %s for tests in:
%s"
-
.formatted(CitrusSettings.getApplicationPropertiesFile(),
citrusApplicationProperties));
- }
- }
- }
-
/**
* Evaluate if the current runtime is using Camel Launcher. Camel
launcher sets a System property marking the
* runtime nature. If the System property is not present we can assume
that the runtime is something different
@@ -184,7 +120,7 @@ public class TestPlugin implements Plugin {
}
Object commandObject = subcommand.commandSpec().userObject();
- return
commandObject.getClass().getName().startsWith("org.citrusframework");
+ return commandObject instanceof CitrusCommand;
}
}
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-test/src/test/java/org/apache/camel/dsl/jbang/core/commands/test/TestPluginTest.java
b/dsl/camel-jbang/camel-jbang-plugin-test/src/test/java/org/apache/camel/dsl/jbang/core/commands/test/TestPluginTest.java
new file mode 100644
index 000000000000..086c39ff2c5b
--- /dev/null
+++
b/dsl/camel-jbang/camel-jbang-plugin-test/src/test/java/org/apache/camel/dsl/jbang/core/commands/test/TestPluginTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.test;
+
+import java.nio.file.Path;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
+import org.apache.camel.dsl.jbang.core.common.Printer;
+import org.apache.camel.dsl.jbang.core.common.StringPrinter;
+import org.apache.camel.dsl.jbang.core.common.VersionHelper;
+import org.citrusframework.spi.Resources;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import picocli.CommandLine;
+
+class TestPluginTest {
+
+ private StringPrinter printer;
+
+ @BeforeEach
+ public void setup() {
+ // Set Camel version with system property value, usually set via Maven
surefire plugin
+ // In case you run this test via local Java IDE you need to provide
the system property or a default value here
+ VersionHelper.setCamelVersion(System.getProperty("camel.version", ""));
+ printer = new StringPrinter();
+ CommandLineHelper.useHomeDir("target");
+ }
+
+ @Test
+ public void shouldListTests() {
+ CamelJBangMain camelJBangMain = createCamelJBangMain();
+
+ camelJBangMain.execute("test", "ps");
+
+ Assertions.assertTrue(printer.getOutput().contains("PID NAME STATUS
AGE"));
+ }
+
+ @Test
+ public void shouldInitYamlTest() {
+ Path targetDir =
CommandLineHelper.getHomeDir().toAbsolutePath().resolve(TestPlugin.TEST_DIR);
+
+ CamelJBangMain camelJBangMain = createCamelJBangMain();
+ camelJBangMain.execute("test", "init", "sample.citrus.it.yaml",
+ "--directory", targetDir.toString());
+
+
Assertions.assertTrue(targetDir.resolve("citrus-application.properties").toFile().exists());
+
Assertions.assertTrue(targetDir.resolve("sample.citrus.it.yaml").toFile().exists());
+ }
+
+ @Test
+ public void shouldInitXmlTest() {
+ Path targetDir =
CommandLineHelper.getHomeDir().toAbsolutePath().resolve(TestPlugin.TEST_DIR);
+
+ CamelJBangMain camelJBangMain = createCamelJBangMain();
+ camelJBangMain.execute("test", "init", "sample.citrus.it.xml",
+ "--directory", targetDir.toString());
+
+
Assertions.assertTrue(targetDir.resolve("citrus-application.properties").toFile().exists());
+
Assertions.assertTrue(targetDir.resolve("sample.citrus.it.xml").toFile().exists());
+ }
+
+ @Test
+ public void shouldRunTest() {
+ Path targetDir =
CommandLineHelper.getHomeDir().toAbsolutePath().resolve(TestPlugin.TEST_DIR);
+
+ CamelJBangMain camelJBangMain = createCamelJBangMain();
+ camelJBangMain.execute("test", "init", "sample.citrus.it.yaml",
+ "--directory", targetDir.toString());
+
+
Assertions.assertTrue(targetDir.resolve("citrus-application.properties").toFile().exists());
+
Assertions.assertTrue(targetDir.resolve("sample.citrus.it.yaml").toFile().exists());
+
+ camelJBangMain.execute("test", "run", targetDir.toString());
+ }
+
+ @Test
+ public void shouldInspectTest() {
+ Path source =
Resources.fromClasspath("my-sample.citrus.it.yaml").file().toPath();
+
+ CamelJBangMain camelJBangMain = createCamelJBangMain();
+ camelJBangMain.execute("test", "inspect", source.toString());
+
+ Assertions.assertEquals("""
+ {
+ "name": "my-sample.citrus.it.yaml",
+ "actions": [
+ "echo"
+ ]
+ }
+ """.trim(), printer.getOutput().trim());
+ }
+
+ /**
+ * Creates CamelJBangMain instance ready for unit testing. Automatically
adds test plugin commands. Automatically
+ * sets the out printer.
+ */
+ private CamelJBangMain createCamelJBangMain() {
+ return new CamelJBangMain() {
+ @Override
+ public void postAddCommands(CommandLine commandLine, String[]
args) {
+ TestPlugin plugin = new TestPlugin();
+ plugin.customize(commandLine, this);
+
+ super.postAddCommands(commandLine, args);
+ }
+
+ @Override
+ public void quit(int exitCode) {
+ if (exitCode < 0) {
+ throw new RuntimeException("Unexpected exit code: " +
exitCode);
+ }
+ }
+
+ @Override
+ public Printer getOut() {
+ return printer;
+ }
+ };
+ }
+
+}
diff --git
a/dsl/camel-jbang/camel-jbang-plugin-test/src/test/resources/my-sample.citrus.it.yaml
b/dsl/camel-jbang/camel-jbang-plugin-test/src/test/resources/my-sample.citrus.it.yaml
new file mode 100644
index 000000000000..cd6a65a9c06d
--- /dev/null
+++
b/dsl/camel-jbang/camel-jbang-plugin-test/src/test/resources/my-sample.citrus.it.yaml
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+name: my-sample.citrus.it
+author: Citrus
+status: FINAL
+description: Sample test in YAML
+variables:
+ - name: message
+ value: Citrus rocks!
+actions:
+ - echo:
+ message: "${message}"