Merge "Test coverage and refactor for GeneratorUtil"
authorTian Lee <TianL@amdocs.com>
Fri, 6 Jul 2018 10:32:55 +0000 (10:32 +0000)
committerGerrit Code Review <gerrit@onap.org>
Fri, 6 Jul 2018 10:32:55 +0000 (10:32 +0000)
24 files changed:
pom.xml
src/main/java/org/onap/aai/babel/csar/vnfcatalog/VnfVendorImageExtractor.java
src/main/java/org/onap/aai/babel/parser/ArtifactGeneratorToscaParser.java
src/main/java/org/onap/aai/babel/xml/generator/api/AaiArtifactGenerator.java
src/main/java/org/onap/aai/babel/xml/generator/api/AaiModelGenerator.java
src/main/java/org/onap/aai/babel/xml/generator/data/GeneratorConstants.java [deleted file]
src/main/java/org/onap/aai/babel/xml/generator/model/Configuration.java [new file with mode: 0644]
src/main/java/org/onap/aai/babel/xml/generator/model/ConfigurationWidget.java [new file with mode: 0644]
src/main/java/org/onap/aai/babel/xml/generator/model/Model.java
src/main/java/org/onap/aai/babel/xml/generator/model/Widget.java
src/test/java/org/onap/aai/babel/csar/extractor/YamlExtractorTest.java
src/test/java/org/onap/aai/babel/csar/vnfcatalog/ConfigurationsToBabelArtifactConverterTest.java [new file with mode: 0644]
src/test/java/org/onap/aai/babel/csar/vnfcatalog/VnfVendorImageExtractorTest.java [new file with mode: 0644]
src/test/java/org/onap/aai/babel/parser/TestToscaParser.java
src/test/java/org/onap/aai/babel/service/CsarToXmlConverterTest.java
src/test/java/org/onap/aai/babel/service/TestGenerateArtifactsServiceImpl.java
src/test/java/org/onap/aai/babel/service/TestRequestHeaders.java [new file with mode: 0644]
src/test/java/org/onap/aai/babel/xml/generator/model/TestModel.java [new file with mode: 0644]
src/test/resources/artifact-generator.properties
src/test/resources/compressedArtifacts/service_PortMirror.csar [new file with mode: 0644]
src/test/resources/generatedXml/AAI-Port Mirror_Test-service-1.0.xml [new file with mode: 0644]
src/test/resources/generatedXml/AAI-Port Mirroring Configuration-resource-35.0.xml [new file with mode: 0644]
src/test/resources/jsonFiles/success_request_vnf_catalog.json [new file with mode: 0644]
src/test/resources/jsonFiles/vnfVendorImageConfigurations.json [new file with mode: 0644]

diff --git a/pom.xml b/pom.xml
index 493012f..8543177 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -42,7 +42,7 @@
 
        <properties>
                <!-- Spring boot version -->
-               <spring.boot.version>1.5.12.RELEASE</spring.boot.version>
+               <spring.boot.version>1.5.14.RELEASE</spring.boot.version>
 
                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
@@ -62,6 +62,7 @@
                <sdc.distribution.client.version>1.3.0</sdc.distribution.client.version>
                <xmlunit.version>1.6</xmlunit.version>
                <logback.version>1.2.3</logback.version>
+               <guava.version>25.1-jre</guava.version>
        </properties>
 
        <dependencyManagement>
                        <artifactId>sdc-tosca</artifactId>
                        <version>${sdc.tosca.version}</version>
                </dependency>
+               <dependency>
+                       <groupId>com.google.guava</groupId>
+                       <artifactId>guava</artifactId>
+                       <version>${guava.version}</version>
+               </dependency>
+
                <dependency>
                        <groupId>org.onap.aai</groupId>
                        <artifactId>rest-client</artifactId>
                                <configuration>
                                        <verbose>true</verbose>
                                        <serverId>docker-hub</serverId>
-                                       <imageName>onap/${project.artifactId}</imageName>
+                                       <imageName>${docker.push.registry}/onap/${project.artifactId}</imageName>
                                        <dockerDirectory>${docker.location}</dockerDirectory>
                                        <imageTags>
                                                <imageTag>latest</imageTag>
