[VVP] Misc tweaks and fixes to preload generation
[vvp/validation-scripts.git] / ice_validator / tests / test_environment_file_parameters.py
index 031f898..99d76a0 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
 #
 # ============LICENSE_END============================================
 #
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
 #
-
 """ environment file structure
 """
+import os
+
 import re
 import pytest
-
-from .helpers import validates, get_environment_pair
-
-
-VERSION = "1.0.0"
-
-# pylint: disable=invalid-name
-
-
-def check_parameter_exists(pattern, parameters):
-    if not parameters:
-        return False
-
-    for param in parameters:
-        if pattern.search(param):
-            return True
-
-    return False
-
-
-def check_param_in_env_file(environment_pair, param, DESIRED, exclude_parameter=None):
-
-    # workaround for internal/external parameters
-    if exclude_parameter and re.match(exclude_parameter, param):
-        return False
-
-    if not environment_pair:
-        pytest.skip("No heat/env pair could be identified")
-
-    env_file = environment_pair.get("eyml")
-
-    pattern = re.compile(r"^{}$".format(param))
-
-    if "parameters" not in env_file:
-        pytest.skip("No parameters specified in the environment file")
-
-    return (
-        check_parameter_exists(pattern, env_file.get("parameters", {})) is not DESIRED
-    )
-
-
-"""
-This function supports this structure, deviations
-may or may not work without enhancement
-
-resource_id:
-    type: <resource_type>
-    properties:
-        prop0: { get_param: parameter_0 }
-        prop1:  # this is a list of dicts
-            - nested_prop_0: { get_param: parameter_1 }
-            - nested_prop_1: { get_param: [parameter_2, {index}] }
-        prop2:  # this is a dict of dicts
-            nested_prop_0: { get_param: parameter_1 }
-"""
-
-
-def check_resource_parameter(
-    environment_pair,
-    prop,
-    DESIRED,
-    resource_type,
-    resource_type_inverse=False,
-    nested_prop="",
-    exclude_resource="",
-    exclude_parameter="",
-):
-
-    if not environment_pair:
-        pytest.skip("No heat/env pair could be identified")
-
-    env_file = environment_pair.get("eyml")
-    template_file = environment_pair.get("yyml")
-
-    if "parameters" not in env_file:
-        pytest.skip("No parameters specified in the environment file")
-
+from tests.helpers import (
+    prop_iterator,
+    get_param,
+    get_environment_pair,
+    validates,
+    find_environment_file,
+    categories,
+)
+from tests.structures import Heat
+from tests.utils.nested_files import file_is_a_nested_template
+
+
+# Whats persistent mean? It means it goes in env.
+# When adding an additional case, note the ","
+# at the end of a property to make it a tuple.
+ENV_PARAMETER_SPEC = {
+    "PLATFORM PROVIDED": [
+        {"property": ("metadata", "vnf_id",), "persistent": False, "kwargs": {}},
+        {"property": ("metadata", "vnf_name",), "persistent": False, "kwargs": {}},
+        {"property": ("metadata", "vf_module_id",), "persistent": False, "kwargs": {}},
+        {"property": ("metadata", "vf_module_index",), "persistent": False, "kwargs": {}},
+        {"property": ("metadata", "vf_module_name",), "persistent": False, "kwargs": {}},
+        {"property": ("metadata", "workload_context",), "persistent": False, "kwargs": {}},
+        {"property": ("metadata", "environment_context",), "persistent": False, "kwargs": {}},
+        {"property": (r"^(.+?)_net_fqdn$",), "persistent": False, "kwargs": {}},
+    ],
+    "ALL": [{"property": ("name",), "persistent": False, "kwargs": {}}],
+    "OS::Nova::Server": [
+        {"property": ("image",), "persistent": True, "kwargs": {}},
+        {"property": ("flavor",), "persistent": True, "kwargs": {}},
+        {"property": ("availability_zone",), "persistent": False, "kwargs": {}},
+    ],
+    "OS::Neutron::Port": [
+        {"property": ("network",), "persistent": False, "kwargs": {}},
+        {
+            "property": ("fixed_ips", "ip_address"),
+            "persistent": False,
+            "network_type": "external",
+            "kwargs": {"exclude_parameter": re.compile(r"^(.+?)_int_(.+?)$")},
+        },
+        {
+            "property": ("fixed_ips", "ip_address"),
+            "persistent": True,
+            "network_type": "internal",
+            "kwargs": {"exclude_parameter": re.compile(r"^((?!_int_).)*$")},
+        },
+        {"property": ("fixed_ips", "subnet"), "persistent": False, "kwargs": {}},
+        {
+            "property": ("allowed_address_pairs", "ip_address"),
+            "persistent": False,
+            "network_type": "external",
+            "kwargs": {"exclude_parameter": re.compile(r"^(.+?)_int_(.+?)$")},
+        },
+        {
+            "property": ("allowed_address_pairs", "ip_address"),
+            "persistent": True,
+            "network_type": "internal",
+            "kwargs": {"exclude_parameter": re.compile(r"^((?!_int_).)*$")},
+        },
+    ],
+    "OS::ContrailV2::InterfaceRouteTable": [
+        {
+            "property": (
+                "interface_route_table_routes",
+                "interface_route_table_routes_route",
+            ),
+            "persistent": False,
+            "kwargs": {},
+        }
+    ],
+    "OS::Heat::ResourceGroup": [
+        {
+            "property": ("count",),
+            "persistent": True,
+            "kwargs": {
+                "exclude_resource": re.compile(
+                    r"^(.+?)_subint_(.+?)_port_(.+?)_subinterfaces$"
+                )
+            },
+        }
+    ],
+    "OS::ContrailV2::InstanceIp": [
+        {
+            "property": ("instance_ip_address",),
+            "persistent": False,
+            "network_type": "external",
+            "kwargs": {"exclude_resource": re.compile(r"^.*_int_.*$")},
+        },
+        {
+            "property": ("instance_ip_address",),
+            "persistent": True,
+            "network_type": "internal",
+            "kwargs": {"exclude_resource": re.compile(r"(?!.*_int_.*)")},
+        },
+        {
+            "property": ("subnet_uuid",),
+            "persistent": False,
+            "network_type": "internal",
+            "kwargs": {"exclude_resource": re.compile(r"(?!.*_int_.*)")},
+        },
+    ],
+    "OS::ContrailV2::VirtualMachineInterface": [
+        {
+            "property": (
+                "virtual_machine_interface_allowed_address_pairs",
+                "virtual_machine_interface_allowed_address_pairs_allowed_address_pair",
+                "virtual_machine_interface_allowed_address_pairs_allowed_address_pair_ip",
+                "virtual_machine_interface_allowed_address_pairs_allowed_address_pair_ip_ip_prefix",
+            ),
+            "persistent": False,
+            "network_type": "external",
+            "kwargs": {"exclude_resource": re.compile(r"(?!.*_int_.*)")},
+        }
+    ],
+}
+
+
+def run_test_parameter(yaml_file, resource_type, *prop, **kwargs):
+    template_parameters = []
     invalid_parameters = []
