From d42a220d769ff8078321df86357a2d7c1b57e39c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=93=D0=B0=D0=B1=D0=B8=D0=B4=D1=83=D0=BB=D0=BB=D0=B8=D0=BD?= Date: Thu, 29 Jan 2026 22:21:50 +0400 Subject: [PATCH] 2 --- tests/unit/plugins/modules/test_logrotate.py | 78 ++++++++++++++------ 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/tests/unit/plugins/modules/test_logrotate.py b/tests/unit/plugins/modules/test_logrotate.py index 080a1d7a0e..48ccf49a80 100644 --- a/tests/unit/plugins/modules/test_logrotate.py +++ b/tests/unit/plugins/modules/test_logrotate.py @@ -410,27 +410,58 @@ class TestLogrotateConfig(unittest.TestCase): """Test error when logrotate is not installed.""" from ansible_collections.community.general.plugins.modules import logrotate - self._setup_module_params() - # Создаем новый mock модуль с get_bin_path возвращающим None - mock_module_for_main = Mock() - mock_module_for_main.params = self.mock_module.params.copy() - mock_module_for_main.fail_json = Mock(side_effect=Exception("fail_json called")) - mock_module_for_main.exit_json = Mock() - mock_module_for_main.check_mode = False - mock_module_for_main.get_bin_path = Mock(return_value=None) # logrotate не установлен - mock_module_for_main.atomic_move = Mock() - mock_module_for_main.warn = Mock() - mock_module_for_main.run_command = Mock(return_value=(0, "", "")) + # Создаем специальный mock для модуля, который будет использовать side_effect + # для get_bin_path, чтобы имитировать поведение при required=True + mock_module_for_test = Mock() + mock_module_for_test.params = { + "name": "test", + "state": "present", + "config_dir": self.config_dir, + "paths": ["/var/log/test/*.log"], + "rotate_count": 7, + "compress": True, + "compression_method": "gzip", + "delaycompress": False, + "missingok": True, + "ifempty": False, + "notifempty": True, + "copytruncate": False, + "dateext": False, + "dateformat": "-%Y%m%d", + "sharedscripts": False, + "enabled": True, + } + mock_module_for_test.fail_json = Mock(side_effect=Exception("fail_json called")) + mock_module_for_test.exit_json = Mock() + mock_module_for_test.check_mode = False - # Патчим AnsibleModule чтобы возвращал наш mock - original_AnsibleModule = logrotate.AnsibleModule - try: - logrotate.AnsibleModule = Mock(return_value=mock_module_for_main) + # Определяем side_effect для get_bin_path + def get_bin_path_side_effect(name, required=False): + if name == "logrotate" and required: + # В реальном AnsibleModule.get_bin_path() с required=True + # при отсутствии бинарника вызывается fail_json + mock_module_for_test.fail_json(msg=f"Failed to find required executable '{name}' in PATH") + return None + + mock_module_for_test.get_bin_path = Mock(side_effect=get_bin_path_side_effect) + mock_module_for_test.atomic_move = Mock() + mock_module_for_test.warn = Mock() + mock_module_for_test.run_command = Mock(return_value=(0, "", "")) + + # Заменяем AnsibleModule в модуле logrotate на наш mock + with patch('ansible_collections.community.general.plugins.modules.logrotate.AnsibleModule', + return_value=mock_module_for_test): + # Когда main() будет вызван, AnsibleModule вернет наш mock_module_for_test + # который при вызове get_bin_path("logrotate", required=True) вызовет fail_json with self.assertRaises(Exception) as context: logrotate.main() + + # Проверяем, что была вызвана ошибка self.assertIn("fail_json called", str(context.exception)) - finally: - logrotate.AnsibleModule = original_AnsibleModule + + # Проверяем, что get_bin_path был вызван с правильными параметрами + mock_module_for_test.get_bin_path.assert_called_once_with("logrotate", required=True) + mock_module_for_test.fail_json.assert_called_once() def test_parse_existing_config_paths(self): """Test parsing paths from existing configuration.""" @@ -996,7 +1027,7 @@ class TestLogrotateConfig(unittest.TestCase): with patch("os.makedirs"): with patch("builtins.open", mock_open()): with patch("os.chmod"): - + # Добавляем mock для _backup_config with patch.object(logrotate.LogrotateConfig, '_backup_config', create=True): logrotate_bin = self.mock_module.get_bin_path.return_value config = logrotate.LogrotateConfig(self.mock_module, logrotate_bin) @@ -1013,9 +1044,9 @@ class TestLogrotateConfig(unittest.TestCase): def exists_side_effect(path): if path == self.config_dir: - return True + return True # Директория существует elif path == config_path: - return False + return False # Файл не существует return False with patch("os.path.exists", side_effect=exists_side_effect): @@ -1033,6 +1064,7 @@ class TestLogrotateConfig(unittest.TestCase): self._setup_module_params() + # Mock logrotate binary path test_logrotate_path = "/usr/local/sbin/logrotate" self.mock_module.get_bin_path.return_value = test_logrotate_path @@ -1040,19 +1072,21 @@ class TestLogrotateConfig(unittest.TestCase): def exists_side_effect(path): if path == self.config_dir: - return True + return True # Директория существует elif path == config_path: - return False + return False # Файл не существует return False with patch("os.path.exists", side_effect=exists_side_effect): with patch("os.makedirs"): with patch("builtins.open", mock_open()): with patch("os.chmod"): + # Добавляем mock для _backup_config with patch.object(logrotate.LogrotateConfig, '_backup_config', create=True): config = logrotate.LogrotateConfig(self.mock_module, test_logrotate_path) result = config.apply() + # Check that logrotate binary path is used when running command self.mock_module.run_command.assert_called_once() call_args = self.mock_module.run_command.call_args[0][0] self.assertEqual(call_args[0], test_logrotate_path)