index 9836e2a..b7d79a0 100644 (file)
@@ -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;
index 70e78ec..c769e9a 100644 (file)
  * 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<String, String> metadata) {
-        return ALLOTTED_RESOURCE.equals(metadata.get(GeneratorConstants.CATEGORY));
+        return ALLOTTED_RESOURCE.equals(metadata.get(CATEGORY));
     }
 
     private boolean hasSubCategoryTunnelXConnect(Map<String, String> 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<String, String> 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))) {
index c6ca460..79c7492 100644 (file)
@@ -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<Artifact> input,
             Map<String, String> 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<NodeTemplate> serviceNodes =
-                        csarHelper.getServiceNodeTemplates();
+                List<NodeTemplate> serviceNodes = csarHelper.getServiceNodeTemplates();
                 Map<String, String> 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<Resource> 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;
index 409dbc2..daf9d36 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * ============LICENSE_START=======================================================
+ * ============LICENSE_START=======================================================
  * org.onap.aai
  * ================================================================================
  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
  */
 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 (file)
index b9d8cb2..0000000
+++ /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 (file)
index 0000000..20dbea9
--- /dev/null
@@ -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 (file)
index 0000000..7822926
--- /dev/null
@@ -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 {
+}
index 0a8f0b1..956db40 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * ============LICENSE_START=======================================================
+ * ============LICENSE_START=======================================================
  * org.onap.aai
  * ================================================================================
  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
  */
 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<Resource> resources = new HashSet<>();
-    protected Set<Widget> 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<String, Class<? extends Model>> 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<String, ModelIdentification> propertyToModelIdent;
+        private String[] keys;
+
+        ModelIdentification(String... keys) {
+            this.keys = keys;
+        }
+
+        static {
+            Map<String, ModelIdentification> mappings = new HashMap<>();
+            for (ModelIdentification ident : ModelIdentification.values()) {
+                for (String key : ident.keys) {
+                    mappings.put(key, ident);
+                }
+            }
+            propertyToModelIdent = Collections.unmodifiableMap(mappings);
+        }
+
+        private static Optional<ModelIdentification> 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<Resource> resources = new HashSet<>();
+    protected Set<Widget> 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<Model> getModelFromType(String typePrefix) {
+        Optional<Model> modelToBeReturned = Optional.empty();
+        Class<? extends Model> 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<String, String> modelIdentInfo) {
         Iterator<String> 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<ModelIdentification> 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);
         }
     }
 }
index 2a85e27..7f39438 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * ============LICENSE_START=======================================================
+ * ============LICENSE_START=======================================================
  * org.onap.aai
  * ================================================================================
  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
  */
 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<String> 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<String> 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<String> 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
-    }
 }
index b53f38d..f783e7c 100644 (file)
@@ -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 (file)
index 0000000..b251401
--- /dev/null
@@ -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<VendorImageConfiguration> configurations =
+                new Gson().fromJson(expectedJson, new TypeToken<ArrayList<VendorImageConfiguration>>() {}.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 (file)
index 0000000..de5ea3f
--- /dev/null
@@ -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));
+    }
+}
index d27396d..a73e64c 100644 (file)
@@ -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);
index 0bc7c31..62e9265 100644 (file)
@@ -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<String, String> expectedXmlFiles = createExpectedXmlFiles();
+        List<BabelArtifact> 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<String> matches(final String expected) {
         return new BaseMatcher<String>() {
             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));
