From 22360c78d550a25b9bdaea12cdb208371b69a488 Mon Sep 17 00:00:00 2001
From: "andre.schmid" <andre.schmid@est.tech>
Date: Fri, 12 Jul 2019 12:33:10 +0000
Subject: Allow relative path for SOL004 descriptors import

Allow the use of relative path on SOL004 descriptors imports. Resolves
imports with "/", "../" or "./" entries during validation and package
processing.
Validate if the reference is inside the package.
Fix problem where imported descriptor files, described as a non string
scalar yaml entry, were not being checked by the validator.

Change-Id: Ie5a32736b6090b4adf178e8714f7460bcd068def
Issue-ID: SDC-2422
Signed-off-by: andre.schmid <andre.schmid@est.tech>
---
 .../core/impl/AbstractToscaSolConverter.java       |  48 +---
 .../InvalidToscaDefinitionImportException.java     |  55 ++++
 .../core/impl/ToscaDefinitionImportHandler.java    | 231 ++++++++++++++++
 .../impl/ToscaDefinitionImportHandlerTest.java     | 291 +++++++++++++++++++++
 .../core/impl/ToscaSolConverterVnfTest.java        |  78 ++++--
 .../org/openecomp/core/util/TestResourcesUtil.java |  80 ++++++
 .../Artifacts/descriptorCyclicReference.yaml       |   6 +
 .../Artifacts/descriptorWithAbsolutePaths.yaml     |   5 +
 .../Definitions/Main.yaml                          |   9 +
 .../Definitions/Main1.yaml                         |   9 +
 .../Definitions/MainWithInvalidImportedFile.yaml   |   9 +
 .../Definitions/MainWithNonexistentReferences.yaml |   9 +
 .../Definitions/descriptorBasicImport.yaml         |   5 +
 .../descriptorFileWithValidImportStatements.yaml   |  12 +
 .../Definitions/descriptorInvalid.yaml             |   9 +
 .../descriptorInvalidImportStatement.yaml          |   5 +
 .../Definitions/descriptorNonexistentImport.yaml   |   9 +
 .../Definitions/descriptorWithRelativePaths.yaml   |   6 +
 .../toscaSOlConverter/sample_import2.yaml          |   2 +-
 .../toscaSOlConverter/sample_import3.yaml          |   3 +-
 20 files changed, 823 insertions(+), 58 deletions(-)
 create mode 100644 openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/main/java/org/openecomp/core/impl/InvalidToscaDefinitionImportException.java
 create mode 100644 openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/main/java/org/openecomp/core/impl/ToscaDefinitionImportHandler.java
 create mode 100644 openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/java/org/openecomp/core/impl/ToscaDefinitionImportHandlerTest.java
 create mode 100644 openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/java/org/openecomp/core/util/TestResourcesUtil.java
 create mode 100644 openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Artifacts/descriptorCyclicReference.yaml
 create mode 100644 openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Artifacts/descriptorWithAbsolutePaths.yaml
 create mode 100644 openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/Main.yaml
 create mode 100644 openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/Main1.yaml
 create mode 100644 openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/MainWithInvalidImportedFile.yaml
 create mode 100644 openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/MainWithNonexistentReferences.yaml
 create mode 100644 openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorBasicImport.yaml
 create mode 100644 openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorFileWithValidImportStatements.yaml
 create mode 100644 openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorInvalid.yaml
 create mode 100644 openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorInvalidImportStatement.yaml
 create mode 100644 openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorNonexistentImport.yaml
 create mode 100644 openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorWithRelativePaths.yaml

(limited to 'openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src')

diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/main/java/org/openecomp/core/impl/AbstractToscaSolConverter.java b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/main/java/org/openecomp/core/impl/AbstractToscaSolConverter.java
index 6371ba67d9..f0d8bb2b3c 100644
--- a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/main/java/org/openecomp/core/impl/AbstractToscaSolConverter.java
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/main/java/org/openecomp/core/impl/AbstractToscaSolConverter.java
@@ -23,8 +23,6 @@
 package org.openecomp.core.impl;
 
 import org.onap.sdc.tosca.datatypes.model.ServiceTemplate;
-import org.openecomp.core.converter.ServiceTemplateReaderService;
-import org.openecomp.core.impl.services.ServiceTemplateReaderServiceImpl;
 import org.openecomp.core.utilities.file.FileContentHandler;
 import org.openecomp.sdc.logging.api.Logger;
 import org.openecomp.sdc.logging.api.LoggerFactory;
@@ -35,12 +33,10 @@ import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import static org.openecomp.core.converter.datatypes.Constants.globalStName;
-import static org.openecomp.sdc.tosca.csar.CSARConstants.NON_FILE_IMPORT_ATTRIBUTES;
 import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_ENTRY_DEFINITIONS;
 import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_PATH_FILE_NAME;
 
@@ -68,8 +64,7 @@ public abstract class AbstractToscaSolConverter extends AbstractToscaConverter {
                                            GlobalSubstitutionServiceTemplate gsst, String mServiceDefinitionFileName) {
         if (mServiceDefinitionFileName != null) {
             handleServiceTemplate(getSimpleName(mServiceDefinitionFileName), mServiceDefinitionFileName, csarFiles, serviceTemplates);
-            String parentDir = mServiceDefinitionFileName.substring(0, mServiceDefinitionFileName.lastIndexOf("/"));
-            handleImportDefinitions(mServiceDefinitionFileName, csarFiles, parentDir, gsst);
+            handleImportDefinitions(mServiceDefinitionFileName, csarFiles, gsst);
         }
     }
 
@@ -86,39 +81,16 @@ public abstract class AbstractToscaSolConverter extends AbstractToscaConverter {
         }
     }
 
