qemu-cr16/tests/functional/qemu_test/linuxkernel.py
Aditya Gupta 945fd61c06
tests/functional: Add test for fadump in PSeries
Add testcases for testing fadump with PSeries and PSeries+KVM
combinations

It tests if fadump is successfully detected and registered in the first
kernel boot. Then crashes the kernel, and verifies whether we have a
/proc/vmcore in the 2nd boot

Also introduce 'wait_for_regex_console_pattern' to check for cases where
there is a single success message, but can have multiple failure
messages.

This is particularly useful for cases such as fadump, where the
success message is
    "Reserved 1024MB ... successfully"
But at the same point, it can fail with multiple errors such as
    "Not supported" or "Allocation failed"

'wait_for_regex_console_pattern' also has a timeout, for cases when we
know the success/failure should appear in a short amount of time,
instead of waiting for the much longer test timeout, such as kernels
with support of fadump will print the success/failure in earlyboot of
the kernel, while kernel without support of fadump won't print anything
for long time, and without a timeout the testcase keeps waiting till
longer test timeout

Signed-off-by: Aditya Gupta <adityag@linux.ibm.com>
Tested-by: Shivang Upadhyay <shivangu@linux.ibm.com>
Link: https://lore.kernel.org/qemu-devel/20251021134823.1861675-8-adityag@linux.ibm.com
Signed-off-by: Harsh Prateek Bora <harshpb@linux.ibm.com>
2025-10-23 17:37:42 +05:30

111 lines
4.2 KiB
Python

# Test class for testing the boot process of a Linux kernel
#
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
import hashlib
import urllib.request
import logging
import re
import time
from .cmd import wait_for_console_pattern, exec_command_and_wait_for_pattern
from .testcase import QemuSystemTest
from .utils import get_usernet_hostfwd_port
class LinuxKernelTest(QemuSystemTest):
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
def wait_for_console_pattern(self, success_message, vm=None):
wait_for_console_pattern(self, success_message,
failure_message='Kernel panic - not syncing',
vm=vm)
def wait_for_regex_console_pattern(self, success_pattern,
failure_pattern=None,
timeout=None):
"""
Similar to 'wait_for_console_pattern', but supports regex patterns,
hence multiple failure/success patterns can be detected at a time.
Args:
success_pattern (str | re.Pattern): A regex pattern that indicates
a successful event. If found, the method exits normally.
failure_pattern (str | re.Pattern, optional): A regex pattern that
indicates a failure event. If found, the test fails
timeout (int, optional): The maximum time (in seconds) to wait for
a match.
If exceeded, the test fails.
"""
console = self.vm.console_file
console_logger = logging.getLogger('console')
self.log.debug(
f"Console interaction: success_msg='{success_pattern}' " +
f"failure_msg='{failure_pattern}' timeout='{timeout}s'")
# Only consume console output if waiting for something
if success_pattern is None and failure_pattern is None:
return
start_time = time.time()
while time.time() - start_time < timeout:
try:
msg = console.readline().decode().strip()
except UnicodeDecodeError:
msg = None
if not msg:
continue
console_logger.debug(msg)
if success_pattern is None or re.search(success_pattern, msg):
break
if failure_pattern:
# Find the matching error to print in log
match = re.search(failure_pattern, msg)
if not match:
continue
console.close()
fail = 'Failure message found in console: "%s".' \
' Expected: "%s"' % \
(match.group(), success_pattern)
self.fail(fail)
if time.time() - start_time >= timeout:
fail = f"Timeout ({timeout}s) while trying to search pattern"
self.fail(fail)
def launch_kernel(self, kernel, initrd=None, dtb=None, console_index=0,
wait_for=None):
self.vm.set_console(console_index=console_index)
self.vm.add_args('-kernel', kernel)
if initrd:
self.vm.add_args('-initrd', initrd)
if dtb:
self.vm.add_args('-dtb', dtb)
self.vm.launch()
if wait_for:
self.wait_for_console_pattern(wait_for)
def check_http_download(self, filename, hashsum, guestport=8080,
pythoncmd='python3 -m http.server'):
exec_command_and_wait_for_pattern(self,
f'{pythoncmd} {guestport} & sleep 1',
f'Serving HTTP on 0.0.0.0 port {guestport}')
hl = hashlib.sha256()
hostport = get_usernet_hostfwd_port(self.vm)
url = f'http://localhost:{hostport}{filename}'
self.log.info(f'Downloading {url} ...')
with urllib.request.urlopen(url) as response:
while True:
chunk = response.read(1 << 20)
if not chunk:
break
hl.update(chunk)
digest = hl.hexdigest()
self.log.info(f'sha256sum of download is {digest}.')
self.assertEqual(digest, hashsum)