[VVP-171] R-84123 and R-76160 test update 19/78719/7
authorstark, steven <steven.stark@att.com>
Tue, 19 Feb 2019 00:22:52 +0000 (16:22 -0800)
committerstark, steven <steven.stark@att.com>
Thu, 28 Feb 2019 00:41:43 +0000 (16:41 -0800)
R-84123 and R-76160
test_neutron_port_internal_fixed_ips
should only be checking incremental modules

Change-Id: I7ef3cd4aa2b01273c2592f0b17751c5cb79c002b
Issue-ID: VVP-171
Signed-off-by: stark, steven <steven.stark@att.com>
ice_validator/tests/fixtures/test_neutron_port_fixed_ips_subnet/fail/fail0.yaml [moved from ice_validator/tests/fixtures/test_neutron_port_fixed_ips/fail/fail0.yaml with 96% similarity]
ice_validator/tests/fixtures/test_neutron_port_fixed_ips_subnet/fail/fail1.yaml [moved from ice_validator/tests/fixtures/test_neutron_port_fixed_ips/fail/fail1.yaml with 93% similarity]
ice_validator/tests/fixtures/test_neutron_port_fixed_ips_subnet/pass/pass0.yaml [moved from ice_validator/tests/fixtures/test_neutron_port_fixed_ips/pass/pass0.yaml with 100% similarity]
ice_validator/tests/fixtures/test_neutron_port_fixed_ips_subnet/pass/pass0_base.yaml [moved from ice_validator/tests/fixtures/test_neutron_port_fixed_ips/pass/pass0_base.yaml with 100% similarity]
ice_validator/tests/helpers.py
ice_validator/tests/test_neutron_port_fixed_ips_subnet.py [moved from ice_validator/tests/test_neutron_port_fixed_ips.py with 58% similarity]
ice_validator/tests/test_neutron_port_internal_network.py

@@ -50,7 +50,7 @@ parameters:
   vm_typeX_bialy_guest_vlans:
     type: comma_delimited_list
   subnet_param:
-    type: string
+    type: comma_delimited_list
   subnet_id_param:
     type: comma_delimited_list
 
@@ -63,7 +63,6 @@ resources:
       fixed_ips:
         - ip_address: { get_param: lb_1_int_intranet_floating_ip }
           subnet: { get_param: subnet_param }
-          subnet_id: { get_param: subnet_id_param }
       binding:vnic_type: direct
       value_specs:
         vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
@@ -82,7 +81,6 @@ resources:
       fixed_ips:
         - ip_address: { get_param: lb_2_extnet_floating_v6_ip }
           subnet: { get_param: subnet_param }
-          subnet_id: { get_param: subnet_id_param }
       binding:vnic_type: direct
       value_specs:
         vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
@@ -49,8 +49,8 @@ parameters:
     type: comma_delimited_list
   vm_typeX_bialy_guest_vlans:
     type: comma_delimited_list
-  bialy_subnet:
-    type: string
+  bialy_susbnet:
+    type: comma_delimited_list
   bialy_subnet_id:
     type: string
 
@@ -62,8 +62,7 @@ resources:
       network: { get_param: int_intranet_net_name }
       fixed_ips:
         - ip_address: { get_param: lb_1_int_intranet_floating_ip }
-          subnet: { get_param: bialy_subnet }
-          subnet_id: { get_param: bialy_subnet_id }
+          subnet: { get_param: bialy_susbnet }
       binding:vnic_type: direct
       value_specs:
         vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
@@ -81,8 +80,7 @@ resources:
       network: { get_param: extnet_net_id }
       fixed_ips:
         - ip_address: { get_param: lb_2_extnet_floating_v6_ip }
-          subnet: { get_param: bialy_subnet }
-          subnet_id: { get_param: bialy_subnet_id }
+          subnet: { get_param: bialy_susbnet }
       binding:vnic_type: direct
       value_specs:
         vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
