[VVP] Allow base templates to not have resources
[vvp/validation-scripts.git] / ice_validator / tests / test_initial_configuration.py
index 7944970..13cc2c7 100644 (file)
 #
 # ============LICENSE_END============================================
 #
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
-#
-
 from os import path
 
 import pytest
-from tests import cached_yaml as yaml
+from yaml import YAMLError
+from yaml.constructor import ConstructorError
 
-from .helpers import validates
-from yamllint.config import YamlLintConfig
-from yamllint import linter
-from .utils.nested_files import check_for_invalid_nesting
-from .utils.nested_iterables import find_all_get_resource_in_yml
-from .utils.nested_iterables import find_all_get_param_in_yml
+from tests import cached_yaml as yaml
+from tests.utils import yaml_custom_utils
 
-"""
-Order tests by number so they execute in order for base tests
-"""
+from tests.helpers import validates, load_yaml
+from tests.utils.nested_files import check_for_invalid_nesting
+from tests.utils.nested_iterables import find_all_get_resource_in_yml
+from tests.utils.nested_iterables import find_all_get_param_in_yml
 
 
 @pytest.mark.base
-@validates('R-95303')
+@validates("R-95303")
 def test_00_valid_yaml(filename):
-    '''
-    Read in each .yaml or .env file. If it is successfully parsed as yaml, save
-    contents, else add filename to list of bad yaml files. Log the result of
-    parse attempt.
-    '''
-    conf = YamlLintConfig('rules: {}')
+    if path.splitext(filename)[-1].lower() not in (".yml", ".yaml", ".env"):
+        pytest.skip("Not a YAML file")
+    try:
+        load_yaml(filename)
+    except YAMLError as e:
+        assert False, (
+            "Invalid YAML detected: {} "
+            "NOTE: Online YAML checkers such as yamllint.com "
+            "can helpful in diagnosing errors in YAML"
+        ).format(str(e).replace("\n", " "))
 
-    if path.splitext(filename)[-1] in [".yml", ".yaml", ".env"]:
-        gen = linter.run(open(filename), conf)
-        errors = list(gen)
 
-        assert not errors, "Error parsing file {} with error {}".format(filename, errors)
-    else:
-        pytest.skip("The file does not have any of the extensions .yml,\
-            .yaml, or .env")
+def check_duplicate_keys(yaml_path):
+    import yaml as normal_yaml
+
+    try:
+        with open(yaml_path) as fh:
+            normal_yaml.load(fh, yaml_custom_utils.UniqueKeyLoader)  # nosec
+    except ConstructorError as e:
+        pytest.fail("{} {}".format(e.problem, e.problem_mark))
+
+
+@pytest.mark.base
+@validates("R-92635")
+def test_02_no_duplicate_keys_in_file(yaml_file):
+    check_duplicate_keys(yaml_file)
 
 
 @pytest.mark.base
-def test_02_all_referenced_resources_exists(yaml_file):
-    '''
+@validates("R-92635")
+def test_02a_no_duplicate_keys_in_env(env_file):
+    check_duplicate_keys(env_file)
+
+
+@pytest.mark.base
+@validates("R-92635")
+def test_03_all_referenced_resources_exists(yaml_file):
+    """
     Check that all resources referenced by get_resource
     actually exists in all yaml files
-    '''
+    """
     with open(yaml_file) as fh:
-        yml = yaml.load(fh)
+        yml = yaml.safe_load(fh)
 
     # skip if resources are not defined
     if "resources" not in yml:
         pytest.skip("No resources specified in the yaml file")
 
-    resource_ids = yml['resources'].keys()
-    referenced_resource_ids = find_all_get_resource_in_yml(yml)
+    resources = yml.get("resources")
+    if resources:
+        resource_ids = resources.keys()
+        referenced_resource_ids = find_all_get_resource_in_yml(yml)
 
-    missing_referenced_resources = set()
-    for referenced_resource_id in referenced_resource_ids:
-        if referenced_resource_id not in resource_ids:
-            missing_referenced_resources.add(referenced_resource_id)
+        missing_referenced_resources = set()
+        for referenced_resource_id in referenced_resource_ids:
+            if referenced_resource_id not in resource_ids:
+                missing_referenced_resources.add(referenced_resource_id)
 
-    assert not missing_referenced_resources, (
-        'missing referenced resources %s' % list(
-            missing_referenced_resources))
+        assert not missing_referenced_resources, (
+            "Unable to resolve get_resource for the following "
+            "resource IDS: {}. Please ensure the resource ID is defined and "
+            "nested under the resources section of the template".format(
+                ", ".join(missing_referenced_resources)
+            )
+        )
 
 
 @pytest.mark.base
-def test_01_valid_nesting(yaml_file):
-    '''
+@validates("R-92635")
+def test_04_valid_nesting(yaml_file):
+    """
     Check that the nesting is following the proper format and
     that all nested files exists and are parsable
-    '''
+    """
     invalid_nesting = []
 
     with open(yaml_file) as fh:
         yml = yaml.load(fh)
     if "resources" in yml:
         try:
-            invalid_nesting.extend(check_for_invalid_nesting(
-                yml["resources"],
-                yaml_file,
-                path.dirname(yaml_file)))
+            invalid_nesting.extend(
+                check_for_invalid_nesting(
+                    yml["resources"], yaml_file, path.dirname(yaml_file)
+                )
+            )
         except Exception:
             invalid_nesting.append(yaml_file)
 
-    assert not invalid_nesting, \
-        "invalid nested file detected in file {}\n\n".format(invalid_nesting)
+    assert not invalid_nesting, "invalid nested file detected in file {}\n\n".format(
+        invalid_nesting
+    )
 
 
 @pytest.mark.base
-def test_03_all_get_param_have_defined_parameter(yaml_file):
-    '''
+@validates("R-92635")
+def test_05_all_get_param_have_defined_parameter(yaml_file):
+    """
     Check that all referenced parameters are actually defined
     as parameters
-    '''
+    """
     invalid_get_params = []
     with open(yaml_file) as fh:
         yml = yaml.load(fh)
 
     resource_params = find_all_get_param_in_yml(yml)
 
-    parameters = set(yml.get('parameters', {}).keys())
+    parameters = set(yml.get("parameters", {}).keys())
     if not parameters:
         pytest.skip("no parameters detected")
 
@@ -144,6 +167,19 @@ def test_03_all_get_param_have_defined_parameter(yaml_file):
         if rp not in parameters:
             invalid_get_params.append(rp)
 
-    assert not invalid_get_params, (
-        "get_param reference detected without corresponding parameter defined {}"
-        .format(invalid_get_params))
+    assert (
+        not invalid_get_params
+    ), "get_param reference detected without corresponding parameter defined {}".format(
+        invalid_get_params
+    )
+
+
+@validates("R-90152")
+@pytest.mark.base
+def test_06_heat_template_resource_section_has_resources(yaml_file):
+    template = load_yaml(yaml_file)
+    if "resources" not in template:
+        pytest.skip("No resources section")
+    assert (
+        len(template["resources"]) > 0
+    ), "If resources section present, then there must be at least 1 resource defined."