From 829257144f542d083f83237cfdf7d701f8256918 Mon Sep 17 00:00:00 2001 From: Adriano Machado <60320+ammachado@users.noreply.github.com> Date: Tue, 23 Jun 2026 13:36:22 -0400 Subject: [PATCH] CAMEL-23688: camel-jbang - add unit tests for catalog listing commands Adds unit tests for the offline catalog listing commands: component, dataformat, language, other, transformer and dev-console. They load the bundled DefaultCamelCatalog and assert the rendered listing, the --filter narrowing, plus the JSON output and no-match suggestion branches (on the component test). Also fixes a NullPointerException in CatalogBaseCommand's --filter predicate, which dereferenced row description and label without a null check. Transformer catalog models legitimately have a null description and label, so "camel catalog transformer --filter=..." crashed. The filter now null-guards both fields, covering all catalog list commands. Co-Authored-By: Claude Opus 4.8 --- .../commands/catalog/CatalogBaseCommand.java | 5 +- .../catalog/CatalogComponentTest.java | 95 +++++++++++++++++++ .../catalog/CatalogDataFormatTest.java | 61 ++++++++++++ .../catalog/CatalogDevConsoleTest.java | 61 ++++++++++++ .../commands/catalog/CatalogLanguageTest.java | 61 ++++++++++++ .../commands/catalog/CatalogOtherTest.java | 61 ++++++++++++ .../catalog/CatalogTransformerTest.java | 62 ++++++++++++ 7 files changed, 404 insertions(+), 2 deletions(-) create mode 100644 dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogComponentTest.java create mode 100644 dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDataFormatTest.java create mode 100644 dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDevConsoleTest.java create mode 100644 dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogLanguageTest.java create mode 100644 dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogOtherTest.java create mode 100644 dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogTransformerTest.java diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java index f350c154f1536..a83f99aa11136 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java @@ -129,8 +129,9 @@ public Integer doCall() throws Exception { rows = rows.stream() .filter( r -> r.name.equalsIgnoreCase(filterName) - || r.description.toLowerCase(Locale.ROOT).contains(filterName) - || r.label.toLowerCase(Locale.ROOT).contains(filterName)) + || (r.description != null + && r.description.toLowerCase(Locale.ROOT).contains(filterName)) + || (r.label != null && r.label.toLowerCase(Locale.ROOT).contains(filterName))) .collect(Collectors.toList()); } if (sinceBefore != null) { diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogComponentTest.java b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogComponentTest.java new file mode 100644 index 0000000000000..e5dd1ed0a6c99 --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogComponentTest.java @@ -0,0 +1,95 @@ +/* + * 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.catalog; + +import org.apache.camel.dsl.jbang.core.commands.CamelCommandBaseTestSupport; +import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; +import org.apache.camel.dsl.jbang.core.commands.MavenResolverMixin; +import org.apache.camel.util.json.JsonArray; +import org.apache.camel.util.json.JsonObject; +import org.apache.camel.util.json.Jsoner; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class CatalogComponentTest extends CamelCommandBaseTestSupport { + + @Test + void shouldListComponentsFromCatalog() throws Exception { + CatalogComponent command = createCommand(); + + int exit = command.doCall(); + + assertEquals(0, exit); + assertTrue(printer.getOutput().contains("kafka"), + "default listing should include the kafka component, was: " + printer.getOutput()); + } + + @Test + void shouldNarrowToFilteredComponent() throws Exception { + CatalogComponent command = createCommand(); + command.filterName = "kafka"; + + int exit = command.doCall(); + + assertEquals(0, exit); + String out = printer.getOutput(); + assertTrue(out.contains("kafka"), "filtered listing should include kafka, was: " + out); + assertFalse(out.contains("timer"), "filtered listing should exclude unrelated components, was: " + out); + } + + @Test + void shouldRenderJsonOutput() throws Exception { + CatalogComponent command = createCommand(); + command.filterName = "kafka"; + command.jsonOutput = true; + + int exit = command.doCall(); + + assertEquals(0, exit); + JsonArray rows = (JsonArray) Jsoner.deserialize(printer.getOutput()); + assertTrue(rows.stream() + .map(JsonObject.class::cast) + .anyMatch(row -> "kafka".equals(row.getString("name"))), + "JSON output should contain a row with name kafka, was: " + printer.getOutput()); + } + + @Test + void shouldSuggestSimilarWhenFilterHasNoMatch() throws Exception { + CatalogComponent command = createCommand(); + command.filterName = "kafkaa"; + + int exit = command.doCall(); + + assertEquals(0, exit); + String out = printer.getOutput(); + assertTrue(out.contains("No results for filter: kafkaa"), + "should report no results for an unknown filter, was: " + out); + assertTrue(out.contains("camel doc kafkaa"), + "should suggest the doc command for the filter, was: " + out); + } + + private CatalogComponent createCommand() { + CatalogComponent command = new CatalogComponent(new CamelJBangMain().withPrinter(printer)); + // options are normally defaulted by picocli; set them as we construct the command directly + command.sort = "name"; + command.mavenResolver = new MavenResolverMixin(); + return command; + } +} diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDataFormatTest.java b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDataFormatTest.java new file mode 100644 index 0000000000000..93fa0e0b94432 --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDataFormatTest.java @@ -0,0 +1,61 @@ +/* + * 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.catalog; + +import org.apache.camel.dsl.jbang.core.commands.CamelCommandBaseTestSupport; +import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; +import org.apache.camel.dsl.jbang.core.commands.MavenResolverMixin; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class CatalogDataFormatTest extends CamelCommandBaseTestSupport { + + @Test + void shouldListDataFormatsFromCatalog() throws Exception { + CatalogDataFormat command = createCommand(); + + int exit = command.doCall(); + + assertEquals(0, exit); + assertTrue(printer.getOutput().contains("jaxb"), + "default listing should include the jaxb data format, was: " + printer.getOutput()); + } + + @Test + void shouldNarrowToFilteredDataFormat() throws Exception { + CatalogDataFormat command = createCommand(); + command.filterName = "jaxb"; + + int exit = command.doCall(); + + assertEquals(0, exit); + String out = printer.getOutput(); + assertTrue(out.contains("jaxb"), "filtered listing should include jaxb, was: " + out); + assertFalse(out.contains("csv"), "filtered listing should exclude unrelated data formats, was: " + out); + } + + private CatalogDataFormat createCommand() { + CatalogDataFormat command = new CatalogDataFormat(new CamelJBangMain().withPrinter(printer)); + // options are normally defaulted by picocli; set them as we construct the command directly + command.sort = "name"; + command.mavenResolver = new MavenResolverMixin(); + return command; + } +} diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDevConsoleTest.java b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDevConsoleTest.java new file mode 100644 index 0000000000000..185bb32164c71 --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDevConsoleTest.java @@ -0,0 +1,61 @@ +/* + * 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.catalog; + +import org.apache.camel.dsl.jbang.core.commands.CamelCommandBaseTestSupport; +import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; +import org.apache.camel.dsl.jbang.core.commands.MavenResolverMixin; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class CatalogDevConsoleTest extends CamelCommandBaseTestSupport { + + @Test + void shouldListDevConsolesFromCatalog() throws Exception { + CatalogDevConsole command = createCommand(); + + int exit = command.doCall(); + + assertEquals(0, exit); + assertTrue(printer.getOutput().contains("context"), + "default listing should include the context dev-console, was: " + printer.getOutput()); + } + + @Test + void shouldNarrowToFilteredDevConsole() throws Exception { + CatalogDevConsole command = createCommand(); + command.filterName = "context"; + + int exit = command.doCall(); + + assertEquals(0, exit); + String out = printer.getOutput(); + assertTrue(out.contains("context"), "filtered listing should include context, was: " + out); + assertFalse(out.contains("gc"), "filtered listing should exclude unrelated dev-consoles, was: " + out); + } + + private CatalogDevConsole createCommand() { + CatalogDevConsole command = new CatalogDevConsole(new CamelJBangMain().withPrinter(printer)); + // options are normally defaulted by picocli; set them as we construct the command directly + command.sort = "name"; + command.mavenResolver = new MavenResolverMixin(); + return command; + } +} diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogLanguageTest.java b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogLanguageTest.java new file mode 100644 index 0000000000000..d816d0196a8ce --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogLanguageTest.java @@ -0,0 +1,61 @@ +/* + * 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.catalog; + +import org.apache.camel.dsl.jbang.core.commands.CamelCommandBaseTestSupport; +import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; +import org.apache.camel.dsl.jbang.core.commands.MavenResolverMixin; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class CatalogLanguageTest extends CamelCommandBaseTestSupport { + + @Test + void shouldListLanguagesFromCatalog() throws Exception { + CatalogLanguage command = createCommand(); + + int exit = command.doCall(); + + assertEquals(0, exit); + assertTrue(printer.getOutput().contains("simple"), + "default listing should include the simple language, was: " + printer.getOutput()); + } + + @Test + void shouldNarrowToFilteredLanguage() throws Exception { + CatalogLanguage command = createCommand(); + command.filterName = "simple"; + + int exit = command.doCall(); + + assertEquals(0, exit); + String out = printer.getOutput(); + assertTrue(out.contains("simple"), "filtered listing should include simple, was: " + out); + assertFalse(out.contains("xpath"), "filtered listing should exclude unrelated languages, was: " + out); + } + + private CatalogLanguage createCommand() { + CatalogLanguage command = new CatalogLanguage(new CamelJBangMain().withPrinter(printer)); + // options are normally defaulted by picocli; set them as we construct the command directly + command.sort = "name"; + command.mavenResolver = new MavenResolverMixin(); + return command; + } +} diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogOtherTest.java b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogOtherTest.java new file mode 100644 index 0000000000000..849d11994d8b0 --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogOtherTest.java @@ -0,0 +1,61 @@ +/* + * 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.catalog; + +import org.apache.camel.dsl.jbang.core.commands.CamelCommandBaseTestSupport; +import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; +import org.apache.camel.dsl.jbang.core.commands.MavenResolverMixin; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class CatalogOtherTest extends CamelCommandBaseTestSupport { + + @Test + void shouldListOtherArtifactsFromCatalog() throws Exception { + CatalogOther command = createCommand(); + + int exit = command.doCall(); + + assertEquals(0, exit); + assertTrue(printer.getOutput().contains("cli-connector"), + "default listing should include the cli-connector artifact, was: " + printer.getOutput()); + } + + @Test + void shouldNarrowToFilteredArtifact() throws Exception { + CatalogOther command = createCommand(); + command.filterName = "cli-connector"; + + int exit = command.doCall(); + + assertEquals(0, exit); + String out = printer.getOutput(); + assertTrue(out.contains("cli-connector"), "filtered listing should include cli-connector, was: " + out); + assertFalse(out.contains("cloudevents"), "filtered listing should exclude unrelated artifacts, was: " + out); + } + + private CatalogOther createCommand() { + CatalogOther command = new CatalogOther(new CamelJBangMain().withPrinter(printer)); + // options are normally defaulted by picocli; set them as we construct the command directly + command.sort = "name"; + command.mavenResolver = new MavenResolverMixin(); + return command; + } +} diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogTransformerTest.java b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogTransformerTest.java new file mode 100644 index 0000000000000..7ce3f8658d7f6 --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogTransformerTest.java @@ -0,0 +1,62 @@ +/* + * 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.catalog; + +import org.apache.camel.dsl.jbang.core.commands.CamelCommandBaseTestSupport; +import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; +import org.apache.camel.dsl.jbang.core.commands.MavenResolverMixin; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class CatalogTransformerTest extends CamelCommandBaseTestSupport { + + @Test + void shouldListTransformersFromCatalog() throws Exception { + CatalogTransformer command = createCommand(); + + int exit = command.doCall(); + + assertEquals(0, exit); + assertTrue(printer.getOutput().contains("application-octet-stream"), + "default listing should include the application-octet-stream transformer, was: " + printer.getOutput()); + } + + @Test + void shouldNarrowToFilteredTransformer() throws Exception { + CatalogTransformer command = createCommand(); + command.filterName = "application-octet-stream"; + + int exit = command.doCall(); + + assertEquals(0, exit); + String out = printer.getOutput(); + assertTrue(out.contains("application-octet-stream"), + "filtered listing should include application-octet-stream, was: " + out); + assertFalse(out.contains("avro-binary"), "filtered listing should exclude unrelated transformers, was: " + out); + } + + private CatalogTransformer createCommand() { + CatalogTransformer command = new CatalogTransformer(new CamelJBangMain().withPrinter(printer)); + // options are normally defaulted by picocli; set them as we construct the command directly + command.sort = "name"; + command.mavenResolver = new MavenResolverMixin(); + return command; + } +}