index 69190d8..12a7a12 100644 (file)
@@ -41,6 +41,7 @@
 """
 
 import os
+import re
 from collections import defaultdict
 
 from boltons import funcutils
@@ -259,3 +260,30 @@ def check_indices(pattern, values, value_type):
                 ).format(value_type, prefix, indices)
             )
     return invalid_params
+
+
+RE_BASE = re.compile(r"(^base$)|(^base_)|(_base_)|(_base$)")
+
+
+def get_base_template_from_yaml_files(yaml_files):
+    """Return first filepath to match RE_BASE
+    """
+    for filepath in yaml_files:
+        basename = get_base_template_from_yaml_file(filepath)
+        if basename:
+            return basename
+    return None
+
+
+def get_base_template_from_yaml_file(yaml_file):
+    (dirname, filename) = os.path.split(yaml_file)
+    files = os.listdir(dirname)
+    for file in files:
+        basename, __ = os.path.splitext(os.path.basename(file))
+        if (
+            (__ == ".yaml" or __ == ".yml")
+            and RE_BASE.search(basename)
+            and basename.find("volume") == -1
+        ):
+            return os.path.join(dirname, "{}{}".format(basename, __))
+    return None
@@ -61,55 +61,40 @@ resources:
     port_type: SR-IOV_Mirrored_Trunk    #SR-IOV Trunk Port
                                         # Receiving Mirrored Traffic
 """
-
-import os
-import os.path
 import re
 
 import pytest
 
 from .structures import Heat
-from .helpers import validates
+from .helpers import validates, get_base_template_from_yaml_file
 
 VERSION = "1.3.0"
 
 RE_BASE = re.compile(r"(^base$)|(^base_)|(_base_)|(_base$)")  # search pattern
 
