mirror of
				https://github.com/kevinveenbirkenbach/computer-playbook.git
				synced 2025-10-31 10:19:09 +00:00 
			
		
		
		
	Reorgenized test structure and added validation of inventory before deployment
This commit is contained in:
		| @@ -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, | ||||
|   | ||||
| @@ -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: | ||||
							
								
								
									
										21
									
								
								tests/integration/test_check_init_files.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								tests/integration/test_check_init_files.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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() | ||||
							
								
								
									
										0
									
								
								tests/unit/cli/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/unit/cli/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||
| 
 | ||||
| @@ -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), | ||||
| @@ -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( | ||||
|             [ | ||||
| @@ -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 | ||||
| 
 | ||||
| @@ -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 | ||||
| 
 | ||||
| @@ -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") | ||||
|     ), | ||||
| ) | ||||
| 
 | ||||
							
								
								
									
										134
									
								
								tests/unit/cli/test_validate_inventory.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								tests/unit/cli/test_validate_inventory.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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() | ||||
							
								
								
									
										0
									
								
								tests/unit/filter_plugins/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/unit/filter_plugins/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||
| 
 | ||||
| @@ -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") | ||||
|     ), | ||||
| ) | ||||
| 
 | ||||
| @@ -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__), "../../../") | ||||
|     ), | ||||
| ) | ||||
| 
 | ||||
| @@ -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__), "../../../") | ||||
|     ), | ||||
| ) | ||||
| 
 | ||||
| @@ -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 | ||||
| 
 | ||||
| @@ -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) | ||||
| 
 | ||||
| @@ -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 | ||||
| @@ -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 | ||||
| @@ -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) | ||||
| 
 | ||||
| @@ -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) | ||||
| 
 | ||||
| @@ -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') | ||||
|     ) | ||||
| ) | ||||
| 
 | ||||
| @@ -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 | ||||
| @@ -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__), "../../../") | ||||
|     ), | ||||
| ) | ||||
| 
 | ||||
| @@ -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 | ||||
| @@ -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 | ||||
| @@ -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 | ||||
							
								
								
									
										0
									
								
								tests/unit/lookup_plugins/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/unit/lookup_plugins/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||
| 
 | ||||
| @@ -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 | ||||
| 
 | ||||
							
								
								
									
										0
									
								
								tests/unit/module_utils/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/unit/module_utils/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| 
 | ||||
							
								
								
									
										0
									
								
								tests/unit/roles/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/unit/roles/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||
		Reference in New Issue
	
	Block a user