-
-    if template_file:
-        for resource, resource_prop in template_file.get("resources", {}).items():
-
-            # workaround for subinterface resource groups
-            if exclude_resource and re.match(exclude_resource, resource):
-                continue
-
-            if (
-                resource_prop.get("type") == resource_type and not resource_type_inverse
-            ) or (resource_prop.get("type") != resource_type and resource_type_inverse):
-
-                pattern = False
-
-                if not resource_prop.get("properties"):
-                    continue
-
-                resource_parameter = resource_prop.get("properties").get(prop)
-
-                if not resource_parameter:
-                    continue
-
-                if isinstance(resource_parameter, list) and nested_prop:
-                    for param in resource_parameter:
-
-                        nested_param = param.get(nested_prop)
-                        if not nested_param:
-                            continue
-
-                        if isinstance(nested_param, dict):
-                            pattern = nested_param.get("get_param")
-                        else:
-                            pattern = ""
-
-                        if not pattern:
-                            continue
-
-                        if isinstance(pattern, list):
-                            pattern = pattern[0]
-
-                        if check_param_in_env_file(
-                            environment_pair,
-                            pattern,
-                            DESIRED,
-                            exclude_parameter=exclude_parameter,
-                        ):
-                            invalid_parameters.append(pattern)
-
-                elif isinstance(resource_parameter, dict):
-
-                    if nested_prop and nested_prop in resource_parameter:
-                        resource_parameter = resource_parameter.get(nested_prop)
-
-                    pattern = resource_parameter.get("get_param")
-                    if not pattern:
-                        continue
-
-                    if check_param_in_env_file(
-                        environment_pair,
-                        pattern,
-                        DESIRED,
-                        exclude_parameter=exclude_parameter,
-                    ):
-                        invalid_parameters.append(pattern)
+    param_spec = {}
+    parameter_spec = ENV_PARAMETER_SPEC.get(
+        resource_type
+    )  # matching spec dict on resource type
+    for spec in parameter_spec:
+        # iterating through spec dict and trying to match on property
+        if spec.get("property") == prop:
+            yep = True
+            for (
+                k,
+                v,
+            ) in (
+                kwargs.items()
+            ):  # now matching on additional kwargs passed in from test (i.e. network_type)
+                if not spec.get(k) or spec.get(k) != v:
+                    yep = False
+            if yep:
+                param_spec = spec
+                if resource_type == "PLATFORM PROVIDED":
+                    if file_is_a_nested_template(yaml_file):
+                        pytest.skip(
+                            "Not checking nested files for PLATFORM PROVIDED params"
+                        )
+                    template_parameters.append(
+                        {"resource": "", "param": param_spec.get("property")[0]}
+                    )
                 else:
