Skip to content

Commit

Permalink
Test for kickstart scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
adamkankovsky committed Oct 17, 2024
1 parent ed73f1a commit d30e646
Show file tree
Hide file tree
Showing 3 changed files with 246 additions and 2 deletions.
138 changes: 137 additions & 1 deletion tests/unit_tests/pyanaconda_tests/modules/boss/test_kickstart.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit d30e646

Please sign in to comment.