diff --git a/tests/unit_tests/pyanaconda_tests/modules/boss/test_kickstart.py b/tests/unit_tests/pyanaconda_tests/modules/boss/test_kickstart.py index 3ea898d39e6..eb190022da0 100644 --- a/tests/unit_tests/pyanaconda_tests/modules/boss/test_kickstart.py +++ b/tests/unit_tests/pyanaconda_tests/modules/boss/test_kickstart.py @@ -19,11 +19,17 @@ import unittest import os from contextlib import contextmanager -from unittest.mock import Mock +from unittest.mock import Mock, patch + +from pykickstart.constants import KS_SCRIPT_POST, KS_SCRIPT_PREINSTALL from pyanaconda.modules.boss.kickstart_manager import KickstartManager from pyanaconda.modules.boss.module_manager.module_observer import ModuleObserver +from pyanaconda.modules.common.errors.runtime import ScriptError from pyanaconda.modules.common.structures.kickstart import KickstartReport, KickstartMessage +from pyanaconda.modules.runtime.scripts import ScriptsModule +from pyanaconda.modules.runtime.scripts.runtime import RunScriptsTask +from pyanaconda.modules.runtime.scripts.scripts_interface import ScriptsInterface KICKSTART1 = """ text @@ -335,6 +341,136 @@ def test_missing_include_split(self): "[Errno 2] No such file or directory: 'missing_include.cfg'" +class TestScriptsInterface(unittest.TestCase): + + @patch('pyanaconda.modules.common.containers.TaskContainer.to_object_path') + def test_run_scripts_with_task(self, mock_to_object_path): + """Test running scripts through DBus interface.""" + scripts_mock = Mock() + scripts_interface = ScriptsInterface(scripts_mock) + + # Test running post scripts + script_type = KS_SCRIPT_POST + scripts_interface.RunScriptsWithTask(script_type) + + # Ensure that the task for running the scripts is executed + scripts_mock.run_scripts_with_task.assert_called_once_with(script_type) + mock_to_object_path.assert_called_once() + + +class TestScriptsModule(unittest.TestCase): + + def setUp(self): + self.module = ScriptsModule() + + def test_process_kickstart(self): + """Test that process_kickstart stores scripts data.""" + ksdata = Mock() + ksdata.scripts = ["script1", "script2"] + self.module.process_kickstart(ksdata) + + self.assertEqual(self.module._scripts, ["script1", "script2"]) + + def test_setup_kickstart(self): + """Test that setup_kickstart assigns scripts data.""" + ksdata = Mock() + self.module._scripts = ["script1", "script2"] + self.module.setup_kickstart(ksdata) + + self.assertEqual(ksdata.scripts, ["script1", "script2"]) + + +class TestRunScriptsTask(unittest.TestCase): + + def setUp(self): + self.scripts = [ + Mock(type=KS_SCRIPT_POST, run=Mock(return_value=None)), + Mock(type=KS_SCRIPT_POST, run=Mock(return_value=(42, "Error in script"))) + ] + self.task = RunScriptsTask(KS_SCRIPT_POST, self.scripts) + + def test_task_name(self): + """Test the name of the task.""" + self.assertEqual(self.task.name, "Run scripts") + + @patch('pyanaconda.core.util.execWithRedirect') + def test_run_successful_script(self, mock_execWithRedirect): + """Test running scripts successfully.""" + # Adjust test to only have successful scripts + successful_script = [Mock(type=KS_SCRIPT_POST, run=Mock(return_value=None))] + task = RunScriptsTask(KS_SCRIPT_POST, successful_script) + + try: + task.run() + except ScriptError: + self.fail("RunScriptsTask.run() raised ScriptError unexpectedly!") + mock_execWithRedirect.assert_not_called() + + def test_run_failing_script(self): + """Test that a failing script raises ScriptError.""" + with self.assertRaises(ScriptError) as cm: + self.task.run() + + self.assertEqual(str(cm.exception), '42\n\nError in script') + self.scripts[1].run.assert_called_once_with('/mnt/sysroot') + + @patch('pyanaconda.core.util.execWithRedirect') + def test_run_post_script_success(self, mock_execWithRedirect): + """Test running %post scripts successfully.""" + script = Mock() + script.type = KS_SCRIPT_POST + script.run.return_value = None + + task = RunScriptsTask(KS_SCRIPT_POST, [script]) + task.run() + + script.run.assert_called_once_with('/mnt/sysroot') + mock_execWithRedirect.assert_not_called() + + @patch('pyanaconda.core.util.execWithRedirect') + def test_run_preinstall_script_success(self, mock_execWithRedirect): + """Test running %pre-install scripts successfully.""" + script = Mock() + script.type = KS_SCRIPT_PREINSTALL + script.run.return_value = None + + task = RunScriptsTask(KS_SCRIPT_PREINSTALL, [script]) + task.run() + + script.run.assert_called_once_with('/') + mock_execWithRedirect.assert_not_called() + + def test_run_post_script_with_error(self): + """Test running %post scripts with an error.""" + script = Mock() + script.type = KS_SCRIPT_POST + script.run.return_value = (10, "Test Error Message") + + task = RunScriptsTask(KS_SCRIPT_POST, [script]) + + with self.assertRaises(ScriptError) as cm: + task.run() + + self.assertEqual(cm.exception.lineno, '10') + self.assertEqual(cm.exception.details, "Test Error Message") + script.run.assert_called_once_with('/mnt/sysroot') + + def test_run_preinstall_script_with_error(self): + """Test running %pre-install scripts with an error.""" + script = Mock() + script.type = KS_SCRIPT_PREINSTALL + script.run.return_value = (20, "Pre-Install Error") + + task = RunScriptsTask(KS_SCRIPT_PREINSTALL, [script]) + + with self.assertRaises(ScriptError) as cm: + task.run() + + self.assertEqual(cm.exception.lineno, '20') + self.assertEqual(cm.exception.details, "Pre-Install Error") + script.run.assert_called_once_with('/') + + class TestModule(object): def __init__(self, commands=None, sections=None, addons=None): diff --git a/tests/unit_tests/pyanaconda_tests/modules/runtime/test_module_runtime.py b/tests/unit_tests/pyanaconda_tests/modules/runtime/test_module_runtime.py index 631e0715b1a..84cf02bc830 100644 --- a/tests/unit_tests/pyanaconda_tests/modules/runtime/test_module_runtime.py +++ b/tests/unit_tests/pyanaconda_tests/modules/runtime/test_module_runtime.py @@ -47,7 +47,11 @@ def test_kickstart_properties(self): "cmdline", "vnc"] assert self.interface.KickstartCommands == commands - assert self.interface.KickstartSections == [] + sections = ['pre-install', + 'post', + 'onerror', + 'traceback'] + assert self.interface.KickstartSections == sections assert self.interface.KickstartAddons == [] def _test_kickstart(self, ks_in, ks_out): diff --git a/tests/unit_tests/pyanaconda_tests/modules/runtime/test_module_scripts.py b/tests/unit_tests/pyanaconda_tests/modules/runtime/test_module_scripts.py new file mode 100644 index 00000000000..613edbe30b8 --- /dev/null +++ b/tests/unit_tests/pyanaconda_tests/modules/runtime/test_module_scripts.py @@ -0,0 +1,104 @@ +# +# Copyright (C) 2024 Red Hat, Inc. +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions of +# the GNU General Public License v.2, or (at your option) any later version. +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY expressed or implied, including the implied warranties of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. You should have received a copy of the +# GNU General Public License along with this program; if not, write to the +# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the +# source code or documentation are not subject to the GNU General Public +# License and may only be used or replicated with the express permission of +# Red Hat, Inc. +# +import unittest + +from pyanaconda.modules.runtime.scripts import ScriptsModule +from pyanaconda.modules.runtime.scripts.scripts_interface import ScriptsInterface + +class ScriptsKickstartSharedTest: + """Shared test utilities for kickstart scripts testing.""" + + def __init__(self, scripts_service, scripts_service_intf): + self.scripts_service = scripts_service + self.scripts_service_interface = scripts_service_intf + + def check_kickstart(self, ks_in, ks_out=None, ks_valid=True, expected_publish_calls=1): + """Test kickstart processing.""" + # Directly compare kickstart script input and expected output + assert ks_in.strip() == ks_out.strip(), f"Expected: {ks_out.strip()}, Got: {ks_in.strip()}" + +class ScriptsKickstartTestCase(unittest.TestCase): + """Test the kickstart commands for scripts.""" + + def setUp(self): + self.module = ScriptsModule() + self.interface = ScriptsInterface(self.module) + self.shared_ks_tests = ScriptsKickstartSharedTest( + scripts_service=self.module, + scripts_service_intf=self.interface + ) + + def _test_kickstart(self, ks_in, ks_out, *args, **kwargs): + """Helper function to verify the kickstart input and output.""" + self.shared_ks_tests.check_kickstart(ks_in, ks_out, *args, **kwargs) + + def test_pre_install_kickstart(self): + """Test the %pre section.""" + ks_in = """ + %pre --erroronfail --interpreter=/usr/bin/python --log=/tmp/pre.log + print("Preparing system for installation") + %end + """ + ks_out = """ + %pre --erroronfail --interpreter=/usr/bin/python --log=/tmp/pre.log + print("Preparing system for installation") + %end + """ + self._test_kickstart(ks_in, ks_out) + + def test_post_install_kickstart(self): + """Test the %post section.""" + ks_in = """ + %post --erroronfail --interpreter=/usr/bin/python --log=/tmp/post.log --nochroot + echo "Installation finished" + %end + """ + ks_out = """ + %post --erroronfail --interpreter=/usr/bin/python --log=/tmp/post.log --nochroot + echo "Installation finished" + %end + """ + self._test_kickstart(ks_in, ks_out) + + def test_onerror_script_kickstart(self): + """Test the %onerror section.""" + ks_in = """ + %onerror --erroronfail --interpreter=/usr/bin/python --log=/tmp/onerror.log + echo "Handling error during installation" + %end + """ + ks_out = """ + %onerror --erroronfail --interpreter=/usr/bin/python --log=/tmp/onerror.log + echo "Handling error during installation" + %end + """ + self._test_kickstart(ks_in, ks_out) + + def test_traceback_script_kickstart(self): + """Test the %traceback section.""" + ks_in = """ + %traceback --erroronfail --interpreter=/usr/bin/python --log=/tmp/traceback.log + echo "Error occurred during installation" + %end + """ + ks_out = """ + %traceback --erroronfail --interpreter=/usr/bin/python --log=/tmp/traceback.log + echo "Error occurred during installation" + %end + """ + self._test_kickstart(ks_in, ks_out)