index 4cc8c8c..c770c60 100644 (file)
@@ -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 (file)
index 0000000..0d81867
--- /dev/null
@@ -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<String, String> 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<String, String> 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<String, String> 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<String, String> 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<String, String> 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<String, String> 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<String, String> 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<String, String> headersMap) {
+        HttpHeaders headers = Mockito.mock(HttpHeaders.class);
+        for (Entry<String, List<String>> entry : headersMap.entrySet()) {
+            List<String> 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<String> createSingletonList(String listItem) {
+        return Collections.<String>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 (file)
index 0000000..fbac64c
--- /dev/null
@@ -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()));
+    }
+
+}
index 1d7e5fa..74897d6 100644 (file)
@@ -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 (file)
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 (file)
index 0000000..5653c8a
--- /dev/null
@@ -0,0 +1,51 @@
+<model xmlns="http://org.onap.aai.inventory/v13">
+    <model-invariant-id>cd674566-ce17-4262-ae99-d526e7b8d47a</model-invariant-id>
+    <model-type>service</model-type>
+    <model-vers>
+        <model-ver>
+            <model-version-id>e033128a-ab5d-4b69-bfe6-c94f93a34f7c</model-version-id>
+            <model-name>Port Mirror_Test</model-name>
+            <model-version>1.0</model-version>
+            <model-description>Port Mirror_Test</model-description>
+            <model-elements>
+                <model-element>
+                    <new-data-del-flag>T</new-data-del-flag>
+                    <cardinality>unbounded</cardinality>
+                    <model-elements>
+                        <model-element>
+                            <new-data-del-flag>T</new-data-del-flag>
+                            <cardinality>unbounded</cardinality>
+                            <model-elements/>
+                            <relationship-list>
+                                <relationship>
+                                    <related-to>model-ver</related-to>
+                                    <relationship-data>
+                                        <relationship-key>model-ver.model-version-id</relationship-key>
+                                        <relationship-value>ea4e93c3-1a6d-4314-8165-c284a91422dc</relationship-value>
+                                    </relationship-data>
+                                    <relationship-data>
+                                        <relationship-key>model.model-invariant-id</relationship-key>
+                                        <relationship-value>cf53c1d6-8708-4b4e-a056-ead7daa57cd5</relationship-value>
+                                    </relationship-data>
+                                </relationship>
+                            </relationship-list>
+                        </model-element>
+                    </model-elements>
+                    <relationship-list>
+                        <relationship>
+                            <related-to>model-ver</related-to>
+                            <relationship-data>
+                                <relationship-key>model-ver.model-version-id</relationship-key>
+                                <relationship-value>46b92144-923a-4d20-b85a-3cbd847668a9</relationship-value>
+                            </relationship-data>
+                            <relationship-data>
+                                <relationship-key>model.model-invariant-id</relationship-key>
+                                <relationship-value>82194af1-3c2c-485a-8f44-420e22a9eaa4</relationship-value>
+                            </relationship-data>
+                        </relationship>
+                    </relationship-list>
+                </model-element>
+            </model-elements>
+        </model-ver>
+    </model-vers>
+</model>
\ 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 (file)
index 0000000..9418205
--- /dev/null
@@ -0,0 +1,32 @@
+<model xmlns="http://org.onap.aai.inventory/v13">
+    <model-invariant-id>cf53c1d6-8708-4b4e-a056-ead7daa57cd5</model-invariant-id>
+    <model-type>resource</model-type>
+    <model-vers>
+        <model-ver>
+            <model-version-id>ea4e93c3-1a6d-4314-8165-c284a91422dc</model-version-id>
+            <model-name>Port Mirroring Configuration</model-name>
+            <model-version>35.0</model-version>
+            <model-description>A port mirroring configuration object</model-description>
+            <model-elements>
+                <model-element>
+                    <new-data-del-flag>T</new-data-del-flag>
+                    <cardinality>unbounded</cardinality>
+                    <model-elements/>
+                    <relationship-list>
+                        <relationship>
+                            <related-to>model-ver</related-to>
+                            <relationship-data>
+                                <relationship-key>model-ver.model-version-id</relationship-key>
+                                <relationship-value>5a175add-57e4-4a5d-8b02-c36f1d69c52b</relationship-value>
+                            </relationship-data>
+                            <relationship-data>
+                                <relationship-key>model.model-invariant-id</relationship-key>
+                                <relationship-value>166c050d-f69d-4305-943e-0bc58c3a26cf</relationship-value>
+                            </relationship-data>
+                        </relationship>
+                    </relationship-list>
+                </model-element>
+            </model-elements>
+        </model-ver>
+    </model-vers>
+</model>
\ 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 (file)
index 0000000..3f0f137
--- /dev/null
@@ -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 (file)
index 0000000..cb836d3
--- /dev/null
@@ -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