Skip to content

Commit

Permalink
Allow partial specification for deeply nested inventories
Browse files Browse the repository at this point in the history
For objects that are not simple attributes of the resource (i.e.
objects, lists) allow specifing subset of values that needs to be
verified.

In case of lists, count of list objects must match, but if values are
objects / dicts, they can be specified as empty dicts which should pass
all the checks, as no keys are specified.
  • Loading branch information
wiktorn committed Sep 26, 2023
1 parent 1c2f0c6 commit 71def9e
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 27 deletions.
50 changes: 34 additions & 16 deletions tests/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,23 +189,8 @@ def plan_validator(module_path, inventory_paths, basedir, tf_var_files=None,
# side of any comparison operators.
# - include a descriptive error message to the assert

# for values:
# - verify each address in the user's inventory exists in the plan
# - for those address that exist on both the user's inventory and
# the plan output, ensure the set of keys on the inventory are a
# subset of the keys in the plan, and compare their values by
# equality
if 'values' in inventory:
expected_values = inventory['values']
for address, expected_value in expected_values.items():
assert address in summary.values, \
f'{relative_path}: {address} is not a valid address in the plan'
for k, v in expected_value.items():
assert k in summary.values[address], \
f'{relative_path}: {k} not found at {address}'
plan_value = summary.values[address][k]
assert plan_value == v, \
f'{relative_path}: {k} at {address} failed. Got `{plan_value}`, expected `{v}`'
validate_plan_object(inventory['values'], summary.values, relative_path, "")

if 'counts' in inventory:
expected_counts = inventory['counts']
Expand All @@ -231,6 +216,39 @@ def plan_validator(module_path, inventory_paths, basedir, tf_var_files=None,
return summary


def validate_plan_object(expected_value, plan_value, relative_path, relative_address):
"""
Validate that plan object matches inventory
1. Verify each address in the user's inventory exists in the plan
2. For those address that exist on both the user's inventory and
the plan output, ensure the set of keys on the inventory are a
subset of the keys in the plan, and compare their values by
equality
3. For lists, verify that they have the same length and check
whether its members are equal (according to this function)
"""
# dictionaries / objects
if isinstance(expected_value, dict) and isinstance(plan_value, dict):
for k, v in expected_value.items():
assert k in plan_value, \
f'{relative_path}: {k} is not a valid address in the plan'
validate_plan_object(v, plan_value[k], relative_path, f'{relative_address}.{k}')

# lists
elif isinstance(expected_value, list) and isinstance(plan_value, list):
assert len(plan_value) == len(expected_value), \
f'{relative_path}: {relative_address} has different length. Got {plan_value}, expected {expected_value}'

for i, (exp, actual) in enumerate(zip(expected_value, plan_value)):
validate_plan_object(exp, actual, relative_path, f'{relative_address}[{i}]')

# all other objects
else:
assert plan_value == expected_value, \
f'{relative_path}: {relative_address} failed. Got `{plan_value}`, expected `{expected_value}`'


@pytest.fixture(name='plan_validator')
def plan_validator_fixture(request):
"""Return a function to build a PlanSummary and compare it to a YAML inventory.
Expand Down
13 changes: 2 additions & 11 deletions tests/modules/cloud_function_v2/examples/secrets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,7 @@ values:
module.cf-http.google_cloudfunctions2_function.function:
name: test-cf-http
service_config:
- all_traffic_on_latest_revision: true
available_cpu: '0.166'
available_memory: 256M
environment_variables: null
ingress_settings: ALLOW_ALL
max_instance_count: 1
min_instance_count: 0
secret_environment_variables:
- secret_environment_variables:
- key: VARIABLE_SECRET
project_id: '1234567890'
secret: var_secret
Expand All @@ -39,9 +32,7 @@ values:
version: '2'
- path: latest
version: latest
timeout_seconds: 180
vpc_connector: null
vpc_connector_egress_settings: null

counts:
google_cloudfunctions2_function: 1
google_storage_bucket_object: 1
Expand Down

0 comments on commit 71def9e

Please sign in to comment.