-                    continue
-
-    return set(invalid_parameters)
+                    all_resources = False
+                    if resource_type == "ALL":
+                        all_resources = True
+                    template_parameters = get_template_parameters(
+                        yaml_file,
+                        resource_type,
+                        param_spec,
+                        all_resources=all_resources,
+                    )  # found the correct spec, proceeding w/ test
+                break
+
+    for parameter in template_parameters:
+        param = parameter.get("param")
+        persistence = param_spec.get("persistent")
+
+        if env_violation(yaml_file, param, spec.get("persistent")):
+            human_text = "must" if persistence else "must not"
+            human_text2 = "was not" if persistence else "was"
+
+            invalid_parameters.append(
+                "{} parameter {} {} be enumerated in an environment file, but "
+                "parameter {} for {} {} found.".format(
+                    resource_type, prop, human_text, param, yaml_file, human_text2
+                )
+            )
+
+    assert not invalid_parameters, "\n".join(invalid_parameters)
+
+
+def get_preload_excluded_parameters(yaml_file, persistent_only=False, env_spec=None):
+    """
+    Returns set of all parameters that should not be included in the preload's
+    vnf parameters/tag-values section.
+
+    if persistent_only only parameters that are marked as persistent will
+    be excluded
+    """
+    env_spec = env_spec or ENV_PARAMETER_SPEC
+    results = []
+    for resource_type, specs in env_spec.items():
+        # apply to all resources if not in the format of an OpenStack resource
+        all_resources = "::" not in resource_type
+        for spec in specs:
+            if persistent_only and not spec.get("persistent"):
+                continue
+            results.extend(get_template_parameters(yaml_file, resource_type,
+                                                   spec, all_resources, nested_resources=True))
+    results = {item["param"] for item in results}
+    for param in Heat(yaml_file).parameters:
+        # AZs often are manipulated and passed into nested templates making
+        # them difficult to detect by looking for the assignment.  We'll
+        # just extract them from the parameters if they are there to be safe
+        if re.match(r"availability_zone_\d+", param):
+            results.add(param)
+    return results
+
+
+def get_template_parameters(yaml_file, resource_type, spec, all_resources=False, nested_resources=False):
+    parameters = []
+
+    heat = Heat(yaml_file)
+    if all_resources:
+        resources = heat.resources if not nested_resources else heat.get_all_resources()
+    else:
+        resources = heat.get_resource_by_type(resource_type, all_resources=nested_resources)
+    for rid, resource_props in resources.items():
+        for param in prop_iterator(resource_props, *spec.get("property")):
+            if param and get_param(param) and param_helper(spec, get_param(param), rid):
+                # this is first getting the param
+                # then checking if its actually using get_param
+                # then checking a custom helper function (mostly for internal vs external networks)
+                parameters.append({"resource": rid, "param": get_param(param)})
+    return parameters
+
+
+def env_violation(yaml_file, parameter, persistent):
+    # Returns True IF there's a violation, False if everything looks good.
+
+    filepath, filename = os.path.split(yaml_file)
+    environment_pair = get_environment_pair(yaml_file)
+    if not environment_pair:  # this is a nested file perhaps?
+        environment_pair = find_environment_file(
+            yaml_file
+        )  # we want to check parent env
+        if not environment_pair:
+            pytest.skip("unable to determine environment file for nested yaml file")
+
+    env_yaml = environment_pair.get("eyml")
+    parameters = env_yaml.get("parameters", {})
+    in_env = False
+    if parameters:  # env file can be just parameters:
+        for param, value in parameters.items():
+            if re.match(parameter, param):
+                in_env = True
+                break
+
+    # confusing return. This function is looking for a violation.
+    return not persistent == in_env
+
+
+def param_helper(spec, param, rid):
+    # helper function that has some predefined additional
+    # checkers, mainly to figure out if internal/external network
+    keeper = True
+    for k, v in spec.get("kwargs").items():
+        if k == "exclude_resource" and re.match(v, rid):
+            keeper = False
+            break
+        elif k == "exclude_parameter" and re.match(v, param):
+            keeper = False
+            break
+
+    return keeper
 
 
 @validates("R-91125")
