import os import unittest import yaml import glob class TestDependencyApplicationId(unittest.TestCase): def test_application_id_matches_folder_for_dependent_roles(self): """ For any role A that depends on role B (listed under A/meta/main.yml → dependencies), if both A and B have vars/main.yml with application_id defined, then application_id must equal the role's folder name for both. """ base_dir = os.path.dirname(__file__) roles_dir = os.path.abspath(os.path.join(base_dir, '..', '..', 'roles')) violations = [] # Helper to load application_id if present def load_app_id(role_path): vars_file = os.path.join(role_path, 'vars', 'main.yml') if not os.path.isfile(vars_file): return None data = yaml.safe_load(open(vars_file, encoding='utf-8')) or {} return data.get('application_id') # Iterate all roles for role_path in glob.glob(os.path.join(roles_dir, '*')): if not os.path.isdir(role_path): continue role_name = os.path.basename(role_path) meta_file = os.path.join(role_path, 'meta', 'main.yml') if not os.path.isfile(meta_file): continue meta = yaml.safe_load(open(meta_file, encoding='utf-8')) or {} deps = meta.get('dependencies', []) if not isinstance(deps, list): continue # collect just the role names this role depends on dep_names = [] for item in deps: if isinstance(item, dict) and 'role' in item: dep_names.append(item['role']) elif isinstance(item, str): dep_names.append(item) # load application_id for this role once app_id_role = load_app_id(role_path) for dep_name in dep_names: dep_path = os.path.join(roles_dir, dep_name) if not os.path.isdir(dep_path): continue app_id_dep = load_app_id(dep_path) # only check if both app_ids are defined if app_id_role is None or app_id_dep is None: continue # check role A if app_id_role != role_name: violations.append( f"{role_name}: application_id='{app_id_role}' ≠ folder name '{role_name}'" ) # check role B if app_id_dep != dep_name: violations.append( f"{dep_name}: application_id='{app_id_dep}' ≠ folder name '{dep_name}'" ) if violations: self.fail( "application_id mismatches between role folder names and vars/main.yml:\n" + "\n".join(violations) ) if __name__ == '__main__': unittest.main()