Finished new role identification system implementation

This commit is contained in:
2025-07-11 00:42:36 +02:00
parent 292918da81
commit 6e32b20240
44 changed files with 212 additions and 218 deletions

View File

@@ -39,7 +39,7 @@ class TestApplicationIdConsistency(unittest.TestCase):
continue
actual_id = vars_data.get("application_id")
if actual_id != expected_id:
if actual_id not in [expected_id, role_name]:
failed_roles.append((
role_name,
f"application_id is '{actual_id}', expected '{expected_id}'"

View File

@@ -0,0 +1,67 @@
import unittest
from pathlib import Path
import re
import os
import sys
# Ensure your project root is on PYTHONPATH so filter_plugins can be imported
ROOT = Path(__file__).parents[2]
sys.path.insert(0, str(ROOT))
from filter_plugins.invokable_paths import get_invokable_paths
STAGES_DIR = ROOT / "tasks" / "stages"
GROUPS_DIR = ROOT / "tasks" / "groups"
class TestMetaRolesIntegration(unittest.TestCase):
@classmethod
def setUpClass(cls):
# Use the filter directly
cls.role_files = get_invokable_paths(suffix="-roles.yml")
cls.invokable_items = get_invokable_paths()
# Read all playbook YAML contents under tasks/stages
cls.playbook_contents = {}
for path in STAGES_DIR.rglob("*.yml"):
cls.playbook_contents[path] = path.read_text(encoding="utf-8")
# Regex for include_tasks line with {{ item }}-roles.yml
cls.include_pattern = re.compile(
r'include_tasks:\s*["\']\./tasks/groups/\{\{\s*item\s*\}\}-roles\.yml["\']'
)
def test_all_role_files_exist(self):
"""Each '-roles.yml' path returned by the filter must exist in the project root."""
missing = []
for fname in self.role_files:
path = GROUPS_DIR / fname
if not path.is_file():
missing.append(fname)
self.assertFalse(
missing,
f"The following role files are missing at project root: {missing}"
)
def test_each_invokable_item_referenced_in_playbooks(self):
"""
Each invokable item (without suffix) must be looped through in at least one playbook
and include its corresponding include_tasks entry.
"""
not_referenced = []
for item in self.invokable_items:
found = False
loop_entry = re.compile(rf"-\s*{re.escape(item)}\b")
for content in self.playbook_contents.values():
if self.include_pattern.search(content) and loop_entry.search(content):
found = True
break
if not found:
not_referenced.append(item)
self.assertEqual(
not_referenced, [],
f"The following invokable items are not referenced in any playbook: {not_referenced}"
)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,39 @@
import os
import glob
import yaml
import unittest
def find_application_ids():
"""
Scans all roles/*/vars/main.yml files and collects application_id values.
Returns a dict mapping application_id to list of file paths where it appears.
"""
ids = {}
# Wenn der Test unter tests/integration liegt, gehen wir zwei Ebenen hoch zum Projekt-Root
base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
pattern = os.path.join(base_dir, "roles", "*", "vars", "main.yml")
for file_path in glob.glob(pattern):
with open(file_path, 'r') as f:
data = yaml.safe_load(f) or {}
app_id = data.get('application_id')
if app_id is not None:
ids.setdefault(app_id, []).append(file_path)
return ids
class TestUniqueApplicationId(unittest.TestCase):
def test_application_ids_are_unique(self):
ids = find_application_ids()
duplicates = {app_id: paths for app_id, paths in ids.items() if len(paths) > 1}
if duplicates:
messages = []
for app_id, paths in duplicates.items():
file_list = '\n '.join(paths)
messages.append(f"application_id '{app_id}' found in multiple files:\n {file_list}")
self.fail("\n\n".join(messages))
if __name__ == '__main__':
unittest.main(verbosity=2)

View File

@@ -8,7 +8,7 @@ import sys
def load_optimizer_module():
module_path = os.path.abspath(os.path.join(
os.path.dirname(__file__),
'..', "..", "..","..",'roles', 'maint-docker-storage-optimizer', 'files', 'maint-docker-storage-optimizer.py'
'..', "..", "..","..",'roles', 'cln-docker-storage-optimizer', 'files', 'cln-docker-storage-optimizer.py'
))
spec = importlib.util.spec_from_file_location('storage_optimizer', module_path)
optimizer = importlib.util.module_from_spec(spec)