xref: /qemu/tests/functional/qemu_test/tuxruntest.py (revision beaf88c895a5eda649777757c80ab4171de777ff)
1c1b24f0fSThomas Huth# Functional test that boots known good tuxboot images the same way
2c1b24f0fSThomas Huth# that tuxrun (www.tuxrun.org) does. This tool is used by things like
3c1b24f0fSThomas Huth# the LKFT project to run regression tests on kernels.
4c1b24f0fSThomas Huth#
5c1b24f0fSThomas Huth# Copyright (c) 2023 Linaro Ltd.
6c1b24f0fSThomas Huth#
7c1b24f0fSThomas Huth# Author:
8c1b24f0fSThomas Huth#  Alex Bennée <alex.bennee@linaro.org>
9c1b24f0fSThomas Huth#
10c1b24f0fSThomas Huth# SPDX-License-Identifier: GPL-2.0-or-later
11c1b24f0fSThomas Huth
12c1b24f0fSThomas Huthimport os
13c9daf680SDaniel P. Berrangéimport stat
14c1b24f0fSThomas Huth
15c1b24f0fSThomas Huthfrom qemu_test import QemuSystemTest
168a6253a4SDaniel P. Berrangéfrom qemu_test import exec_command_and_wait_for_pattern
17c1b24f0fSThomas Huthfrom qemu_test import wait_for_console_pattern
189132fff8SDaniel P. Berrangéfrom qemu_test import which, run_cmd, get_qemu_img
19c1b24f0fSThomas Huth
20c1b24f0fSThomas Huthclass TuxRunBaselineTest(QemuSystemTest):
21c1b24f0fSThomas Huth
22c1b24f0fSThomas Huth    KERNEL_COMMON_COMMAND_LINE = 'printk.time=0'
23c1b24f0fSThomas Huth    # Tests are ~10-40s, allow for --debug/--enable-gcov overhead
24c1b24f0fSThomas Huth    timeout = 100
25c1b24f0fSThomas Huth
26c1b24f0fSThomas Huth    def get_tag(self, tagname, default=None):
27c1b24f0fSThomas Huth        """
28c1b24f0fSThomas Huth        Get the metadata tag or return the default.
29c1b24f0fSThomas Huth        """
30c1b24f0fSThomas Huth        utag = self._get_unique_tag_val(tagname)
31c1b24f0fSThomas Huth        print(f"{tagname}/{default} -> {utag}")
32c1b24f0fSThomas Huth        if utag:
33c1b24f0fSThomas Huth            return utag
34c1b24f0fSThomas Huth
35c1b24f0fSThomas Huth        return default
36c1b24f0fSThomas Huth
37c1b24f0fSThomas Huth    def setUp(self):
38c1b24f0fSThomas Huth        super().setUp()
39c1b24f0fSThomas Huth
40c1b24f0fSThomas Huth        # We need zstd for all the tuxrun tests
419132fff8SDaniel P. Berrangé        if which('zstd') is None:
429132fff8SDaniel P. Berrangé            self.skipTest("zstd not found in $PATH")
43c1b24f0fSThomas Huth
44c1b24f0fSThomas Huth        # Pre-init TuxRun specific settings: Most machines work with
45c1b24f0fSThomas Huth        # reasonable defaults but we sometimes need to tweak the
46c1b24f0fSThomas Huth        # config. To avoid open coding everything we store all these
47c1b24f0fSThomas Huth        # details in the metadata for each test.
48c1b24f0fSThomas Huth
49c1b24f0fSThomas Huth        # The tuxboot tag matches the root directory
50c1b24f0fSThomas Huth        self.tuxboot = self.arch
51c1b24f0fSThomas Huth
52c1b24f0fSThomas Huth        # Most Linux's use ttyS0 for their serial port
53c1b24f0fSThomas Huth        self.console = "ttyS0"
54c1b24f0fSThomas Huth
55c1b24f0fSThomas Huth        # Does the machine shutdown QEMU nicely on "halt"
56c1b24f0fSThomas Huth        self.wait_for_shutdown = True
57c1b24f0fSThomas Huth
58c1b24f0fSThomas Huth        self.root = "vda"
59c1b24f0fSThomas Huth
60c1b24f0fSThomas Huth        # Occasionally we need extra devices to hook things up
61c1b24f0fSThomas Huth        self.extradev = None
62c1b24f0fSThomas Huth
63c1b24f0fSThomas Huth        self.qemu_img = get_qemu_img(self)
64c1b24f0fSThomas Huth
65c1b24f0fSThomas Huth    def wait_for_console_pattern(self, success_message, vm=None):
66c1b24f0fSThomas Huth        wait_for_console_pattern(self, success_message,
67c1b24f0fSThomas Huth                                 failure_message='Kernel panic - not syncing',
68c1b24f0fSThomas Huth                                 vm=vm)
69c1b24f0fSThomas Huth
70c1b24f0fSThomas Huth    def fetch_tuxrun_assets(self, kernel_asset, rootfs_asset, dtb_asset=None):
71c1b24f0fSThomas Huth        """
72c1b24f0fSThomas Huth        Fetch the TuxBoot assets.
73c1b24f0fSThomas Huth        """
74c1b24f0fSThomas Huth        kernel_image =  kernel_asset.fetch()
75c1b24f0fSThomas Huth        disk_image_zst = rootfs_asset.fetch()
76c1b24f0fSThomas Huth
77*beaf88c8SDaniel P. Berrangé        disk_image = self.scratch_file("rootfs.ext4")
78c9daf680SDaniel P. Berrangé
799132fff8SDaniel P. Berrangé        run_cmd(['zstd', "-f", "-d", disk_image_zst,
80c9daf680SDaniel P. Berrangé                 "-o", disk_image])
81c9daf680SDaniel P. Berrangé        # zstd copies source archive permissions for the output
82c9daf680SDaniel P. Berrangé        # file, so must make this writable for QEMU
83c9daf680SDaniel P. Berrangé        os.chmod(disk_image, stat.S_IRUSR | stat.S_IWUSR)
84c1b24f0fSThomas Huth
85c1b24f0fSThomas Huth        dtb = dtb_asset.fetch() if dtb_asset is not None else None
86c1b24f0fSThomas Huth
87c9daf680SDaniel P. Berrangé        return (kernel_image, disk_image, dtb)
88c1b24f0fSThomas Huth
89c1b24f0fSThomas Huth    def prepare_run(self, kernel, disk, drive, dtb=None, console_index=0):
90c1b24f0fSThomas Huth        """
91c1b24f0fSThomas Huth        Setup to run and add the common parameters to the system
92c1b24f0fSThomas Huth        """
93c1b24f0fSThomas Huth        self.vm.set_console(console_index=console_index)
94c1b24f0fSThomas Huth
95c1b24f0fSThomas Huth        # all block devices are raw ext4's
96c1b24f0fSThomas Huth        blockdev = "driver=raw,file.driver=file," \
97c1b24f0fSThomas Huth            + f"file.filename={disk},node-name=hd0"
98c1b24f0fSThomas Huth
99c1b24f0fSThomas Huth        kcmd_line = self.KERNEL_COMMON_COMMAND_LINE
100c1b24f0fSThomas Huth        kcmd_line += f" root=/dev/{self.root}"
101c1b24f0fSThomas Huth        kcmd_line += f" console={self.console}"
102c1b24f0fSThomas Huth
103c1b24f0fSThomas Huth        self.vm.add_args('-kernel', kernel,
104c1b24f0fSThomas Huth                         '-append', kcmd_line,
105c1b24f0fSThomas Huth                         '-blockdev', blockdev)
106c1b24f0fSThomas Huth
107c1b24f0fSThomas Huth        # Sometimes we need extra devices attached
108c1b24f0fSThomas Huth        if self.extradev:
109c1b24f0fSThomas Huth            self.vm.add_args('-device', self.extradev)
110c1b24f0fSThomas Huth
111c1b24f0fSThomas Huth        self.vm.add_args('-device',
112c1b24f0fSThomas Huth                         f"{drive},drive=hd0")
113c1b24f0fSThomas Huth
114c1b24f0fSThomas Huth        # Some machines need an explicit DTB
115c1b24f0fSThomas Huth        if dtb:
116c1b24f0fSThomas Huth            self.vm.add_args('-dtb', dtb)
117c1b24f0fSThomas Huth
118c1b24f0fSThomas Huth    def run_tuxtest_tests(self, haltmsg):
119c1b24f0fSThomas Huth        """
120c1b24f0fSThomas Huth        Wait for the system to boot up, wait for the login prompt and
121c1b24f0fSThomas Huth        then do a few things on the console. Trigger a shutdown and
122c1b24f0fSThomas Huth        wait to exit cleanly.
123c1b24f0fSThomas Huth        """
12497d79319SDaniel P. Berrangé        ps1='root@tuxtest:~#'
12597d79319SDaniel P. Berrangé        self.wait_for_console_pattern('tuxtest login:')
12697d79319SDaniel P. Berrangé        exec_command_and_wait_for_pattern(self, 'root', ps1)
12797d79319SDaniel P. Berrangé        exec_command_and_wait_for_pattern(self, 'cat /proc/interrupts', ps1)
12897d79319SDaniel P. Berrangé        exec_command_and_wait_for_pattern(self, 'cat /proc/self/maps', ps1)
12997d79319SDaniel P. Berrangé        exec_command_and_wait_for_pattern(self, 'uname -a', ps1)
130c1b24f0fSThomas Huth        exec_command_and_wait_for_pattern(self, 'halt', haltmsg)
131c1b24f0fSThomas Huth
132c1b24f0fSThomas Huth        # Wait for VM to shut down gracefully if it can
133c1b24f0fSThomas Huth        if self.wait_for_shutdown:
134c1b24f0fSThomas Huth            self.vm.wait()
135c1b24f0fSThomas Huth        else:
136c1b24f0fSThomas Huth            self.vm.shutdown()
137c1b24f0fSThomas Huth
138c1b24f0fSThomas Huth    def common_tuxrun(self,
139c1b24f0fSThomas Huth                      kernel_asset,
140c1b24f0fSThomas Huth                      rootfs_asset,
141c1b24f0fSThomas Huth                      dtb_asset=None,
142c1b24f0fSThomas Huth                      drive="virtio-blk-device",
143c1b24f0fSThomas Huth                      haltmsg="reboot: System halted",
144c1b24f0fSThomas Huth                      console_index=0):
145c1b24f0fSThomas Huth        """
146c1b24f0fSThomas Huth        Common path for LKFT tests. Unless we need to do something
147c1b24f0fSThomas Huth        special with the command line we can process most things using
148c1b24f0fSThomas Huth        the tag metadata.
149c1b24f0fSThomas Huth        """
150c1b24f0fSThomas Huth        (kernel, disk, dtb) = self.fetch_tuxrun_assets(kernel_asset, rootfs_asset,
151c1b24f0fSThomas Huth                                                       dtb_asset)
152c1b24f0fSThomas Huth
153c1b24f0fSThomas Huth        self.prepare_run(kernel, disk, drive, dtb, console_index)
154c1b24f0fSThomas Huth        self.vm.launch()
155c1b24f0fSThomas Huth        self.run_tuxtest_tests(haltmsg)
156c1b24f0fSThomas Huth        os.remove(disk)
157