blob: eb10a8133532f4d071c04c95b603bd8cbfe81183 [file] [log] [blame]
# 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)