From ccc4435556545f58b411692eb76d3c40e5162fd2 Mon Sep 17 00:00:00 2001 From: "Ricardo M." Date: Wed, 2 Oct 2024 14:50:27 +0200 Subject: [PATCH] chore(catalog-generator): Add tests for the Catalog generator At this time, we're adding tests for the `ConfigBean` class and the `GenerateCommandTest` class. fix: https://github.com/KaotoIO/kaoto/issues/1250 --- .../commands/GenerateCommand.java | 14 +- .../generator/CatalogGenerator.java | 375 ++++++++++++++++++ .../generator/CatalogGeneratorBuilder.java | 372 +---------------- .../camelcatalog/model/CatalogLibrary.java | 3 +- .../camelcatalog/beans/ConfigBeanTest.java | 75 ++++ .../commands/GenerateCommandTest.java | 114 ++++++ 6 files changed, 584 insertions(+), 369 deletions(-) create mode 100644 packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/generator/CatalogGenerator.java create mode 100644 packages/catalog-generator/src/test/java/io/kaoto/camelcatalog/beans/ConfigBeanTest.java create mode 100644 packages/catalog-generator/src/test/java/io/kaoto/camelcatalog/commands/GenerateCommandTest.java diff --git a/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/commands/GenerateCommand.java b/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/commands/GenerateCommand.java index e95c35442..20d4b31fe 100644 --- a/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/commands/GenerateCommand.java +++ b/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/commands/GenerateCommand.java @@ -1,22 +1,20 @@ package io.kaoto.camelcatalog.commands; -import java.io.File; -import java.io.IOException; -import java.util.logging.Logger; - -import org.apache.commons.io.FileUtils; - import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; - import io.kaoto.camelcatalog.beans.ConfigBean; import io.kaoto.camelcatalog.generator.CatalogGeneratorBuilder; import io.kaoto.camelcatalog.model.CatalogDefinition; import io.kaoto.camelcatalog.model.CatalogLibrary; +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.util.logging.Logger; public class GenerateCommand implements Runnable { private static final Logger LOGGER = Logger.getLogger(GenerateCommand.class.getName()); - private ConfigBean configBean; + private final ConfigBean configBean; public GenerateCommand(ConfigBean configBean) { this.configBean = configBean; diff --git a/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/generator/CatalogGenerator.java b/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/generator/CatalogGenerator.java new file mode 100644 index 000000000..1a72b9fbe --- /dev/null +++ b/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/generator/CatalogGenerator.java @@ -0,0 +1,375 @@ +package io.kaoto.camelcatalog.generator; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition; +import io.kaoto.camelcatalog.maven.CamelCatalogVersionLoader; +import io.kaoto.camelcatalog.model.CatalogDefinition; +import io.kaoto.camelcatalog.model.CatalogDefinitionEntry; + +import java.io.*; +import java.nio.file.Files; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static io.kaoto.camelcatalog.model.Constants.*; + +public class CatalogGenerator { + private static final Logger LOGGER = Logger.getLogger(CatalogGenerator.class.getName()); + + private static final ObjectMapper jsonMapper = new ObjectMapper() + .configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true); + private static final ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory()); + + private final CatalogGeneratorBuilder catalogGeneratorBuilder; + private final CamelCatalogVersionLoader camelCatalogVersionLoader; + private final File outputDirectory; + private String camelCatalogVersion; + private String kameletsVersion; + private String camelKCRDsVersion; + + CatalogGenerator(CatalogGeneratorBuilder catalogGeneratorBuilder, CamelCatalogVersionLoader camelCatalogVersionLoader, + File outputDirectory) { + this.catalogGeneratorBuilder = catalogGeneratorBuilder; + this.camelCatalogVersionLoader = camelCatalogVersionLoader; + this.outputDirectory = outputDirectory; + } + + public CatalogDefinition generate() { + camelCatalogVersionLoader.loadKameletBoundaries(); + camelCatalogVersionLoader.loadKamelets(kameletsVersion); + camelCatalogVersionLoader.loadKubernetesSchema(); + camelCatalogVersionLoader.loadCamelKCRDs(camelKCRDsVersion); + camelCatalogVersionLoader.loadLocalSchemas(); + camelCatalogVersionLoader.loadCamelYamlDsl(camelCatalogVersion); + camelCatalogVersionLoader.loadCamelCatalog(camelCatalogVersion); + + var catalogDefinition = new CatalogDefinition(); + var yamlDslSchemaProcessor = processCamelSchema(catalogDefinition); + processCatalog(yamlDslSchemaProcessor, catalogDefinition); + processKameletBoundaries(catalogDefinition); + processKamelets(catalogDefinition); + processK8sSchema(catalogDefinition); + processKameletsCRDs(catalogDefinition); + processAdditionalSchemas(catalogDefinition); + + try { + String filename = String.format("%s-%s.json", "index", + Util.generateHash(catalogDefinition.toString())); + + File indexFile = outputDirectory.toPath().resolve(filename).toFile(); + catalogDefinition + .setName("Camel " + camelCatalogVersionLoader.getRuntime().getLabel() + " " + camelCatalogVersion); + catalogDefinition.setVersion(camelCatalogVersion); + catalogDefinition.setRuntime(camelCatalogVersionLoader.getRuntime()); + catalogDefinition.setFileName(indexFile.getName()); + + jsonMapper.writerWithDefaultPrettyPrinter().writeValue(indexFile, catalogDefinition); + + return catalogDefinition; + } catch (Exception e) { + LOGGER.log(Level.SEVERE, e.toString(), e); + } + + return null; + } + + public String getKameletsVersion() { + return kameletsVersion; + } + + public void setKameletsVersion(String kameletsVersion) { + this.kameletsVersion = kameletsVersion; + } + + public String getCamelCatalogVersion() { + return camelCatalogVersion; + } + + public void setCamelCatalogVersion(String camelCatalogVersion) { + this.camelCatalogVersion = camelCatalogVersion; + } + + public String getCamelKCRDsVersion() { + return camelKCRDsVersion; + } + + public void setCamelKCRDsVersion(String camelKCRDsVersion) { + this.camelKCRDsVersion = camelKCRDsVersion; + } + + private CamelYamlDslSchemaProcessor processCamelSchema(CatalogDefinition index) { + if (camelCatalogVersionLoader.getCamelYamlDslSchema() == null) { + LOGGER.severe("Camel YAML DSL JSON Schema is not loaded"); + return null; + } + + var camelYamlDSLSchema07 = camelCatalogVersionLoader.getCamelYamlDslSchema().replace( + "http://json-schema.org/draft-04/schema#", "http://json-schema.org/draft-07/schema#"); + try { + var outputFileName = String.format("%s-%s.json", CAMEL_YAML_DSL_FILE_NAME, + Util.generateHash(camelYamlDSLSchema07)); + var output = outputDirectory.toPath().resolve(outputFileName); + output.getParent().toFile().mkdirs(); + + Files.writeString(output, camelYamlDSLSchema07); + + var indexEntry = new CatalogDefinitionEntry( + CAMEL_YAML_DSL_FILE_NAME, + "Camel YAML DSL JSON schema", + camelCatalogVersion, + outputFileName); + index.getSchemas().put(CAMEL_YAML_DSL_FILE_NAME, indexEntry); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, e.toString(), e); + return null; + } + + try { + var yamlDslSchema = (ObjectNode) jsonMapper.readTree(camelYamlDSLSchema07); + + var schemaProcessor = new CamelYamlDslSchemaProcessor(jsonMapper, yamlDslSchema); + var schemaMap = schemaProcessor.processSubSchema(); + + schemaMap.forEach((name, subSchema) -> { + try { + var subSchemaFileName = String.format( + "%s-%s-%s.json", + CAMEL_YAML_DSL_FILE_NAME, + name, + Util.generateHash(subSchema)); + var subSchemaPath = outputDirectory.toPath().resolve(subSchemaFileName); + subSchemaPath.getParent().toFile().mkdirs(); + Files.writeString(subSchemaPath, subSchema); + var subSchemaIndexEntry = new CatalogDefinitionEntry( + name, + "Camel YAML DSL JSON schema: " + name, + camelCatalogVersion, + subSchemaFileName); + index.getSchemas().put(name, subSchemaIndexEntry); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, e.toString(), e); + } + }); + + return schemaProcessor; + } catch (Exception e) { + LOGGER.log(Level.SEVERE, e.toString(), e); + return null; + } + } + + private void processCatalog(CamelYamlDslSchemaProcessor schemaProcessor, CatalogDefinition index) { + var catalogProcessor = new CamelCatalogProcessor(camelCatalogVersionLoader.getCamelCatalog(), jsonMapper, + schemaProcessor, catalogGeneratorBuilder.getRuntime(), catalogGeneratorBuilder.isVerbose()); + try { + var catalogMap = catalogProcessor.processCatalog(); + catalogMap.forEach((name, catalog) -> { + try { + // Adding Kamelet & Pipe Configuration Schema to the Entities Catalog + if (name.equals("entities")) { + var catalogNode = jsonMapper.readTree(catalog); + String customSchemas[] = {"KameletConfiguration", "PipeConfiguration"}; + for (String customSchema : customSchemas) { + ((ObjectNode) catalogNode).putObject(customSchema) + .putObject("propertiesSchema"); + ((ObjectNode) catalogNode.path(customSchema).path("propertiesSchema")) + .setAll((ObjectNode) jsonMapper.readTree( + camelCatalogVersionLoader.getLocalSchemas().get(customSchema))); + } + + StringWriter writer = new StringWriter(); + var jsonGenerator = new JsonFactory().createGenerator(writer).useDefaultPrettyPrinter(); + jsonMapper.writeTree(jsonGenerator, catalogNode); + catalog = writer.toString(); + } + + var outputFileName = String.format( + "%s-%s-%s.json", CAMEL_CATALOG_AGGREGATE, name, Util.generateHash(catalog)); + var output = outputDirectory.toPath().resolve(outputFileName); + Files.writeString(output, catalog); + var indexEntry = new CatalogDefinitionEntry( + name, + "Aggregated Camel catalog for " + name, + camelCatalogVersion, + outputFileName); + index.getCatalogs().put(name, indexEntry); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, e.toString(), e); + } + }); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, e.toString(), e); + } + } + + private void processKameletBoundaries(CatalogDefinition index) { + if (camelCatalogVersionLoader.getKameletBoundaries().isEmpty()) { + LOGGER.severe("Kamelet boundaries are not loaded"); + return; + } + + var indexEntry = getKameletsEntry(camelCatalogVersionLoader.getKameletBoundaries(), KAMELET_BOUNDARIES_KEY, + KAMELET_BOUNDARIES_FILENAME, "Aggregated Kamelet boundaries in JSON"); + index.getCatalogs().put(indexEntry.name(), indexEntry); + } + + private void processKamelets(CatalogDefinition index) { + if (camelCatalogVersionLoader.getKamelets().isEmpty()) { + LOGGER.severe("Kamelets are not loaded"); + } + + var indexEntry = getKameletsEntry(camelCatalogVersionLoader.getKamelets(), KAMELETS, KAMELETS_AGGREGATE, + "Aggregated Kamelets in JSON"); + index.getCatalogs().put(indexEntry.name(), indexEntry); + } + + private CatalogDefinitionEntry getKameletsEntry(List kamelets, String name, String filename, + String description) { + var root = jsonMapper.createObjectNode(); + + try { + kamelets.forEach(kamelet -> { + processKameletFile(kamelet, root); + }); + + JsonFactory jsonFactory = new JsonFactory(); + var outputStream = new ByteArrayOutputStream(); + var writer = new OutputStreamWriter(outputStream); + + try (JsonGenerator jsonGenerator = jsonFactory.createGenerator(writer).useDefaultPrettyPrinter()) { + jsonMapper.writeTree(jsonGenerator, root); + var rootBytes = outputStream.toByteArray(); + var outputFileName = String.format("%s-%s.json", filename, Util.generateHash(rootBytes)); + var output = outputDirectory.toPath().resolve(outputFileName); + + Files.write(output, rootBytes); + + return new CatalogDefinitionEntry( + name, + description, + kameletsVersion, + outputFileName); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, e.toString(), e); + } + } catch (Exception e) { + LOGGER.log(Level.SEVERE, e.toString(), e); + } + + return null; + } + + private void processKameletFile(String kamelet, ObjectNode targetObject) { + try { + JsonNode kameletNode = yamlMapper.readTree(kamelet); + String lowerFileName = kameletNode.get("metadata").get("name").asText().toLowerCase(); + + KameletProcessor.process((ObjectNode) kameletNode); + targetObject.putIfAbsent(lowerFileName, kameletNode); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, e.toString(), e); + } + } + + private void processK8sSchema(CatalogDefinition index) { + if (camelCatalogVersionLoader.getKubernetesSchema() == null) { + LOGGER.severe("Kubernetes JSON Schema is not loaded"); + } + + try { + var openapiSpec = (ObjectNode) jsonMapper.readTree(camelCatalogVersionLoader.getKubernetesSchema()); + var processor = new K8sSchemaProcessor(jsonMapper, openapiSpec); + var schemaMap = processor.processK8sDefinitions(KUBERNETES_DEFINITIONS); + for (var entry : schemaMap.entrySet()) { + var name = entry.getKey(); + var schema = entry.getValue(); + var outputFileName = String.format("%s-%s-%s.json", K8S_V1_OPENAPI, name, + Util.generateHash(schema)); + var output = outputDirectory.toPath().resolve(outputFileName); + Files.writeString(output, schema); + var indexEntry = new CatalogDefinitionEntry( + name, + "Kubernetes OpenAPI JSON schema: " + name, + "v1", + outputFileName); + index.getSchemas().put(name, indexEntry); + } + } catch (Exception e) { + LOGGER.log(Level.SEVERE, e.toString(), e); + } + } + + private void processKameletsCRDs(CatalogDefinition index) { + if (camelCatalogVersionLoader.getCamelKCRDs().isEmpty()) { + LOGGER.severe("CamelK CRDs are not loaded"); + return; + } + + camelCatalogVersionLoader.getCamelKCRDs().forEach(crdString -> { + processKameletCRD(crdString, index); + }); + } + + private void processKameletCRD(String crdString, CatalogDefinition index) { + try { + var crd = yamlMapper.readValue(crdString, CustomResourceDefinition.class); + var schema = crd.getSpec().getVersions().get(0).getSchema().getOpenAPIV3Schema(); + var name = crd.getSpec().getNames().getKind(); + + var bytes = jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsBytes(schema); + var outputFileName = String.format( + "%s-%s-%s.json", CRD_SCHEMA, name.toLowerCase(), Util.generateHash(bytes)); + + var output = outputDirectory.toPath().resolve(outputFileName); + Files.write(output, bytes); + var description = name; + + var indexEntry = new CatalogDefinitionEntry( + name, + description, + camelKCRDsVersion, + outputFileName); + index.getSchemas().put(name, indexEntry); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, e.toString(), e); + } + } + + private void processAdditionalSchemas(CatalogDefinition index) { + if (camelCatalogVersionLoader.getLocalSchemas().isEmpty()) { + LOGGER.severe("Local schemas are not loaded"); + return; + } + + for (var localSchemaEntry : camelCatalogVersionLoader.getLocalSchemas().entrySet()) { + try { + var schema = (ObjectNode) jsonMapper.readTree(localSchemaEntry.getValue()); + var name = localSchemaEntry.getKey(); + var description = schema.get("description").asText(); + + var outputFileName = String.format("%s-%s.%s", localSchemaEntry.getKey(), + Util.generateHash(localSchemaEntry.getValue()), "json"); + var output = outputDirectory.toPath().resolve(outputFileName); + + Files.writeString(output, localSchemaEntry.getValue()); + + var indexEntry = new CatalogDefinitionEntry( + name, + description, + "1", + outputFileName); + + index.getSchemas().put(name, indexEntry); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, e.toString(), e); + } + } + } +} diff --git a/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/generator/CatalogGeneratorBuilder.java b/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/generator/CatalogGeneratorBuilder.java index fb1e7a227..1cd620d8f 100644 --- a/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/generator/CatalogGeneratorBuilder.java +++ b/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/generator/CatalogGeneratorBuilder.java @@ -15,38 +15,9 @@ */ package io.kaoto.camelcatalog.generator; -import static io.kaoto.camelcatalog.model.Constants.CAMEL_CATALOG_AGGREGATE; -import static io.kaoto.camelcatalog.model.Constants.CAMEL_YAML_DSL_FILE_NAME; -import static io.kaoto.camelcatalog.model.Constants.CRD_SCHEMA; -import static io.kaoto.camelcatalog.model.Constants.K8S_V1_OPENAPI; -import static io.kaoto.camelcatalog.model.Constants.KAMELETS; -import static io.kaoto.camelcatalog.model.Constants.KAMELETS_AGGREGATE; -import static io.kaoto.camelcatalog.model.Constants.KAMELET_BOUNDARIES_FILENAME; -import static io.kaoto.camelcatalog.model.Constants.KAMELET_BOUNDARIES_KEY; -import static io.kaoto.camelcatalog.model.Constants.KUBERNETES_DEFINITIONS; - -import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.StringWriter; -import java.nio.file.Files; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition; import io.kaoto.camelcatalog.maven.CamelCatalogVersionLoader; -import io.kaoto.camelcatalog.model.CatalogDefinition; -import io.kaoto.camelcatalog.model.CatalogDefinitionEntry; import io.kaoto.camelcatalog.model.CatalogRuntime; /** @@ -103,340 +74,21 @@ public CatalogGeneratorBuilder withVerbose(boolean verbose) { return this; } + public CatalogRuntime getRuntime() { + return runtime; + } + + public boolean isVerbose() { + return verbose; + } + public CatalogGenerator build() { CamelCatalogVersionLoader camelCatalogVersionLoader = new CamelCatalogVersionLoader(runtime, verbose); - var catalogGenerator = new CatalogGenerator(camelCatalogVersionLoader, runtime, outputDirectory); - catalogGenerator.camelCatalogVersion = camelCatalogVersion; - catalogGenerator.kameletsVersion = kameletsVersion; - catalogGenerator.camelKCRDsVersion = camelKCRDsVersion; + var catalogGenerator = new CatalogGenerator(this, camelCatalogVersionLoader, outputDirectory); + catalogGenerator.setCamelCatalogVersion(camelCatalogVersion); + catalogGenerator.setKameletsVersion(kameletsVersion); + catalogGenerator.setCamelKCRDsVersion(camelKCRDsVersion); return catalogGenerator; } - public class CatalogGenerator { - private static final Logger LOGGER = Logger.getLogger(CatalogGenerator.class.getName()); - - private static final ObjectMapper jsonMapper = new ObjectMapper() - .configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true); - private static final ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory()); - - private CamelCatalogVersionLoader camelCatalogVersionLoader; - private File outputDirectory; - private String camelCatalogVersion; - private String kameletsVersion; - private String camelKCRDsVersion; - - private CatalogGenerator(CamelCatalogVersionLoader camelCatalogVersionLoader, CatalogRuntime runtime, - File outputDirectory) { - this.camelCatalogVersionLoader = camelCatalogVersionLoader; - this.outputDirectory = outputDirectory; - } - - public CatalogDefinition generate() { - camelCatalogVersionLoader.loadKameletBoundaries(); - camelCatalogVersionLoader.loadKamelets(kameletsVersion); - camelCatalogVersionLoader.loadKubernetesSchema(); - camelCatalogVersionLoader.loadCamelKCRDs(camelKCRDsVersion); - camelCatalogVersionLoader.loadLocalSchemas(); - camelCatalogVersionLoader.loadCamelYamlDsl(camelCatalogVersion); - camelCatalogVersionLoader.loadCamelCatalog(camelCatalogVersion); - - var catalogDefinition = new CatalogDefinition(); - var yamlDslSchemaProcessor = processCamelSchema(catalogDefinition); - processCatalog(yamlDslSchemaProcessor, catalogDefinition); - processKameletBoundaries(catalogDefinition); - processKamelets(catalogDefinition); - processK8sSchema(catalogDefinition); - processKameletsCRDs(catalogDefinition); - processAdditionalSchemas(catalogDefinition); - - try { - String filename = String.format("%s-%s.json", "index", - Util.generateHash(catalogDefinition.toString())); - - File indexFile = outputDirectory.toPath().resolve(filename).toFile(); - catalogDefinition - .setName("Camel " + camelCatalogVersionLoader.getRuntime().getLabel() + " " + camelCatalogVersion); - catalogDefinition.setVersion(camelCatalogVersion); - catalogDefinition.setRuntime(camelCatalogVersionLoader.getRuntime()); - catalogDefinition.setFileName(indexFile.getName()); - - jsonMapper.writerWithDefaultPrettyPrinter().writeValue(indexFile, catalogDefinition); - - return catalogDefinition; - } catch (Exception e) { - LOGGER.log(Level.SEVERE, e.toString(), e); - } - - return null; - } - - private CamelYamlDslSchemaProcessor processCamelSchema(CatalogDefinition index) { - if (camelCatalogVersionLoader.getCamelYamlDslSchema() == null) { - LOGGER.severe("Camel YAML DSL JSON Schema is not loaded"); - return null; - } - - var camelYamlDSLSchema07 = camelCatalogVersionLoader.getCamelYamlDslSchema().replace( - "http://json-schema.org/draft-04/schema#", "http://json-schema.org/draft-07/schema#"); - try { - var outputFileName = String.format("%s-%s.json", CAMEL_YAML_DSL_FILE_NAME, - Util.generateHash(camelYamlDSLSchema07)); - var output = outputDirectory.toPath().resolve(outputFileName); - output.getParent().toFile().mkdirs(); - - Files.writeString(output, camelYamlDSLSchema07); - - var indexEntry = new CatalogDefinitionEntry( - CAMEL_YAML_DSL_FILE_NAME, - "Camel YAML DSL JSON schema", - camelCatalogVersion, - outputFileName); - index.getSchemas().put(CAMEL_YAML_DSL_FILE_NAME, indexEntry); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, e.toString(), e); - return null; - } - - try { - var yamlDslSchema = (ObjectNode) jsonMapper.readTree(camelYamlDSLSchema07); - - var schemaProcessor = new CamelYamlDslSchemaProcessor(jsonMapper, yamlDslSchema); - var schemaMap = schemaProcessor.processSubSchema(); - - schemaMap.forEach((name, subSchema) -> { - try { - var subSchemaFileName = String.format( - "%s-%s-%s.json", - CAMEL_YAML_DSL_FILE_NAME, - name, - Util.generateHash(subSchema)); - var subSchemaPath = outputDirectory.toPath().resolve(subSchemaFileName); - subSchemaPath.getParent().toFile().mkdirs(); - Files.writeString(subSchemaPath, subSchema); - var subSchemaIndexEntry = new CatalogDefinitionEntry( - name, - "Camel YAML DSL JSON schema: " + name, - camelCatalogVersion, - subSchemaFileName); - index.getSchemas().put(name, subSchemaIndexEntry); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, e.toString(), e); - } - }); - - return schemaProcessor; - } catch (Exception e) { - LOGGER.log(Level.SEVERE, e.toString(), e); - return null; - } - } - - private void processCatalog(CamelYamlDslSchemaProcessor schemaProcessor, CatalogDefinition index) { - var catalogProcessor = new CamelCatalogProcessor(camelCatalogVersionLoader.getCamelCatalog(), jsonMapper, - schemaProcessor, runtime, verbose); - try { - var catalogMap = catalogProcessor.processCatalog(); - catalogMap.forEach((name, catalog) -> { - try { - // Adding Kamelet & Pipe Configuration Schema to the Entities Catalog - if (name.equals("entities")) { - var catalogNode = jsonMapper.readTree(catalog); - String customSchemas[] = { "KameletConfiguration", "PipeConfiguration" }; - for (String customSchema : customSchemas) { - ((ObjectNode) catalogNode).putObject(customSchema) - .putObject("propertiesSchema"); - ((ObjectNode) catalogNode.path(customSchema).path("propertiesSchema")) - .setAll((ObjectNode) jsonMapper.readTree( - camelCatalogVersionLoader.getLocalSchemas().get(customSchema))); - } - - StringWriter writer = new StringWriter(); - var jsonGenerator = new JsonFactory().createGenerator(writer).useDefaultPrettyPrinter(); - jsonMapper.writeTree(jsonGenerator, catalogNode); - catalog = writer.toString(); - } - - var outputFileName = String.format( - "%s-%s-%s.json", CAMEL_CATALOG_AGGREGATE, name, Util.generateHash(catalog)); - var output = outputDirectory.toPath().resolve(outputFileName); - Files.writeString(output, catalog); - var indexEntry = new CatalogDefinitionEntry( - name, - "Aggregated Camel catalog for " + name, - camelCatalogVersion, - outputFileName); - index.getCatalogs().put(name, indexEntry); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, e.toString(), e); - } - }); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, e.toString(), e); - } - } - - private void processKameletBoundaries(CatalogDefinition index) { - if (camelCatalogVersionLoader.getKameletBoundaries().isEmpty()) { - LOGGER.severe("Kamelet boundaries are not loaded"); - return; - } - - var indexEntry = getKameletsEntry(camelCatalogVersionLoader.getKameletBoundaries(), KAMELET_BOUNDARIES_KEY, - KAMELET_BOUNDARIES_FILENAME, "Aggregated Kamelet boundaries in JSON"); - index.getCatalogs().put(indexEntry.name(), indexEntry); - } - - private void processKamelets(CatalogDefinition index) { - if (camelCatalogVersionLoader.getKamelets().isEmpty()) { - LOGGER.severe("Kamelets are not loaded"); - } - - var indexEntry = getKameletsEntry(camelCatalogVersionLoader.getKamelets(), KAMELETS, KAMELETS_AGGREGATE, - "Aggregated Kamelets in JSON"); - index.getCatalogs().put(indexEntry.name(), indexEntry); - } - - private CatalogDefinitionEntry getKameletsEntry(List kamelets, String name, String filename, - String description) { - var root = jsonMapper.createObjectNode(); - - try { - kamelets.forEach(kamelet -> { - processKameletFile(kamelet, root); - }); - - JsonFactory jsonFactory = new JsonFactory(); - var outputStream = new ByteArrayOutputStream(); - var writer = new OutputStreamWriter(outputStream); - - try (JsonGenerator jsonGenerator = jsonFactory.createGenerator(writer).useDefaultPrettyPrinter()) { - jsonMapper.writeTree(jsonGenerator, root); - var rootBytes = outputStream.toByteArray(); - var outputFileName = String.format("%s-%s.json", filename, Util.generateHash(rootBytes)); - var output = outputDirectory.toPath().resolve(outputFileName); - - Files.write(output, rootBytes); - - return new CatalogDefinitionEntry( - name, - description, - kameletsVersion, - outputFileName); - } catch (IOException e) { - LOGGER.log(Level.SEVERE, e.toString(), e); - } - } catch (Exception e) { - LOGGER.log(Level.SEVERE, e.toString(), e); - } - - return null; - } - - private void processKameletFile(String kamelet, ObjectNode targetObject) { - try { - JsonNode kameletNode = yamlMapper.readTree(kamelet); - String lowerFileName = kameletNode.get("metadata").get("name").asText().toLowerCase(); - - KameletProcessor.process((ObjectNode) kameletNode); - targetObject.putIfAbsent(lowerFileName, kameletNode); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, e.toString(), e); - } - } - - private void processK8sSchema(CatalogDefinition index) { - if (camelCatalogVersionLoader.getKubernetesSchema() == null) { - LOGGER.severe("Kubernetes JSON Schema is not loaded"); - } - - try { - var openapiSpec = (ObjectNode) jsonMapper.readTree(camelCatalogVersionLoader.getKubernetesSchema()); - var processor = new K8sSchemaProcessor(jsonMapper, openapiSpec); - var schemaMap = processor.processK8sDefinitions(KUBERNETES_DEFINITIONS); - for (var entry : schemaMap.entrySet()) { - var name = entry.getKey(); - var schema = entry.getValue(); - var outputFileName = String.format("%s-%s-%s.json", K8S_V1_OPENAPI, name, - Util.generateHash(schema)); - var output = outputDirectory.toPath().resolve(outputFileName); - Files.writeString(output, schema); - var indexEntry = new CatalogDefinitionEntry( - name, - "Kubernetes OpenAPI JSON schema: " + name, - "v1", - outputFileName); - index.getSchemas().put(name, indexEntry); - } - } catch (Exception e) { - LOGGER.log(Level.SEVERE, e.toString(), e); - } - } - - private void processKameletsCRDs(CatalogDefinition index) { - if (camelCatalogVersionLoader.getCamelKCRDs().isEmpty()) { - LOGGER.severe("CamelK CRDs are not loaded"); - return; - } - - camelCatalogVersionLoader.getCamelKCRDs().forEach(crdString -> { - processKameletCRD(crdString, index); - }); - } - - private void processKameletCRD(String crdString, CatalogDefinition index) { - try { - var crd = yamlMapper.readValue(crdString, CustomResourceDefinition.class); - var schema = crd.getSpec().getVersions().get(0).getSchema().getOpenAPIV3Schema(); - var name = crd.getSpec().getNames().getKind(); - - var bytes = jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsBytes(schema); - var outputFileName = String.format( - "%s-%s-%s.json", CRD_SCHEMA, name.toLowerCase(), Util.generateHash(bytes)); - - var output = outputDirectory.toPath().resolve(outputFileName); - Files.write(output, bytes); - var description = name; - - var indexEntry = new CatalogDefinitionEntry( - name, - description, - camelKCRDsVersion, - outputFileName); - index.getSchemas().put(name, indexEntry); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, e.toString(), e); - } - } - - private void processAdditionalSchemas(CatalogDefinition index) { - if (camelCatalogVersionLoader.getLocalSchemas().isEmpty()) { - LOGGER.severe("Local schemas are not loaded"); - return; - } - - for (var localSchemaEntry : camelCatalogVersionLoader.getLocalSchemas().entrySet()) { - try { - var schema = (ObjectNode) jsonMapper.readTree(localSchemaEntry.getValue()); - var name = localSchemaEntry.getKey(); - var description = schema.get("description").asText(); - - var outputFileName = String.format("%s-%s.%s", localSchemaEntry.getKey(), - Util.generateHash(localSchemaEntry.getValue()), "json"); - var output = outputDirectory.toPath().resolve(outputFileName); - - Files.writeString(output, localSchemaEntry.getValue()); - - var indexEntry = new CatalogDefinitionEntry( - name, - description, - "1", - outputFileName); - - index.getSchemas().put(name, indexEntry); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, e.toString(), e); - } - } - } - } } diff --git a/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/model/CatalogLibrary.java b/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/model/CatalogLibrary.java index c539656b3..4041c7440 100644 --- a/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/model/CatalogLibrary.java +++ b/packages/catalog-generator/src/main/java/io/kaoto/camelcatalog/model/CatalogLibrary.java @@ -4,8 +4,9 @@ import java.util.List; public class CatalogLibrary { + /* Visible for testing */ + public List definitions = new ArrayList<>(); private String name; - private List definitions = new ArrayList<>(); public String getName() { return name; diff --git a/packages/catalog-generator/src/test/java/io/kaoto/camelcatalog/beans/ConfigBeanTest.java b/packages/catalog-generator/src/test/java/io/kaoto/camelcatalog/beans/ConfigBeanTest.java new file mode 100644 index 000000000..be9d6d105 --- /dev/null +++ b/packages/catalog-generator/src/test/java/io/kaoto/camelcatalog/beans/ConfigBeanTest.java @@ -0,0 +1,75 @@ +package io.kaoto.camelcatalog.beans; + +import io.kaoto.camelcatalog.model.CatalogCliArgument; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class ConfigBeanTest { + + @Test + void testGetOutputFolder() { + ConfigBean configBean = new ConfigBean(); + assertNull(configBean.getOutputFolder()); + } + + @Test + void testSetOutputFolder() { + ConfigBean configBean = new ConfigBean(); + configBean.setOutputFolder("outputFolder"); + assertEquals("outputFolder", configBean.getOutputFolder().getPath()); + } + + @Test + void testGetCatalogsName() { + ConfigBean configBean = new ConfigBean(); + assertNull(configBean.getCatalogsName()); + } + + @Test + void testSetCatalogsName() { + ConfigBean configBean = new ConfigBean(); + configBean.setCatalogsName("catalogsName"); + assertEquals("catalogsName", configBean.getCatalogsName()); + } + + @Test + void testAddCatalogVersion() { + ConfigBean configBean = new ConfigBean(); + CatalogCliArgument catalogCliArgument = new CatalogCliArgument(); + configBean.addCatalogVersion(catalogCliArgument); + assertTrue(configBean.getCatalogVersionSet().contains(catalogCliArgument)); + } + + @Test + void testGetCatalogVersionSet() { + ConfigBean configBean = new ConfigBean(); + assertNotNull(configBean.getCatalogVersionSet()); + } + + @Test + void testGetKameletsVersion() { + ConfigBean configBean = new ConfigBean(); + assertNull(configBean.getKameletsVersion()); + } + + @Test + void testSetKameletsVersion() { + ConfigBean configBean = new ConfigBean(); + configBean.setKameletsVersion("kameletsVersion"); + assertEquals("kameletsVersion", configBean.getKameletsVersion()); + } + + @Test + void testIsVerbose() { + ConfigBean configBean = new ConfigBean(); + assertFalse(configBean.isVerbose()); + } + + @Test + void testSetVerbose() { + ConfigBean configBean = new ConfigBean(); + configBean.setVerbose(true); + assertTrue(configBean.isVerbose()); + } +} \ No newline at end of file diff --git a/packages/catalog-generator/src/test/java/io/kaoto/camelcatalog/commands/GenerateCommandTest.java b/packages/catalog-generator/src/test/java/io/kaoto/camelcatalog/commands/GenerateCommandTest.java new file mode 100644 index 000000000..76b2ecb17 --- /dev/null +++ b/packages/catalog-generator/src/test/java/io/kaoto/camelcatalog/commands/GenerateCommandTest.java @@ -0,0 +1,114 @@ +package io.kaoto.camelcatalog.commands; + +import io.kaoto.camelcatalog.beans.ConfigBean; +import io.kaoto.camelcatalog.generator.CatalogGenerator; +import io.kaoto.camelcatalog.generator.CatalogGeneratorBuilder; +import io.kaoto.camelcatalog.model.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.util.ArrayList; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; + +class GenerateCommandTest { + @TempDir + File tempDir; + + private GenerateCommand generateCommand; + private CatalogDefinition catalogDefinition; + + @BeforeEach + void setUp() { + catalogDefinition = new CatalogDefinition(); + catalogDefinition.setFileName("index.json"); + catalogDefinition.setName("test-camel-catalog"); + catalogDefinition.setVersion("4.8.0"); + catalogDefinition.setRuntime(CatalogRuntime.Main); + + CatalogCliArgument catalogCliArg = new CatalogCliArgument(); + catalogCliArg.setRuntime(CatalogRuntime.Main); + catalogCliArg.setCatalogVersion("4.8.0"); + + ConfigBean configBean = new ConfigBean(); + configBean.setOutputFolder(tempDir.toString()); + configBean.setCatalogsName("test-camel-catalog"); + configBean.addCatalogVersion(catalogCliArg); + configBean.setKameletsVersion("1.0.0"); + + generateCommand = new GenerateCommand(configBean); + } + + @Test + void testGeneratorCalledWithCorrectParameters() { + try (var mockedBuilder = mockConstruction(CatalogGeneratorBuilder.class, (mockBuilder, context) -> { + when(mockBuilder.withRuntime(any(CatalogRuntime.class))).thenCallRealMethod().thenReturn(mockBuilder); + when(mockBuilder.withCamelCatalogVersion(anyString())).thenCallRealMethod().thenReturn(mockBuilder); + when(mockBuilder.withKameletsVersion(anyString())).thenCallRealMethod().thenReturn(mockBuilder); + when(mockBuilder.withCamelKCRDsVersion(anyString())).thenCallRealMethod().thenReturn(mockBuilder); + + when(mockBuilder.withOutputDirectory(any(File.class))).thenReturn(mockBuilder); + when(mockBuilder.build()).thenAnswer(invocation -> { + CatalogGenerator catalogGenerator = mock(CatalogGenerator.class); + when(catalogGenerator.generate()).thenReturn(catalogDefinition); + return catalogGenerator; + }); + })) { + generateCommand.run(); + + CatalogGeneratorBuilder builder = mockedBuilder.constructed().getFirst(); + + verify(builder, times(1)).withRuntime(CatalogRuntime.Main); + verify(builder, times(1)).withCamelCatalogVersion("4.8.0"); + verify(builder, times(1)).withKameletsVersion("1.0.0"); + verify(builder, times(1)).withCamelKCRDsVersion("2.3.1"); + + File expectedFolder = new File(tempDir, "camel-main/4.8.0"); + verify(builder, times(1)).withOutputDirectory(expectedFolder); + + assertEquals(catalogDefinition.getFileName(), "camel-main/4.8.0/index.json"); + } + } + + @Test + void testCatalogLibraryOutput() { + try ( + var mockedBuilder = mockConstruction(CatalogGeneratorBuilder.class, (mockBuilder, context) -> { + when(mockBuilder.withRuntime(any(CatalogRuntime.class))).thenCallRealMethod().thenReturn(mockBuilder); + when(mockBuilder.withCamelCatalogVersion(anyString())).thenCallRealMethod().thenReturn(mockBuilder); + when(mockBuilder.withKameletsVersion(anyString())).thenCallRealMethod().thenReturn(mockBuilder); + when(mockBuilder.withCamelKCRDsVersion(anyString())).thenCallRealMethod().thenReturn(mockBuilder); + + when(mockBuilder.withOutputDirectory(any(File.class))).thenReturn(mockBuilder); + when(mockBuilder.build()).thenAnswer(invocation -> { + CatalogGenerator catalogGenerator = mock(CatalogGenerator.class); + when(catalogGenerator.generate()).thenReturn(catalogDefinition); + return catalogGenerator; + }); + }); + var mockedLibrary = mockConstruction(CatalogLibrary.class, (mockLibrary, context) -> { + mockLibrary.definitions = new ArrayList<>(); + doCallRealMethod().when(mockLibrary).getName(); + doCallRealMethod().when(mockLibrary).setName(anyString()); + doCallRealMethod().when(mockLibrary).getDefinitions(); + doCallRealMethod().when(mockLibrary).addDefinition(any(CatalogDefinition.class)); + }) + ) { + generateCommand.run(); + + CatalogLibrary library = mockedLibrary.constructed().getFirst(); + + assertEquals(library.getName(), "test-camel-catalog"); + assertEquals(library.getDefinitions().size(), 1); + + CatalogLibraryEntry catalogLibraryEntry = library.getDefinitions().getFirst(); + assertEquals(catalogLibraryEntry.name(), "test-camel-catalog"); + assertEquals(catalogLibraryEntry.version(), "4.8.0"); + assertEquals(catalogLibraryEntry.runtime(), "Main"); + assertEquals(catalogLibraryEntry.fileName(), "camel-main/4.8.0/index.json"); + } + } +} \ No newline at end of file