From: Tian Lee Date: Fri, 6 Jul 2018 10:32:55 +0000 (+0000) Subject: Merge "Test coverage and refactor for GeneratorUtil" X-Git-Tag: 1.3.0~29 X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=5b6b32d3ab0dc27c72351f6aa9e0bdef8d599e13;hp=9cd520cdd384ce196800c802118e25d89fd653fd;p=aai%2Fbabel.git Merge "Test coverage and refactor for GeneratorUtil" --- diff --git a/pom.xml b/pom.xml index 493012f..8543177 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ - 1.5.12.RELEASE + 1.5.14.RELEASE UTF-8 UTF-8 @@ -62,6 +62,7 @@ 1.3.0 1.6 1.2.3 + 25.1-jre @@ -131,6 +132,12 @@ sdc-tosca ${sdc.tosca.version} + + com.google.guava + guava + ${guava.version} + + org.onap.aai rest-client @@ -365,7 +372,7 @@ true docker-hub - onap/${project.artifactId} + ${docker.push.registry}/onap/${project.artifactId} ${docker.location} latest diff --git a/src/main/java/org/onap/aai/babel/csar/vnfcatalog/VnfVendorImageExtractor.java b/src/main/java/org/onap/aai/babel/csar/vnfcatalog/VnfVendorImageExtractor.java index 9836e2a..b7d79a0 100644 --- a/src/main/java/org/onap/aai/babel/csar/vnfcatalog/VnfVendorImageExtractor.java +++ b/src/main/java/org/onap/aai/babel/csar/vnfcatalog/VnfVendorImageExtractor.java @@ -30,7 +30,6 @@ import java.util.Map.Entry; import java.util.Objects; import java.util.function.Consumer; import java.util.stream.Collectors; - import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.time.StopWatch; import org.apache.commons.lang3.tuple.ImmutablePair; diff --git a/src/main/java/org/onap/aai/babel/parser/ArtifactGeneratorToscaParser.java b/src/main/java/org/onap/aai/babel/parser/ArtifactGeneratorToscaParser.java index 70e78ec..c769e9a 100644 --- a/src/main/java/org/onap/aai/babel/parser/ArtifactGeneratorToscaParser.java +++ b/src/main/java/org/onap/aai/babel/parser/ArtifactGeneratorToscaParser.java @@ -18,12 +18,8 @@ * limitations under the License. * ============LICENSE_END========================================================= */ -package org.onap.aai.babel.parser; -import static org.onap.aai.babel.xml.generator.data.GeneratorConstants.GENERATOR_AAI_CONFIGFILE_NOT_FOUND; -import static org.onap.aai.babel.xml.generator.data.GeneratorConstants.GENERATOR_AAI_CONFIGLOCATION_NOT_FOUND; -import static org.onap.aai.babel.xml.generator.data.GeneratorConstants.GENERATOR_AAI_PROVIDING_SERVICE_METADATA_MISSING; -import static org.onap.aai.babel.xml.generator.data.GeneratorConstants.GENERATOR_AAI_PROVIDING_SERVICE_MISSING; +package org.onap.aai.babel.parser; import java.io.File; import java.io.FileInputStream; @@ -33,9 +29,7 @@ import java.util.List; import java.util.Map; import java.util.Properties; import java.util.stream.Collectors; - import org.onap.aai.babel.logging.LogHelper; -import org.onap.aai.babel.xml.generator.data.GeneratorConstants; import org.onap.aai.babel.xml.generator.data.WidgetConfigurationUtil; import org.onap.aai.babel.xml.generator.model.AllotedResource; import org.onap.aai.babel.xml.generator.model.L3NetworkWidget; @@ -55,11 +49,26 @@ import org.onap.sdc.toscaparser.api.Property; public class ArtifactGeneratorToscaParser { - public static final String GENERATOR_AAI_ERROR_INVALID_ID = - "Invalid value for mandatory attribute <%s> in Artifact: <%s>"; + private static Logger log = LogHelper.INSTANCE; + + public static final String PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE = "artifactgenerator.config"; + + private static final String GENERATOR_AAI_CONFIGFILE_NOT_FOUND = + "Cannot generate artifacts. Artifact Generator Configuration file not found at %s"; + private static final String GENERATOR_AAI_CONFIGLOCATION_NOT_FOUND = + "Cannot generate artifacts. artifactgenerator.config system property not configured"; + private static final String GENERATOR_AAI_PROVIDING_SERVICE_METADATA_MISSING = + "Cannot generate artifacts. Providing Service Metadata is missing for allotted resource %s"; + private static final String GENERATOR_AAI_PROVIDING_SERVICE_MISSING = + "Cannot generate artifacts. Providing Service is missing for allotted resource %s"; + + // Metadata properties + private static final String CATEGORY = "category"; private static final String ALLOTTED_RESOURCE = "Allotted Resource"; + private static final String SUBCATEGORY = "subcategory"; private static final String TUNNEL_XCONNECT = "Tunnel XConnect"; - private static Logger log = LogHelper.INSTANCE; + + private static final String VERSION = "version"; private ISdcCsarHelper csarHelper; @@ -95,7 +104,7 @@ public class ArtifactGeneratorToscaParser { */ public static void initWidgetConfiguration() throws IOException { log.debug("Getting Widget Configuration"); - String configLocation = System.getProperty(GeneratorConstants.PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE); + String configLocation = System.getProperty(PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE); if (configLocation != null) { File file = new File(configLocation); if (file.exists()) { @@ -111,7 +120,7 @@ public class ArtifactGeneratorToscaParser { } /** - * Generates a Resource List using input Service Node Templates + * Generates a Resource List using input Service Node Templates. * * @param serviceNodes input Service Node Templates * @param idTypeStore ID->Type mapping @@ -254,11 +263,11 @@ public class ArtifactGeneratorToscaParser { } private boolean hasAllottedResource(Map metadata) { - return ALLOTTED_RESOURCE.equals(metadata.get(GeneratorConstants.CATEGORY)); + return ALLOTTED_RESOURCE.equals(metadata.get(CATEGORY)); } private boolean hasSubCategoryTunnelXConnect(Map metadata) { - return TUNNEL_XCONNECT.equals(metadata.get(GeneratorConstants.SUBCATEGORY)); + return TUNNEL_XCONNECT.equals(metadata.get(SUBCATEGORY)); } /** @@ -286,7 +295,7 @@ public class ArtifactGeneratorToscaParser { String.format(GENERATOR_AAI_PROVIDING_SERVICE_METADATA_MISSING, model.getModelId())); } Map properties = populateStringProperties(nodeProperties); - properties.put(GeneratorConstants.VERSION, "1.0"); + properties.put(VERSION, "1.0"); resourceNode.populateModelIdentificationInformation(properties); model.addResource((Resource) resourceNode); } else if (resourceNode instanceof Resource && !(resourceNode.getWidgetType().equals(Widget.Type.L3_NET))) { diff --git a/src/main/java/org/onap/aai/babel/xml/generator/api/AaiArtifactGenerator.java b/src/main/java/org/onap/aai/babel/xml/generator/api/AaiArtifactGenerator.java index c6ca460..79c7492 100644 --- a/src/main/java/org/onap/aai/babel/xml/generator/api/AaiArtifactGenerator.java +++ b/src/main/java/org/onap/aai/babel/xml/generator/api/AaiArtifactGenerator.java @@ -1,5 +1,5 @@ /** - * ============LICENSE_START======================================================= + * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. @@ -26,7 +26,6 @@ import java.nio.file.Path; import java.util.HashMap; import java.util.List; import java.util.Map; - import org.apache.commons.io.FileUtils; import org.onap.aai.babel.logging.ApplicationMsgs; import org.onap.aai.babel.logging.LogHelper; @@ -35,7 +34,6 @@ import org.onap.aai.babel.xml.generator.data.AdditionalParams; import org.onap.aai.babel.xml.generator.data.Artifact; import org.onap.aai.babel.xml.generator.data.ArtifactType; import org.onap.aai.babel.xml.generator.data.GenerationData; -import org.onap.aai.babel.xml.generator.data.GeneratorConstants; import org.onap.aai.babel.xml.generator.data.GeneratorUtil; import org.onap.aai.babel.xml.generator.data.GroupType; import org.onap.aai.babel.xml.generator.model.Model; @@ -49,10 +47,16 @@ import org.slf4j.MDC; public class AaiArtifactGenerator implements ArtifactGenerator { - private static final String ARTIFACT_MODEL_INFO = "ARTIFACT_MODEL_INFO"; - private static Logger log = LogHelper.INSTANCE; + private static final String MDC_PARAM_MODEL_INFO = "ARTIFACT_MODEL_INFO"; + private static final String GENERATOR_AAI_GENERATED_ARTIFACT_EXTENSION = "xml"; + private static final String GENERATOR_AAI_ERROR_MISSING_SERVICE_TOSCA = "Service tosca missing from list of input artifacts"; + private static final String GENERATOR_AAI_ERROR_MISSING_SERVICE_VERSION = "Cannot generate artifacts. Service version is not specified"; + private static final String GENERATOR_AAI_INVALID_SERVICE_VERSION = "Cannot generate artifacts. Service version is incorrect"; + + private AaiModelGenerator modelGenerator = new AaiModelGeneratorImpl(); + @Override public GenerationData generateArtifact(byte[] csarArchive, List input, Map additionalParams) { @@ -65,15 +69,14 @@ public class AaiArtifactGenerator implements ArtifactGenerator { path = createTempFile(csarArchive); if (path != null) { - ISdcCsarHelper csarHelper = - SdcToscaParserFactory.getInstance().getSdcCsarHelper(path.toAbsolutePath().toString()); + ISdcCsarHelper csarHelper = SdcToscaParserFactory.getInstance() + .getSdcCsarHelper(path.toAbsolutePath().toString()); - List serviceNodes = - csarHelper.getServiceNodeTemplates(); + List serviceNodes = csarHelper.getServiceNodeTemplates(); Map serviceMetaData = csarHelper.getServiceMetadataAllProperties(); if (serviceNodes == null) { - throw new IllegalArgumentException(GeneratorConstants.GENERATOR_AAI_ERROR_MISSING_SERVICE_TOSCA); + throw new IllegalArgumentException(GENERATOR_AAI_ERROR_MISSING_SERVICE_TOSCA); } // Populate basic service model metadata @@ -91,15 +94,13 @@ public class AaiArtifactGenerator implements ArtifactGenerator { // Process the resource TOSCA files List resources = parser.processResourceToscas(serviceNodes, idTypeStore); - // Generate AAI XML service model - AaiModelGenerator modelGenerator = AaiModelGenerator.getInstance(); - MDC.put(ARTIFACT_MODEL_INFO, serviceModel.getModelName() + "," + getArtifactLabel(serviceModel)); + MDC.put(MDC_PARAM_MODEL_INFO, serviceModel.getModelName() + "," + getArtifactLabel(serviceModel)); String aaiServiceModel = modelGenerator.generateModelFor(serviceModel); generationData.add(getServiceArtifact(serviceModel, aaiServiceModel)); // Generate AAI XML resource model for (Resource res : resources) { - MDC.put(ARTIFACT_MODEL_INFO, res.getModelName() + "," + getArtifactLabel(res)); + MDC.put(MDC_PARAM_MODEL_INFO, res.getModelName() + "," + getArtifactLabel(res)); String aaiResourceModel = modelGenerator.generateModelFor(res); generationData.add(getResourceArtifact(res, aaiResourceModel)); @@ -149,7 +150,8 @@ public class AaiArtifactGenerator implements ArtifactGenerator { /** * Method to generate the artifact name for an AAI model. * - * @param model AAI artifact model + * @param model + * AAI artifact model * @return Model artifact name */ private String getArtifactName(Model model) { @@ -165,15 +167,17 @@ public class AaiArtifactGenerator implements ArtifactGenerator { artifactName.append(model.getModelVersion()); artifactName.append("."); - artifactName.append(GeneratorConstants.GENERATOR_AAI_GENERATED_ARTIFACT_EXTENSION); + artifactName.append(GENERATOR_AAI_GENERATED_ARTIFACT_EXTENSION); return artifactName.toString(); } /** * Create Resource artifact model from the AAI xml model string. * - * @param resourceModel Model of the resource artifact - * @param aaiResourceModel AAI model as string + * @param resourceModel + * Model of the resource artifact + * @param aaiResourceModel + * AAI model as string * @return Generated {@link Artifact} model for the resource */ private Artifact getResourceArtifact(Model resourceModel, String aaiResourceModel) { @@ -191,8 +195,10 @@ public class AaiArtifactGenerator implements ArtifactGenerator { /** * Create Service artifact model from the AAI xml model string. * - * @param serviceModel Model of the service artifact - * @param aaiServiceModel AAI model as string + * @param serviceModel + * Model of the service artifact + * @param aaiServiceModel + * AAI model as string * @return Generated {@link Artifact} model for the service */ private Artifact getServiceArtifact(Service serviceModel, String aaiServiceModel) { @@ -227,12 +233,12 @@ public class AaiArtifactGenerator implements ArtifactGenerator { String serviceVersion; serviceVersion = additionalParams.get(AdditionalParams.SERVICE_VERSION.getName()); if (serviceVersion == null) { - throw new IllegalArgumentException(GeneratorConstants.GENERATOR_AAI_ERROR_MISSING_SERVICE_VERSION); + throw new IllegalArgumentException(GENERATOR_AAI_ERROR_MISSING_SERVICE_VERSION); } else { String versionRegex = "^[1-9]\\d*(\\.0)$"; if (!(serviceVersion.matches(versionRegex))) { throw new IllegalArgumentException( - String.format(GeneratorConstants.GENERATOR_AAI_INVALID_SERVICE_VERSION)); + String.format(GENERATOR_AAI_INVALID_SERVICE_VERSION)); } } return serviceVersion; diff --git a/src/main/java/org/onap/aai/babel/xml/generator/api/AaiModelGenerator.java b/src/main/java/org/onap/aai/babel/xml/generator/api/AaiModelGenerator.java index 409dbc2..daf9d36 100644 --- a/src/main/java/org/onap/aai/babel/xml/generator/api/AaiModelGenerator.java +++ b/src/main/java/org/onap/aai/babel/xml/generator/api/AaiModelGenerator.java @@ -1,5 +1,5 @@ /** - * ============LICENSE_START======================================================= + * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. @@ -20,44 +20,11 @@ */ package org.onap.aai.babel.xml.generator.api; -import static org.onap.aai.babel.xml.generator.data.GeneratorConstants.ERROR_CATEGORY; -import static org.onap.aai.babel.xml.generator.data.GeneratorConstants.ERROR_CODE; -import static org.onap.aai.babel.xml.generator.data.GeneratorConstants.ERROR_DESCRIPTION; -import static org.onap.aai.babel.xml.generator.data.GeneratorConstants.GENERATOR_ERROR_CODE; -import static org.onap.aai.babel.xml.generator.data.GeneratorConstants.GENERATOR_ERROR_SERVICE_INSTANTIATION_FAILED; -import static org.onap.aai.babel.xml.generator.data.GeneratorConstants.GENERATOR_PARTNER_NAME; -import static org.onap.aai.babel.xml.generator.data.GeneratorConstants.PARTNER_NAME; - -import org.onap.aai.babel.logging.ApplicationMsgs; -import org.onap.aai.babel.logging.LogHelper; -import org.onap.aai.babel.xml.generator.logging.CategoryLogLevel; import org.onap.aai.babel.xml.generator.model.Resource; import org.onap.aai.babel.xml.generator.model.Service; -import org.onap.aai.cl.api.Logger; -import org.slf4j.MDC; public interface AaiModelGenerator { - /** - * Gets instance. - * - * @return the instance - */ - public static AaiModelGenerator getInstance() { - Logger log = LogHelper.INSTANCE; - try { - return AaiModelGenerator.class - .cast(Class.forName("org.onap.aai.babel.xml.generator.api.AaiModelGeneratorImpl").newInstance()); - } catch (Exception exception) { - MDC.put(PARTNER_NAME, GENERATOR_PARTNER_NAME); - MDC.put(ERROR_CATEGORY, CategoryLogLevel.ERROR.name()); - MDC.put(ERROR_CODE, GENERATOR_ERROR_CODE); - MDC.put(ERROR_DESCRIPTION, GENERATOR_ERROR_SERVICE_INSTANTIATION_FAILED); - log.error(ApplicationMsgs.PROCESS_REQUEST_ERROR, exception); - } - return null; - } - public String generateModelFor(Service service); public String generateModelFor(Resource resource); diff --git a/src/main/java/org/onap/aai/babel/xml/generator/data/GeneratorConstants.java b/src/main/java/org/onap/aai/babel/xml/generator/data/GeneratorConstants.java deleted file mode 100644 index b9d8cb2..0000000 --- a/src/main/java/org/onap/aai/babel/xml/generator/data/GeneratorConstants.java +++ /dev/null @@ -1,92 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * Copyright © 2017-2018 European Software Marketing Ltd. - * ================================================================================ - * Licensed 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. - * ============LICENSE_END========================================================= - */ -package org.onap.aai.babel.xml.generator.data; - -public class GeneratorConstants { - - /* - * Private constructor to prevent instantiation - */ - private GeneratorConstants() { - throw new UnsupportedOperationException("This static class should not be instantiated!"); - } - - public static final String PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE = "artifactgenerator.config"; - - public static final String VERSION = "version"; - public static final String CATEGORY = "category"; - public static final String SUBCATEGORY = "subcategory"; - public static final int ID_LENGTH = 36; - - public static final String GENERATOR_AAI_GENERATED_ARTIFACT_EXTENSION = "xml"; - - // Error codes - public static final String GENERATOR_INVOCATION_ERROR_CODE = "ARTIFACT_GENERATOR_INVOCATION_ERROR"; - - // Error Constants - public static final String GENERATOR_ERROR_INVALID_CLIENT_CONFIGURATION = "Invalid Client Configuration"; - public static final String GENERATOR_ERROR_ARTIFACT_GENERATION_FAILED = - "Unable to generate artifacts for the provided input"; - public static final String GENERATOR_ERROR_SERVICE_INSTANTIATION_FAILED = - "Artifact Generation Service Instantiation failed"; - - // AAI Generator Error Messages - public static final String GENERATOR_AAI_ERROR_CHECKSUM_MISMATCH = "Checksum Mismatch for file : %s"; - public static final String GENERATOR_AAI_ERROR_INVALID_TOSCA = "Invalid format for Tosca YML : %s"; - public static final String GENERATOR_AAI_ERROR_UNSUPPORTED_WIDGET_OPERATION = "Operation Not Supported for Widgets"; - public static final String GENERATOR_AAI_ERROR_MISSING_SERVICE_TOSCA = - "Service tosca missing from list of input artifacts"; - public static final String GENERATOR_AAI_ERROR_NULL_RESOURCE_VERSION_IN_SERVICE_TOSCA = - "Invalid Service definition mandatory attribute version missing for resource with UUID: <%s>"; - - public static final String GENERATOR_AAI_ERROR_INVALID_RESOURCE_VERSION_IN_SERVICE_TOSCA = - "Cannot generate artifacts. Invalid Resource version in Service tosca for resource with " + "UUID: " - + "<%s>"; - public static final String GENERATOR_AAI_ERROR_MISSING_RESOURCE_TOSCA = - "Cannot generate artifacts. Resource Tosca missing for resource with UUID: <%s>"; - - public static final String GENERATOR_AAI_ERROR_MISSING_SERVICE_VERSION = - "Cannot generate artifacts. Service version is not specified"; - - public static final String GENERATOR_AAI_INVALID_SERVICE_VERSION = - "Cannot generate artifacts. Service version is incorrect"; - - // Logging constants - public static final String PARTNER_NAME = "userId"; - public static final String ERROR_CATEGORY = "ErrorCategory"; - public static final String ERROR_CODE = "ErrorCode"; - public static final String ERROR_DESCRIPTION = "ErrorDescription"; - - public static final String GENERATOR_ERROR_CODE = "300F"; - public static final String GENERATOR_PARTNER_NAME = "SDC Catalog"; - - // AAI Generator Error Messages for Logging - public static final String GENERATOR_AAI_CONFIGFILE_NOT_FOUND = - "Cannot generate artifacts. Artifact Generator Configuration file not found at %s"; - public static final String GENERATOR_AAI_CONFIGLOCATION_NOT_FOUND = - "Cannot generate artifacts. artifactgenerator.config system property not configured"; - public static final String GENERATOR_AAI_CONFIGLPROP_NOT_FOUND = - "Cannot generate artifacts. Widget configuration not found for %s"; - public static final String GENERATOR_AAI_PROVIDING_SERVICE_MISSING = - "Cannot generate artifacts. Providing Service is missing for allotted resource %s"; - public static final String GENERATOR_AAI_PROVIDING_SERVICE_METADATA_MISSING = - "Cannot generate artifacts. Providing Service Metadata is missing for allotted resource %s"; -} diff --git a/src/main/java/org/onap/aai/babel/xml/generator/model/Configuration.java b/src/main/java/org/onap/aai/babel/xml/generator/model/Configuration.java new file mode 100644 index 0000000..20dbea9 --- /dev/null +++ b/src/main/java/org/onap/aai/babel/xml/generator/model/Configuration.java @@ -0,0 +1,28 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 European Software Marketing Ltd. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.babel.xml.generator.model; + +import org.onap.aai.babel.xml.generator.types.Cardinality; +import org.onap.aai.babel.xml.generator.types.Model; + +@Model(widget = Widget.Type.CONFIGURATION, cardinality = Cardinality.UNBOUNDED, dataDeleteFlag = true) +public class Configuration extends Resource { +} diff --git a/src/main/java/org/onap/aai/babel/xml/generator/model/ConfigurationWidget.java b/src/main/java/org/onap/aai/babel/xml/generator/model/ConfigurationWidget.java new file mode 100644 index 0000000..7822926 --- /dev/null +++ b/src/main/java/org/onap/aai/babel/xml/generator/model/ConfigurationWidget.java @@ -0,0 +1,31 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 European Software Marketing Ltd. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.babel.xml.generator.model; + +import org.onap.aai.babel.xml.generator.types.Cardinality; +import org.onap.aai.babel.xml.generator.types.ModelType; +import org.onap.aai.babel.xml.generator.types.ModelWidget; + +@org.onap.aai.babel.xml.generator.types.Model(widget = Widget.Type.CONFIGURATION, cardinality = Cardinality.UNBOUNDED, + dataDeleteFlag = true) +@ModelWidget(type = ModelType.WIDGET, name = "configuration") +public class ConfigurationWidget extends ResourceWidget { +} diff --git a/src/main/java/org/onap/aai/babel/xml/generator/model/Model.java b/src/main/java/org/onap/aai/babel/xml/generator/model/Model.java index 0a8f0b1..956db40 100644 --- a/src/main/java/org/onap/aai/babel/xml/generator/model/Model.java +++ b/src/main/java/org/onap/aai/babel/xml/generator/model/Model.java @@ -1,5 +1,5 @@ /** - * ============LICENSE_START======================================================= + * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. @@ -20,69 +20,149 @@ */ package org.onap.aai.babel.xml.generator.model; +import java.lang.reflect.InvocationTargetException; +import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; +import java.util.Optional; import java.util.Set; -import org.onap.aai.babel.xml.generator.data.GeneratorConstants; +import org.onap.aai.babel.logging.ApplicationMsgs; +import org.onap.aai.babel.logging.LogHelper; import org.onap.aai.babel.xml.generator.error.IllegalAccessException; import org.onap.aai.babel.xml.generator.types.Cardinality; import org.onap.aai.babel.xml.generator.types.ModelType; +import org.onap.aai.cl.api.Logger; public abstract class Model { - protected Set resources = new HashSet<>(); - protected Set widgets = new HashSet<>(); + public static final String GENERATOR_AAI_ERROR_UNSUPPORTED_WIDGET_OPERATION = "Operation Not Supported for Widgets"; + + private static Logger log = LogHelper.INSTANCE; + + private static Map> typeToModel = new HashMap<>(); + static { + typeToModel.put("org.openecomp.resource.vf.allottedResource", AllotedResource.class); + typeToModel.put("org.openecomp.resource.vfc.AllottedResource", ProvidingService.class); + typeToModel.put("org.openecomp.resource.vfc", VServerWidget.class); + typeToModel.put("org.openecomp.resource.cp", LIntfWidget.class); + typeToModel.put("org.openecomp.cp", LIntfWidget.class); + typeToModel.put("org.openecomp.resource.vl", L3Network.class); + typeToModel.put("org.openecomp.resource.vf", VirtualFunction.class); + typeToModel.put("org.openecomp.groups.vfmodule", VfModule.class); + typeToModel.put("org.openecomp.groups.VfModule", VfModule.class); + typeToModel.put("org.openecomp.resource.vfc.nodes.heat.cinder", VolumeWidget.class); + typeToModel.put("org.openecomp.nodes.PortMirroringConfiguration", Configuration.class); + } + + private enum ModelIdentification { + ID("vfModuleModelInvariantUUID", "serviceInvariantUUID", "resourceInvariantUUID", "invariantUUID", + "providing_service_invariant_uuid") { + @Override + public void populate(Model model, String value) { + model.modelId = value; + } + }, + NAME_VERSION_ID("vfModuleModelUUID", "resourceUUID", "serviceUUID", "UUID", "providing_service_uuid") { + @Override + public void populate(Model model, String value) { + model.modelNameVersionId = value; + } + }, + VERSION("vfModuleModelVersion", "serviceVersion", "resourceversion", "version") { + @Override + public void populate(Model model, String value) { + model.modelVersion = value; + } + }, + NAME("vfModuleModelName", "serviceName", "resourceName", "name") { + @Override + public void populate(Model model, String value) { + model.modelName = value; + } + }, + DESCRIPTION("serviceDescription", "resourceDescription", "vf_module_description", "description") { + @Override + public void populate(Model model, String value) { + model.modelDescription = value; + } + }, + NAME_AND_DESCRIPTION("providing_service_name") { + @Override + public void populate(Model model, String value) { + model.modelName = model.modelDescription = value; + } + }; + + private static final Map propertyToModelIdent; + private String[] keys; + + ModelIdentification(String... keys) { + this.keys = keys; + } + + static { + Map mappings = new HashMap<>(); + for (ModelIdentification ident : ModelIdentification.values()) { + for (String key : ident.keys) { + mappings.put(key, ident); + } + } + propertyToModelIdent = Collections.unmodifiableMap(mappings); + } + + private static Optional getModelIdentFromProperty(String property) { + return Optional.ofNullable(propertyToModelIdent.get(property)); + } + + public abstract void populate(Model model, String value); + } + private String modelId; private String modelName; - private String modelVersion; private String modelNameVersionId; + private String modelVersion; private String modelDescription; + protected Set resources = new HashSet<>(); + protected Set widgets = new HashSet<>(); + /** * Gets the object (model) corresponding to the supplied TOSCA type. * - * @param toscaType the tosca type + * @param toscaType + * the tosca type * @return the model for the type, or null */ public static Model getModelFor(String toscaType) { - Model modelToBeReturned = null; - String typePrefix = toscaType; - while (modelToBeReturned == null && typePrefix != null && typePrefix.lastIndexOf('.') != -1) { - switch (typePrefix) { - case "org.openecomp.resource.vf.allottedResource": - modelToBeReturned = new AllotedResource(); - break; - case "org.openecomp.resource.vfc.AllottedResource": - modelToBeReturned = new ProvidingService(); - break; - case "org.openecomp.resource.vfc": - modelToBeReturned = new VServerWidget(); - break; - case "org.openecomp.resource.cp": - case "org.openecomp.cp": - modelToBeReturned = new LIntfWidget(); - break; - case "org.openecomp.resource.vl": - modelToBeReturned = new L3Network(); - break; - case "org.openecomp.resource.vf": - modelToBeReturned = new VirtualFunction(); - break; - case "org.openecomp.groups.vfmodule": - case "org.openecomp.groups.VfModule": - modelToBeReturned = new VfModule(); - break; - case "org.openecomp.resource.vfc.nodes.heat.cinder": - modelToBeReturned = new VolumeWidget(); - break; - default: - modelToBeReturned = null; - break; - } - typePrefix = typePrefix.substring(0, typePrefix.lastIndexOf('.')); + Model model = null; + if (toscaType != null && !toscaType.isEmpty()) { + model = getModelFromType(toscaType).orElseGet(() -> Model.getModelFromPrefix(toscaType)); } + return model; + } + + private static Model getModelFromPrefix(String toscaType) { + Model model = null; + int lastSeparator = toscaType.lastIndexOf('.'); + if (lastSeparator != -1) { + model = getModelFor(toscaType.substring(0, lastSeparator)); + } + return model; + } + private static Optional getModelFromType(String typePrefix) { + Optional modelToBeReturned = Optional.empty(); + Class clazz = typeToModel.get(typePrefix); + if (clazz != null) { + try { + modelToBeReturned = Optional.ofNullable(clazz.getConstructor().newInstance()); + } catch (InstantiationException | java.lang.IllegalAccessException | IllegalArgumentException + | InvocationTargetException | NoSuchMethodException | SecurityException e) { + log.error(ApplicationMsgs.INVALID_CSAR_FILE, e); + } + } return modelToBeReturned; } @@ -90,26 +170,17 @@ public abstract class Model { public abstract boolean addWidget(Widget resource); - /** - * Gets widget version id. - * - * @return the widget version id - */ - public String getWidgetId() { - org.onap.aai.babel.xml.generator.types.Model model = - this.getClass().getAnnotation(org.onap.aai.babel.xml.generator.types.Model.class); - return Widget.getWidget(model.widget()).getId(); - } + public abstract Widget.Type getWidgetType(); /** - * Gets invariant id. + * Gets cardinality. * - * @return the invariant id + * @return the cardinality */ - public String getWidgetInvariantId() { - org.onap.aai.babel.xml.generator.types.Model model = - this.getClass().getAnnotation(org.onap.aai.babel.xml.generator.types.Model.class); - return Widget.getWidget(model.widget()).getWidgetId(); + public Cardinality getCardinality() { + org.onap.aai.babel.xml.generator.types.Model model = this.getClass() + .getAnnotation(org.onap.aai.babel.xml.generator.types.Model.class); + return model.cardinality(); } /** @@ -118,29 +189,33 @@ public abstract class Model { * @return the delete flag */ public boolean getDeleteFlag() { - org.onap.aai.babel.xml.generator.types.Model model = - this.getClass().getAnnotation(org.onap.aai.babel.xml.generator.types.Model.class); + org.onap.aai.babel.xml.generator.types.Model model = this.getClass() + .getAnnotation(org.onap.aai.babel.xml.generator.types.Model.class); return model.dataDeleteFlag(); } - /** - * Gets cardinality. - * - * @return the cardinality - */ - public Cardinality getCardinality() { - org.onap.aai.babel.xml.generator.types.Model model = - this.getClass().getAnnotation(org.onap.aai.babel.xml.generator.types.Model.class); - return model.cardinality(); + public String getModelDescription() { + return modelDescription; } - public abstract Widget.Type getWidgetType(); - public String getModelId() { checkSupported(); return modelId; } + public String getModelName() { + return modelName; + } + + public String getModelVersion() { + return modelVersion; + } + + public String getModelNameVersionId() { + checkSupported(); + return modelNameVersionId; + } + /** * Gets model type. * @@ -158,72 +233,42 @@ public abstract class Model { } } - public String getModelName() { - return modelName; - } - - public String getModelVersion() { - return modelVersion; - } - - public String getModelNameVersionId() { - checkSupported(); - return modelNameVersionId; + /** + * Gets widget version id. + * + * @return the widget version id + */ + public String getWidgetId() { + org.onap.aai.babel.xml.generator.types.Model model = this.getClass() + .getAnnotation(org.onap.aai.babel.xml.generator.types.Model.class); + return Widget.getWidget(model.widget()).getId(); } - public String getModelDescription() { - return modelDescription; + /** + * Gets invariant id. + * + * @return the invariant id + */ + public String getWidgetInvariantId() { + org.onap.aai.babel.xml.generator.types.Model model = this.getClass() + .getAnnotation(org.onap.aai.babel.xml.generator.types.Model.class); + return Widget.getWidget(model.widget()).getWidgetId(); } /** * Populate model identification information. * - * @param modelIdentInfo the model ident info + * @param modelIdentInfo + * the model ident info */ public void populateModelIdentificationInformation(Map modelIdentInfo) { Iterator iter = modelIdentInfo.keySet().iterator(); String property; while (iter.hasNext()) { property = iter.next(); - switch (property) { - case "vfModuleModelInvariantUUID": - case "serviceInvariantUUID": - case "resourceInvariantUUID": - case "invariantUUID": - case "providing_service_invariant_uuid": - modelId = modelIdentInfo.get(property); - break; - case "vfModuleModelUUID": - case "resourceUUID": - case "serviceUUID": - case "UUID": - case "providing_service_uuid": - modelNameVersionId = modelIdentInfo.get(property); - break; - case "vfModuleModelVersion": - case "serviceVersion": - case "resourceversion": - case "version": - modelVersion = modelIdentInfo.get(property); - break; - case "vfModuleModelName": - case "serviceName": - case "resourceName": - case "name": - modelName = modelIdentInfo.get(property); - break; - case "serviceDescription": - case "resourceDescription": - case "vf_module_description": - case "description": - modelDescription = modelIdentInfo.get(property); - break; - case "providing_service_name": - modelName = modelIdentInfo.get(property); - modelDescription = modelIdentInfo.get(property); - break; - default: - break; + Optional modelIdent = ModelIdentification.getModelIdentFromProperty(property); + if (modelIdent.isPresent()) { + modelIdent.get().populate(this, modelIdentInfo.get(property)); } } } @@ -242,7 +287,7 @@ public abstract class Model { private void checkSupported() { if (this instanceof Widget) { - throw new IllegalAccessException(GeneratorConstants.GENERATOR_AAI_ERROR_UNSUPPORTED_WIDGET_OPERATION); + throw new IllegalAccessException(GENERATOR_AAI_ERROR_UNSUPPORTED_WIDGET_OPERATION); } } } diff --git a/src/main/java/org/onap/aai/babel/xml/generator/model/Widget.java b/src/main/java/org/onap/aai/babel/xml/generator/model/Widget.java index 2a85e27..7f39438 100644 --- a/src/main/java/org/onap/aai/babel/xml/generator/model/Widget.java +++ b/src/main/java/org/onap/aai/babel/xml/generator/model/Widget.java @@ -1,5 +1,5 @@ /** - * ============LICENSE_START======================================================= + * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. @@ -20,15 +20,12 @@ */ package org.onap.aai.babel.xml.generator.model; -import static org.onap.aai.babel.xml.generator.data.GeneratorConstants.GENERATOR_AAI_CONFIGLPROP_NOT_FOUND; - import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import org.onap.aai.babel.xml.generator.data.ArtifactType; -import org.onap.aai.babel.xml.generator.data.GeneratorConstants; import org.onap.aai.babel.xml.generator.data.WidgetConfigurationUtil; import org.onap.aai.babel.xml.generator.error.IllegalAccessException; import org.onap.aai.babel.xml.generator.types.ModelType; @@ -36,16 +33,22 @@ import org.onap.aai.babel.xml.generator.types.ModelWidget; public abstract class Widget extends Model { + public static final String GENERATOR_AAI_CONFIGLPROP_NOT_FOUND = "Cannot generate artifacts. Widget configuration not found for %s"; + + public enum Type { + SERVICE, VF, VFC, VSERVER, VOLUME, FLAVOR, TENANT, VOLUME_GROUP, LINT, L3_NET, VFMODULE, IMAGE, OAM_NETWORK, ALLOTTED_RESOURCE, TUNNEL_XCONNECT, CONFIGURATION; + } + private Set keys = new HashSet<>(); /** * Gets widget. * - * @param type the type + * @param type + * the type * @return the widget */ public static Widget getWidget(Type type) { - switch (type) { case SERVICE: return new ServiceWidget(); @@ -77,16 +80,13 @@ public abstract class Widget extends Model { return new AllotedResourceWidget(); case TUNNEL_XCONNECT: return new TunnelXconnectWidget(); + case CONFIGURATION: + return new ConfigurationWidget(); default: return null; } } - /** - * Gets id. - * - * @return the id - */ public String getId() { Properties properties = WidgetConfigurationUtil.getConfig(); String id = properties.getProperty(ArtifactType.AAI.name() + ".model-version-id." + getName()); @@ -136,7 +136,8 @@ public abstract class Widget extends Model { /** * Equals. * - * @param obj Object + * @param obj + * Object * @return the boolean */ @Override @@ -159,7 +160,8 @@ public abstract class Widget extends Model { /** * Member of boolean. * - * @param keys the keys + * @param keys + * the keys * @return the boolean */ public boolean memberOf(List keys) { @@ -172,7 +174,8 @@ public abstract class Widget extends Model { /** * All instances used boolean. * - * @param collection the collection + * @param collection + * the collection * @return the boolean */ public boolean allInstancesUsed(Set collection) { @@ -183,7 +186,7 @@ public abstract class Widget extends Model { @Override public boolean addResource(Resource resource) { - throw new IllegalAccessException(GeneratorConstants.GENERATOR_AAI_ERROR_UNSUPPORTED_WIDGET_OPERATION); + throw new IllegalAccessException(Model.GENERATOR_AAI_ERROR_UNSUPPORTED_WIDGET_OPERATION); } @Override @@ -191,21 +194,4 @@ public abstract class Widget extends Model { return true; } - public enum Type { - SERVICE, - VF, - VFC, - VSERVER, - VOLUME, - FLAVOR, - TENANT, - VOLUME_GROUP, - LINT, - L3_NET, - VFMODULE, - IMAGE, - OAM_NETWORK, - ALLOTTED_RESOURCE, - TUNNEL_XCONNECT - } } diff --git a/src/test/java/org/onap/aai/babel/csar/extractor/YamlExtractorTest.java b/src/test/java/org/onap/aai/babel/csar/extractor/YamlExtractorTest.java index b53f38d..f783e7c 100644 --- a/src/test/java/org/onap/aai/babel/csar/extractor/YamlExtractorTest.java +++ b/src/test/java/org/onap/aai/babel/csar/extractor/YamlExtractorTest.java @@ -129,7 +129,7 @@ public class YamlExtractorTest { try { new YamlExtractor().extract(archive, name, version); fail("An instance of InvalidArchiveException should have been thrown"); - } catch (Exception ex) { + } catch (InvalidArchiveException ex) { assertTrue(ex instanceof InvalidArchiveException); assertEquals(expectedErrorMessage, ex.getLocalizedMessage()); } diff --git a/src/test/java/org/onap/aai/babel/csar/vnfcatalog/ConfigurationsToBabelArtifactConverterTest.java b/src/test/java/org/onap/aai/babel/csar/vnfcatalog/ConfigurationsToBabelArtifactConverterTest.java new file mode 100644 index 0000000..b251401 --- /dev/null +++ b/src/test/java/org/onap/aai/babel/csar/vnfcatalog/ConfigurationsToBabelArtifactConverterTest.java @@ -0,0 +1,64 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 European Software Marketing Ltd. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.babel.csar.vnfcatalog; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import org.junit.Test; +import org.onap.aai.babel.service.data.BabelArtifact; +import org.onap.aai.babel.service.data.BabelArtifact.ArtifactType; +import org.onap.aai.babel.util.ArtifactTestUtils; + +/** + * Tests {@link ConfigurationsToBabelArtifactConverter}. + */ +public class ConfigurationsToBabelArtifactConverterTest { + @Test + public void testNullListSupplied() { + assertThat(ConfigurationsToBabelArtifactConverter.convert(null), is(nullValue())); + } + + @Test + public void testEmptyListSupplied() { + assertThat(ConfigurationsToBabelArtifactConverter.convert(new ArrayList<>()), is(nullValue())); + } + + @Test + public void testValidListSupplied() throws IOException { + String expectedJson = new ArtifactTestUtils().getRequestJson("vnfVendorImageConfigurations.json"); + List configurations = + new Gson().fromJson(expectedJson, new TypeToken>() {}.getType()); + + BabelArtifact artifact = ConfigurationsToBabelArtifactConverter.convert(configurations); + + assertThat(artifact.getName(), is(equalTo("vnfVendorImageConfigurations"))); + assertThat(artifact.getType(), is(equalTo(ArtifactType.VNFCATALOG))); + assertThat(artifact.getPayload(), is(equalTo(expectedJson))); + } +} diff --git a/src/test/java/org/onap/aai/babel/csar/vnfcatalog/VnfVendorImageExtractorTest.java b/src/test/java/org/onap/aai/babel/csar/vnfcatalog/VnfVendorImageExtractorTest.java new file mode 100644 index 0000000..de5ea3f --- /dev/null +++ b/src/test/java/org/onap/aai/babel/csar/vnfcatalog/VnfVendorImageExtractorTest.java @@ -0,0 +1,76 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 European Software Marketing Ltd. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.babel.csar.vnfcatalog; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +import java.io.IOException; +import org.junit.Test; +import org.onap.aai.babel.service.data.BabelArtifact; +import org.onap.aai.babel.service.data.BabelArtifact.ArtifactType; +import org.onap.aai.babel.util.ArtifactTestUtils; + +/** + * Tests {@link VnfVendorImageExtractor} + */ +public class VnfVendorImageExtractorTest { + + @Test(expected = NullPointerException.class) + public void createVendorImageMappingsNullCsarSupplied() throws ToscaToCatalogException, IOException { + new VnfVendorImageExtractor().extract(null); + } + + @Test(expected = ToscaToCatalogException.class) + public void createVendorImageMappingsEmptyCsarSupplied() throws ToscaToCatalogException, IOException { + new VnfVendorImageExtractor().extract(new byte[0]); + } + + @Test(expected = ToscaToCatalogException.class) + public void createVendorImageMappingsInvalidCsarFile() throws IOException, ToscaToCatalogException { + extractArtifact("noYmlFilesArchive.zip"); + } + + @Test(expected = ToscaToCatalogException.class) + public void createVendorImageMappingsInvalidFile() throws IOException, ToscaToCatalogException { + extractArtifact("Duff.txt"); + } + + @Test + public void createVendorImageMappingsNoVnfConfigurationExists() throws IOException, ToscaToCatalogException { + assertThat(extractArtifact("noVnfConfiguration.csar"), is(nullValue())); + } + + @Test + public void createVendorImageMappingsValidFile() throws IOException, ToscaToCatalogException { + BabelArtifact artifact = extractArtifact("catalog_csar.csar"); + assertThat(artifact.getName(), is(equalTo("vnfVendorImageConfigurations"))); + assertThat(artifact.getType(), is(equalTo(ArtifactType.VNFCATALOG))); + assertThat(artifact.getPayload(), + is(equalTo(new ArtifactTestUtils().getRequestJson("vnfVendorImageConfigurations.json")))); + } + + private BabelArtifact extractArtifact(String artifactName) throws ToscaToCatalogException, IOException { + return new VnfVendorImageExtractor().extract(new ArtifactTestUtils().getCompressedArtifact(artifactName)); + } +} diff --git a/src/test/java/org/onap/aai/babel/parser/TestToscaParser.java b/src/test/java/org/onap/aai/babel/parser/TestToscaParser.java index d27396d..a73e64c 100644 --- a/src/test/java/org/onap/aai/babel/parser/TestToscaParser.java +++ b/src/test/java/org/onap/aai/babel/parser/TestToscaParser.java @@ -40,7 +40,6 @@ import org.onap.aai.babel.xml.generator.api.AaiArtifactGenerator; import org.onap.aai.babel.xml.generator.data.AdditionalParams; import org.onap.aai.babel.xml.generator.data.Artifact; import org.onap.aai.babel.xml.generator.data.GenerationData; -import org.onap.aai.babel.xml.generator.data.GeneratorConstants; import org.onap.aai.babel.xml.generator.data.WidgetConfigurationUtil; /** @@ -54,10 +53,12 @@ public class TestToscaParser { } } + private static final String ARTIFACT_GENERATOR_CONFIG = "artifact-generator.properties"; + @Before public void setup() throws FileNotFoundException, IOException { - System.setProperty(GeneratorConstants.PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE, - new ArtifactTestUtils().getResourcePath("artifact-generator.properties")); + System.setProperty(ArtifactGeneratorToscaParser.PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE, + new ArtifactTestUtils().getResourcePath(ARTIFACT_GENERATOR_CONFIG)); InputStream in = TestToscaParser.class.getClassLoader().getResourceAsStream("artifact-generator.properties"); Properties properties = new Properties(); properties.load(in); diff --git a/src/test/java/org/onap/aai/babel/service/CsarToXmlConverterTest.java b/src/test/java/org/onap/aai/babel/service/CsarToXmlConverterTest.java index 0bc7c31..62e9265 100644 --- a/src/test/java/org/onap/aai/babel/service/CsarToXmlConverterTest.java +++ b/src/test/java/org/onap/aai/babel/service/CsarToXmlConverterTest.java @@ -37,10 +37,10 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.onap.aai.babel.csar.CsarConverterException; import org.onap.aai.babel.csar.CsarToXmlConverter; +import org.onap.aai.babel.parser.ArtifactGeneratorToscaParser; import org.onap.aai.babel.service.data.BabelArtifact; import org.onap.aai.babel.util.ArtifactTestUtils; import org.onap.aai.babel.xml.generator.XmlArtifactGenerationException; -import org.onap.aai.babel.xml.generator.data.GeneratorConstants; /** * Tests {@link CsarToXmlConverter} @@ -58,7 +58,15 @@ public class CsarToXmlConverterTest { } private enum CsarTest { - VALID_CSAR_FILE("service-SdWanServiceTest-csar.csar"), NO_YAML_FILES("noYmlFilesArchive.zip"); + VALID_CSAR_FILE( + "service-SdWanServiceTest-csar.csar" + ), + NO_YAML_FILES( + "noYmlFilesArchive.zip" + ), + PORT_MIRROR_CSAR( + "service_PortMirror.csar" + ); private String filename; private ArtifactTestUtils artifactTestUtils = new ArtifactTestUtils(); @@ -84,7 +92,7 @@ public class CsarToXmlConverterTest { @Before public void setup() { - System.setProperty(GeneratorConstants.PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE, + System.setProperty(ArtifactGeneratorToscaParser.PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE, new ArtifactTestUtils().getResourcePath(ARTIFACT_GENERATOR_CONFIG)); converter = new CsarToXmlConverter(); } @@ -95,27 +103,27 @@ public class CsarToXmlConverterTest { } @Test(expected = NullPointerException.class) - public void generateXmlFromCsar_nullArtifactSupplied() throws CsarConverterException { + public void testNullArtifactSupplied() throws CsarConverterException { converter.generateXmlFromCsar(null, null, null); } @Test(expected = NullPointerException.class) - public void generateXmlFromCsar_missingName() throws CsarConverterException, IOException { + public void testMissingName() throws CsarConverterException, IOException { converter.generateXmlFromCsar(CsarTest.VALID_CSAR_FILE.getContent(), null, null); } @Test(expected = NullPointerException.class) - public void generateXmlFromCsar_missingVersion() throws CsarConverterException, IOException { + public void testMissingVersion() throws CsarConverterException, IOException { converter.generateXmlFromCsar(CsarTest.VALID_CSAR_FILE.getContent(), INCORRECT_CSAR_NAME, null); } @Test(expected = CsarConverterException.class) - public void generateXmlFromCsar_noPayloadExists() throws CsarConverterException { + public void testNoPayloadExists() throws CsarConverterException { converter.generateXmlFromCsar(new byte[0], INCORRECT_CSAR_NAME, SERVICE_VERSION); } @Test(expected = CsarConverterException.class) - public void generateXmlFromCsar_csarFileHasNoYmlFiles() throws CsarConverterException, IOException { + public void testCsarFileHasNoYmlFiles() throws CsarConverterException, IOException { converter.generateXmlFromCsar(CsarTest.NO_YAML_FILES.getContent(), "noYmlFilesArchive.zip", SERVICE_VERSION); } @@ -126,7 +134,7 @@ public class CsarToXmlConverterTest { exception.expectMessage("Cannot generate artifacts. artifactgenerator.config system property not configured"); // Unset the required system property - System.clearProperty(GeneratorConstants.PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE); + System.clearProperty(ArtifactGeneratorToscaParser.PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE); converter.generateXmlFromCsar(CsarTest.VALID_CSAR_FILE.getContent(), CsarTest.VALID_CSAR_FILE.getName(), SERVICE_VERSION); } @@ -142,6 +150,18 @@ public class CsarToXmlConverterTest { ga.getPayload(), matches(expectedXmlFiles.get(ga.getName())))); } + @Test + public void generatePortMirrorConfigurationModel() + throws CsarConverterException, IOException, XmlArtifactGenerationException { + Map expectedXmlFiles = createExpectedXmlFiles(); + List generatedArtifacts = converter.generateXmlFromCsar(CsarTest.PORT_MIRROR_CSAR.getContent(), + CsarTest.PORT_MIRROR_CSAR.getName(), SERVICE_VERSION); + + generatedArtifacts + .forEach(ga -> assertThat("The content of " + ga.getName() + " must match the expected content", + ga.getPayload(), matches(expectedXmlFiles.get(ga.getName())))); + } + public Matcher matches(final String expected) { return new BaseMatcher() { protected String theExpected = expected; @@ -166,6 +186,8 @@ public class CsarToXmlConverterTest { filesToLoad.add("AAI-SdWanTestVsp..DUMMY..module-0-resource-2.xml"); filesToLoad.add("AAI-Tunnel_XConnTest-resource-2.0.xml"); filesToLoad.add("AAI-SD-WAN-Test-VSP-resource-1.0.xml"); + filesToLoad.add("AAI-Port Mirror_Test-service-1.0.xml"); + filesToLoad.add("AAI-Port Mirroring Configuration-resource-35.0.xml"); for (String filename : filesToLoad) { xmlMap.put(filename, new ArtifactTestUtils().loadResourceAsString("generatedXml/" + filename)); diff --git a/src/test/java/org/onap/aai/babel/service/TestGenerateArtifactsServiceImpl.java b/src/test/java/org/onap/aai/babel/service/TestGenerateArtifactsServiceImpl.java index 4cc8c8c..c770c60 100644 --- a/src/test/java/org/onap/aai/babel/service/TestGenerateArtifactsServiceImpl.java +++ b/src/test/java/org/onap/aai/babel/service/TestGenerateArtifactsServiceImpl.java @@ -41,18 +41,18 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.onap.aai.auth.AAIMicroServiceAuth; +import org.onap.aai.babel.parser.ArtifactGeneratorToscaParser; import org.onap.aai.babel.util.ArtifactTestUtils; -import org.onap.aai.babel.xml.generator.data.GeneratorConstants; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** - * Direct invocation of the generate artifacts service implementation + * Direct invocation of the generate artifacts service implementation. * */ @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations = { "classpath:/babel-beans.xml" }) +@ContextConfiguration(locations = {"classpath:/babel-beans.xml"}) public class TestGenerateArtifactsServiceImpl { static { @@ -62,13 +62,22 @@ public class TestGenerateArtifactsServiceImpl { System.setProperty("CONFIG_HOME", "src/test/resources"); } + private static final String ARTIFACT_GENERATOR_CONFIG = "artifact-generator.properties"; + @Inject private AAIMicroServiceAuth auth; @BeforeClass public static void setup() { - System.setProperty(GeneratorConstants.PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE, - new ArtifactTestUtils().getResourcePath("artifact-generator.properties")); + System.setProperty(ArtifactGeneratorToscaParser.PROPERTY_ARTIFACT_GENERATOR_CONFIG_FILE, + new ArtifactTestUtils().getResourcePath(ARTIFACT_GENERATOR_CONFIG)); + } + + @Test + public void testGenerateArtifacts() throws Exception { + Response response = processJsonRequest("success_request_vnf_catalog.json"); + assertThat(response.getStatus(), is(Response.Status.OK.getStatusCode())); + assertThat(response.getEntity(), is(getResponseJson("response.json"))); } @Test @@ -107,13 +116,12 @@ public class TestGenerateArtifactsServiceImpl { } /** - * Create a (mocked) HTTPS request and invoke the Babel generate artifacts API + * Create a (mocked) HTTPS request and invoke the Babel generate artifacts API. * - * @param resource - * path to the incoming JSON request + * @param resource path to the incoming JSON request * @return the Response from the HTTP API - * @throws URISyntaxException - * @throws IOException + * @throws URISyntaxException if the URI cannot be created + * @throws IOException if the resource cannot be loaded */ private Response processJsonRequest(String resource) throws URISyntaxException, IOException { UriInfo mockUriInfo = Mockito.mock(UriInfo.class); @@ -144,7 +152,7 @@ public class TestGenerateArtifactsServiceImpl { Mockito.when(mockCertificate.getSubjectX500Principal()) .thenReturn(new X500Principal("CN=test, OU=qa, O=Test Ltd, L=London, ST=London, C=GB")); - servletRequest.setAttribute("javax.servlet.request.X509Certificate", new X509Certificate[] { mockCertificate }); + servletRequest.setAttribute("javax.servlet.request.X509Certificate", new X509Certificate[] {mockCertificate}); servletRequest.setAttribute("javax.servlet.request.cipher_suite", ""); GenerateArtifactsServiceImpl service = new GenerateArtifactsServiceImpl(auth); diff --git a/src/test/java/org/onap/aai/babel/service/TestRequestHeaders.java b/src/test/java/org/onap/aai/babel/service/TestRequestHeaders.java new file mode 100644 index 0000000..0d81867 --- /dev/null +++ b/src/test/java/org/onap/aai/babel/service/TestRequestHeaders.java @@ -0,0 +1,159 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 European Software Marketing Ltd. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.babel.service; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map.Entry; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MultivaluedHashMap; +import org.junit.Test; +import org.mockito.Mockito; +import org.onap.aai.babel.request.RequestHeaders; + +/** + * Tests {@link RequestHeaders}. + * + */ +public class TestRequestHeaders { + + /** + * Tests compatibility with the X-ECOMP-* request headers. + */ + @Test + public void testECOMPHeaders() { + String transactionId = "transaction-id"; + String serviceInstanceId = "service-instance-id"; + + MultivaluedHashMap headersMap = new MultivaluedHashMap<>(); + headersMap.put(RequestHeaders.HEADER_REQUEST_ID, createSingletonList(transactionId)); + headersMap.put(RequestHeaders.HEADER_SERVICE_INSTANCE_ID, createSingletonList(serviceInstanceId)); + headersMap.put("X-FromAppId", createSingletonList("app-id")); + headersMap.put("Host", createSingletonList("hostname")); + + HttpHeaders headers = createMockedHeaders(headersMap); + RequestHeaders requestHeaders = new RequestHeaders(headers); + assertThat(requestHeaders.getRequestId(), is(equalTo(transactionId))); + assertThat(requestHeaders.getInstanceId(), is(equalTo(serviceInstanceId))); + } + + @Test + public void testMultipleHeaderValues() { + String transactionId = "transaction-id"; + String serviceInstanceId = "service-instance-id"; + + MultivaluedHashMap headersMap = new MultivaluedHashMap<>(); + headersMap.put(RequestHeaders.HEADER_REQUEST_ID, Arrays.asList(transactionId, "fred")); + headersMap.put(RequestHeaders.HEADER_SERVICE_INSTANCE_ID, Arrays.asList(serviceInstanceId, "bob")); + + HttpHeaders headers = createMockedHeaders(headersMap); + RequestHeaders requestHeaders = new RequestHeaders(headers); + assertThat(requestHeaders.getRequestId(), is(equalTo(transactionId))); + assertThat(requestHeaders.getInstanceId(), is(equalTo(serviceInstanceId))); + } + + @Test + public void testStandardHeaders() { + MultivaluedHashMap headersMap = new MultivaluedHashMap<>(); + headersMap.put("X-TransactionId", createSingletonList("transaction-id")); + headersMap.put("X-FromAppId", createSingletonList("app-id")); + headersMap.put("Host", createSingletonList("hostname")); + + HttpHeaders headers = createMockedHeaders(headersMap); + RequestHeaders requestHeaders = new RequestHeaders(headers); + assertThat(requestHeaders.getRequestId(), is(nullValue())); + assertThat(requestHeaders.getInstanceId(), is(nullValue())); + } + + @Test + public void testHeadersWithTransactionIdSuffix() { + MultivaluedHashMap headersMap = new MultivaluedHashMap<>(); + headersMap.put("X-TransactionId", createSingletonList("transaction-id:123")); + headersMap.put("X-FromAppId", createSingletonList("app-id")); + headersMap.put("Host", createSingletonList("hostname")); + + HttpHeaders headers = createMockedHeaders(headersMap); + RequestHeaders requestHeaders = new RequestHeaders(headers); + assertThat(requestHeaders.getCorrelationId(), is(equalTo("transaction-id"))); + assertThat(requestHeaders.getInstanceId(), is(nullValue())); + } + + @Test + public void testEmptyHeaders() { + MultivaluedHashMap headersMap = new MultivaluedHashMap<>(); + headersMap.put(RequestHeaders.HEADER_REQUEST_ID, Collections.emptyList()); + headersMap.put(RequestHeaders.HEADER_SERVICE_INSTANCE_ID, Collections.emptyList()); + + HttpHeaders headers = createMockedHeaders(headersMap); + RequestHeaders requestHeaders = new RequestHeaders(headers); + assertThat(requestHeaders.getRequestId(), is(nullValue())); + assertThat(requestHeaders.getInstanceId(), is(nullValue())); + } + + @Test + public void testNullHeaders() { + MultivaluedHashMap headersMap = new MultivaluedHashMap<>(); + headersMap.put(RequestHeaders.HEADER_REQUEST_ID, Collections.emptyList()); + + HttpHeaders headers = createMockedHeaders(headersMap); + Mockito.when(headers.getRequestHeader(RequestHeaders.HEADER_SERVICE_INSTANCE_ID)).thenReturn(null); + + RequestHeaders requestHeaders = new RequestHeaders(headers); + assertThat(requestHeaders.getRequestId(), is(nullValue())); + assertThat(requestHeaders.getInstanceId(), is(nullValue())); + } + + @Test + public void testToString() { + String transactionId = "transaction-id"; + String serviceInstanceId = "service-instance-id"; + + MultivaluedHashMap headersMap = new MultivaluedHashMap<>(); + headersMap.put(RequestHeaders.HEADER_REQUEST_ID, createSingletonList(transactionId)); + headersMap.put(RequestHeaders.HEADER_SERVICE_INSTANCE_ID, createSingletonList(serviceInstanceId)); + + HttpHeaders headers = createMockedHeaders(headersMap); + RequestHeaders requestHeaders = new RequestHeaders(headers); + assertThat(requestHeaders.toString(), is(equalTo( + "RequestHeaders [requestId=transaction-id, instanceId=service-instance-id, transactionId=null]"))); + } + + private HttpHeaders createMockedHeaders(MultivaluedHashMap headersMap) { + HttpHeaders headers = Mockito.mock(HttpHeaders.class); + for (Entry> entry : headersMap.entrySet()) { + List valuesList = entry.getValue(); + String value = valuesList == null || valuesList.isEmpty() ? null : valuesList.get(0); + Mockito.when(headers.getHeaderString(entry.getKey())).thenReturn(value); + } + Mockito.when(headers.getRequestHeaders()).thenReturn(headersMap); + return headers; + } + + private List createSingletonList(String listItem) { + return Collections.singletonList(listItem); + } +} diff --git a/src/test/java/org/onap/aai/babel/xml/generator/model/TestModel.java b/src/test/java/org/onap/aai/babel/xml/generator/model/TestModel.java new file mode 100644 index 0000000..fbac64c --- /dev/null +++ b/src/test/java/org/onap/aai/babel/xml/generator/model/TestModel.java @@ -0,0 +1,124 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2018 European Software Marketing Ltd. + * ================================================================================ + * Licensed 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. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.babel.xml.generator.model; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; +import org.junit.Before; +import org.junit.Test; +import org.onap.aai.babel.xml.generator.data.WidgetConfigurationUtil; +import org.onap.aai.babel.xml.generator.model.Widget.Type; +import org.onap.aai.babel.xml.generator.types.ModelType; + +/** + * Direct tests of the Model abstract class (to improve code coverage). Not all methods are tested here. Some are + * covered by the tests of derived classes. + */ +public class TestModel { + + private Service serviceModel = new Service(); + private Resource resourceModel = new VirtualFunction(); + private Widget widgetModel = new OamNetwork(); + private Model anonymousModel; + + static { + System.setProperty("APP_HOME", "."); + } + + @Before + public void setup() throws FileNotFoundException, IOException { + InputStream in = TestModel.class.getClassLoader().getResourceAsStream("artifact-generator.properties"); + Properties properties = new Properties(); + properties.load(in); + in.close(); + WidgetConfigurationUtil.setConfig(properties); + + anonymousModel = new Model() { + @Override + public boolean addResource(Resource resource) { + return false; + } + + @Override + public boolean addWidget(Widget resource) { + return false; + } + + @Override + public Type getWidgetType() { + return null; + } + }; + } + + @Test + public void testGetModels() { + assertThat(Model.getModelFor(null), is(nullValue())); + assertThat(Model.getModelFor(""), is(nullValue())); + assertThat(Model.getModelFor("any.unknown.type"), is(nullValue())); + + assertThat(Model.getModelFor("org.openecomp.resource.vf.allottedResource"), instanceOf(AllotedResource.class)); + assertThat(Model.getModelFor("org.openecomp.resource.vfc.AllottedResource"), + instanceOf(ProvidingService.class)); + assertThat(Model.getModelFor("org.openecomp.resource.vfc"), instanceOf(VServerWidget.class)); + assertThat(Model.getModelFor("org.openecomp.resource.cp"), instanceOf(LIntfWidget.class)); + assertThat(Model.getModelFor("org.openecomp.cp"), instanceOf(LIntfWidget.class)); + assertThat(Model.getModelFor("org.openecomp.cp.some.suffix"), instanceOf(LIntfWidget.class)); + assertThat(Model.getModelFor("org.openecomp.resource.vl"), instanceOf(L3Network.class)); + assertThat(Model.getModelFor("org.openecomp.resource.vf"), instanceOf(VirtualFunction.class)); + assertThat(Model.getModelFor("org.openecomp.groups.vfmodule"), instanceOf(VfModule.class)); + assertThat(Model.getModelFor("org.openecomp.groups.VfModule"), instanceOf(VfModule.class)); + assertThat(Model.getModelFor("org.openecomp.resource.vfc.nodes.heat.cinder"), instanceOf(VolumeWidget.class)); + assertThat(Model.getModelFor("org.openecomp.nodes.PortMirroringConfiguration"), + instanceOf(Configuration.class)); + } + + @Test + public void testGetCardinality() { + resourceModel.getCardinality(); + } + + @Test + public void testGetModelType() { + assertThat(serviceModel.getModelType(), is(ModelType.SERVICE)); + assertThat(resourceModel.getModelType(), is(ModelType.RESOURCE)); + assertThat(widgetModel.getModelType(), is(ModelType.WIDGET)); + assertThat(anonymousModel.getModelType(), is(nullValue())); + } + + @Test + public void testGetModelNameVersionId() { + assertThat(anonymousModel.getModelNameVersionId(), is(nullValue())); + } + + @Test(expected = org.onap.aai.babel.xml.generator.error.IllegalAccessException.class) + public void testGetModelNameVersionIdIsUnsupported() { + assertThat(widgetModel.getModelNameVersionId(), is(nullValue())); + } + +} diff --git a/src/test/resources/artifact-generator.properties b/src/test/resources/artifact-generator.properties index 1d7e5fa..74897d6 100644 --- a/src/test/resources/artifact-generator.properties +++ b/src/test/resources/artifact-generator.properties @@ -22,6 +22,9 @@ AAI.model-invariant-id.cloud-region=425b2158-e51d-4509-9945-dad4556474a3 #complex widget details AAI.model-invariant-id.complex=af91c2f7-35fc-43cf-a13d-443f385b2353 AAI.model-version-id.complex=3a8ab1ee-9220-4fe8-b89c-9251d160ddc2 +#configuration widget details +AAI.model-invariant-id.configuration=166c050d-f69d-4305-943e-0bc58c3a26cf +AAI.model-version-id.configuration=5a175add-57e4-4a5d-8b02-c36f1d69c52b #connector widget details AAI.model-version-id.connector=22104c9f-29fd-462f-be07-96cd6b46dd33 AAI.model-invariant-id.connector=4c01c948-7607-4d66-8a6c-99c2c2717936 diff --git a/src/test/resources/compressedArtifacts/service_PortMirror.csar b/src/test/resources/compressedArtifacts/service_PortMirror.csar new file mode 100644 index 0000000..e04a3bc Binary files /dev/null and b/src/test/resources/compressedArtifacts/service_PortMirror.csar differ diff --git a/src/test/resources/generatedXml/AAI-Port Mirror_Test-service-1.0.xml b/src/test/resources/generatedXml/AAI-Port Mirror_Test-service-1.0.xml new file mode 100644 index 0000000..5653c8a --- /dev/null +++ b/src/test/resources/generatedXml/AAI-Port Mirror_Test-service-1.0.xml @@ -0,0 +1,51 @@ + + cd674566-ce17-4262-ae99-d526e7b8d47a + service + + + e033128a-ab5d-4b69-bfe6-c94f93a34f7c + Port Mirror_Test + 1.0 + Port Mirror_Test + + + T + unbounded + + + T + unbounded + + + + model-ver + + model-ver.model-version-id + ea4e93c3-1a6d-4314-8165-c284a91422dc + + + model.model-invariant-id + cf53c1d6-8708-4b4e-a056-ead7daa57cd5 + + + + + + + + model-ver + + model-ver.model-version-id + 46b92144-923a-4d20-b85a-3cbd847668a9 + + + model.model-invariant-id + 82194af1-3c2c-485a-8f44-420e22a9eaa4 + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/generatedXml/AAI-Port Mirroring Configuration-resource-35.0.xml b/src/test/resources/generatedXml/AAI-Port Mirroring Configuration-resource-35.0.xml new file mode 100644 index 0000000..9418205 --- /dev/null +++ b/src/test/resources/generatedXml/AAI-Port Mirroring Configuration-resource-35.0.xml @@ -0,0 +1,32 @@ + + cf53c1d6-8708-4b4e-a056-ead7daa57cd5 + resource + + + ea4e93c3-1a6d-4314-8165-c284a91422dc + Port Mirroring Configuration + 35.0 + A port mirroring configuration object + + + T + unbounded + + + + model-ver + + model-ver.model-version-id + 5a175add-57e4-4a5d-8b02-c36f1d69c52b + + + model.model-invariant-id + 166c050d-f69d-4305-943e-0bc58c3a26cf + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/jsonFiles/success_request_vnf_catalog.json b/src/test/resources/jsonFiles/success_request_vnf_catalog.json new file mode 100644 index 0000000..3f0f137 --- /dev/null +++ b/src/test/resources/jsonFiles/success_request_vnf_catalog.json @@ -0,0 +1,3 @@ +{"csar": "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EwAARGVmaW5pdGlvbnMvYXJ0aWZhY3RzLnltbFBLAQIUABQACAgIAKVc3UpsImIhMAsAAO8uAAAcAAAAAAAAAAAAAAAAAOMYAABEZWZpbml0aW9ucy9jYXBhYmlsaXRpZXMueW1sUEsBAhQAFAAICAgApVzdSv6TiLWYJgAAaj4BABQAAAAAAAAAAAAAAAAAXSQAAERlZmluaXRpb25zL2RhdGEueW1sUEsBAhQAFAAICAgApVzdSh6ZzlcpBQAASg4AABYAAAAAAAAAAAAAAAAAN0sAAERlZmluaXRpb25zL2dyb3Vwcy55bWxQSwECFAAUAAgICAClXN1KIbWTjkgDAAB9CQAAGgAAAAAAAAAAAAAAAACkUAAARGVmaW5pdGlvbnMvaW50ZXJmYWNlcy55bWxQSwECFAAUAAgICAClXN1KhQB32bcoAACIPQEAFQAAAAAAAAAAAAAAAAA0VAAARGVmaW5pdGlvbnMvbm9kZXMueW1sUEsBAhQAFAAICAgApVzdSkWW8QFmAgAAlgYAABgAAAAAAAAAAAAAAAAALn0AAERlZmluaXRpb25zL3BvbGljaWVzLnltbFBLAQIUABQACAgIAKVc3UpjF0jHQAYAAEYVAAAdAAAAAAAAAAAAAAAAANp/AABEZWZpbml0aW9ucy9yZWxhdGlvbnNoaXBzLnltbFBLAQIUABQACAgIAKVc3UrByuWAxgEAAAYEAABaAAAAAAAAAAAAAAAAAGWGAABBcnRpZmFjdHMvb3JnLm9wZW5lY29tcC5yZXNvdXJjZS52Zi4yOW5mb2RfdjEuMC9EZXBsb3ltZW50L1ZGX0xJQ0VOU0UvdmYtbGljZW5zZS1tb2RlbC54bWxQSwECFAAUAAgICAClXN1KGmkFhO4BAAALBQAAYgAAAAAAAAAAAAAAAACziAAAQXJ0aWZhY3RzL29yZy5vcGVuZWNvbXAucmVzb3VyY2UudmYuMjluZm9kX3YxLjAvRGVwbG95bWVudC9WRU5ET1JfTElDRU5TRS92ZW5kb3ItbGljZW5zZS1tb2RlbC54bWxQSwECFAAUAAgICAClXN1K9QcNsqsBAABBBgAASAAAAAAAAAAAAAAAAAAxiwAAQXJ0aWZhY3RzL0RlcGxveW1lbnQvTU9ERUxfSU5WRU5UT1JZX1BST0ZJTEUvQUFJLTI5TkZPRC1yZXNvdXJjZS0xLjAueG1sUEsBAhQAFAAICAgApVzdSotT44MdAgAADwsAAEkAAAAAAAAAAAAAAAAAUo0AAEFydGlmYWN0cy9EZXBsb3ltZW50L01PREVMX0lOVkVOVE9SWV9QUk9GSUxFL0FBSS0yOU5GT0RfUy1zZXJ2aWNlLTEuMC54bWxQSwECFAAUAAAACADvcv9K9uhElIoAAACwAAAAGQAAAAAAAAABACAAAADmjwAAVE9TQ0EtTWV0YWRhdGEvVE9TQ0EubWV0YVBLBQYAAAAAFQAVAFUHAACnkAAAAAA=", + "artifactVersion":"1.0", + "artifactName":"catalog_csar.csar"} \ No newline at end of file diff --git a/src/test/resources/jsonFiles/vnfVendorImageConfigurations.json b/src/test/resources/jsonFiles/vnfVendorImageConfigurations.json new file mode 100644 index 0000000..cb836d3 --- /dev/null +++ b/src/test/resources/jsonFiles/vnfVendorImageConfigurations.json @@ -0,0 +1 @@ +[{"application":"VM00","application-vendor":"29NFOD","application-version":"3.16.1"},{"application":"VM00","application-vendor":"29NFOD","application-version":"3.16.9"},{"application":"VM01","application-vendor":"29NFOD","application-version":"3.16.1"},{"application":"VM01","application-vendor":"29NFOD","application-version":"3.16.9"}] \ No newline at end of file