-RE_EXTERNAL_PARAM_SUBNET_ID = re.compile(  # match pattern
+RE_EXTERNAL_PARAM_SUBNET = re.compile(  # match pattern
     r"(?P<network_role>.+)(_v6)?_subnet_id$"
 )
-RE_EXTERNAL_PARAM_SUBNET = RE_EXTERNAL_PARAM_SUBNET_ID
-# RE_EXTERNAL_PARAM_SUBNET = re.compile( # match pattern
-#        r'(?P<network_role>.+)(_v6)?_subnet$')
 
-RE_INTERNAL_PARAM_SUBNET_ID = re.compile(  # match pattern
+RE_INTERNAL_PARAM_SUBNET = re.compile(  # match pattern
     r"int_(?P<network_role>.+)(_v6)?_subnet_id$"
 )
-RE_INTERNAL_PARAM_SUBNET = RE_INTERNAL_PARAM_SUBNET_ID
-# RE_INTERNAL_PARAM_SUBNET = re.compile( # match pattern
-#        r'int_(?P<network_role>.+)(_v6)?_subnet$')
 
 
-def get_network(base_template_filepath):
+def get_base(base_template_filepath):
     """Return the base template's Heat instance.
     """
     if base_template_filepath is None:
         pytest.skip("No base template found")
     base_template = Heat(filepath=base_template_filepath)
-    for r in base_template.resources.values():
-        if (
-            base_template.nested_get(r, "type") == "OS::Neutron::Net"
-            or base_template.nested_get(r, "type") == "OS::ContrailV2::VirtualNetwork"
-        ):
-            return base_template
-    return None
+    return base_template
 
 
-def run_test(heat_template, validate):
+def run_test(heat_template, validate, validator=None):
     """call validate for each fixed_ips
     """
     heat = Heat(filepath=heat_template)
-    base_template = get_base_template(heat_template)
+    base_template = get_base_template_from_yaml_file(heat_template)
     if not heat.resources:
         pytest.skip("No resources found")
 
@@ -125,163 +110,109 @@ def run_test(heat_template, validate):
         if not isinstance(fixed_ips, list):
             bad[rid] = "properties.fixed_ips must be a list."
             continue
-        if not heat.parameters:
-            bad[rid] = "fixed_ips requires parameters"
-            continue
         for fixed_ip in fixed_ips:
-            error = validate(heat, fixed_ip, base_template)
+            error = validate(heat, fixed_ip, base_template, validator)
             if error:
                 bad[rid] = error
                 break
     if bad:
         # raise RuntimeError(
         raise AssertionError(
-            "Bad OS::Neutron::Port: %s"
-            % (", ".join("%s: %s" % (rid, error) for rid, error in bad.items()))
+            "%s"
+            % (",   ".join("%s: %s" % (rid, error) for rid, error in bad.items()))
         )
 
 
-def validate_external_fixed_ip(heat, fixed_ip, base_template):
-    """ensure fixed_ip subnet and subnet_id for external network
+def validate_external_fixed_ip_subnet(heat, fixed_ip, base_template, validator):
+    """ensure fixed_ip subnet for external network
     match the pattern.
     Returns error message string or None.
     """
     subnet = heat.nested_get(fixed_ip, "subnet", "get_param")
-    subnet_id = heat.nested_get(fixed_ip, "subnet_id", "get_param")
-    if subnet and subnet_id:
-        error = 'fixed_ip %s has both "subnet" and "subnet_id"' % (fixed_ip)
-    elif subnet:
-        error = validate_external_subnet(subnet)
-    elif subnet_id:
-        error = validate_external_subnet_id(subnet_id)
+    if subnet:
+        error = validator(subnet, RE_EXTERNAL_PARAM_SUBNET)
     else:
         error = None
     return error
 
 
-def validate_external_subnet(subnet):
+def validate_external_subnet_parameter_format(subnet, regx):
     """ensure subnet matches template.
     Returns error message string or None.
     """
-    if (
-        subnet
-        and not subnet.startswith("int_")
-        and RE_EXTERNAL_PARAM_SUBNET.match(subnet) is None
-    ):
-        return 'fixed_ip subnet parameter "%s" does not match "%s"' % (
-            subnet,
-            RE_EXTERNAL_PARAM_SUBNET.pattern,
+    if subnet and not subnet.startswith("int_") and regx.match(subnet) is None:
+        return (
+            'fixed_ip subnet parameter "%s" does not match '
+            "{network-role}_subnet_id or {network-role}_v6_subnet_id" % (subnet)
         )
     return None
 
 
-def validate_external_subnet_id(subnet_id):
-    """ensure subnet_id matches template.
-    Returns error message string or None.
-    """
-    if (
-        subnet_id
-        and not subnet_id.startswith("int_")
-        and RE_EXTERNAL_PARAM_SUBNET_ID.match(subnet_id) is None
-    ):
-        return 'fixed_ip subnet_id parameter "%s" does not match "%s"' % (
-            subnet_id,
-            RE_EXTERNAL_PARAM_SUBNET_ID.pattern,
-        )
-    return None
-
-
-def validate_internal_fixed_ip(heat, fixed_ip, base_template):
-    """ensure fixed_ip subnet and subnet_id for internal network
+def validate_internal_fixed_ip_subnet(heat, fixed_ip, base_template, validator):
+    """ensure fixed_ip subnet for internal network
     match the pattern.
     Returns error message string or None.
     """
-    base_module = get_network(base_template)
+    base_module = get_base(base_template)
     subnet = heat.nested_get(fixed_ip, "subnet", "get_param")
-    subnet_id = heat.nested_get(fixed_ip, "subnet_id", "get_param")
-    if subnet and subnet_id:
-        error = 'fixed_ip %s has both "subnet" and "subnet_id"' % (fixed_ip)
-    elif subnet:
-        error = validate_internal_subnet(heat, base_module, subnet)
-    elif subnet_id:
-        error = validate_internal_subnet_id(heat, base_module, subnet_id)
+    if subnet:
+        error = validator(heat, base_module, subnet, RE_INTERNAL_PARAM_SUBNET)
     else:
         error = None
     return error
 
 
-def validate_internal_subnet(heat, base_module, subnet):
+def validate_internal_subnet_parameter_format(heat, base_module, subnet, regx):
     """ensure if subnet matches template then its parameter exists.
     Returns error message string or None.
     """
-    if (
-        subnet
-        and subnet.startswith("int_")
-        and RE_INTERNAL_PARAM_SUBNET.match(subnet)
-        and heat.nested_get(base_module.outputs, subnet) is None
-    ):
-        return 'fixed_ip subnet parameter "%s" not in base outputs"' % (subnet)
+    if subnet and subnet.startswith("int_") and regx.match(subnet) is None:
+        return (
+            'fixed_ip subnet parameter "%s" does not match '
+            "int_{network-role}_subnet_id or int_{network-role}_v6_subnet_id" % (subnet)
+        )
     return None
 
 
-def validate_internal_subnet_id(heat, base_module, subnet_id):
-    """ensure if subnet_id matches template then its parameter exists.
+def validate_internal_subnet_exists_in_base_output(heat, base_module, subnet, regx):
+    """ensure if subnet matches template then its parameter exists.
     Returns error message string or None.
     """
     if (
-        subnet_id
-        and subnet_id.startswith("int_")
-        and RE_INTERNAL_PARAM_SUBNET_ID.match(subnet_id)
-        and heat.nested_get(base_module.outputs, subnet_id) is None
+        subnet
+        and subnet.startswith("int_")
+        and regx.match(subnet)
+        and heat.nested_get(base_module.outputs, subnet) is None
     ):
-        return 'fixed_ip subnet_id parameter "%s" not in base outputs"' % (subnet_id)
+        return 'fixed_ip subnet(_id) parameter "%s" not in base outputs"' % (subnet)
     return None
 
 
-def validate_fixed_ip(heat, fixed_ip, base_template):
+def validate_fixed_ip_subnet(heat, fixed_ip, base_template, validator):
     """ensure fixed_ip has proper parameters
     Returns error message string or None.
     """
     subnet = heat.nested_get(fixed_ip, "subnet", "get_param")
-    subnet_id = heat.nested_get(fixed_ip, "subnet_id", "get_param")
-    if subnet and subnet_id:
-        error = 'fixed_ip %s has both "subnet" and "subnet_id"' % (fixed_ip)
-    elif subnet and heat.nested_get(heat.parameters, subnet, "type") != "string":
+    if subnet and heat.nested_get(heat.parameters, subnet, "type") != "string":
         error = 'subnet parameter "%s" must be type "string"' % subnet
-    elif subnet_id and heat.nested_get(heat.parameters, subnet_id, "type") != "string":
-        error = 'subnet_id parameter "%s" must be type "string"' % subnet_id
     else:
         error = None
     return error
 
 
-def get_base_template(heat_template):
-    (dirname, filename) = os.path.split(heat_template)
-    files = os.listdir(dirname)
-    for file in files:
-        basename, __ = os.path.splitext(os.path.basename(file))
-        if (
-            __ == ".yaml"
-            and basename.find("base") != -1
-            and basename.find("volume") == -1
-        ):
-            return os.path.join(dirname, "{}{}".format(basename, __))
-    return None
-
-
 @validates("R-38236")
-def test_neutron_port_fixed_ips(yaml_file):
+def test_neutron_port_fixed_ips_subnet(yaml_file):
     """
     The VNF's Heat Orchestration Template's
     resource ``OS::Neutron::Port`` property ``fixed_ips``
     map property ``subnet``/``subnet_id`` parameter
     **MUST** be declared type ``string``.
     """
-    run_test(yaml_file, validate_fixed_ip)
+    run_test(yaml_file, validate_fixed_ip_subnet)
 
 
 @validates("R-62802", "R-15287")
-def test_neutron_port_external_fixed_ips(yaml_file):
+def test_neutron_port_external_fixed_ips_subnet(yaml_file):
     """
     When the VNF's Heat Orchestration Template's
     resource ``OS::Neutron::Port`` is attaching
@@ -296,12 +227,46 @@ def test_neutron_port_external_fixed_ips(yaml_file):
     and the external network IPv6 subnet is to be specified
       * ``{network-role}_v6_subnet_id``
     """
-    run_test(yaml_file, validate_external_fixed_ip)
+    run_test(
+        yaml_file,
+        validate_external_fixed_ip_subnet,
+        validate_external_subnet_parameter_format,
+    )
+
+
+@validates("R-84123", "R-76160")
+def test_neutron_port_internal_fixed_ips_subnet(yaml_file):
+    """
+    When
+
+      * the VNF's Heat Orchestration Template's
+        resource ``OS::Neutron::Port`` in an Incremental Module is attaching
+        to an internal network
+        that is created in the Base Module, AND
+      * an IPv4 address is being cloud assigned by OpenStack's DHCP Service AND
+      * the internal network IPv4 subnet is to be specified
+        using the property ``fixed_ips`` map property ``subnet``/``subnet_id``,
+
+    the parameter **MUST** follow the naming convention
+
+      * ``int_{network-role}_subnet_id``
+    an IPv6 address is being cloud assigned by OpenStack's DHCP Service AND
+      * ``int_{network-role}_v6_subnet_id``
+
+    """
+    run_test(
+        yaml_file,
+        validate_internal_fixed_ip_subnet,
+        validate_internal_subnet_parameter_format,
+    )
 
 
 @validates("R-84123", "R-76160")
-def test_neutron_port_internal_fixed_ips(yaml_file):
+def test_neutron_port_internal_fixed_ips_subnet_in_base(heat_template):
     """
+    Only check parent incremental modules, because nested file parameter
+    name may have been changed.
+
     When
 
       * the VNF's Heat Orchestration Template's
@@ -318,5 +283,11 @@ def test_neutron_port_internal_fixed_ips(yaml_file):
     an IPv6 address is being cloud assigned by OpenStack's DHCP Service AND
       * ``int_{network-role}_v6_subnet_id``
 
+    Note that the parameter MUST be defined as an output parameter in
+    the base module.
     """
-    run_test(yaml_file, validate_internal_fixed_ip)
+    run_test(
+        heat_template,
+        validate_internal_fixed_ip_subnet,
+        validate_internal_subnet_exists_in_base_output,
+    )
index 00a3a93..e90f87c 100644 (file)
 # ============LICENSE_END============================================
 #
 
-import os.path
-import re
-
 from tests.parametrizers import get_nested_files
 from tests.utils.network_roles import get_network_type_from_port
 from .structures import Heat
-from .helpers import validates, load_yaml
-
-
-RE_BASE = re.compile(r"(^base$)|(^base_)|(_base_)|(_base$)")
-
-
-def get_base_template_filepath(yaml_files):
-    """Return first filepath to match RE_BASE
-    """
-    for filepath in yaml_files:
-        basename, __ = os.path.splitext(os.path.basename(filepath))
-        if RE_BASE.search(basename) and basename.find("volume") == -1:
-            return filepath
-    return None
+from .helpers import validates, load_yaml, get_base_template_from_yaml_files
 
 
 @validates("R-22688")
 def test_neutron_port_internal_network_v2(yaml_files):
-    base_path = get_base_template_filepath(yaml_files)
+    base_path = get_base_template_from_yaml_files(yaml_files)
     nested_template_paths = get_nested_files(yaml_files)
     errors = []
     for yaml_file in yaml_files:
         if yaml_file == base_path or yaml_file in nested_template_paths:
             continue  # Only applies to incremental modules
         heat = Heat(filepath=yaml_file)
-        internal_ports = {r_id: p for r_id, p in heat.neutron_port_resources.items()
-                          if get_network_type_from_port(p) == "internal"}
+        internal_ports = {
+            r_id: p
+            for r_id, p in heat.neutron_port_resources.items()
+            if get_network_type_from_port(p) == "internal"
+        }
         for r_id, port in internal_ports.items():
             props = port.get("properties") or {}
             network_value = props.get("network") or {}
@@ -80,15 +67,19 @@ def test_neutron_port_internal_network_v2(yaml_files):
             base_heat = load_yaml(base_path)
             base_outputs = base_heat.get("outputs") or {}
             if not param.endswith("_net_id"):
-                errors.append((
-                    "Internal network {} is attached to port {}, but the "
-                    "network must be attached via UUID of the network not "
-                    "the name (ex: int_{{network-role}}_net_id)."
-                ).format(param, r_id))
+                errors.append(
+                    (
+                        "Internal network {} is attached to port {}, but the "
+                        "network must be attached via UUID of the network not "
+                        "the name (ex: int_{{network-role}}_net_id)."
+                    ).format(param, r_id)
+                )
             if param not in base_outputs:
-                errors.append((
-                    "Internal network {} is attached to port {}, but network "
-                    "is not defined as an output in the base module ({})."
-                ).format(param, r_id, base_path))
+                errors.append(
+                    (
+                        "Internal network {} is attached to port {}, but network "
+                        "is not defined as an output in the base module ({})."
+                    ).format(param, r_id, base_path)
+                )
 
     assert not errors, " ".join(errors)