Huge role refactoring/cleanup. Other commits will propably follow. Because some bugs will exist. Still important for longrun and also for auto docs/help/slideshow generation

This commit is contained in:
2025-07-08 23:43:13 +02:00
parent 6b87a049d4
commit 563d5fd528
1242 changed files with 2301 additions and 1355 deletions

View File

@@ -11,11 +11,11 @@ class TestApplicationIdConsistency(unittest.TestCase):
failed_roles = []
for role_path in ROLES_DIR.iterdir():
if role_path.name in ["docker-container","docker-compose", "docker-central-database", "docker-repository-setup"]:
if role_path.name in ["docker-container","docker-compose", "service-rdbms-central", "docker-repository-setup"]:
continue
if role_path.is_dir() and role_path.name.startswith("docker-"):
expected_id = role_path.name.replace("docker-", "", 1)
if role_path.is_dir() and role_path.name.startswith("web-app-"):
expected_id = role_path.name.replace("web-app-", "", 1)
vars_file = role_path / "vars" / "main.yml"
if not vars_file.exists():

View File

@@ -5,7 +5,7 @@ import yaml
class TestDeprecatedVersionKey(unittest.TestCase):
def test_version_key_deprecation(self):
"""
Checks all roles/docker-*/vars/configuration.yml for deprecated use of 'version'.
Checks all roles/web-app-*/vars/configuration.yml for deprecated use of 'version'.
Warns if 'version' is set but 'images' is missing.
Prints warnings but does NOT fail the test.
"""
@@ -14,7 +14,7 @@ class TestDeprecatedVersionKey(unittest.TestCase):
warnings = []
for role_path in roles_dir.iterdir():
if not (role_path.is_dir() and role_path.name.startswith("docker-")):
if not (role_path.is_dir() and role_path.name.startswith("web-app-")):
continue
cfg_file = role_path / "vars" / "configuration.yml"

View File

@@ -6,11 +6,11 @@ import re
class TestDockerRoleImagesConfiguration(unittest.TestCase):
def test_images_keys_and_templates(self):
"""
For each docker-* role, check that:
- roles/docker-*/vars/configuration.yml contains 'images' as a dict with keys/values
For each web-app-* role, check that:
- roles/web-app-*/vars/configuration.yml contains 'images' as a dict with keys/values
- Each image key is referenced as:
image: "{{ applications[application_id].images.<key> }}"
in either roles/docker-*/templates/docker-compose.yml.j2 or env.j2
in either roles/web-app-*/templates/docker-compose.yml.j2 or env.j2
"""
repo_root = Path(__file__).resolve().parent.parent.parent
roles_dir = repo_root / "roles"
@@ -18,7 +18,7 @@ class TestDockerRoleImagesConfiguration(unittest.TestCase):
warnings = []
for role_path in roles_dir.iterdir():
if not (role_path.is_dir() and role_path.name.startswith("docker-")):
if not (role_path.is_dir() and role_path.name.startswith("web-app-")):
continue
cfg_file = role_path / "vars" / "configuration.yml"

View File

@@ -0,0 +1,47 @@
import unittest
import os
import glob
import yaml
class TestRoleDependencies(unittest.TestCase):
def test_dependencies_exist(self):
# Determine the path to the roles directory relative to this test file
tests_dir = os.path.dirname(__file__)
project_root = os.path.abspath(os.path.join(tests_dir, os.pardir, os.pardir))
roles_dir = os.path.join(project_root, 'roles')
# Find all meta/main.yml files under roles/*/meta/main.yml
pattern = os.path.join(roles_dir, '*', 'meta', 'main.yml')
meta_files = glob.glob(pattern)
self.assertTrue(meta_files, f"No meta/main.yml files found with pattern {pattern}")
for meta_file in meta_files:
role_dir = os.path.dirname(os.path.dirname(meta_file))
role_name = os.path.basename(role_dir)
with self.subTest(role=role_name):
# Load the YAML metadata
with open(meta_file, 'r') as f:
meta = yaml.safe_load(f) or {}
# Extract dependencies list
dependencies = meta.get('dependencies', [])
self.assertIsInstance(dependencies, list, f"'dependencies' for role '{role_name}' is not a list")
for dep in dependencies:
# Dependencies can be strings or dicts with a 'role' key
if isinstance(dep, str):
dep_name = dep
elif isinstance(dep, dict) and 'role' in dep:
dep_name = dep['role']
else:
self.fail(f"Invalid dependency format {dep!r} in role '{role_name}'")
dep_path = os.path.join(roles_dir, dep_name)
# Assert that the dependency role directory exists
self.assertTrue(
os.path.isdir(dep_path),
f"Role '{role_name}' declares dependency '{dep_name}' but '{dep_path}' does not exist"
)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,74 @@
import unittest
import os
import glob
import yaml
import re
class TestIncludeImportRoleExistence(unittest.TestCase):
def setUp(self):
# Determine project root and roles directory
tests_dir = os.path.dirname(__file__)
project_root = os.path.abspath(os.path.join(tests_dir, os.pardir, os.pardir))
self.roles_dir = os.path.join(project_root, 'roles')
# Collect all .yml files in project (recursive), excluding .git and tests dirs
self.files_to_scan = []
for filepath in glob.glob(os.path.join(project_root, '**', '*.yml'), recursive=True):
# Skip .git, tests folders
if '/.git/' in filepath or '/tests/' in filepath:
continue
self.files_to_scan.append(filepath)
def _collect_includes(self, data):
"""
Recursively collect all roles referenced via include_role or import_role.
Supports scalar, block, and block-list syntax, plus templating and wildcards.
"""
roles = []
if isinstance(data, dict):
for key, val in data.items():
if key in ('include_role', 'import_role'):
# Scalar syntax: include_role: role_name
if isinstance(val, str):
roles.append(val)
# Block syntax: include_role: { name: role_name }
elif isinstance(val, dict) and 'name' in val:
roles.append(val['name'])
# Block-list syntax: include_role:
# - name: foo
# - name: bar
elif isinstance(val, list):
for item in val:
if isinstance(item, dict) and 'name' in item:
roles.append(item['name'])
else:
roles.extend(self._collect_includes(val))
elif isinstance(data, list):
for item in data:
roles.extend(self._collect_includes(item))
return roles
def test_include_import_roles_exist(self):
missing = []
for file_path in self.files_to_scan:
with open(file_path) as f:
try:
docs = list(yaml.safe_load_all(f))
except yaml.YAMLError:
self.fail(f"Failed to parse YAML in {file_path}")
for doc in docs:
for role_name in self._collect_includes(doc):
# Convert Jinja2 templates and wildcards to glob patterns
pattern = re.sub(r"\{\{.*?\}\}", '*', role_name)
glob_path = os.path.join(self.roles_dir, pattern)
# Check for matching role directories
matches = [p for p in glob.glob(glob_path) if os.path.isdir(p)]
if not matches:
missing.append((file_path, role_name))
if missing:
messages = [f"File '{fp}' references missing role '{rn}'" for fp, rn in missing]
self.fail("\n".join(messages))
if __name__ == '__main__':
unittest.main()