diff --git a/tests/collectors.py b/tests/collectors.py index 4ba3c7bc..2ab59136 100644 --- a/tests/collectors.py +++ b/tests/collectors.py @@ -15,19 +15,44 @@ import pytest import yaml -from .fixtures import generic_plan_summary, generic_plan_validator +from .fixtures import plan_summary, plan_validator class FabricTestFile(pytest.File): def collect(self): + """Read yaml test spec and yield test items for each test definition. + + Test spec should contain a `module` key with the path of the + terraform module to test, relative to the root of the repository + + All other top-level keys in the yaml are taken as test names, and + should have the following structure: + + test-name: + tfvars: + - tfvars1.tfvars + - tfvars2.tfvars + inventory: + - inventory1.yaml + - inventory2.yaml + + All paths specifications are relative to the location of the test + spec. The inventory key is optional, if omitted, the inventory + will be taken from the file test-name.yaml + + """ raw = yaml.safe_load(self.path.open()) - module = raw['module'] - for test_name, spec in raw['tests'].items(): - inventory = spec.get('inventory', f'{test_name}.yaml') + module = raw.pop('module') + for test_name, spec in raw.items(): + inventories = spec.get('inventory', [f'{test_name}.yaml']) tfvars = spec['tfvars'] - yield FabricTestItem.from_parent(self, name=test_name, module=module, - inventory=inventory, tfvars=tfvars) + for i in inventories: + name = test_name + if isinstance(inventories, list) and len(inventories) > 1: + name = f'{test_name}[{i}]' + yield FabricTestItem.from_parent(self, name=name, module=module, + inventory=[i], tfvars=tfvars) class FabricTestItem(pytest.Item): @@ -39,13 +64,14 @@ class FabricTestItem(pytest.Item): self.tfvars = tfvars def runtest(self): - s = generic_plan_validator(self.module, self.inventory, - self.parent.path.parent, self.tfvars) + s = plan_validator(self.module, self.inventory, self.parent.path.parent, + self.tfvars) def reportinfo(self): return self.path, None, self.name def pytest_collect_file(parent, file_path): + 'Collect tftest*.yaml files and run plan_validator from them.' if file_path.suffix == '.yaml' and file_path.name.startswith('tftest'): return FabricTestFile.from_parent(parent, path=file_path) diff --git a/tests/conftest.py b/tests/conftest.py index 778989fd..0d928798 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -23,8 +23,7 @@ import tftest import yaml from .collectors import pytest_collect_file -from .fixtures import generic_plan_summary_fixture, generic_plan_validator_fixture -from .fixtures import generic_plan_summary, generic_plan_validator +from .fixtures import plan_summary_fixture, plan_validator_fixture BASEDIR = os.path.dirname(os.path.dirname(__file__)) diff --git a/tests/fast/stages/s00_bootstrap/tftest.yaml b/tests/fast/stages/s00_bootstrap/tftest.yaml index 4656859b..9f9ce107 100644 --- a/tests/fast/stages/s00_bootstrap/tftest.yaml +++ b/tests/fast/stages/s00_bootstrap/tftest.yaml @@ -2,11 +2,10 @@ module: fast/stages/00-bootstrap -tests: - simple: - tfvars: - - simple.tfvars - inventory: - - simple.yaml - - simple_projects.yaml - - simple_sas.yaml +simple: + tfvars: + - simple.tfvars + inventory: + - simple.yaml + - simple_projects.yaml + - simple_sas.yaml diff --git a/tests/fixtures.py b/tests/fixtures.py index 43b2128c..a225d871 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -25,7 +25,7 @@ import yaml PlanSummary = collections.namedtuple('PlanSummary', 'values counts outputs') -def generic_plan_summary(module_path, basedir, tf_var_files=None, **tf_vars): +def plan_summary(module_path, basedir, tf_var_files=None, **tf_vars): """ Run a Terraform plan on the module located at `module_path`. @@ -117,8 +117,8 @@ def generic_plan_summary(module_path, basedir, tf_var_files=None, **tf_vars): return PlanSummary(values, dict(counts), outputs) -@pytest.fixture(name='generic_plan_summary') -def generic_plan_summary_fixture(request): +@pytest.fixture(name='plan_summary') +def plan_summary_fixture(request): """Return a function to generate a PlanSummary. In the returned function `basedir` becomes optional and it defaults @@ -128,17 +128,16 @@ def generic_plan_summary_fixture(request): def inner(module_path, basedir=None, tf_var_files=None, **tf_vars): if basedir is None: basedir = Path(request.fspath).parent - return generic_plan_summary(module_path=module_path, basedir=basedir, - tf_var_files=tf_var_files, **tf_vars) + return plan_summary(module_path=module_path, basedir=basedir, + tf_var_files=tf_var_files, **tf_vars) return inner -def generic_plan_validator(module_path, inventory_paths, basedir, - tf_var_files=None, **tf_vars): - summary = generic_plan_summary(module_path=module_path, - tf_var_files=tf_var_files, basedir=basedir, - **tf_vars) +def plan_validator(module_path, inventory_paths, basedir, tf_var_files=None, + **tf_vars): + summary = plan_summary(module_path=module_path, tf_var_files=tf_var_files, + basedir=basedir, **tf_vars) # allow single single string for inventory_paths if not isinstance(inventory_paths, list): @@ -201,8 +200,8 @@ def generic_plan_validator(module_path, inventory_paths, basedir, return summary -@pytest.fixture(name='generic_plan_validator') -def generic_plan_validator_fixture(request): +@pytest.fixture(name='plan_validator') +def plan_validator_fixture(request): """Return a function to builds a PlanSummary and compare it to YAML inventory. @@ -215,9 +214,8 @@ def generic_plan_validator_fixture(request): **tf_vars): if basedir is None: basedir = Path(request.fspath).parent - return generic_plan_validator(module_path=module_path, - inventory_paths=inventory_paths, - basedir=basedir, tf_var_files=tf_var_paths, - **tf_vars) + return plan_validator(module_path=module_path, + inventory_paths=inventory_paths, basedir=basedir, + tf_var_files=tf_var_paths, **tf_vars) return inner diff --git a/tests/modules/net_vpc/test_routes.py b/tests/modules/net_vpc/test_routes.py index e4df8d6b..01d9673d 100644 --- a/tests/modules/net_vpc/test_routes.py +++ b/tests/modules/net_vpc/test_routes.py @@ -22,7 +22,7 @@ _route_parameters = [('gateway', 'global/gateways/default-internet-gateway'), @pytest.mark.parametrize('next_hop_type,next_hop', _route_parameters) -def test_vpc_routes(generic_plan_summary, next_hop_type, next_hop): +def test_vpc_routes(plan_summary, next_hop_type, next_hop): 'Test vpc routes.' var_routes = '''{ @@ -40,9 +40,8 @@ def test_vpc_routes(generic_plan_summary, next_hop_type, next_hop): next_hop = "global/gateways/default-internet-gateway" } }''' % (next_hop_type, next_hop) - summary = generic_plan_summary('modules/net-vpc', - tf_var_files=['common.tfvars'], - routes=var_routes) + summary = plan_summary('modules/net-vpc', tf_var_files=['common.tfvars'], + routes=var_routes) assert len(summary.values) == 3 route = summary.values[f'google_compute_route.{next_hop_type}["next-hop"]'] assert route[f'next_hop_{next_hop_type}'] == next_hop diff --git a/tests/modules/net_vpc/tftest.yaml b/tests/modules/net_vpc/tftest.yaml index 3a8060dd..4463a184 100644 --- a/tests/modules/net_vpc/tftest.yaml +++ b/tests/modules/net_vpc/tftest.yaml @@ -14,49 +14,46 @@ module: modules/net-vpc -tests: - simple: - tfvars: - - common.tfvars +simple: + tfvars: + - common.tfvars - subnets: - tfvars: - - common.tfvars - - subnets.tfvars +subnets: + tfvars: + - common.tfvars + - subnets.tfvars - peering: - tfvars: - - common.tfvars - - peering.tfvars +peering: + tfvars: + - common.tfvars + - peering.tfvars - shared_vpc: - tfvars: - - common.tfvars - - shared_vpc.tfvars +shared_vpc: + tfvars: + - common.tfvars + - shared_vpc.tfvars - factory: - tfvars: - - common.tfvars - - factory.tfvars - inventory: - - factory.yaml +factory: + tfvars: + - common.tfvars + - factory.tfvars - psa_simple: - tfvars: - - common.tfvars - - psa_simple.tfvars +psa_simple: + tfvars: + - common.tfvars + - psa_simple.tfvars - psa_routes_export: - tfvars: - - common.tfvars - - psa_routes_export.tfvars +psa_routes_export: + tfvars: + - common.tfvars + - psa_routes_export.tfvars - psa_routes_import: - tfvars: - - common.tfvars - - psa_routes_import.tfvars +psa_routes_import: + tfvars: + - common.tfvars + - psa_routes_import.tfvars - psa_routes_import_export: - tfvars: - - common.tfvars - - psa_routes_import_export.tfvars +psa_routes_import_export: + tfvars: + - common.tfvars + - psa_routes_import_export.tfvars diff --git a/tests/modules/organization/test_plan_org_policies.py b/tests/modules/organization/test_plan_org_policies.py index 0a5d9a35..1e041dbc 100644 --- a/tests/modules/organization/test_plan_org_policies.py +++ b/tests/modules/organization/test_plan_org_policies.py @@ -20,28 +20,26 @@ _params = ['boolean', 'list'] @pytest.mark.parametrize('policy_type', _params) -def test_policy_factory(generic_plan_summary, tfvars_to_yaml, tmp_path, - policy_type): +def test_policy_factory(plan_summary, tfvars_to_yaml, tmp_path, policy_type): dest = tmp_path / 'policies.yaml' tfvars_to_yaml(f'org_policies_{policy_type}.tfvars', dest, 'org_policies') - tfvars_plan = generic_plan_summary( + tfvars_plan = plan_summary( 'modules/organization', tf_var_files=['common.tfvars', f'org_policies_{policy_type}.tfvars']) - yaml_plan = generic_plan_summary('modules/organization', - tf_var_files=['common.tfvars'], - org_policies_data_path=f'{tmp_path}') + yaml_plan = plan_summary('modules/organization', + tf_var_files=['common.tfvars'], + org_policies_data_path=f'{tmp_path}') assert tfvars_plan.values == yaml_plan.values -def test_custom_constraint_factory(generic_plan_summary, tfvars_to_yaml, - tmp_path): +def test_custom_constraint_factory(plan_summary, tfvars_to_yaml, tmp_path): dest = tmp_path / 'constraints.yaml' tfvars_to_yaml(f'org_policies_custom_constraints.tfvars', dest, 'org_policy_custom_constraints') - tfvars_plan = generic_plan_summary( + tfvars_plan = plan_summary( 'modules/organization', tf_var_files=['common.tfvars', f'org_policies_custom_constraints.tfvars']) - yaml_plan = generic_plan_summary( + yaml_plan = plan_summary( 'modules/organization', tf_var_files=['common.tfvars'], org_policy_custom_constraints_data_path=f'{tmp_path}') assert tfvars_plan.values == yaml_plan.values diff --git a/tests/modules/organization/tftest.yaml b/tests/modules/organization/tftest.yaml index 662b6b1a..6389aba0 100644 --- a/tests/modules/organization/tftest.yaml +++ b/tests/modules/organization/tftest.yaml @@ -14,67 +14,64 @@ module: modules/organization -tests: - audit_config: - tfvars: - - common.tfvars - - audit_config.tfvars +audit_config: + tfvars: + - common.tfvars + - audit_config.tfvars - iam: - tfvars: - - common.tfvars - - iam.tfvars +iam: + tfvars: + - common.tfvars + - iam.tfvars - iam_additive: - tfvars: - - common.tfvars - - iam_additive.tfvars +iam_additive: + tfvars: + - common.tfvars + - iam_additive.tfvars - logging: - tfvars: - - common.tfvars - - logging.tfvars +logging: + tfvars: + - common.tfvars + - logging.tfvars - logging_exclusions: - tfvars: - - common.tfvars - - logging_exclusions.tfvars +logging_exclusions: + tfvars: + - common.tfvars + - logging_exclusions.tfvars - org_policies_list: - tfvars: - - common.tfvars - - org_policies_list.tfvars +org_policies_list: + tfvars: + - common.tfvars + - org_policies_list.tfvars - org_policies_boolean: - tfvars: - - common.tfvars - - org_policies_boolean.tfvars +org_policies_boolean: + tfvars: + - common.tfvars + - org_policies_boolean.tfvars - org_policies_custom_constraints: - tfvars: - - common.tfvars - - org_policies_custom_constraints.tfvars +org_policies_custom_constraints: + tfvars: + - common.tfvars + - org_policies_custom_constraints.tfvars - tags: - tfvars: - - common.tfvars - - network_tags.tfvars - - resource_tags.tfvars - inventory: - - tags.yaml +tags: + tfvars: + - common.tfvars + - network_tags.tfvars + - resource_tags.tfvars - firewall_policies: - tfvars: - - common.tfvars - - firewall_policies.tfvars +firewall_policies: + tfvars: + - common.tfvars + - firewall_policies.tfvars - firewall_policies_factory: - tfvars: - - common.tfvars - - firewall_policies_factory.tfvars +firewall_policies_factory: + tfvars: + - common.tfvars + - firewall_policies_factory.tfvars - firewall_policies_factory_combined: - tfvars: - - common.tfvars - - firewall_policies.tfvars - - firewall_policies_factory.tfvars +firewall_policies_factory_combined: + tfvars: + - common.tfvars + - firewall_policies.tfvars + - firewall_policies_factory.tfvars