mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-07-18 06:24:25 +02:00
62 lines
2.0 KiB
Python
62 lines
2.0 KiB
Python
import os
|
|
import glob
|
|
import yaml
|
|
import unittest
|
|
|
|
|
|
def find_none_values(data, prefix=None):
|
|
"""
|
|
Recursively find keys with None values in a nested dict or list.
|
|
Returns a list of (path, value) tuples where value is None.
|
|
"""
|
|
errors = []
|
|
if prefix is None:
|
|
prefix = []
|
|
|
|
if isinstance(data, dict):
|
|
for key, value in data.items():
|
|
path = prefix + [str(key)]
|
|
if value is None:
|
|
errors.append((".".join(path), value))
|
|
elif isinstance(value, (dict, list)):
|
|
errors.extend(find_none_values(value, path))
|
|
elif isinstance(data, list):
|
|
for idx, item in enumerate(data):
|
|
path = prefix + [f"[{idx}]"]
|
|
if item is None:
|
|
errors.append((".".join(path), item))
|
|
elif isinstance(item, (dict, list)):
|
|
errors.extend(find_none_values(item, path))
|
|
|
|
return errors
|
|
|
|
|
|
class TestConfigurationNoNone(unittest.TestCase):
|
|
def test_configuration_files_have_no_none_values(self):
|
|
# Find all config/main.yml files under roles/*/vars
|
|
pattern = os.path.join(
|
|
os.path.dirname(__file__),
|
|
os.pardir, os.pardir,
|
|
'roles', '*', "config" , "main.yml"
|
|
)
|
|
files = glob.glob(pattern)
|
|
self.assertTrue(files, f"No config/main.yml files found with pattern: {pattern}")
|
|
|
|
all_errors = []
|
|
for filepath in files:
|
|
with open(filepath, 'r') as f:
|
|
try:
|
|
data = yaml.safe_load(f)
|
|
except yaml.YAMLError as e:
|
|
self.fail(f"Failed to parse YAML in {filepath}: {e}")
|
|
errors = find_none_values(data)
|
|
for path, value in errors:
|
|
all_errors.append(f"{filepath}: Key '{path}' is None")
|
|
|
|
if all_errors:
|
|
self.fail("None values found in configuration files:\n" + "\n".join(all_errors))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|