-def test_nova_server_image_parameter_exists_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "image"
-    DESIRED = True
-    resource_type = "OS::Nova::Server"
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair, prop, DESIRED, resource_type
-    )
-
-    assert not invalid_parameters, (
-        "OS::Nova::Server {} parameters not"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
+def test_nova_server_image_parameter_exists_in_environment_file(yaml_file):
+    run_test_parameter(yaml_file, "OS::Nova::Server", "image")
 
 
 @validates("R-69431")
-def test_nova_server_flavor_parameter_exists_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "flavor"
-    DESIRED = True
-    resource_type = "OS::Nova::Server"
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair, prop, DESIRED, resource_type
-    )
-
-    assert not invalid_parameters, (
-        "OS::Nova::Server {} parameters not"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
-
-
-@validates("R-22838")
-def test_nova_server_name_parameter_doesnt_exist_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
+def test_nova_server_flavor_parameter_exists_in_environment_file(yaml_file):
+    run_test_parameter(yaml_file, "OS::Nova::Server", "flavor")
 
-    environment_pair = get_environment_pair(heat_template)
 
-    prop = "name"
-    DESIRED = False
-    resource_type = "OS::Nova::Server"
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair, prop, DESIRED, resource_type
-    )
-
-    assert not invalid_parameters, (
-        "OS::Nova::Server {} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
+@categories("environment_file")
+@validates("R-22838", "R-99812")
+def test_nova_server_name_parameter_doesnt_exist_in_environment_file(yaml_file):
+    run_test_parameter(yaml_file, "ALL", "name")
 
 
+@categories("environment_file")
 @validates("R-59568")
-def test_nova_server_az_parameter_doesnt_exist_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "availability_zone"
-    DESIRED = False
-    resource_type = "OS::Nova::Server"
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair, prop, DESIRED, resource_type
-    )
-
-    assert not invalid_parameters, (
-        "OS::Nova::Server {} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
+def test_nova_server_az_parameter_doesnt_exist_in_environment_file(yaml_file):
+    run_test_parameter(yaml_file, "OS::Nova::Server", "availability_zone")
 
 
+@categories("environment_file")
 @validates("R-20856")
-def test_nova_server_vnf_id_parameter_doesnt_exist_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "vnf_id"
-    DESIRED = False
-
-    invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
-
-    assert not invalid_parameters, (
-        "{} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
+def test_nova_server_vnf_id_parameter_doesnt_exist_in_environment_file(yaml_file):
+    run_test_parameter(yaml_file, "PLATFORM PROVIDED", "vnf_id")
 
 
+@categories("environment_file")
 @validates("R-72871")
-def test_nova_server_vf_module_id_parameter_doesnt_exist_in_environment_file(
-    heat_template
-):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "vf_module_id"
-    DESIRED = False
-
-    invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
-
-    assert not invalid_parameters, (
-        "{} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
+def test_nova_server_vf_module_id_parameter_doesnt_exist_in_environment_file(yaml_file):
+    run_test_parameter(yaml_file, "PLATFORM PROVIDED", "vf_module_id")
 
 
+@categories("environment_file")
 @validates("R-37039")
 def test_nova_server_vf_module_index_parameter_doesnt_exist_in_environment_file(
-    heat_template
+    yaml_file
 ):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "vf_module_index"
-    DESIRED = False
-
-    invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
-
-    assert not invalid_parameters, (
-        "{} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
+    run_test_parameter(yaml_file, "PLATFORM PROVIDED", "vf_module_index")
 
 
+@categories("environment_file")
 @validates("R-36542")
-def test_nova_server_vnf_name_parameter_doesnt_exist_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "vnf_name"
-    DESIRED = False
-
-    invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
-
-    assert not invalid_parameters, (
-        "{} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
+def test_nova_server_vnf_name_parameter_doesnt_exist_in_environment_file(yaml_file):
+    run_test_parameter(yaml_file, "PLATFORM PROVIDED", "vnf_name")
 
 
+@categories("environment_file")
 @validates("R-80374")
 def test_nova_server_vf_module_name_parameter_doesnt_exist_in_environment_file(
-    heat_template
+    yaml_file
 ):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "vf_module_name"
-    DESIRED = False
-
-    invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
-
-    assert not invalid_parameters, (
-        "{} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
+    run_test_parameter(yaml_file, "PLATFORM PROVIDED", "vf_module_name")
 
 
+@categories("environment_file")
 @validates("R-02691")
 def test_nova_server_workload_context_parameter_doesnt_exist_in_environment_file(
-    heat_template
+    yaml_file
 ):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "workload_context"
-    DESIRED = False
-
-    invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
-
-    assert not invalid_parameters, (
-        "{} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
+    run_test_parameter(yaml_file, "PLATFORM PROVIDED", "workload_context")
 
 
+@categories("environment_file")
 @validates("R-13194")
 def test_nova_server_environment_context_parameter_doesnt_exist_in_environment_file(
-    heat_template
+    yaml_file
 ):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "environment_context"
-    DESIRED = False
-
-    invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
-
-    assert not invalid_parameters, (
-        "{} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
+    run_test_parameter(yaml_file, "PLATFORM PROVIDED", "environment_context")
 
 
+@categories("environment_file")
 @validates("R-29872")
-def test_nova_server_network_parameter_doesnt_exist_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "networks"
-    nested_prop = "network"
-    DESIRED = False
-    resource_type = "OS::Nova::Server"
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair, prop, DESIRED, resource_type, nested_prop=nested_prop
-    )
-
-    assert not invalid_parameters, (
-        "{} {} parameters"
-        " found in {} environment file {}".format(
-            resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
+def test_neutron_port_network_parameter_doesnt_exist_in_environment_file(yaml_file):
+    run_test_parameter(yaml_file, "OS::Neutron::Port", "network")
 
 
+@categories("environment_file")
 @validates("R-39841", "R-87123", "R-62590", "R-98905", "R-93030", "R-62590")
 def test_neutron_port_external_fixedips_ipaddress_parameter_doesnt_exist_in_environment_file(
-    heat_template
+    yaml_file
 ):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "fixed_ips"
-    nested_prop = "ip_address"
-    DESIRED = False
-    resource_type = "OS::Neutron::Port"
-    exclude_parameter = re.compile(r"^(.+?)_int_(.+?)$")
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair,
-        prop,
-        DESIRED,
-        resource_type,
-        nested_prop=nested_prop,
-        exclude_parameter=exclude_parameter,
-    )
-
-    assert not invalid_parameters, (
-        "{} {} external parameters"
-        " found in {} environment file {}".format(
-            resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
-        )
+    run_test_parameter(
+        yaml_file,
+        "OS::Neutron::Port",
+        "fixed_ips",
+        "ip_address",
+        network_type="external",
     )
 
 
 @validates("R-28795", "R-97201", "R-93496", "R-90206", "R-98569", "R-93496")
 def test_neutron_port_internal_fixedips_ipaddress_parameter_exists_in_environment_file(
-    heat_template
+    yaml_file
 ):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "fixed_ips"
-    nested_prop = "ip_address"
-    DESIRED = True
-    resource_type = "OS::Neutron::Port"
-    exclude_parameter = re.compile(r"^((?!_int_).)*$")
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair,
-        prop,
-        DESIRED,
-        resource_type,
-        nested_prop=nested_prop,
-        exclude_parameter=exclude_parameter,
-    )
-
-    assert not invalid_parameters, (
-        "{} {} internal parameters"
-        " not found in {} environment file {}".format(
-            resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
-        )
+    run_test_parameter(
+        yaml_file,
+        "OS::Neutron::Port",
+        "fixed_ips",
+        "ip_address",
+        network_type="internal",
     )
 
 
+@categories("environment_file")
 @validates("R-83677", "R-80829", "R-69634", "R-22288")
 def test_neutron_port_fixedips_subnet_parameter_doesnt_exist_in_environment_file(
-    heat_template
+    yaml_file
 ):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "fixed_ips"
-    nested_prop = "subnet"
-    DESIRED = False
-    resource_type = "OS::Neutron::Port"
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair, prop, DESIRED, resource_type, nested_prop=nested_prop
-    )
-
-    assert not invalid_parameters, (
-        "{} {} parameters"
-        " found in {} environment file {}".format(
-            resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
-        )
+    run_test_parameter(
+        yaml_file, "OS::Neutron::Port", "fixed_ips", "subnet", network_type="internal"
     )
 
 
+@categories("environment_file")
 @validates("R-83412", "R-83418")
-def test_neutron_port_aap_ip_parameter_doesnt_exist_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "allowed_address_pairs"
-    nested_prop = "ip_address"
-    DESIRED = False
-    resource_type = "OS::Neutron::Port"
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair, prop, DESIRED, resource_type, nested_prop=nested_prop
-    )
-
-    assert not invalid_parameters, (
-        "{} {} parameters"
-        " found in {} environment file {}".format(
-            resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
-
-
-@validates("R-99812")
-def test_non_nova_server_name_parameter_doesnt_exist_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "name"
-    DESIRED = False
-    resource_type = "OS::Nova::Server"
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair, prop, DESIRED, resource_type, resource_type_inverse=True
-    )
-
-    assert not invalid_parameters, (
-        "non-{} {} parameters"
-        " found in {} environment file {}".format(
-            resource_type, prop, environment_pair.get("name"), invalid_parameters
-        )
+def test_neutron_port_external_aap_ip_parameter_doesnt_exist_in_environment_file(
+    yaml_file
+):
+    run_test_parameter(
+        yaml_file,
+        "OS::Neutron::Port",
+        "allowed_address_pairs",
+        "subnet",
+        network_type="external",
     )
 
 
+@categories("environment_file")
 @validates("R-92193")
-def test_network_fqdn_parameter_doesnt_exist_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = r"^(.+?)_net_fqdn$"
-    DESIRED = False
-
-    invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
-
-    assert not invalid_parameters, (
-        "{} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
+def test_network_fqdn_parameter_doesnt_exist_in_environment_file(yaml_file):
+    run_test_parameter(yaml_file, "PLATFORM PROVIDED", r"^(.+?)_net_fqdn$")
 
 
+@categories("environment_file")
 @validates("R-76682")
-def test_contrail_route_prefixes_parameter_doesnt_exist_in_environment_file(
-    heat_template
-):
+def test_contrail_route_prefixes_parameter_doesnt_exist_in_environment_file(yaml_file):
+    run_test_parameter(
+        yaml_file,
+        "OS::ContrailV2::InterfaceRouteTable",
+        "interface_route_table_routes",
+        "interface_route_table_routes_route",
+    )
 
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
 
-    environment_pair = get_environment_pair(heat_template)
+@validates("R-50011")
+def test_heat_rg_count_parameter_exists_in_environment_file(yaml_file):
+    run_test_parameter(yaml_file, "OS::Heat::ResourceGroup", "count")
 
-    prop = "interface_route_table_routes"
-    nested_prop = "interface_route_table_routes_route"
-    DESIRED = False
-    resource_type = "OS::ContrailV2::InterfaceRouteTable"
 
-    invalid_parameters = check_resource_parameter(
-        environment_pair, prop, DESIRED, resource_type, nested_prop=nested_prop
+@categories("environment_file")
+@validates("R-100020", "R-100040", "R-100060", "R-100080", "R-100170")
+def test_contrail_external_instance_ip_does_not_exist_in_environment_file(yaml_file):
+    run_test_parameter(
+        yaml_file,
+        "OS::ContrailV2::InstanceIp",
+        "instance_ip_address",
+        network_type="external",
     )
 
-    assert not invalid_parameters, (
-        "{} {} parameters"
-        " found in {} environment file {}".format(
-            resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
 
+@validates("R-100100", "R-100120", "R-100140", "R-100160", "R-100180")
+def test_contrail_internal_instance_ip_does_exist_in_environment_file(yaml_file):
+    run_test_parameter(
+        yaml_file,
+        "OS::ContrailV2::InstanceIp",
+        "instance_ip_address",
+        network_type="internal",
+    )
 
-@validates("R-50011")
-def test_heat_rg_count_parameter_exists_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
 
-    prop = "count"
-    DESIRED = True
-    resource_type = "OS::Heat::ResourceGroup"
-    exclude_resource = re.compile(r"^(.+?)_subint_(.+?)_port_(.+?)_subinterfaces$")
+@categories("environment_file")
+@validates("R-100210", "R-100230", "R-100250", "R-100270")
+def test_contrail_subnet_uuid_does_not_exist_in_environment_file(yaml_file):
+    run_test_parameter(yaml_file, "OS::ContrailV2::InstanceIp", "subnet_uuid")
 
-    invalid_parameters = check_resource_parameter(
-        environment_pair,
-        prop,
-        DESIRED,
-        resource_type,
-        exclude_resource=exclude_resource,
-    )
 
-    assert not invalid_parameters, (
-        "{} {} parameters not"
-        " found in {} environment file {}".format(
-            resource_type, prop, environment_pair.get("name"), invalid_parameters
-        )
+@categories("environment_file")
+@validates("R-100320", "R-100340")
+def test_contrail_vmi_aap_does_not_exist_in_environment_file(yaml_file):
+    run_test_parameter(
+        yaml_file,
+        "OS::ContrailV2::VirtualMachineInterface",
+        "virtual_machine_interface_allowed_address_pairs",
+        "virtual_machine_interface_allowed_address_pairs_allowed_address_pair",
+        "virtual_machine_interface_allowed_address_pairs_allowed_address_pair_ip",
+        "virtual_machine_interface_allowed_address_pairs_allowed_address_pair_ip_ip_prefix",
     )