From 0d853abbc3a044d8ad26c540ce17a3932f8a25c9 Mon Sep 17 00:00:00 2001 From: git_admin Date: Mon, 27 Apr 2026 08:45:21 +0000 Subject: [PATCH] Tower: upload cetmix_tower_yaml 16.0.2.0.3 (via marketplace) --- .../cetmix_tower_yaml/tests/test_command.py | 347 ++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 addons/cetmix_tower_yaml/tests/test_command.py diff --git a/addons/cetmix_tower_yaml/tests/test_command.py b/addons/cetmix_tower_yaml/tests/test_command.py new file mode 100644 index 0000000..bb4257f --- /dev/null +++ b/addons/cetmix_tower_yaml/tests/test_command.py @@ -0,0 +1,347 @@ +# Copyright (C) 2024 Cetmix OÜ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import yaml + +from odoo.exceptions import ValidationError +from odoo.tests import TransactionCase + + +class TestTowerCommand(TransactionCase): + @classmethod + def setUpClass(cls, *args, **kwargs): + super().setUpClass(*args, **kwargs) + + cls.Command = cls.env["cx.tower.command"] + + # Expected YAML content of the test command + cls.command_test_yaml = """cetmix_tower_model: command +access_level: manager +reference: test_yaml_in_tests +name: Test YAML +action: ssh_command +allow_parallel_run: false +note: |- + Test YAML command conversion. + Ensure all fields are rendered properly. +os_ids: false +tag_ids: false +path: false +file_template_id: false +flight_plan_id: false +code: |- + cd /home/{{ tower.server.ssh_username }} \\ + && ls -lha +server_status: false +variable_ids: false +secret_ids: false +no_split_for_sudo: false +if_file_exists: skip +disconnect_file: false +""" + + # YAML content translated into Python dict + cls.command_test_yaml_dict = yaml.safe_load(cls.command_test_yaml) + + def test_yaml_from_command(self): + """Test if YAML is generated properly from a command""" + + # -- 0 -- + # Create test command + # Test command + command_test = self.Command.create( + { + "name": "Test YAML", + "reference": "test_yaml_in_tests", + "action": "ssh_command", + "code": """cd /home/{{ tower.server.ssh_username }} \\ +&& ls -lha""", + "note": """Test YAML command conversion. +Ensure all fields are rendered properly.""", + } + ) + + # -- 1 -- + # Check it YAML generated by the command matches + # YAML from the template file + self.assertEqual( + command_test.yaml_code, + self.command_test_yaml, + "YAML generated from command doesn't match template file one", + ) + + # -- 2 -- + # Check if YAML key values match Cetmix Tower ones + + self.assertEqual( + command_test.access_level, + self.Command.TO_TOWER_ACCESS_LEVEL[ + self.command_test_yaml_dict["access_level"] + ], + "YAML value doesn't match Cetmix Tower one", + ) + self.assertEqual( + command_test.action, + self.command_test_yaml_dict["action"], + "YAML value doesn't match Cetmix Tower one", + ) + self.assertEqual( + command_test.allow_parallel_run, + self.command_test_yaml_dict["allow_parallel_run"], + "YAML value doesn't match Cetmix Tower one", + ) + self.assertEqual( + command_test.code, + self.command_test_yaml_dict["code"], + "YAML value doesn't match Cetmix Tower one", + ) + self.assertEqual( + command_test.name, + self.command_test_yaml_dict["name"], + "YAML value doesn't match Cetmix Tower one", + ) + self.assertEqual( + command_test.note, + self.command_test_yaml_dict["note"], + "YAML value doesn't match Cetmix Tower one", + ) + self.assertEqual( + command_test.path, + self.command_test_yaml_dict["path"], + "YAML value doesn't match Cetmix Tower one", + ) + self.assertEqual( + command_test.reference, + self.command_test_yaml_dict["reference"], + "YAML value doesn't match Cetmix Tower one", + ) + self.assertEqual( + command_test.if_file_exists, + self.command_test_yaml_dict["if_file_exists"], + "YAML value doesn't match Cetmix Tower one", + ) + self.assertEqual( + command_test.disconnect_file, + self.command_test_yaml_dict["disconnect_file"], + "YAML value doesn't match Cetmix Tower one", + ) + + def test_command_from_yaml(self): + """Test if YAML is generated properly from a command""" + + def test_yaml(command): + """Checks if yaml values are inserted correctly + + Args: + command(cx.tower.command): _description_ + """ + self.assertEqual( + command.access_level, + self.Command.TO_TOWER_ACCESS_LEVEL[ + self.command_test_yaml_dict["access_level"] + ], + "YAML value doesn't match Cetmix Tower one", + ) + self.assertEqual( + command.action, + self.command_test_yaml_dict["action"], + "YAML value doesn't match Cetmix Tower one", + ) + self.assertEqual( + command.allow_parallel_run, + self.command_test_yaml_dict["allow_parallel_run"], + "YAML value doesn't match Cetmix Tower one", + ) + self.assertEqual( + command.code, + self.command_test_yaml_dict["code"], + "YAML value doesn't match Cetmix Tower one", + ) + self.assertEqual( + command.name, + self.command_test_yaml_dict["name"], + "YAML value doesn't match Cetmix Tower one", + ) + self.assertEqual( + command.note, + self.command_test_yaml_dict["note"], + "YAML value doesn't match Cetmix Tower one", + ) + self.assertEqual( + command.path, + self.command_test_yaml_dict["path"], + "YAML value doesn't match Cetmix Tower one", + ) + self.assertEqual( + command.reference, + self.command_test_yaml_dict["reference"], + "YAML value doesn't match Cetmix Tower one", + ) + self.assertEqual( + command.if_file_exists, + self.command_test_yaml_dict["if_file_exists"], + "YAML value doesn't match Cetmix Tower one", + ) + self.assertEqual( + command.disconnect_file, + self.command_test_yaml_dict["disconnect_file"], + "YAML value doesn't match Cetmix Tower one", + ) + + # Create test command + command_test = self.Command.create( + {"name": "New Command", "action": "python_code"} + ) + + # -- 1 -- + # Insert YAML into the command and + # check if YAML key values match Cetmix Tower ones + command_test.yaml_code = self.command_test_yaml + test_yaml(command_test) + + # -- 2 -- + # Insert some non supported keys and ensure nothing bad happens + yaml_with_non_supported_keys = """access_level: manager +action: ssh_command +doge: wow +memes: much nice! +allow_parallel_run: false +cetmix_tower_model: command +code: |- + cd /home/{{ tower.server.ssh_username }} \\ + && ls -lha +file_template_id: false +flight_plan_id: false +name: Test YAML +note: |- + Test YAML command conversion. + Ensure all fields are rendered properly. +path: false +reference: test_yaml_in_tests +tag_ids: false +""" + command_test.yaml_code = yaml_with_non_supported_keys + test_yaml(command_test) + + # -- 3 -- + # Insert non existing selection field value and exception is raised + yaml_with_non_supported_keys = """access_level: manager +action: non_existing_action +doge: wow +memes: much nice! +allow_parallel_run: false +cetmix_tower_model: command +code: |- + cd /home/{{ tower.server.ssh_username }} \\ + && ls -lha +file_template_id: false +flight_plan_id: false +name: Test YAML +note: |- + Test YAML command conversion. + Ensure all fields are rendered properly. +path: false +reference: test_yaml_in_tests +tag_ids: false +""" + with self.assertRaises(ValidationError) as e: + command_test.yaml_code = yaml_with_non_supported_keys + self.assertIn("non_existing_action", str(e.exception)) + self.assertEqual( + str(e), + "Wrong value for cx.tower.command.action: 'non_existing_action'", + "Exception message doesn't match", + ) + + def test_command_with_action_file_template(self): + """Test command with 'File from template' action""" + yaml_with_reference = """cetmix_tower_model: command +access_level: manager +reference: such_much_test_command +name: Such Much Command +action: file_using_template +allow_parallel_run: false +note: Just a note +os_ids: false +tag_ids: false +path: false +file_template_id: my_custom_test_template +flight_plan_id: false +code: false +server_status: false +variable_ids: false +secret_ids: false +no_split_for_sudo: false +if_file_exists: skip +disconnect_file: false +""" + # Add file template + file_template = self.env["cx.tower.file.template"].create( + { + "name": "Such much demo", + "reference": "my_custom_test_template", + "file_name": "much_logs.txt", + "server_dir": "/var/log/my/files", + "source": "tower", + "file_type": "text", + "note": "Hey!", + "keep_when_deleted": False, + } + ) + command_with_template = self.Command.create( + { + "name": "Such Much Command", + "reference": "such_much_test_command", + "action": "file_using_template", + "note": "Just a note", + "file_template_id": file_template.id, + } + ) + + # -- 1 -- + # Check if final YAML composed correctly + self.assertEqual( + command_with_template.yaml_code, + yaml_with_reference, + "YAML is not composed correctly", + ) + + # -- 2 -- + # Explode related record and check the YAML + yaml_with_reference_exploded = """cetmix_tower_model: command +access_level: manager +reference: such_much_test_command +name: Such Much Command +action: file_using_template +allow_parallel_run: false +note: Just a note +os_ids: false +tag_ids: false +path: false +file_template_id: + reference: my_custom_test_template + name: Such much demo + source: tower + file_type: text + server_dir: /var/log/my/files + file_name: much_logs.txt + keep_when_deleted: false + tag_ids: false + note: Hey! + code: false + variable_ids: false + secret_ids: false +flight_plan_id: false +code: false +server_status: false +variable_ids: false +secret_ids: false +no_split_for_sudo: false +if_file_exists: skip +disconnect_file: false +""" + command_with_template.invalidate_recordset(["yaml_code"]) + self.assertEqual( + command_with_template.with_context(explode_related_record=True).yaml_code, + yaml_with_reference_exploded, + "YAML is not composed correctly", + )