mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-08-29 23:08:06 +02:00
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:
@@ -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():
|
||||
|
@@ -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"
|
||||
|
@@ -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"
|
||||
|
47
tests/integration/test_role_dependencies_meta_resolve.py
Normal file
47
tests/integration/test_role_dependencies_meta_resolve.py
Normal 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()
|
74
tests/integration/test_role_include_import_roles_exist.py
Normal file
74
tests/integration/test_role_include_import_roles_exist.py
Normal 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()
|
@@ -1,6 +1,6 @@
|
||||
# Unit Tests
|
||||
|
||||
This directory contains unit tests for various custom components in the project, such as the custom lookup plugin `docker_cards` used in the `docker-portfolio` role.
|
||||
This directory contains unit tests for various custom components in the project, such as the custom lookup plugin `docker_cards` used in the `web-app-portfolio` role.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -31,7 +31,7 @@ You can run the tests using one of the following methods:
|
||||
## How It Works
|
||||
|
||||
- **Setup:**
|
||||
The test script creates a temporary directory to simulate your roles folder. It then creates a sample role (`docker-portfolio`) with a `README.md` file (containing a header for the title) and a `meta/main.yml` file (with the required metadata).
|
||||
The test script creates a temporary directory to simulate your roles folder. It then creates a sample role (`web-app-portfolio`) with a `README.md` file (containing a header for the title) and a `meta/main.yml` file (with the required metadata).
|
||||
|
||||
- **Execution:**
|
||||
Dummy variable values for `domains` and `applications` are provided (these are the variables the lookup plugin expects). The lookup plugin is then run, which processes the sample role and returns the card information.
|
||||
|
@@ -6,7 +6,7 @@ import tempfile
|
||||
from ruamel.yaml import YAML
|
||||
|
||||
# Import functions to test; adjust path as needed
|
||||
from cli.create_docker_role import (
|
||||
from cli.create_web_app import (
|
||||
get_next_network,
|
||||
get_next_port,
|
||||
load_yaml_with_comments,
|
@@ -14,7 +14,7 @@ class TestGenerateDefaultApplicationsUsers(unittest.TestCase):
|
||||
self.roles_dir.mkdir()
|
||||
|
||||
# Sample role with users meta
|
||||
self.role = self.roles_dir / "docker-app-with-users"
|
||||
self.role = self.roles_dir / "web-app-app-with-users"
|
||||
(self.role / "vars").mkdir(parents=True)
|
||||
(self.role / "meta").mkdir(parents=True)
|
||||
|
||||
|
@@ -15,7 +15,7 @@ class TestGenerateDefaultApplications(unittest.TestCase):
|
||||
self.roles_dir.mkdir()
|
||||
|
||||
# Sample role
|
||||
self.sample_role = self.roles_dir / "docker-testapp"
|
||||
self.sample_role = self.roles_dir / "web-app-testapp"
|
||||
(self.sample_role / "vars").mkdir(parents=True)
|
||||
|
||||
# Write application_id and configuration
|
||||
|
@@ -5,7 +5,7 @@ import unittest
|
||||
sys.path.insert(
|
||||
0,
|
||||
os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), "../../../roles/docker-matrix/filter_plugins")
|
||||
os.path.join(os.path.dirname(__file__), "../../../roles/web-app-matrix/filter_plugins")
|
||||
),
|
||||
)
|
||||
|
||||
|
@@ -23,10 +23,10 @@ class TestApplicationGidLookup(unittest.TestCase):
|
||||
|
||||
# Define mock application_ids
|
||||
self.applications = {
|
||||
"nextcloud": "docker-nextcloud",
|
||||
"moodle": "docker-moodle",
|
||||
"wordpress": "docker-wordpress",
|
||||
"taiga": "docker-taiga"
|
||||
"nextcloud": "web-app-nextcloud",
|
||||
"moodle": "web-app-moodle",
|
||||
"wordpress": "web-app-wordpress",
|
||||
"taiga": "web-app-taiga"
|
||||
}
|
||||
|
||||
# Create fake role dirs and vars/main.yml
|
||||
|
@@ -4,8 +4,8 @@ import tempfile
|
||||
import shutil
|
||||
import unittest
|
||||
|
||||
# Adjust the PYTHONPATH to include the lookup_plugins folder from the docker-portfolio role.
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../../roles/docker-portfolio/lookup_plugins'))
|
||||
# Adjust the PYTHONPATH to include the lookup_plugins folder from the web-app-portfolio role.
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../../roles/web-app-portfolio/lookup_plugins'))
|
||||
|
||||
from docker_cards import LookupModule
|
||||
|
||||
@@ -13,8 +13,8 @@ class TestDockerCardsLookup(unittest.TestCase):
|
||||
def setUp(self):
|
||||
# Create a temporary directory to simulate the roles directory.
|
||||
self.test_roles_dir = tempfile.mkdtemp(prefix="test_roles_")
|
||||
# Create a sample role "docker-portfolio".
|
||||
self.role_name = "docker-portfolio"
|
||||
# Create a sample role "web-app-portfolio".
|
||||
self.role_name = "web-app-portfolio"
|
||||
self.role_dir = os.path.join(self.test_roles_dir, self.role_name)
|
||||
os.makedirs(os.path.join(self.role_dir, "meta"))
|
||||
|
||||
|
@@ -8,7 +8,7 @@ import sys
|
||||
def load_optimizer_module():
|
||||
module_path = os.path.abspath(os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
'..', "..", "..","..",'roles', 'system-storage-optimizer', 'files', 'system-storage-optimizer.py'
|
||||
'..', "..", "..","..",'roles', 'maintenance-docker-storage-optimizer', 'files', 'maintenance-docker-storage-optimizer.py'
|
||||
))
|
||||
spec = importlib.util.spec_from_file_location('storage_optimizer', module_path)
|
||||
optimizer = importlib.util.module_from_spec(spec)
|
@@ -5,7 +5,7 @@ import importlib.util
|
||||
|
||||
# Dynamisch den Filter-Plugin Pfad hinzufügen
|
||||
current_dir = os.path.dirname(__file__)
|
||||
filter_plugin_path = os.path.abspath(os.path.join(current_dir, "../../../../roles/docker-ldap/filter_plugins"))
|
||||
filter_plugin_path = os.path.abspath(os.path.join(current_dir, "../../../../roles/service-openldap/filter_plugins"))
|
||||
|
||||
# Modul dynamisch laden
|
||||
spec = importlib.util.spec_from_file_location("build_ldap_role_entries", os.path.join(filter_plugin_path, "build_ldap_role_entries.py"))
|
Reference in New Issue
Block a user