From a9f55579a20416d37d9058d17eef7dd1ec636222 Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Fri, 4 Jul 2025 01:14:00 +0200 Subject: [PATCH] Reorgenized test structure and added validation of inventory before deployment --- cli/deploy.py | 18 ++- ...ify_inventory.py => validate_inventory.py} | 45 +++++- tests/integration/test_check_init_files.py | 21 +++ tests/unit/cli/__init__.py | 0 .../unit/{ => cli}/test_create_credentials.py | 2 +- ...st_generate_applications_defaults_users.py | 2 +- .../test_generate_default_applications.py | 2 +- .../unit/{ => cli}/test_generate_playbook.py | 2 +- tests/unit/{ => cli}/test_generate_users.py | 2 +- .../unit/{ => cli}/test_inventory_manager.py | 2 +- tests/unit/cli/test_validate_inventory.py | 134 ++++++++++++++++++ tests/unit/filter_plugins/__init__.py | 0 .../test_applications_if_group_and_deps.py | 2 +- .../test_bridge_filters.py | 2 +- .../test_configuration_filters.py | 2 +- .../{ => filter_plugins}/test_csp_filters.py | 2 +- .../{ => filter_plugins}/test_docker_image.py | 2 +- .../test_domain_filters_alias.py | 2 +- .../test_domain_filters_all_domains.py | 2 +- .../test_domain_filters_base_sld_domains.py | 2 +- .../test_domain_filters_canonical.py | 2 +- .../test_domain_mappings.py | 2 +- .../test_get_domain_filter.py | 2 +- .../test_load_configuration.py | 2 +- .../test_merge_mapping.py | 0 .../test_redirect_filters.py | 2 +- .../{ => filter_plugins}/test_safe_join.py | 2 +- .../test_safe_placeholders_filter.py | 2 +- .../{ => filter_plugins}/test_safe_var.py | 2 +- tests/unit/lookup_plugins/__init__.py | 0 .../test_application_gid.py | 2 +- .../{ => lookup_plugins}/test_docker_cards.py | 2 +- tests/unit/module_utils/__init__.py | 0 .../{ => module_utils}/test_cert_utils.py | 15 +- tests/unit/roles/__init__.py | 0 .../system-storage-optimizer/__init__.py | 0 .../test_storage_optimizer.py | 2 +- 37 files changed, 241 insertions(+), 42 deletions(-) rename cli/{verify_inventory.py => validate_inventory.py} (66%) create mode 100644 tests/integration/test_check_init_files.py create mode 100644 tests/unit/cli/__init__.py rename tests/unit/{ => cli}/test_create_credentials.py (98%) rename tests/unit/{ => cli}/test_generate_applications_defaults_users.py (97%) rename tests/unit/{ => cli}/test_generate_default_applications.py (97%) rename tests/unit/{ => cli}/test_generate_playbook.py (98%) rename tests/unit/{ => cli}/test_generate_users.py (99%) rename tests/unit/{ => cli}/test_inventory_manager.py (98%) create mode 100644 tests/unit/cli/test_validate_inventory.py create mode 100644 tests/unit/filter_plugins/__init__.py rename tests/unit/{ => filter_plugins}/test_applications_if_group_and_deps.py (97%) rename tests/unit/{ => filter_plugins}/test_bridge_filters.py (96%) rename tests/unit/{ => filter_plugins}/test_configuration_filters.py (94%) rename tests/unit/{ => filter_plugins}/test_csp_filters.py (99%) rename tests/unit/{ => filter_plugins}/test_docker_image.py (98%) rename tests/unit/{ => filter_plugins}/test_domain_filters_alias.py (97%) rename tests/unit/{ => filter_plugins}/test_domain_filters_all_domains.py (98%) rename tests/unit/{ => filter_plugins}/test_domain_filters_base_sld_domains.py (99%) rename tests/unit/{ => filter_plugins}/test_domain_filters_canonical.py (97%) rename tests/unit/{ => filter_plugins}/test_domain_mappings.py (97%) rename tests/unit/{ => filter_plugins}/test_get_domain_filter.py (96%) rename tests/unit/{ => filter_plugins}/test_load_configuration.py (99%) rename tests/unit/{ => filter_plugins}/test_merge_mapping.py (100%) rename tests/unit/{ => filter_plugins}/test_redirect_filters.py (96%) rename tests/unit/{ => filter_plugins}/test_safe_join.py (98%) rename tests/unit/{ => filter_plugins}/test_safe_placeholders_filter.py (98%) rename tests/unit/{ => filter_plugins}/test_safe_var.py (98%) create mode 100644 tests/unit/lookup_plugins/__init__.py rename tests/unit/{ => lookup_plugins}/test_application_gid.py (96%) rename tests/unit/{ => lookup_plugins}/test_docker_cards.py (98%) create mode 100644 tests/unit/module_utils/__init__.py rename tests/unit/{ => module_utils}/test_cert_utils.py (88%) create mode 100644 tests/unit/roles/__init__.py create mode 100644 tests/unit/roles/system-storage-optimizer/__init__.py rename tests/unit/{ => roles/system-storage-optimizer}/test_storage_optimizer.py (95%) diff --git a/cli/deploy.py b/cli/deploy.py index 23188602..fb045a99 100644 --- a/cli/deploy.py +++ b/cli/deploy.py @@ -4,8 +4,9 @@ import argparse import subprocess import os import datetime +import sys -def run_ansible_playbook(inventory, playbook, modes, limit=None, password_file=None, verbose=0, skip_tests:bool=False): +def run_ansible_playbook(inventory, playbook, modes, limit=None, password_file=None, verbose=0, skip_tests=False): start_time = datetime.datetime.now() print(f"\n▶️ Script started at: {start_time.isoformat()}\n") @@ -94,6 +95,10 @@ def main(): "--skip-tests", action="store_true", help="Skip running 'make test' even if tests are normally enabled." ) + parser.add_argument( + "--skip-validation", action="store_true", + help="Skip inventory validation before deployment." + ) parser.add_argument( "-v", "--verbose", action="count", default=0, help="Increase verbosity level. Multiple -v flags increase detail (e.g., -vvv for maximum log output)." @@ -101,6 +106,17 @@ def main(): args = parser.parse_args() + if not args.skip_validation: + print("\n🔍 Validating inventory before deployment...\n") + try: + subprocess.run( + [sys.executable, os.path.join(script_dir, "validate_inventory.py"), os.path.dirname(args.inventory)], + check=True + ) + except subprocess.CalledProcessError: + print("\n❌ Inventory validation failed. Deployment aborted.\n", file=sys.stderr) + sys.exit(1) + modes = { "mode_reset": args.reset, "mode_test": args.test, diff --git a/cli/verify_inventory.py b/cli/validate_inventory.py similarity index 66% rename from cli/verify_inventory.py rename to cli/validate_inventory.py index 1723678c..937429b0 100644 --- a/cli/verify_inventory.py +++ b/cli/validate_inventory.py @@ -46,6 +46,22 @@ def compare_application_keys(applications, defaults, source_file): return errors +def compare_user_keys(users, default_users, source_file): + errors = [] + for username, user_conf in users.items(): + if username not in default_users: + print(f"Warning: {source_file}: Unknown user '{username}' (not in default_users)", file=sys.stderr) + continue + + default_conf = default_users.get(username, {}) + for key in user_conf: + if key in ("password", "credentials", "mailu_token"): + continue # ignore credentials/password + if key not in default_conf: + raise Exception(f"{source_file}: Missing default for user '{username}': key '{key}'") + return errors + + def load_inventory_files(inventory_dir): all_data = {} inventory_path = Path(inventory_dir) @@ -69,32 +85,51 @@ def load_inventory_files(inventory_dir): return all_data -def find_defaults_applications_file(): - candidates = list(Path("group_vars/all").glob("*_applications.yml")) +def find_single_file(pattern): + candidates = list(Path("group_vars/all").glob(pattern)) if len(candidates) != 1: - raise RuntimeError(f"Expected exactly one *_applications.yml file in group_vars/all, found {len(candidates)}") + raise RuntimeError(f"Expected exactly one {pattern} file in group_vars/all, found {len(candidates)}") return candidates[0] def main(): - parser = argparse.ArgumentParser(description="Verify application variable consistency with defaults.") + parser = argparse.ArgumentParser(description="Verify application and user variable consistency with defaults.") parser.add_argument("inventory_dir", help="Path to inventory directory (contains inventory.yml and *_vars/)") args = parser.parse_args() - defaults_path = find_defaults_applications_file() + defaults_path = find_single_file("*_applications.yml") + users_path = find_single_file("*users.yml") + defaults_data = load_yaml_file(defaults_path) + default_users_data = load_yaml_file(users_path) + defaults = defaults_data.get("defaults_applications", {}) if defaults_data else {} + default_users = default_users_data.get("default_users", {}) if default_users_data else {} if not defaults: print(f"Error: No 'defaults_applications' found in {defaults_path}.", file=sys.stderr) sys.exit(1) + if not default_users: + print(f"Error: No 'default_users' found in {users_path}.", file=sys.stderr) + sys.exit(1) all_errors = [] + inventory_files = load_inventory_files(args.inventory_dir) for source_path, app_data in inventory_files.items(): errors = compare_application_keys(app_data, defaults, str(source_path)) all_errors.extend(errors) + # Load all users.yml files from inventory + for path in Path(args.inventory_dir).rglob("*.yml"): + data = load_yaml_file(path) + if isinstance(data, dict) and "users" in data: + try: + compare_user_keys(data["users"], default_users, str(path)) + except Exception as e: + print(e, file=sys.stderr) + sys.exit(1) + if all_errors: print("Validation failed with the following issues:") for err in all_errors: diff --git a/tests/integration/test_check_init_files.py b/tests/integration/test_check_init_files.py new file mode 100644 index 00000000..0352ecda --- /dev/null +++ b/tests/integration/test_check_init_files.py @@ -0,0 +1,21 @@ +import unittest +from pathlib import Path + +class TestInitFiles(unittest.TestCase): + def test_all_test_dirs_have_init(self): + """ + Ensure every subdirectory in the 'tests' folder (excluding '__pycache__') contains an '__init__.py' file. + """ + tests_root = Path(__file__).resolve().parents[2] / "tests" + + for path in tests_root.rglob("*"): + if path.is_dir() and "__pycache__" not in path.parts: + init_file = path / "__init__.py" + with self.subTest(directory=str(path.relative_to(tests_root))): + self.assertTrue( + init_file.exists(), + f"Missing __init__.py in directory: {path}" + ) + +if __name__ == "__main__": + unittest.main() diff --git a/tests/unit/cli/__init__.py b/tests/unit/cli/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/test_create_credentials.py b/tests/unit/cli/test_create_credentials.py similarity index 98% rename from tests/unit/test_create_credentials.py rename to tests/unit/cli/test_create_credentials.py index e7e37ca8..f5b1e556 100644 --- a/tests/unit/test_create_credentials.py +++ b/tests/unit/cli/test_create_credentials.py @@ -5,7 +5,7 @@ from unittest import mock # Ensure cli module is importable dir_path = os.path.abspath( - os.path.join(os.path.dirname(__file__), '../../cli') + os.path.join(os.path.dirname(__file__), '../../../cli') ) sys.path.insert(0, dir_path) diff --git a/tests/unit/test_generate_applications_defaults_users.py b/tests/unit/cli/test_generate_applications_defaults_users.py similarity index 97% rename from tests/unit/test_generate_applications_defaults_users.py rename to tests/unit/cli/test_generate_applications_defaults_users.py index 47beec6d..20f8a93d 100644 --- a/tests/unit/test_generate_applications_defaults_users.py +++ b/tests/unit/cli/test_generate_applications_defaults_users.py @@ -43,7 +43,7 @@ class TestGenerateDefaultApplicationsUsers(unittest.TestCase): When a users.yml exists with defined users, the script should inject a 'users' mapping in the generated YAML, mapping each username to a Jinja2 reference. """ - script_path = Path(__file__).resolve().parents[2] / "cli" / "generate_applications.py" + script_path = Path(__file__).resolve().parents[3] / "cli" / "generate_applications.py" result = subprocess.run([ "python3", str(script_path), "--roles-dir", str(self.roles_dir), diff --git a/tests/unit/test_generate_default_applications.py b/tests/unit/cli/test_generate_default_applications.py similarity index 97% rename from tests/unit/test_generate_default_applications.py rename to tests/unit/cli/test_generate_default_applications.py index fe511778..5683952c 100644 --- a/tests/unit/test_generate_default_applications.py +++ b/tests/unit/cli/test_generate_default_applications.py @@ -29,7 +29,7 @@ class TestGenerateDefaultApplications(unittest.TestCase): shutil.rmtree(self.temp_dir) def test_script_generates_expected_yaml(self): - script_path = Path(__file__).resolve().parent.parent.parent / "cli" / "generate_applications.py" + script_path = Path(__file__).resolve().parent.parent.parent.parent / "cli" / "generate_applications.py" result = subprocess.run( [ diff --git a/tests/unit/test_generate_playbook.py b/tests/unit/cli/test_generate_playbook.py similarity index 98% rename from tests/unit/test_generate_playbook.py rename to tests/unit/cli/test_generate_playbook.py index 03d52539..8f4bfb2f 100644 --- a/tests/unit/test_generate_playbook.py +++ b/tests/unit/cli/test_generate_playbook.py @@ -7,7 +7,7 @@ import shutil import yaml # Adjust path to include cli/ folder -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../..", "cli"))) +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../..", "cli"))) from generate_playbook import build_dependency_graph, topological_sort, generate_playbook_entries diff --git a/tests/unit/test_generate_users.py b/tests/unit/cli/test_generate_users.py similarity index 99% rename from tests/unit/test_generate_users.py rename to tests/unit/cli/test_generate_users.py index e5ec9b2f..80cb4794 100644 --- a/tests/unit/test_generate_users.py +++ b/tests/unit/cli/test_generate_users.py @@ -7,7 +7,7 @@ import yaml from collections import OrderedDict # Add cli/ to import path -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../..", "cli"))) +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../..", "cli"))) import generate_users diff --git a/tests/unit/test_inventory_manager.py b/tests/unit/cli/test_inventory_manager.py similarity index 98% rename from tests/unit/test_inventory_manager.py rename to tests/unit/cli/test_inventory_manager.py index 0a12806e..162ca3c0 100644 --- a/tests/unit/test_inventory_manager.py +++ b/tests/unit/cli/test_inventory_manager.py @@ -10,7 +10,7 @@ from unittest.mock import patch sys.path.insert( 0, os.path.abspath( - os.path.join(os.path.dirname(__file__), "../../cli") + os.path.join(os.path.dirname(__file__), "../../../cli") ), ) diff --git a/tests/unit/cli/test_validate_inventory.py b/tests/unit/cli/test_validate_inventory.py new file mode 100644 index 00000000..192370fa --- /dev/null +++ b/tests/unit/cli/test_validate_inventory.py @@ -0,0 +1,134 @@ +import unittest +import tempfile +import shutil +import os +from pathlib import Path +import subprocess +import sys +import yaml + +SCRIPT_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../cli/validate_inventory.py")) + +class TestValidateInventory(unittest.TestCase): + def setUp(self): + self.temp_dir = tempfile.mkdtemp() + self.group_vars_all = Path(self.temp_dir) / "group_vars" / "all" + self.group_vars_all.mkdir(parents=True) + + self.inventory_dir = Path(self.temp_dir) / "inventory" + self.inventory_dir.mkdir() + + # Create default applications file + self.default_applications = { + "defaults_applications": { + "app1": { + "port": 8080, + "enabled": True, + "settings": { + "theme": "dark" + } + } + } + } + (self.group_vars_all / "01_applications.yml").write_text( + yaml.dump(self.default_applications), encoding="utf-8" + ) + + # Create default users file + self.default_users = { + "default_users": { + "alice": { + "email": "alice@example.com", + "role": "admin" + } + } + } + (self.group_vars_all / "01_users.yml").write_text( + yaml.dump(self.default_users), encoding="utf-8" + ) + + def tearDown(self): + shutil.rmtree(self.temp_dir) + + def run_script(self, expected_code=0): + result = subprocess.run( + [sys.executable, SCRIPT_PATH, str(self.inventory_dir)], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + encoding="utf-8", + cwd=self.temp_dir + ) + if result.returncode != expected_code: + print("STDOUT:", result.stdout) + print("STDERR:", result.stderr) + return result + + def test_valid_inventory(self): + (self.inventory_dir / "group_vars.yml").write_text(yaml.dump({ + "applications": { + "app1": { + "port": 8080, + "enabled": True, + "settings": { + "theme": "dark" + } + } + }, + "users": { + "alice": { + "email": "alice@example.com", + "role": "admin", + "password": "secret" + } + } + }), encoding="utf-8") + + result = self.run_script(expected_code=0) + self.assertIn("Inventory directory is valid against defaults", result.stdout) + + def test_unknown_user_warning(self): + (self.inventory_dir / "invalid_users.yml").write_text(yaml.dump({ + "users": { + "bob": { + "email": "bob@example.com", + "role": "user" + } + } + }), encoding="utf-8") + + result = self.run_script(expected_code=0) + self.assertIn("Warning", result.stderr) + + def test_missing_user_key_fails(self): + (self.inventory_dir / "invalid_key.yml").write_text(yaml.dump({ + "users": { + "alice": { + "email": "alice@example.com", + "role": "admin", + "extra": "unexpected" + } + } + }), encoding="utf-8") + + result = self.run_script(expected_code=1) + self.assertIn("Missing default for user 'alice': key 'extra'", result.stderr) + + def test_missing_application_key_fails(self): + (self.inventory_dir / "missing_key.yml").write_text(yaml.dump({ + "applications": { + "app1": { + "port": 8080, + "enabled": True, + "settings": { + "theme": "dark" + }, + "extra_setting": True + } + } + }), encoding="utf-8") + + result = self.run_script(expected_code=1) + self.assertIn("Missing default for app1: extra_setting", result.stdout) + +if __name__ == "__main__": + unittest.main() diff --git a/tests/unit/filter_plugins/__init__.py b/tests/unit/filter_plugins/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/test_applications_if_group_and_deps.py b/tests/unit/filter_plugins/test_applications_if_group_and_deps.py similarity index 97% rename from tests/unit/test_applications_if_group_and_deps.py rename to tests/unit/filter_plugins/test_applications_if_group_and_deps.py index 7f617b52..6a3f039a 100644 --- a/tests/unit/test_applications_if_group_and_deps.py +++ b/tests/unit/filter_plugins/test_applications_if_group_and_deps.py @@ -6,7 +6,7 @@ from ansible.errors import AnsibleFilterError # ensure filter_plugins is on the path dir_path = os.path.abspath( - os.path.join(os.path.dirname(__file__), '../../filter_plugins') + os.path.join(os.path.dirname(__file__), '../../../filter_plugins') ) sys.path.insert(0, dir_path) diff --git a/tests/unit/test_bridge_filters.py b/tests/unit/filter_plugins/test_bridge_filters.py similarity index 96% rename from tests/unit/test_bridge_filters.py rename to tests/unit/filter_plugins/test_bridge_filters.py index 2a882fdb..074794d1 100644 --- a/tests/unit/test_bridge_filters.py +++ b/tests/unit/filter_plugins/test_bridge_filters.py @@ -6,7 +6,7 @@ import unittest sys.path.insert( 0, os.path.abspath( - os.path.join(os.path.dirname(__file__), "../../roles/docker-matrix") + os.path.join(os.path.dirname(__file__), "../../../roles/docker-matrix") ), ) diff --git a/tests/unit/test_configuration_filters.py b/tests/unit/filter_plugins/test_configuration_filters.py similarity index 94% rename from tests/unit/test_configuration_filters.py rename to tests/unit/filter_plugins/test_configuration_filters.py index 08aaf76b..f813285c 100644 --- a/tests/unit/test_configuration_filters.py +++ b/tests/unit/filter_plugins/test_configuration_filters.py @@ -7,7 +7,7 @@ import os sys.path.insert( 0, os.path.abspath( - os.path.join(os.path.dirname(__file__), "../../") + os.path.join(os.path.dirname(__file__), "../../../") ), ) diff --git a/tests/unit/test_csp_filters.py b/tests/unit/filter_plugins/test_csp_filters.py similarity index 99% rename from tests/unit/test_csp_filters.py rename to tests/unit/filter_plugins/test_csp_filters.py index a12cf787..e4165302 100644 --- a/tests/unit/test_csp_filters.py +++ b/tests/unit/filter_plugins/test_csp_filters.py @@ -7,7 +7,7 @@ import os sys.path.insert( 0, os.path.abspath( - os.path.join(os.path.dirname(__file__), "../../") + os.path.join(os.path.dirname(__file__), "../../../") ), ) diff --git a/tests/unit/test_docker_image.py b/tests/unit/filter_plugins/test_docker_image.py similarity index 98% rename from tests/unit/test_docker_image.py rename to tests/unit/filter_plugins/test_docker_image.py index 44e34c20..2f6fa038 100644 --- a/tests/unit/test_docker_image.py +++ b/tests/unit/filter_plugins/test_docker_image.py @@ -5,7 +5,7 @@ import sys import unittest # Add filter_plugins/ to the import path -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../..", "filter_plugins"))) +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../..", "filter_plugins"))) from docker_image import FilterModule diff --git a/tests/unit/test_domain_filters_alias.py b/tests/unit/filter_plugins/test_domain_filters_alias.py similarity index 97% rename from tests/unit/test_domain_filters_alias.py rename to tests/unit/filter_plugins/test_domain_filters_alias.py index 75b18ad2..d4948c50 100644 --- a/tests/unit/test_domain_filters_alias.py +++ b/tests/unit/filter_plugins/test_domain_filters_alias.py @@ -4,7 +4,7 @@ import unittest # Add the filter_plugins directory to the import path dir_path = os.path.abspath( - os.path.join(os.path.dirname(__file__), '../../filter_plugins') + os.path.join(os.path.dirname(__file__), '../../../filter_plugins') ) sys.path.insert(0, dir_path) diff --git a/tests/unit/test_domain_filters_all_domains.py b/tests/unit/filter_plugins/test_domain_filters_all_domains.py similarity index 98% rename from tests/unit/test_domain_filters_all_domains.py rename to tests/unit/filter_plugins/test_domain_filters_all_domains.py index d8b5a984..4ced3904 100644 --- a/tests/unit/test_domain_filters_all_domains.py +++ b/tests/unit/filter_plugins/test_domain_filters_all_domains.py @@ -5,7 +5,7 @@ import os # Ensure filter_plugins directory is on the path sys.path.insert( 0, - os.path.abspath(os.path.join(os.path.dirname(__file__), '../../filter_plugins')) + os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../filter_plugins')) ) from generate_all_domains import FilterModule diff --git a/tests/unit/test_domain_filters_base_sld_domains.py b/tests/unit/filter_plugins/test_domain_filters_base_sld_domains.py similarity index 99% rename from tests/unit/test_domain_filters_base_sld_domains.py rename to tests/unit/filter_plugins/test_domain_filters_base_sld_domains.py index 44d5e010..d4fa7a6a 100644 --- a/tests/unit/test_domain_filters_base_sld_domains.py +++ b/tests/unit/filter_plugins/test_domain_filters_base_sld_domains.py @@ -5,7 +5,7 @@ import os # Ensure filter_plugins directory is on the path sys.path.insert( 0, - os.path.abspath(os.path.join(os.path.dirname(__file__), '../filter_plugins')) + os.path.abspath(os.path.join(os.path.dirname(__file__), '../../filter_plugins')) ) from generate_base_sld_domains import FilterModule diff --git a/tests/unit/test_domain_filters_canonical.py b/tests/unit/filter_plugins/test_domain_filters_canonical.py similarity index 97% rename from tests/unit/test_domain_filters_canonical.py rename to tests/unit/filter_plugins/test_domain_filters_canonical.py index f25eed83..a7953a69 100644 --- a/tests/unit/test_domain_filters_canonical.py +++ b/tests/unit/filter_plugins/test_domain_filters_canonical.py @@ -4,7 +4,7 @@ import unittest # Add the filter_plugins directory to the import path dir_path = os.path.abspath( - os.path.join(os.path.dirname(__file__), '../../filter_plugins') + os.path.join(os.path.dirname(__file__), '../../../filter_plugins') ) sys.path.insert(0, dir_path) diff --git a/tests/unit/test_domain_mappings.py b/tests/unit/filter_plugins/test_domain_mappings.py similarity index 97% rename from tests/unit/test_domain_mappings.py rename to tests/unit/filter_plugins/test_domain_mappings.py index 5ab22cdf..61e18d85 100644 --- a/tests/unit/test_domain_mappings.py +++ b/tests/unit/filter_plugins/test_domain_mappings.py @@ -4,7 +4,7 @@ import unittest # Add the filter_plugins directory to the import path dir_path = os.path.abspath( - os.path.join(os.path.dirname(__file__), '../../filter_plugins') + os.path.join(os.path.dirname(__file__), '../../../filter_plugins') ) sys.path.insert(0, dir_path) diff --git a/tests/unit/test_get_domain_filter.py b/tests/unit/filter_plugins/test_get_domain_filter.py similarity index 96% rename from tests/unit/test_get_domain_filter.py rename to tests/unit/filter_plugins/test_get_domain_filter.py index e3625399..ed635a1e 100644 --- a/tests/unit/test_get_domain_filter.py +++ b/tests/unit/filter_plugins/test_get_domain_filter.py @@ -7,7 +7,7 @@ import os sys.path.insert( 0, os.path.abspath( - os.path.join(os.path.dirname(__file__), '../../filter_plugins') + os.path.join(os.path.dirname(__file__), '../../../filter_plugins') ) ) diff --git a/tests/unit/test_load_configuration.py b/tests/unit/filter_plugins/test_load_configuration.py similarity index 99% rename from tests/unit/test_load_configuration.py rename to tests/unit/filter_plugins/test_load_configuration.py index fcb9258c..ada0045d 100644 --- a/tests/unit/test_load_configuration.py +++ b/tests/unit/filter_plugins/test_load_configuration.py @@ -5,7 +5,7 @@ from unittest.mock import patch, mock_open from ansible.errors import AnsibleFilterError # make sure our plugin is on PYTHONPATH -root = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../filter_plugins')) +root = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../filter_plugins')) sys.path.insert(0, root) import load_configuration diff --git a/tests/unit/test_merge_mapping.py b/tests/unit/filter_plugins/test_merge_mapping.py similarity index 100% rename from tests/unit/test_merge_mapping.py rename to tests/unit/filter_plugins/test_merge_mapping.py diff --git a/tests/unit/test_redirect_filters.py b/tests/unit/filter_plugins/test_redirect_filters.py similarity index 96% rename from tests/unit/test_redirect_filters.py rename to tests/unit/filter_plugins/test_redirect_filters.py index aa87fbd1..c1327b6e 100644 --- a/tests/unit/test_redirect_filters.py +++ b/tests/unit/filter_plugins/test_redirect_filters.py @@ -5,7 +5,7 @@ import unittest sys.path.insert( 0, os.path.abspath( - os.path.join(os.path.dirname(__file__), "../../") + os.path.join(os.path.dirname(__file__), "../../../") ), ) diff --git a/tests/unit/test_safe_join.py b/tests/unit/filter_plugins/test_safe_join.py similarity index 98% rename from tests/unit/test_safe_join.py rename to tests/unit/filter_plugins/test_safe_join.py index 1d3fd75f..5486e486 100644 --- a/tests/unit/test_safe_join.py +++ b/tests/unit/filter_plugins/test_safe_join.py @@ -5,7 +5,7 @@ import os # Ensure filter_plugins directory is on the path sys.path.insert( 0, - os.path.abspath(os.path.join(os.path.dirname(__file__), '../../filter_plugins')) + os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../filter_plugins')) ) from safe_join import safe_join diff --git a/tests/unit/test_safe_placeholders_filter.py b/tests/unit/filter_plugins/test_safe_placeholders_filter.py similarity index 98% rename from tests/unit/test_safe_placeholders_filter.py rename to tests/unit/filter_plugins/test_safe_placeholders_filter.py index 4150e485..227fa94b 100644 --- a/tests/unit/test_safe_placeholders_filter.py +++ b/tests/unit/filter_plugins/test_safe_placeholders_filter.py @@ -5,7 +5,7 @@ import os # Ensure filter_plugins directory is on the path sys.path.insert( 0, - os.path.abspath(os.path.join(os.path.dirname(__file__), '../../filter_plugins')) + os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../filter_plugins')) ) from safe import safe_placeholders diff --git a/tests/unit/test_safe_var.py b/tests/unit/filter_plugins/test_safe_var.py similarity index 98% rename from tests/unit/test_safe_var.py rename to tests/unit/filter_plugins/test_safe_var.py index 8564b19b..24c5c716 100644 --- a/tests/unit/test_safe_var.py +++ b/tests/unit/filter_plugins/test_safe_var.py @@ -6,7 +6,7 @@ from jinja2 import Undefined # Ensure filter_plugins directory is on the path sys.path.insert( 0, - os.path.abspath(os.path.join(os.path.dirname(__file__), '../../filter_plugins')) + os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../filter_plugins')) ) from safe import FilterModule diff --git a/tests/unit/lookup_plugins/__init__.py b/tests/unit/lookup_plugins/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/test_application_gid.py b/tests/unit/lookup_plugins/test_application_gid.py similarity index 96% rename from tests/unit/test_application_gid.py rename to tests/unit/lookup_plugins/test_application_gid.py index 532b4efe..f7aa8980 100644 --- a/tests/unit/test_application_gid.py +++ b/tests/unit/lookup_plugins/test_application_gid.py @@ -6,7 +6,7 @@ import unittest import yaml dir_path = os.path.abspath( - os.path.join(os.path.dirname(__file__), '../../lookup_plugins') + os.path.join(os.path.dirname(__file__), '../../../lookup_plugins') ) sys.path.insert(0, dir_path) diff --git a/tests/unit/test_docker_cards.py b/tests/unit/lookup_plugins/test_docker_cards.py similarity index 98% rename from tests/unit/test_docker_cards.py rename to tests/unit/lookup_plugins/test_docker_cards.py index c54878a7..c42c7ff2 100644 --- a/tests/unit/test_docker_cards.py +++ b/tests/unit/lookup_plugins/test_docker_cards.py @@ -5,7 +5,7 @@ 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')) +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../../roles/docker-portfolio/lookup_plugins')) from docker_cards import LookupModule diff --git a/tests/unit/module_utils/__init__.py b/tests/unit/module_utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/test_cert_utils.py b/tests/unit/module_utils/test_cert_utils.py similarity index 88% rename from tests/unit/test_cert_utils.py rename to tests/unit/module_utils/test_cert_utils.py index 367a355d..ccdcdf24 100644 --- a/tests/unit/test_cert_utils.py +++ b/tests/unit/module_utils/test_cert_utils.py @@ -4,17 +4,10 @@ import os import sys import unittest -# Add module_utils/ to the import path -sys.path.insert( - 0, - os.path.abspath( - os.path.join( - os.path.dirname(__file__), - "../../..", - "module_utils", - ) - ), -) +# Add the project root/module_utils to the import path +CURRENT_DIR = os.path.dirname(__file__) +PROJECT_ROOT = os.path.abspath(os.path.join(CURRENT_DIR, "../../..")) +sys.path.insert(0, PROJECT_ROOT) from module_utils.cert_utils import CertUtils diff --git a/tests/unit/roles/__init__.py b/tests/unit/roles/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/roles/system-storage-optimizer/__init__.py b/tests/unit/roles/system-storage-optimizer/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/test_storage_optimizer.py b/tests/unit/roles/system-storage-optimizer/test_storage_optimizer.py similarity index 95% rename from tests/unit/test_storage_optimizer.py rename to tests/unit/roles/system-storage-optimizer/test_storage_optimizer.py index 863a58d6..33b0c58a 100644 --- a/tests/unit/test_storage_optimizer.py +++ b/tests/unit/roles/system-storage-optimizer/test_storage_optimizer.py @@ -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', 'system-storage-optimizer', 'files', 'system-storage-optimizer.py' )) spec = importlib.util.spec_from_file_location('storage_optimizer', module_path) optimizer = importlib.util.module_from_spec(spec)