computer-playbook/tests/integration/test_role_dependencies.py

68 lines
2.3 KiB
Python

import unittest
import os
import yaml
def load_yaml_file(file_path):
"""Load a YAML file and return its content."""
with open(file_path, 'r') as file:
return yaml.safe_load(file) or {}
def get_meta_info(role_path):
"""Extract dependencies from the meta/main.yml of a role."""
meta_file = os.path.join(role_path, 'meta', 'main.yml')
if not os.path.isfile(meta_file):
return []
meta_data = load_yaml_file(meta_file)
dependencies = meta_data.get('dependencies', [])
return dependencies
def resolve_dependencies(roles_dir):
"""Resolve all role dependencies and detect circular dependencies."""
visited = set() # Tracks roles that have been processed
def visit(role_path, stack):
role_name = os.path.basename(role_path)
# Check for circular dependencies (if role is already in the current stack)
if role_name in stack:
raise ValueError(f"Circular dependency detected: {' -> '.join(stack)} -> {role_name}")
# Check if role is already processed
if role_name in visited:
return []
# Mark role as visited and add to stack
visited.add(role_name)
stack.append(role_name)
# Get dependencies and resolve them
dependencies = get_meta_info(role_path)
for dep in dependencies:
dep_path = os.path.join(roles_dir, dep)
visit(dep_path, stack) # Recurse into dependencies
stack.pop() # Remove the current role from the stack
for role_name in os.listdir(roles_dir):
role_path = os.path.join(roles_dir, role_name)
if os.path.isdir(role_path):
try:
visit(role_path, []) # Start recursion from this role
except ValueError as e:
raise ValueError(f"Error processing role '{role_name}' at path '{role_path}': {str(e)}")
class TestRoleDependencies(unittest.TestCase):
def test_no_circular_dependencies(self):
roles_dir = "roles" # Path to the roles directory
try:
resolve_dependencies(roles_dir)
except ValueError as e:
self.fail(f"Circular dependency detected: {e}")
# If no exception, the test passed
self.assertTrue(True)
if __name__ == '__main__':
unittest.main()