-    private void handleImportDefinitions(String fileName, Map<String, byte[]> csarFiles, String parentDir, GlobalSubstitutionServiceTemplate gsst) {
-        handledDefinitionFilesList.add(fileName);
-        ServiceTemplateReaderService readerService = new ServiceTemplateReaderServiceImpl(csarFiles.get(fileName));
-        List<Object> imports = (readerService).getImports();
-        for (Object o : imports) {
-            String importPath = getImportedFilePath(o, parentDir);
-            if (importPath != null && !handledDefinitionFilesList.contains(importPath)) {
-                handleDefintionTemplate(importPath, csarFiles, gsst);
-                if (importPath.contains("/")) {
-                    parentDir = importPath.substring(0, importPath.lastIndexOf("/"));
-                }
-                handleImportDefinitions(importPath, csarFiles, parentDir, gsst);
-            }
+    private void handleImportDefinitions(final String fileName, final Map<String, byte[]> csarFiles
+        , final GlobalSubstitutionServiceTemplate gsst) {
+        final ToscaDefinitionImportHandler toscaDefinitionImportHandler = new ToscaDefinitionImportHandler(csarFiles, fileName);
+        if (toscaDefinitionImportHandler.hasError()) {
+            throw new InvalidToscaDefinitionImportException(toscaDefinitionImportHandler.getErrors());
         }
-        return;
-    }
-
-    private String getImportedFilePath(Object o, String parentDir) {
-        if (o instanceof String) {
-            String fileName = (String) o;
-            if (!fileName.contains("/")) {
-                fileName = parentDir + "/" + fileName;
-            }
-            return fileName;
-        } else if (o instanceof Map) {
-            Map<String, Object> o1 = (Map) o;
-            for (Map.Entry<String, Object> entry : o1.entrySet()) {
-                if (NON_FILE_IMPORT_ATTRIBUTES.stream().noneMatch(attr -> entry.getKey().equals(attr))) {
-                    getImportedFilePath(entry.getValue(), parentDir);
-                }
-            }
+        handledDefinitionFilesList.addAll(toscaDefinitionImportHandler.getHandledDefinitionFilesList());
+        for (final String file : handledDefinitionFilesList) {
+            handleDefintionTemplate(file, csarFiles, gsst);
         }
-        return null;
     }
 
     private String getMainServiceDefinitionFileName(FileContentHandler contentHandler) throws IOException {
@@ -134,7 +106,7 @@ public abstract class AbstractToscaSolConverter extends AbstractToscaConverter {
 
     private String getSimpleName(String path) {
         if (path != null && path.contains("/")) {
-            path = path.substring(path.lastIndexOf("/") + 1);
+            path = path.substring(path.lastIndexOf('/') + 1);
         }
         return path;
     }
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/main/java/org/openecomp/core/impl/InvalidToscaDefinitionImportException.java b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/main/java/org/openecomp/core/impl/InvalidToscaDefinitionImportException.java
new file mode 100644
index 0000000000..ac2e5eccc2
--- /dev/null
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/main/java/org/openecomp/core/impl/InvalidToscaDefinitionImportException.java
@@ -0,0 +1,55 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2019 Nordix Foundation
+ *  ================================================================================
+ *  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.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.core.impl;
+
+import java.util.List;
+import java.util.StringJoiner;
+import org.apache.commons.collections.CollectionUtils;
+import org.openecomp.sdc.datatypes.error.ErrorMessage;
+
+/**
+ * Runtime exception for errors in import statements inside a TOSCA definition yaml file.
+ */
+public class InvalidToscaDefinitionImportException extends RuntimeException {
+
+    private final String message;
+
+    /**
+     * Builds the exception message based on the provided validation error list.
+     * @param validationErrorList   The error list
+     */
+    public InvalidToscaDefinitionImportException(final List<ErrorMessage> validationErrorList) {
+        final StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append("The provided package is invalid as it contains descriptors import errors:\n");
+        if (CollectionUtils.isNotEmpty(validationErrorList)) {
+            final StringJoiner joiner = new StringJoiner(";\n");
+            validationErrorList.forEach(
+                errorMessage -> joiner.add(String.format("%s: %s", errorMessage.getLevel(), errorMessage.getMessage())));
+            message = stringBuilder.append(joiner.toString()).toString();
+        } else {
+            message = stringBuilder.toString();
+        }
+    }
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+}
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/main/java/org/openecomp/core/impl/ToscaDefinitionImportHandler.java b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/main/java/org/openecomp/core/impl/ToscaDefinitionImportHandler.java
new file mode 100644
index 0000000000..8422c89f2e
--- /dev/null
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/main/java/org/openecomp/core/impl/ToscaDefinitionImportHandler.java
@@ -0,0 +1,231 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2019 Nordix Foundation
+ *  ================================================================================
+ *  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.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.core.impl;
+
+import static org.openecomp.sdc.tosca.csar.CSARConstants.NON_FILE_IMPORT_ATTRIBUTES;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.openecomp.core.converter.ServiceTemplateReaderService;
+import org.openecomp.core.impl.services.ServiceTemplateReaderServiceImpl;
+import org.openecomp.sdc.common.errors.Messages;
+import org.openecomp.sdc.datatypes.error.ErrorLevel;
+import org.openecomp.sdc.datatypes.error.ErrorMessage;
+
+/**
+ * Handles TOSCA definition imports, checking for import definition errors.
+ */
+public class ToscaDefinitionImportHandler {
+
+    private final Map<String, byte[]> fileMap;
+    private final Set<String> handledDefinitionFilesList = new LinkedHashSet<>();
+    private final List<ErrorMessage> validationErrorList = new ArrayList<>();
+    private String currentFile;
+
+    /**
+     * Reads the provided package structure starting from a main definition yaml file.
+     * @param fileStructureMap      The package structure with file path and respective file byte
+     * @param mainDefinitionFilePath    The main descriptor yaml file to start the reading
+     */
+    public ToscaDefinitionImportHandler(final Map<String, byte[]> fileStructureMap, final String mainDefinitionFilePath) {
+        this.fileMap = fileStructureMap;
+        handleImports(mainDefinitionFilePath);
+    }
+
+    /**
+     * Reads and validates the descriptor imports recursively.
+     * Starts from the provided descriptor and goes until the end of the import tree.
+     * Processes each file just once.
+     *
+     * @param fileName      the descriptor file path
+     */
+    private void handleImports(final String fileName) {
+        currentFile = fileName;
+        if (!checkImportExists(fileName)) {
+            return;
+        }
+        final ServiceTemplateReaderService readerService;
+        try {
+            readerService = new ServiceTemplateReaderServiceImpl(fileMap.get(fileName));
+        } catch (final Exception ex) {
+            reportError(ErrorLevel.ERROR,
+                String.format(Messages.INVALID_YAML_FORMAT.getErrorMessage(), ex.getMessage()));
+            return;
+        }
+        handledDefinitionFilesList.add(fileName);
+        final List<Object> imports = readerService.getImports();
+        final List<String> extractImportFiles = extractFileImports(imports);
+        for (final String importedFile : extractImportFiles) {
+            final String resolvedPath = resolveImportPath(FilenameUtils.getPath(fileName), importedFile);
+            if (!handledDefinitionFilesList.contains(resolvedPath)) {
+                handleImports(resolvedPath);
+            }
+        }
+    }
+
+    /**
+     * Iterates reads each import statement in the given list.
+     * <pre>
+     * example of a descriptor.yaml import statement
+     * imports:
+     * - /Artifacts/anImportedDescriptor.yaml
+     * - anotherDescriptor: anotherImportedDescriptor.yaml
+     * - yetAnotherDescriptor:
+     *     yetAnotherDescriptor: ../Definitions/yetAnotherDescriptor.yaml
+     * </pre>
+     * @param imports   the import statements
+     * @return
+     *  The list of import file paths found
+     */
+    private List<String> extractFileImports(final List<Object> imports) {
+        final List<String> importedFileList = new ArrayList<>();
+        imports.forEach(importObject -> importedFileList.addAll(readImportStatement(importObject)));
+
+        return importedFileList;
+    }
+
+    /**
+     * Reads an import statement which can be a value, a [key:value] or a [key:[key:value]].
+     * Ignores entries which contains the same keys as
+     * {@link org.openecomp.sdc.tosca.csar.CSARConstants#NON_FILE_IMPORT_ATTRIBUTES}.
+     * Reports invalid import statements.
+     * <pre>
+     * example of yaml imports statements:
+     * - /Artifacts/anImportedDescriptor.yaml
+     * - anotherDescriptor: anotherImportedDescriptor.yaml
+     * - yetAnotherDescriptor:
+     *     yetAnotherDescriptor: ../Definitions/yetAnotherDescriptor.yaml
+     * </pre>
+     * @param importObject      the object representing the yaml import statement
+     * @return
+     *  The list of import file paths found
+     */
+    private List<String> readImportStatement(final Object importObject) {
+        final List<String> importedFileList = new ArrayList<>();
+        if (importObject instanceof String) {
+            importedFileList.add((String) importObject);
+        } else if (importObject instanceof Map) {
+            final Map<String, Object> importObjectMap = (Map) importObject;
+            for (final Map.Entry entry : importObjectMap.entrySet()) {
+                if (NON_FILE_IMPORT_ATTRIBUTES.stream().noneMatch(attr -> entry.getKey().equals(attr))) {
+                    importedFileList.addAll(readImportStatement(entry.getValue()));
+                }
+            }
+        } else {
+            reportError(ErrorLevel.ERROR,
+                String.format(Messages.INVALID_IMPORT_STATEMENT.getErrorMessage(), currentFile, importObject));
+        }
+
+        return importedFileList;
+    }
+
+    /**
+     * Given a directory path, resolves the import path.
+     * @param directoryPath     A directory path to resolve the import path
+     * @param importPath        An import statement path
+     * @return
+     *  The resolved path of the import, using as base the directory path
+     */
+    private String resolveImportPath(final String directoryPath, final String importPath) {
+        final String fixedParentDir;
+        if (StringUtils.isEmpty(directoryPath)) {
+            fixedParentDir = "/";
+        } else {
+            fixedParentDir = String.format("%s%s%s",
+                directoryPath.startsWith("/") ? "" : "/"
+                , directoryPath
+                , directoryPath.endsWith("/") ? "" : "/");
+        }
+
+        final URI parentDirUri = URI.create(fixedParentDir);
+
+        String resolvedImportPath = parentDirUri.resolve(importPath).toString();
+        if (resolvedImportPath.contains("../")) {
+            reportError(ErrorLevel.ERROR,
+                Messages.INVALID_IMPORT_STATEMENT.formatMessage(currentFile, importPath));
+            return null;
+        }
+        if (resolvedImportPath.startsWith("/")) {
+            resolvedImportPath = resolvedImportPath.substring(1);
+        }
+
+        return resolvedImportPath;
+    }
+
+    /**
+     * Checks if the given file path exists inside the file structure.
+     * Reports an error if the file was not found.
+     *
+     * @param filePath  file path to check inside the file structure
+     * @return
+     *  {@code true} if the file exists, {@code false} otherwise
+     */
+    private boolean checkImportExists(final String filePath) {
+        if (!fileMap.keySet().contains(filePath)) {
+            reportError(ErrorLevel.ERROR, Messages.MISSING_IMPORT_FILE.formatMessage(filePath));
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Gets all processed files during the import handling.
+     * @return
+     *  A list containing the processed files paths
+     */
+    public Set<String> getHandledDefinitionFilesList() {
+        return handledDefinitionFilesList;
+    }
+
+    /**
+     * Adds an error to the validation error list.
+     *
+     * @param errorLevel        the error level
+     * @param errorMessage      the error message
+     */
+    private void reportError(final ErrorLevel errorLevel, final String errorMessage) {
+        validationErrorList.add(new ErrorMessage(errorLevel, errorMessage));
+    }
+
+    /**
+     * Gets the list of errors.
+     * @return
+     *  The import validation errors detected
+     */
+    public List<ErrorMessage> getErrors() {
+        return validationErrorList;
+    }
+
+    /**
+     * Checks if the handler detected a import error.
+     * @return
+     *  {@code true} if the handler detected any error, {@code false} otherwise.
+     */
+    public boolean hasError() {
+        return !validationErrorList.isEmpty();
+    }
+}
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/java/org/openecomp/core/impl/ToscaDefinitionImportHandlerTest.java b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/java/org/openecomp/core/impl/ToscaDefinitionImportHandlerTest.java
new file mode 100644
index 0000000000..30cba677f2
--- /dev/null
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/java/org/openecomp/core/impl/ToscaDefinitionImportHandlerTest.java
@@ -0,0 +1,291 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2019 Nordix Foundation
+ *  ================================================================================
+ *  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.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.core.impl;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.hasSize;
+import static org.openecomp.core.util.TestResourcesUtil.getResourceBytesOrFail;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.junit.Before;
+import org.junit.Test;
+import org.openecomp.sdc.common.errors.Messages;
+import org.openecomp.sdc.datatypes.error.ErrorLevel;
+import org.openecomp.sdc.datatypes.error.ErrorMessage;
+
+public class ToscaDefinitionImportHandlerTest {
+
+    private static final String RESOURCES_FILE_PATH = "/toscaDefinitionImportHandler/";
+    private Map<String, byte[]> descriptorFileMap;
+
+    @Before
+    public void setUp() {
+        descriptorFileMap = new HashMap<>();
+    }
+
+    /**
+     * Tests correct descriptor files.
+     */
+    @Test
+    public void testGivenDescriptorFiles_whenMainDescriptorImportsAreHandled_allDescriptorsAreProcessedWithoutError() {
+        final List<String> filesToHandleList = Arrays.asList("Definitions/Main.yaml", "Definitions/descriptorBasicImport.yaml",
+            "Definitions/descriptorWithRelativePaths.yaml", "Artifacts/descriptorWithAbsolutePaths.yaml",
+            "Artifacts/descriptorCyclicReference.yaml");
+
+        filesToHandleList.forEach(file -> descriptorFileMap.put(file, getResourceBytesOrFail(RESOURCES_FILE_PATH + file)));
+
+        final ToscaDefinitionImportHandler toscaDefinitionImportHandler = new ToscaDefinitionImportHandler(
+            descriptorFileMap,
+            "Definitions/Main.yaml");
+        final Set<String> actualHandledFiles = toscaDefinitionImportHandler.getHandledDefinitionFilesList();
+
+        assertThat("The handled files should be the same", actualHandledFiles, hasSize(filesToHandleList.size()));
+        assertThat("The handled files should be the same"
+            , actualHandledFiles, containsInAnyOrder(filesToHandleList.toArray(new String[0]))
+        );
+
+        final List<ErrorMessage> validationErrorList = toscaDefinitionImportHandler.getErrors();
+        assertThat("No errors should be detected", validationErrorList, hasSize(0));
+    }
+
+    /**
+     * Tests an empty package.
+     */
+    @Test
+    public void testGivenEmptyPackage_whenMainDescriptorIsHandled_aMissingFileErrorIsReported() {
+        final List<String> filesToHandleList = Collections.emptyList();
+
+        final ToscaDefinitionImportHandler toscaDefinitionImportHandler = new ToscaDefinitionImportHandler(
+            descriptorFileMap,
+            "Definitions/Main.yaml");
+        final Set<String> actualHandledFiles = toscaDefinitionImportHandler.getHandledDefinitionFilesList();
+
+        assertThat("The handled files should be the same", actualHandledFiles, hasSize(filesToHandleList.size()));
+        assertThat("The handled files should be the same"
+            , actualHandledFiles, containsInAnyOrder(filesToHandleList.toArray(new String[0]))
+        );
+
+        final List<ErrorMessage> expectedErrorList = new ArrayList<>();
+        expectedErrorList.add(new ErrorMessage(ErrorLevel.ERROR,
+            Messages.MISSING_IMPORT_FILE.formatMessage("Definitions/Main.yaml")));
+
+        final List<ErrorMessage> validationErrorList = toscaDefinitionImportHandler.getErrors();
+        assertThat("The errors should be the same", validationErrorList, hasSize(expectedErrorList.size()));
+        assertThat("The errors should be the same"
+            , validationErrorList, containsInAnyOrder(expectedErrorList.toArray(new ErrorMessage[0]))
+        );
+    }
+
+    /**
+     * Tests a file imported in a descriptor but missing in the package.
+     */
+    @Test
+    public void testGivenOneMissingDescriptorFile_whenMainDescriptorImportsAreHandled_aMissingFileErrorIsReported() {
+        final List<String> filesToHandleList = Arrays.asList("Definitions/Main.yaml",
+            "Definitions/descriptorBasicImport.yaml", "Definitions/descriptorWithRelativePaths.yaml",
+            "Artifacts/descriptorWithAbsolutePaths.yaml");
+        filesToHandleList.forEach(file -> descriptorFileMap.put(file, getResourceBytesOrFail(RESOURCES_FILE_PATH + file)));
+
+        final List<ErrorMessage> expectedErrorList = new ArrayList<>();
+        expectedErrorList.add(new ErrorMessage(ErrorLevel.ERROR,
+            String.format(Messages.MISSING_IMPORT_FILE.getErrorMessage(), "Artifacts/descriptorCyclicReference.yaml")));
+
+        final ToscaDefinitionImportHandler toscaDefinitionImportHandler = new ToscaDefinitionImportHandler(
+            descriptorFileMap,
+            "Definitions/Main.yaml");
+        final Set<String> actualHandledFiles = toscaDefinitionImportHandler.getHandledDefinitionFilesList();
+
+        assertThat("The handled files should be the same", actualHandledFiles, hasSize(filesToHandleList.size()));
+        assertThat("The handled files should be the same"
+            , actualHandledFiles, containsInAnyOrder(filesToHandleList.toArray(new String[0]))
+        );
+
+        final List<ErrorMessage> validationErrorList = toscaDefinitionImportHandler.getErrors();
+        assertThat("The errors should be the same", validationErrorList, hasSize(expectedErrorList.size()));
+        assertThat("The errors should be the same"
+            , validationErrorList, containsInAnyOrder(expectedErrorList.toArray(new ErrorMessage[0]))
+        );
+    }
+
+    /**
+     * Tests a descriptor with invalid import statements.
+     */
+    @Test
+    public void testGivenDescriptorWithInvalidImportStatement_whenMainDescriptorImportsAreHandled_aInvalidImportStatementErrorIsReported() {
+        final String mainDefinitionFile = "Definitions/MainWithInvalidImportedFile.yaml";
+
+        final List<String> filesToHandleList = Arrays.asList(mainDefinitionFile,
+            "Definitions/descriptorInvalidImportStatement.yaml");
+        filesToHandleList.forEach(file -> descriptorFileMap.put(file, getResourceBytesOrFail(RESOURCES_FILE_PATH + file)));
+
+        final List<ErrorMessage> expectedErrorList = new ArrayList<>();
+        expectedErrorList.add(new ErrorMessage(ErrorLevel.ERROR,
+            Messages.INVALID_IMPORT_STATEMENT.formatMessage("Definitions/descriptorInvalidImportStatement.yaml", "null")));
+
+        final ToscaDefinitionImportHandler toscaDefinitionImportHandler = new ToscaDefinitionImportHandler(
+            descriptorFileMap,
+            mainDefinitionFile);
+        final Set<String> actualHandledFiles = toscaDefinitionImportHandler.getHandledDefinitionFilesList();
+
+        assertThat("The handled files should be the same", actualHandledFiles, hasSize(filesToHandleList.size()));
+        assertThat("The handled files should be the same"
+            , actualHandledFiles, containsInAnyOrder(filesToHandleList.toArray(new String[0]))
+        );
+
+        final List<ErrorMessage> validationErrorList = toscaDefinitionImportHandler.getErrors();
+        assertThat("The errors should be the same", validationErrorList, hasSize(expectedErrorList.size()));
+        assertThat("The errors should be the same"
+            , validationErrorList, containsInAnyOrder(expectedErrorList.toArray(new ErrorMessage[0]))
+        );
+    }
+
+    /**
+     * Tests an invalid main descriptor file path.
+     */
+    @Test
+    public void testGivenInvalidMainDescriptorFilePath_whenDescriptorIsHandled_aMissingImportErrorIsReported() {
+        final String mainDefinitionFilePath = "Definitions/Main1.yaml";
+        final String invalidMainDefinitionFilePath = "../Definitions/InvalidMainDefinitionFile.yaml";
+
+        final List<String> filesToHandleList = Arrays.asList(mainDefinitionFilePath);
+        filesToHandleList.forEach(file -> descriptorFileMap.put(file, getResourceBytesOrFail(RESOURCES_FILE_PATH + file)));
+
+        final List<ErrorMessage> expectedErrorList = new ArrayList<>();
+        expectedErrorList.add(new ErrorMessage(ErrorLevel.ERROR, Messages.MISSING_IMPORT_FILE.formatMessage(invalidMainDefinitionFilePath)));
+
+        final ToscaDefinitionImportHandler toscaDefinitionImportHandler = new ToscaDefinitionImportHandler(
+            descriptorFileMap,
+            invalidMainDefinitionFilePath);
+        final Set<String> actualHandledFiles = toscaDefinitionImportHandler.getHandledDefinitionFilesList();
+
+        assertThat("No files should be handled", actualHandledFiles, hasSize(0));
+
+        final List<ErrorMessage> validationErrorList = toscaDefinitionImportHandler.getErrors();
+
+        assertThat("The errors should be the same", validationErrorList, hasSize(expectedErrorList.size()));
+        assertThat("The errors should be the same"
+            , validationErrorList, containsInAnyOrder(expectedErrorList.toArray(new ErrorMessage[0]))
+        );
+    }
+
+    /**
+     * Tests a descriptor with invalid yaml.
+     */
+    @Test
+    public void testGivenInvalidYamlDescriptorFile_whenDescriptorIsHandled_aInvalidYamlFormatErrorIsReported() {
+        final String mainDefinitionFile = "Definitions/descriptorInvalid.yaml";
+
+        final List<String> filesToHandleList = Arrays.asList(mainDefinitionFile);
+        filesToHandleList.forEach(file -> descriptorFileMap.put(file, getResourceBytesOrFail(RESOURCES_FILE_PATH + file)));
+
+        final List<ErrorMessage> expectedErrorList = new ArrayList<>();
+        expectedErrorList.add(new ErrorMessage(ErrorLevel.ERROR, String.format(Messages.INVALID_YAML_FORMAT.getErrorMessage()
+            , "while scanning a simple key\n"
+                + " in 'string', line 5, column 3:\n"
+                + "      template_author= onap\n"
+                + "      ^\n"
+                + "could not find expected ':'\n"
+                + " in 'string', line 6, column 1:\n"
+                + "    description: vCPE_vgw\n"
+                + "    ^\n")));
+
+        final ToscaDefinitionImportHandler toscaDefinitionImportHandler = new ToscaDefinitionImportHandler(
+            descriptorFileMap,
+            mainDefinitionFile);
+        final Set<String> actualHandledFiles = toscaDefinitionImportHandler.getHandledDefinitionFilesList();
+
+        assertThat("No files should be handled", actualHandledFiles, hasSize(0));
+
+        final List<ErrorMessage> validationErrorList = toscaDefinitionImportHandler.getErrors();
+
+        assertThat("The errors should be the same", validationErrorList, hasSize(expectedErrorList.size()));
+        assertThat("The errors should be the same"
+            , validationErrorList, containsInAnyOrder(expectedErrorList.toArray(new ErrorMessage[0]))
+        );
+    }
+
+    /**
+     * Tests all forms of import statements.
+     */
+    @Test
+    public void testGivenDescriptorFiles_whenMainDescriptorWithDifferentImportStatementsIsHandled_noErrorsAreReported() {
+        final String mainDefinitionFile = "Definitions/descriptorFileWithValidImportStatements.yaml";
+
+        final List<String> filesToHandleList = Arrays.asList(mainDefinitionFile, "Artifacts/descriptorCyclicReference.yaml");
+        filesToHandleList.forEach(file -> descriptorFileMap.put(file, getResourceBytesOrFail(RESOURCES_FILE_PATH + file)));
+
+        final ToscaDefinitionImportHandler toscaDefinitionImportHandler =
+            new ToscaDefinitionImportHandler(descriptorFileMap, mainDefinitionFile);
+        final Set<String> actualHandledFiles = toscaDefinitionImportHandler.getHandledDefinitionFilesList();
+
+        assertThat("The handled files should be the same", actualHandledFiles, hasSize(filesToHandleList.size()));
+        assertThat("The handled files should be the same"
+            , actualHandledFiles, containsInAnyOrder(filesToHandleList.toArray(new String[0]))
+        );
+
+        final List<ErrorMessage> validationErrorList = toscaDefinitionImportHandler.getErrors();
+        assertThat("No errors should be detected", validationErrorList, hasSize(0));
+    }
+
+    /**
+     * Tests a descriptor with nonexistent import paths.
+     */
+    @Test
+    public void testGivenDescriptorFileWithNonexistentRelativeImport_whenIncorrectMainDescriptorIsHandled_aMissingFileErrorIsReported() {
+        final String mainDefinitionFile = "Definitions/MainWithNonexistentReferences.yaml";
+
+        final List<String> filesToHandleList = Arrays.asList(mainDefinitionFile, "Definitions/descriptorNonexistentImport.yaml",
+            "Artifacts/descriptorCyclicReference.yaml");
+        filesToHandleList.forEach(file -> descriptorFileMap.put(file, getResourceBytesOrFail(RESOURCES_FILE_PATH + file)));
+
+        final List<ErrorMessage> expectedErrorList = new ArrayList<>();
+        expectedErrorList.add(new ErrorMessage(ErrorLevel.ERROR,
+            String.format(Messages.MISSING_IMPORT_FILE.getErrorMessage(), "Definitions/descriptorCyclicReference.yaml")));
+        expectedErrorList.add(new ErrorMessage(ErrorLevel.ERROR,
+            String.format(Messages.MISSING_IMPORT_FILE.getErrorMessage(), "Definitions/descriptorCyclicReference.yaml")));
+        expectedErrorList.add(new ErrorMessage(ErrorLevel.ERROR,
+            String.format(Messages.MISSING_IMPORT_FILE.getErrorMessage(), "Definitions/descriptorCyclicReference.yaml")));
+
+        final ToscaDefinitionImportHandler toscaDefinitionImportHandler = new ToscaDefinitionImportHandler(
+            descriptorFileMap,
+            mainDefinitionFile);
+        final Set<String> actualHandledFiles = toscaDefinitionImportHandler.getHandledDefinitionFilesList();
+
+        assertThat("The handled files should be the same", actualHandledFiles, hasSize(filesToHandleList.size()));
+        assertThat("The handled files should be the same"
+            , actualHandledFiles, containsInAnyOrder(filesToHandleList.toArray(new String[0]))
+        );
+
+        final List<ErrorMessage> validationErrorList = toscaDefinitionImportHandler.getErrors();
+
+        assertThat("The errors should be the same", validationErrorList, hasSize(expectedErrorList.size()));
+        assertThat("The errors should be the same"
+            , validationErrorList, containsInAnyOrder(expectedErrorList.toArray(new ErrorMessage[0]))
+        );
+    }
+
+}
\ No newline at end of file
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/java/org/openecomp/core/impl/ToscaSolConverterVnfTest.java b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/java/org/openecomp/core/impl/ToscaSolConverterVnfTest.java
index 532573bcf4..f130f262a7 100644
--- a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/java/org/openecomp/core/impl/ToscaSolConverterVnfTest.java
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/java/org/openecomp/core/impl/ToscaSolConverterVnfTest.java
@@ -22,6 +22,8 @@
 
 package org.openecomp.core.impl;
 
+import static org.junit.Assert.fail;
+
 import org.apache.commons.io.IOUtils;
 import org.junit.Assert;
 import org.junit.Before;
@@ -29,6 +31,8 @@ import org.junit.Test;
 import org.onap.sdc.tosca.datatypes.model.ServiceTemplate;
 import org.openecomp.core.utilities.file.FileContentHandler;
 import org.openecomp.sdc.common.errors.CoreException;
+import org.openecomp.sdc.logging.api.Logger;
+import org.openecomp.sdc.logging.api.LoggerFactory;
 import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel;
 import java.io.IOException;
 import java.io.InputStream;
@@ -37,6 +41,7 @@ import java.util.Map;
 
 
 public class ToscaSolConverterVnfTest {
+    private static final Logger LOGGER = LoggerFactory.getLogger(ToscaSolConverterVnfTest.class);
 
     private AbstractToscaSolConverter toscaSolConverter;
     private FileContentHandler fileContentHandler;
@@ -47,10 +52,8 @@ public class ToscaSolConverterVnfTest {
         fileContentHandler = new FileContentHandler();
     }
 
-
     @Test
-    public void testGivenSOL004WithMetadataDirectoryPackage_whenToscaSolConverterIsCalled_validToscaServiceModelIsReturned()
-            throws IOException{
+    public void testGivenSOL004WithMetadataDirectoryPackage_whenToscaSolConverterIsCalled_validToscaServiceModelIsReturned() {
         fileContentHandler.addFile("TOSCA-Metadata/TOSCA.meta",
                 ("TOSCA-Meta-File-Version: 1.0\n " +
                 "CSAR-Version: 1.1\n" +
@@ -60,29 +63,52 @@ public class ToscaSolConverterVnfTest {
                 "Entry-Change-Log: Artifacts/ChangeLog.txt")
                         .getBytes(StandardCharsets.UTF_8));
 
-        fileContentHandler.addFile("Definitions/Main.yaml", getFileResource("/toscaSOlConverter/Main.yaml"));
-        fileContentHandler.addFile("Main.mf", "".getBytes());
+        final String mainServiceTemplate = "Main.yaml";
+        final String mainManifest = "Main.mf";
+
+        fileContentHandler.addFile("Definitions/" + mainServiceTemplate, getFileResource("/toscaSOlConverter/Main.yaml"));
+        fileContentHandler.addFile(mainManifest, "".getBytes());
         fileContentHandler.addFile("Definitions/sample_import1.yaml", getFileResource("/toscaSOlConverter/sample_import1.yaml"));
         fileContentHandler.addFile("Definitions/sample_import2.yaml", getFileResource("/toscaSOlConverter/sample_import2.yaml"));
         fileContentHandler.addFile("Artifacts/sample_import3.yaml", getFileResource("/toscaSOlConverter/sample_import3.yaml"));
         fileContentHandler.addFile("Artifacts/sample_import4.yaml", getFileResource("/toscaSOlConverter/sample_import4.yaml"));
-        ToscaServiceModel toscaServiceModel = toscaSolConverter.convert(fileContentHandler);
-        FileContentHandler contentHandler = toscaServiceModel.getArtifactFiles();
-        Map<String, ServiceTemplate> serviceTemplateMap = toscaServiceModel.getServiceTemplates();
-        String entryDefinitionTemplateName = toscaServiceModel.getEntryDefinitionServiceTemplate();
-        Assert.assertTrue("Artifacts should contain external files", contentHandler.containsFile("Main.mf"));
-        Assert.assertTrue("Main service template should exist", serviceTemplateMap.containsKey("Main.yaml"));
+        fileContentHandler.addFile("sample_import5.yaml", getFileResource("/toscaSOlConverter/sample_import3.yaml"));
+
+        final ToscaServiceModel toscaServiceModel = convertToscaSol();
+        final FileContentHandler contentHandler = toscaServiceModel.getArtifactFiles();
+        final Map<String, ServiceTemplate> serviceTemplateMap = toscaServiceModel.getServiceTemplates();
+        final String entryDefinitionTemplateName = toscaServiceModel.getEntryDefinitionServiceTemplate();
+        Assert.assertTrue("Artifacts should contain external files", contentHandler.containsFile(mainManifest));
+        Assert.assertTrue("Main service template should exist", serviceTemplateMap.containsKey(mainServiceTemplate));
         Assert.assertEquals("Entry Definition name should be same as passed in TOSCA.meta",
-                "Main.yaml", entryDefinitionTemplateName);
+            mainServiceTemplate, entryDefinitionTemplateName);
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void testGivenSOL004InvalidDirectoryPackage_whenToscaSolConverterIsCalled_exceptionIsExpected() {
+        fileContentHandler.addFile("TOSCA-Metadata/TOSCA.meta",
+            ("TOSCA-Meta-File-Version: 1.0\n " +
+                "CSAR-Version: 1.1\n" +
+                "Created-by: Ericsson\n" +
+                "Entry-Definitions: Definitions/Main.yaml\n" +
+                "Entry-Manifest: Main.mf\n" +
+                "Entry-Change-Log: Artifacts/ChangeLog.txt")
+                .getBytes(StandardCharsets.UTF_8));
+
+        fileContentHandler.addFile("Definitions/Main.yaml", getFileResource("/toscaSOlConverter/Main.yaml"));
+        fileContentHandler.addFile("Main.mf", "".getBytes());
+        fileContentHandler.addFile("Definitions/sample_import1.yaml", getFileResource("/toscaSOlConverter/sample_import3.yaml"));
+
+        convertToscaSol();
     }
 
     @Test(expected = IOException.class)
-    public void testGivenMetaFileDoesNotExist_thenAnExceptionIsThrown() throws IOException{
+    public void testGivenMetaFileDoesNotExist_thenAnExceptionIsThrown() throws IOException {
         toscaSolConverter.convert(fileContentHandler);
     }
 
     @Test(expected = CoreException.class)
-    public void testGivenInvalidServiceTemplate_thenAnExceptionIsThrown() throws IOException{
+    public void testGivenInvalidServiceTemplate_thenAnExceptionIsThrown() {
 
         fileContentHandler.addFile("TOSCA-Metadata/TOSCA.meta",
                 ("TOSCA-Meta-File-Version: 1.0\n " +
@@ -94,12 +120,28 @@ public class ToscaSolConverterVnfTest {
                         .getBytes(StandardCharsets.UTF_8));
 
         fileContentHandler.addFile("Definitions/Main.yaml", getFileResource("/toscaSOlConverter/invalidMainService.yaml"));
-        toscaSolConverter.convert(fileContentHandler);
+        convertToscaSol();
     }
 
-    private byte[] getFileResource(String filePath) throws IOException {
-        InputStream inputStream = ClassLoader.class.getClass().getResourceAsStream(filePath);
-        return IOUtils.toByteArray(inputStream);
+    private ToscaServiceModel convertToscaSol() {
+        try {
+            return toscaSolConverter.convert(fileContentHandler);
+        } catch (final IOException e) {
+            final String errorMsg = "Could convert file content handler";
+            LOGGER.error(errorMsg, e);
+            fail(errorMsg);
+        }
+        return null;
+    }
+
+    private byte[] getFileResource(final String filePath) {
+        try (final InputStream inputStream = ClassLoader.class.getResourceAsStream(filePath)) {
+            return IOUtils.toByteArray(inputStream);
+        } catch (final IOException ex) {
+            fail(String.format("Could not load file: %s", filePath));
+        }
+
+        return null;
     }
 
 }
\ No newline at end of file
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/java/org/openecomp/core/util/TestResourcesUtil.java b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/java/org/openecomp/core/util/TestResourcesUtil.java
new file mode 100644
index 0000000000..34559f5386
--- /dev/null
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/java/org/openecomp/core/util/TestResourcesUtil.java
@@ -0,0 +1,80 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2019 Nordix Foundation
+ *  ================================================================================
+ *  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.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.core.util;
+
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.io.InputStream;
+import org.apache.commons.io.IOUtils;
+import org.openecomp.sdc.logging.api.Logger;
+import org.openecomp.sdc.logging.api.LoggerFactory;
+
+/**
+ * Test resources utility class.
+ */
+public class TestResourcesUtil {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(TestResourcesUtil.class);
+
+    private TestResourcesUtil() {
+
+    }
+
+    /**
+     * Reads a file and coverts it to a byte array.
+     *
+     * @param resourcePath      The resource file path
+     * @return
+     *  The resource file byte array
+     * @throws IOException
+     *  When the file was not found or the input stream could not be opened
+     */
+    public static byte[] getFileResource(final String resourcePath) throws IOException {
+        try(final InputStream inputStream = ClassLoader.class.getResourceAsStream(resourcePath)) {
+            if (inputStream == null) {
+                throw new IOException(String.format("Could not find the resource on path \"%s\"", resourcePath));
+            }
+            return IOUtils.toByteArray(inputStream);
+        } catch (final IOException ex) {
+            throw new IOException(String.format("Could not open the input stream for resource on path \"%s\"", resourcePath), ex);
+        }
+    }
+
+    /**
+     * Reads a file in the given path.
+     * The method forces an assertion fail if the resource could not be loaded.
+     * @param resourcePath      The resource file path
+     * @return
+     *  The resource file byte array
+     */
+    public static byte[] getResourceBytesOrFail(final String resourcePath) {
+        try {
+            return getFileResource(resourcePath);
+        } catch (final IOException e) {
+            final String errorMsg = String.format("Could not load resource '%s'", resourcePath);
+            LOGGER.error(errorMsg, e);
+            fail(errorMsg);
+        }
+
+        return null;
+    }
+
+}
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Artifacts/descriptorCyclicReference.yaml b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Artifacts/descriptorCyclicReference.yaml
new file mode 100644
index 0000000000..41163a0690
--- /dev/null
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Artifacts/descriptorCyclicReference.yaml
@@ -0,0 +1,6 @@
+tosca_definitions_version: tosca_simple_yaml_1_2
+description: ETSI NFV SOL 001 pnfd types definitions version 2.5.1
+
+imports:
+  - descriptorCyclicReference.yaml
+
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Artifacts/descriptorWithAbsolutePaths.yaml b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Artifacts/descriptorWithAbsolutePaths.yaml
new file mode 100644
index 0000000000..8c95c67697
--- /dev/null
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Artifacts/descriptorWithAbsolutePaths.yaml
@@ -0,0 +1,5 @@
+tosca_definitions_version: tosca_simple_yaml_1_2
+description: ETSI NFV SOL 001 pnfd types definitions version 2.5.1
+
+imports:
+  - /Artifacts/descriptorCyclicReference.yaml
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/Main.yaml b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/Main.yaml
new file mode 100644
index 0000000000..426d2d79b9
--- /dev/null
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/Main.yaml
@@ -0,0 +1,9 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+metadata:
+  template_name: vCPE_vgw
+  template_version: "1.0"
+  template_author: onap
+description: vCPE_vgw
+
+imports:
+  - descriptorBasicImport.yaml
\ No newline at end of file
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/Main1.yaml b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/Main1.yaml
new file mode 100644
index 0000000000..46a2bc2ef4
--- /dev/null
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/Main1.yaml
@@ -0,0 +1,9 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+metadata:
+  template_name: vCPE_vgw
+  template_version: "1.0"
+  template_author: onap
+description: vCPE_vgw
+
+imports:
+  - descriptorFileWithValidImportStatements.yaml
\ No newline at end of file
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/MainWithInvalidImportedFile.yaml b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/MainWithInvalidImportedFile.yaml
new file mode 100644
index 0000000000..fd94381cb8
--- /dev/null
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/MainWithInvalidImportedFile.yaml
@@ -0,0 +1,9 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+metadata:
+  template_name: vCPE_vgw
+  template_version: "1.0"
+  template_author: onap
+description: vCPE_vgw
+
+imports:
+  - descriptorInvalidImportStatement.yaml
\ No newline at end of file
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/MainWithNonexistentReferences.yaml b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/MainWithNonexistentReferences.yaml
new file mode 100644
index 0000000000..6b33c84638
--- /dev/null
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/MainWithNonexistentReferences.yaml
@@ -0,0 +1,9 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+metadata:
+  template_name: vCPE_vgw
+  template_version: "1.0"
+  template_author: onap
+description: vCPE_vgw
+
+imports:
+  - descriptorNonexistentImport.yaml
\ No newline at end of file
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorBasicImport.yaml b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorBasicImport.yaml
new file mode 100644
index 0000000000..2b7011ff5a
--- /dev/null
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorBasicImport.yaml
@@ -0,0 +1,5 @@
+tosca_definitions_version: tosca_simple_yaml_1_2
+description: ETSI NFV SOL 001 pnfd types definitions version 2.5.1
+
+imports:
+  - descriptorWithRelativePaths.yaml
\ No newline at end of file
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorFileWithValidImportStatements.yaml b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorFileWithValidImportStatements.yaml
new file mode 100644
index 0000000000..c867813be8
--- /dev/null
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorFileWithValidImportStatements.yaml
@@ -0,0 +1,12 @@
+tosca_definitions_version: tosca_simple_yaml_1_2
+
+description: example definition file for testing
+
+imports:
+  - /Artifacts/descriptorCyclicReference.yaml
+  - file: ../Artifacts/descriptorCyclicReference.yaml
+  - repository: <some_repository>
+  - namespace_uri: <some_namespace_uri>
+  - definitionFile3: ../Artifacts/descriptorCyclicReference.yaml
+  - definitionFile4:
+      file: ./../Artifacts/descriptorCyclicReference.yaml
\ No newline at end of file
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorInvalid.yaml b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorInvalid.yaml
new file mode 100644
index 0000000000..4d5b542826
--- /dev/null
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorInvalid.yaml
@@ -0,0 +1,9 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+metadata:
+  template_name: vCPE_vgw
+  template_version: "1.0"
+  template_author= onap
+description: vCPE_vgw
+
+imports:
+  - descriptorFileWithValidImportStatements.yaml
\ No newline at end of file
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorInvalidImportStatement.yaml b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorInvalidImportStatement.yaml
new file mode 100644
index 0000000000..7ccfa4b1a6
--- /dev/null
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorInvalidImportStatement.yaml
@@ -0,0 +1,5 @@
+tosca_definitions_version: tosca_simple_yaml_1_2
+description: ETSI NFV SOL 001 pnfd types definitions version 2.5.1
+
+imports:
+  - file:
\ No newline at end of file
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorNonexistentImport.yaml b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorNonexistentImport.yaml
new file mode 100644
index 0000000000..ac60b6c700
--- /dev/null
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorNonexistentImport.yaml
@@ -0,0 +1,9 @@
+tosca_definitions_version: tosca_simple_yaml_1_2
+description: ETSI NFV SOL 001 pnfd types definitions version 2.5.1
+
+imports:
+  - validPath1: /Artifacts/descriptorCyclicReference.yaml
+  - invalidPath1: descriptorCyclicReference.yaml
+  - validPath2: ../Artifacts/descriptorCyclicReference.yaml
+  - invalidPath2: /Definitions/descriptorCyclicReference.yaml
+  - invalidPath3: ../Definitions/descriptorCyclicReference.yaml
\ No newline at end of file
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorWithRelativePaths.yaml b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorWithRelativePaths.yaml
new file mode 100644
index 0000000000..f5eb7d61cb
--- /dev/null
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaDefinitionImportHandler/Definitions/descriptorWithRelativePaths.yaml
@@ -0,0 +1,6 @@
+tosca_definitions_version: tosca_simple_yaml_1_2
+description: ETSI NFV SOL 001 pnfd types definitions version 2.5.1
+
+imports:
+  - /Definitions/descriptorWithRelativePaths.yaml
+  - ./../Artifacts/./descriptorWithAbsolutePaths.yaml
\ No newline at end of file
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaSOlConverter/sample_import2.yaml b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaSOlConverter/sample_import2.yaml
index 42816eeb73..b77ff08d52 100644
--- a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaSOlConverter/sample_import2.yaml
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaSOlConverter/sample_import2.yaml
@@ -3,4 +3,4 @@ description: ETSI NFV SOL 001 pnfd types definitions version 2.5.1
 
 imports:
   - sample_import2.yaml
-  - Artifacts/sample_import3.yaml
\ No newline at end of file
+  - ../Artifacts/sample_import3.yaml
\ No newline at end of file
diff --git a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaSOlConverter/sample_import3.yaml b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaSOlConverter/sample_import3.yaml
index 99eb46be4d..8656e5befe 100644
--- a/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaSOlConverter/sample_import3.yaml
+++ b/openecomp-be/lib/openecomp-tosca-converter-lib/openecomp-tosca-converter-core/src/test/resources/toscaSOlConverter/sample_import3.yaml
@@ -2,4 +2,5 @@ tosca_definitions_version: tosca_simple_yaml_1_2
 description: ETSI NFV SOL 001 pnfd types definitions version 2.5.1
 
 imports:
-  - sample_import4.yaml
\ No newline at end of file
+  - /Artifacts/sample_import4.yaml
+  - /sample_import5.yaml
\ No newline at end of file
-- 
cgit 1.2.3-korg