aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2024-12-18 20:24:51 -0500
committerStefan Hajnoczi <stefanha@redhat.com>2024-12-18 20:24:51 -0500
commitba182a693fe15a4f6f2a04e8ecb865c2630e5a16 (patch)
tree6256215ea27b7d2028fdf212a9b4ba492f1a27fc
parent877fad2a3e1a76fa3f9508b26858c6e659cc728f (diff)
parente2d98f257138b83b6a492d1da5847a7fe0930d10 (diff)
downloadqemu-ba182a693fe15a4f6f2a04e8ecb865c2630e5a16.zip
qemu-ba182a693fe15a4f6f2a04e8ecb865c2630e5a16.tar.gz
qemu-ba182a693fe15a4f6f2a04e8ecb865c2630e5a16.tar.bz2
Merge tag 'pull-request-2024-12-18' of https://gitlab.com/thuth/qemu into staging
* Lots of functional test improvements (clean-ups, don't fail on temporary download errors, etc.) * Convert some more avocado tests to the functional framework * Disallow building with libnfs v6 due to an API breakage # -----BEGIN PGP SIGNATURE----- # # iQJFBAABCAAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmdirOIRHHRodXRoQHJl # ZGhhdC5jb20ACgkQLtnXdP5wLbU0NRAAke8X0B6OOD+99lY5nc7Hrh7N1m+sw5Lw # TVwIpxdhxU11vgdlCodfdoVJCV1NGVHwkR57lLNr+bdspWDBBwlmUWn0+t2QCXGe # oyQsV+boznsjG9pan6v6DcU/gOu7/7ZydhJi+M8Msf8ah0lcn/otAdC4ZFB93JLh # 6xPnj69y8HomCW+wMyXl7WTjcWX0wQFzweEYY8p7X7p1rtjYyseiZlRjNAvPgTMI # jznZ6v9/qU54xR9RnKdW+0m1Qu06nx26Wz+ZBlvrJS1Llloe23X9+LY1tDD0Xh1D # 9P0v9PuaBWRRF+UjVjl37LMyn9h1aaKFKBoWQiKMbyvOVr4ncobjRgN8r5kdNxDP # FZ/fA1GiX8O3foN9uB9JLKd6Hl49LAqQSPzAneEc3pfQLH3NdAjPxJDbJH5fyMa7 # qVOQC0Bdy8+2kCxFfKbemrwDOFcyq1fVYcADPDZySjMiPnwFJ1Qpni1tXY1PZ+Tl # Q18AsFJanyAAn7L+8R3Yl54983SuR5eXIFxO+Tq9mw1V1V2h+Cm09HGcS8y5bxFG # Xh+jhMsMB98NFLR87W6olwl57gKllSbTYuGtiz9TrbnuT/THhUJ0k/B76L7C9HWE # ZefkFxC5Zy8jrcz3pgarO+19V+eXg5rwGtEngRQrji/3cY5CbK7Jeh5nvZQeASpb # nZ/gJ/gC8Gs= # =SWw6 # -----END PGP SIGNATURE----- # gpg: Signature made Wed 18 Dec 2024 06:07:14 EST # gpg: using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5 # gpg: issuer "thuth@redhat.com" # gpg: Good signature from "Thomas Huth <th.huth@gmx.de>" [full] # gpg: aka "Thomas Huth <thuth@redhat.com>" [full] # gpg: aka "Thomas Huth <huth@tuxfamily.org>" [full] # gpg: aka "Thomas Huth <th.huth@posteo.de>" [unknown] # Primary key fingerprint: 27B8 8847 EEE0 2501 18F3 EAB9 2ED9 D774 FE70 2DB5 * tag 'pull-request-2024-12-18' of https://gitlab.com/thuth/qemu: (38 commits) meson.build: Disallow libnfs v6 to fix the broken macOS build tests/functional: Convert the hotplug_cpu avocado test tests/functional: Convert the intel_iommu avocado test tests/functional: Add a helper function for retrieving the hostfwd port tests/functional: Convert the arm virt avocado test tests/functional: Convert the quanta-gsj avocado test MAINTAINERS: add myself as reviewer for functional test suite tests/functional: ignore errors when caching assets, except for 404 tests/functional: skip tests if assets are not available tests/functional: remove now unused 'run_cmd' helper tests/functional: replace 'run_cmd' with subprocess helpers tests/functional: drop back compat imports from utils.py tests/functional: convert tests to new uncompress helper tests/functional: add 'uncompress' to QemuBaseTest tests/functional: add a generalized uncompress helper tests/functional: convert tests to new archive_extract helper tests/functional: add 'archive_extract' to QemuBaseTest tests/functional: add a generalized archive_extract tests/functional: let cpio_extract accept filenames tests/functional: add common deb_extract helper ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
-rw-r--r--MAINTAINERS3
-rw-r--r--meson.build2
-rw-r--r--tests/avocado/boot_linux_console.py107
-rw-r--r--tests/avocado/hotplug_cpu.py37
-rw-r--r--tests/avocado/intel_iommu.py122
-rw-r--r--tests/functional/meson.build8
-rw-r--r--tests/functional/qemu_test/__init__.py9
-rw-r--r--tests/functional/qemu_test/archive.py117
-rw-r--r--tests/functional/qemu_test/asset.py26
-rw-r--r--tests/functional/qemu_test/cmd.py76
-rw-r--r--tests/functional/qemu_test/decorators.py107
-rw-r--r--tests/functional/qemu_test/linuxkernel.py29
-rw-r--r--tests/functional/qemu_test/tesseract.py21
-rw-r--r--tests/functional/qemu_test/testcase.py205
-rw-r--r--tests/functional/qemu_test/tuxruntest.py19
-rw-r--r--tests/functional/qemu_test/uncompress.py83
-rw-r--r--tests/functional/qemu_test/utils.py52
-rwxr-xr-x[-rw-r--r--]tests/functional/test_aarch64_aspeed.py23
-rwxr-xr-xtests/functional/test_aarch64_raspi3.py9
-rwxr-xr-xtests/functional/test_aarch64_raspi4.py21
-rwxr-xr-xtests/functional/test_aarch64_sbsaref.py12
-rwxr-xr-xtests/functional/test_aarch64_sbsaref_alpine.py1
-rwxr-xr-xtests/functional/test_aarch64_sbsaref_freebsd.py1
-rwxr-xr-xtests/functional/test_aarch64_virt.py14
-rwxr-xr-xtests/functional/test_acpi_bits.py124
-rwxr-xr-xtests/functional/test_alpha_clipper.py6
-rwxr-xr-x[-rw-r--r--]tests/functional/test_arm_aspeed_ast1030.py18
-rwxr-xr-x[-rw-r--r--]tests/functional/test_arm_aspeed_ast2500.py8
-rwxr-xr-x[-rw-r--r--]tests/functional/test_arm_aspeed_ast2600.py14
-rwxr-xr-x[-rw-r--r--]tests/functional/test_arm_aspeed_palmetto.py0
-rwxr-xr-x[-rw-r--r--]tests/functional/test_arm_aspeed_rainier.py11
-rwxr-xr-x[-rw-r--r--]tests/functional/test_arm_aspeed_romulus.py0
-rwxr-xr-xtests/functional/test_arm_bflt.py13
-rwxr-xr-xtests/functional/test_arm_bpim2u.py44
-rwxr-xr-xtests/functional/test_arm_canona1100.py10
-rwxr-xr-xtests/functional/test_arm_collie.py2
-rwxr-xr-xtests/functional/test_arm_cubieboard.py40
-rwxr-xr-xtests/functional/test_arm_emcraft_sf2.py2
-rwxr-xr-xtests/functional/test_arm_integratorcp.py28
-rwxr-xr-xtests/functional/test_arm_orangepi.py60
-rwxr-xr-xtests/functional/test_arm_quanta_gsj.py94
-rwxr-xr-xtests/functional/test_arm_raspi2.py21
-rwxr-xr-xtests/functional/test_arm_smdkc210.py18
-rwxr-xr-xtests/functional/test_arm_sx1.py2
-rwxr-xr-xtests/functional/test_arm_vexpress.py10
-rwxr-xr-xtests/functional/test_arm_virt.py30
-rwxr-xr-xtests/functional/test_info_usernet.py8
-rwxr-xr-xtests/functional/test_intel_iommu.py175
-rwxr-xr-xtests/functional/test_linux_initrd.py7
-rwxr-xr-xtests/functional/test_m68k_mcf5208evb.py8
-rwxr-xr-xtests/functional/test_m68k_nextcube.py24
-rwxr-xr-xtests/functional/test_m68k_q800.py5
-rwxr-xr-xtests/functional/test_microblaze_s3adsp1800.py9
-rwxr-xr-xtests/functional/test_microblazeel_s3adsp1800.py10
-rwxr-xr-xtests/functional/test_mips64el_fuloong2e.py10
-rwxr-xr-xtests/functional/test_mips64el_loongson3v.py8
-rwxr-xr-xtests/functional/test_mips64el_malta.py45
-rwxr-xr-xtests/functional/test_mips_malta.py19
-rwxr-xr-xtests/functional/test_mipsel_malta.py24
-rwxr-xr-xtests/functional/test_or1k_sim.py7
-rwxr-xr-xtests/functional/test_ppc64_e500.py7
-rwxr-xr-xtests/functional/test_ppc64_hv.py39
-rwxr-xr-xtests/functional/test_ppc64_tuxrun.py7
-rwxr-xr-xtests/functional/test_ppc_40p.py7
-rwxr-xr-xtests/functional/test_ppc_amiga.py20
-rwxr-xr-xtests/functional/test_ppc_bamboo.py15
-rwxr-xr-xtests/functional/test_ppc_mac.py8
-rwxr-xr-xtests/functional/test_ppc_mpc8544ds.py8
-rwxr-xr-xtests/functional/test_ppc_virtex_ml507.py10
-rwxr-xr-xtests/functional/test_rx_gdbsim.py13
-rwxr-xr-xtests/functional/test_s390x_ccw_virtio.py6
-rwxr-xr-xtests/functional/test_s390x_topology.py7
-rwxr-xr-xtests/functional/test_sh4_r2d.py14
-rwxr-xr-xtests/functional/test_sh4eb_r2d.py14
-rwxr-xr-xtests/functional/test_sparc64_sun4u.py11
-rwxr-xr-xtests/functional/test_sparc_sun4m.py7
-rwxr-xr-xtests/functional/test_virtio_gpu.py16
-rwxr-xr-xtests/functional/test_x86_64_hotplug_cpu.py69
-rwxr-xr-xtests/functional/test_xtensa_lx60.py8
79 files changed, 1275 insertions, 1029 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 822f343..430a0f4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -872,6 +872,7 @@ F: tests/qtest/adm1266-test.c
F: pc-bios/npcm7xx_bootrom.bin
F: roms/vbootrom
F: docs/system/arm/nuvoton.rst
+F: tests/functional/test_arm_quanta_gsj.py
Raspberry Pi
M: Peter Maydell <peter.maydell@linaro.org>
@@ -3681,6 +3682,7 @@ S: Supported
F: hw/i386/intel_iommu.c
F: hw/i386/intel_iommu_internal.h
F: include/hw/i386/intel_iommu.h
+F: tests/functional/test_intel_iommu.py
AMD-Vi Emulation
S: Orphan
@@ -4157,6 +4159,7 @@ W: https://cirrus-ci.com/github/qemu/qemu
Functional testing framework
M: Thomas Huth <thuth@redhat.com>
R: Philippe Mathieu-Daudé <philmd@linaro.org>
+R: Daniel P. Berrange <berrange@redhat.com>
F: tests/functional/qemu_test/
Windows Hosted Continuous Integration
diff --git a/meson.build b/meson.build
index 85f7485..6149b50 100644
--- a/meson.build
+++ b/meson.build
@@ -1145,7 +1145,7 @@ endif
libnfs = not_found
if not get_option('libnfs').auto() or have_block
- libnfs = dependency('libnfs', version: '>=1.9.3',
+ libnfs = dependency('libnfs', version: ['>=1.9.3', '<6.0.0'],
required: get_option('libnfs'),
method: 'pkg-config')
endif
diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py
index 268b40c..c15f39a 100644
--- a/tests/avocado/boot_linux_console.py
+++ b/tests/avocado/boot_linux_console.py
@@ -94,110 +94,3 @@ class BootLinuxConsole(LinuxKernelTest):
self.vm.launch()
console_pattern = 'Kernel command line: %s' % kernel_command_line
self.wait_for_console_pattern(console_pattern)
-
- def test_arm_virt(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:virt
- :avocado: tags=accel:tcg
- """
- kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora'
- '/linux/releases/29/Everything/armhfp/os/images/pxeboot'
- '/vmlinuz')
- kernel_hash = 'e9826d741b4fb04cadba8d4824d1ed3b7fb8b4d4'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyAMA0')
- self.vm.add_args('-kernel', kernel_path,
- '-append', kernel_command_line)
- self.vm.launch()
- console_pattern = 'Kernel command line: %s' % kernel_command_line
- self.wait_for_console_pattern(console_pattern)
-
- @skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
- def test_arm_quanta_gsj(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:quanta-gsj
- :avocado: tags=accel:tcg
- """
- # 25 MiB compressed, 32 MiB uncompressed.
- image_url = (
- 'https://github.com/hskinnemoen/openbmc/releases/download/'
- '20200711-gsj-qemu-0/obmc-phosphor-image-gsj.static.mtd.gz')
- image_hash = '14895e634923345cb5c8776037ff7876df96f6b1'
- image_path_gz = self.fetch_asset(image_url, asset_hash=image_hash)
- image_name = 'obmc.mtd'
- image_path = os.path.join(self.workdir, image_name)
- archive.gzip_uncompress(image_path_gz, image_path)
-
- self.vm.set_console()
- drive_args = 'file=' + image_path + ',if=mtd,bus=0,unit=0'
- self.vm.add_args('-drive', drive_args)
- self.vm.launch()
-
- # Disable drivers and services that stall for a long time during boot,
- # to avoid running past the 90-second timeout. These may be removed
- # as the corresponding device support is added.
- kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + (
- 'console=${console} '
- 'mem=${mem} '
- 'initcall_blacklist=npcm_i2c_bus_driver_init '
- 'systemd.mask=systemd-random-seed.service '
- 'systemd.mask=dropbearkey.service '
- )
-
- self.wait_for_console_pattern('> BootBlock by Nuvoton')
- self.wait_for_console_pattern('>Device: Poleg BMC NPCM730')
- self.wait_for_console_pattern('>Skip DDR init.')
- self.wait_for_console_pattern('U-Boot ')
- interrupt_interactive_console_until_pattern(
- self, 'Hit any key to stop autoboot:', 'U-Boot>')
- exec_command_and_wait_for_pattern(
- self, "setenv bootargs ${bootargs} " + kernel_command_line,
- 'U-Boot>')
- exec_command_and_wait_for_pattern(
- self, 'run romboot', 'Booting Kernel from flash')
- self.wait_for_console_pattern('Booting Linux on physical CPU 0x0')
- self.wait_for_console_pattern('CPU1: thread -1, cpu 1, socket 0')
- self.wait_for_console_pattern('OpenBMC Project Reference Distro')
- self.wait_for_console_pattern('gsj login:')
-
- def test_arm_quanta_gsj_initrd(self):
- """
- :avocado: tags=arch:arm
- :avocado: tags=machine:quanta-gsj
- :avocado: tags=accel:tcg
- """
- initrd_url = (
- 'https://github.com/hskinnemoen/openbmc/releases/download/'
- '20200711-gsj-qemu-0/obmc-phosphor-initramfs-gsj.cpio.xz')
- initrd_hash = '98fefe5d7e56727b1eb17d5c00311b1b5c945300'
- initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
- kernel_url = (
- 'https://github.com/hskinnemoen/openbmc/releases/download/'
- '20200711-gsj-qemu-0/uImage-gsj.bin')
- kernel_hash = 'fa67b2f141d56d39b3c54305c0e8a899c99eb2c7'
- kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- dtb_url = (
- 'https://github.com/hskinnemoen/openbmc/releases/download/'
- '20200711-gsj-qemu-0/nuvoton-npcm730-gsj.dtb')
- dtb_hash = '18315f7006d7b688d8312d5c727eecd819aa36a4'
- dtb_path = self.fetch_asset(dtb_url, asset_hash=dtb_hash)
-
- self.vm.set_console()
- kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
- 'console=ttyS0,115200n8 '
- 'earlycon=uart8250,mmio32,0xf0001000')
- self.vm.add_args('-kernel', kernel_path,
- '-initrd', initrd_path,
- '-dtb', dtb_path,
- '-append', kernel_command_line)
- self.vm.launch()
-
- self.wait_for_console_pattern('Booting Linux on physical CPU 0x0')
- self.wait_for_console_pattern('CPU1: thread -1, cpu 1, socket 0')
- self.wait_for_console_pattern(
- 'Give root password for system maintenance')
diff --git a/tests/avocado/hotplug_cpu.py b/tests/avocado/hotplug_cpu.py
deleted file mode 100644
index 342c838..0000000
--- a/tests/avocado/hotplug_cpu.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# Functional test that hotplugs a CPU and checks it on a Linux guest
-#
-# Copyright (c) 2021 Red Hat, Inc.
-#
-# Author:
-# Cleber Rosa <crosa@redhat.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2 or
-# later. See the COPYING file in the top-level directory.
-
-from avocado_qemu.linuxtest import LinuxTest
-
-
-class HotPlugCPU(LinuxTest):
-
- def test(self):
- """
- :avocado: tags=arch:x86_64
- :avocado: tags=machine:q35
- :avocado: tags=accel:kvm
- """
- self.require_accelerator('kvm')
- self.vm.add_args('-accel', 'kvm')
- self.vm.add_args('-cpu', 'Haswell')
- self.vm.add_args('-smp', '1,sockets=1,cores=2,threads=1,maxcpus=2')
- self.launch_and_wait()
-
- self.ssh_command('test -e /sys/devices/system/cpu/cpu0')
- with self.assertRaises(AssertionError):
- self.ssh_command('test -e /sys/devices/system/cpu/cpu1')
-
- self.vm.cmd('device_add',
- driver='Haswell-x86_64-cpu',
- socket_id=0,
- core_id=1,
- thread_id=0)
- self.ssh_command('test -e /sys/devices/system/cpu/cpu1')
diff --git a/tests/avocado/intel_iommu.py b/tests/avocado/intel_iommu.py
deleted file mode 100644
index 992583f..0000000
--- a/tests/avocado/intel_iommu.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# INTEL_IOMMU Functional tests
-#
-# Copyright (c) 2021 Red Hat, Inc.
-#
-# Author:
-# Eric Auger <eric.auger@redhat.com>
-#
-# 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 os
-
-from avocado import skipUnless
-from avocado_qemu.linuxtest import LinuxTest
-
-@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
-class IntelIOMMU(LinuxTest):
- """
- :avocado: tags=arch:x86_64
- :avocado: tags=distro:fedora
- :avocado: tags=distro_version:31
- :avocado: tags=machine:q35
- :avocado: tags=accel:kvm
- :avocado: tags=intel_iommu
- :avocado: tags=flaky
- """
-
- IOMMU_ADDON = ',iommu_platform=on,disable-modern=off,disable-legacy=on'
- kernel_path = None
- initrd_path = None
- kernel_params = None
-
- def set_up_boot(self):
- path = self.download_boot()
- self.vm.add_args('-device', 'virtio-blk-pci,bus=pcie.0,' +
- 'drive=drv0,id=virtio-disk0,bootindex=1,'
- 'werror=stop,rerror=stop' + self.IOMMU_ADDON)
- self.vm.add_args('-device', 'virtio-gpu-pci' + self.IOMMU_ADDON)
- self.vm.add_args('-drive',
- 'file=%s,if=none,cache=writethrough,id=drv0' % path)
-
- def setUp(self):
- super(IntelIOMMU, self).setUp(None, 'virtio-net-pci' + self.IOMMU_ADDON)
-
- def add_common_args(self):
- self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0')
- self.vm.add_args('-object',
- 'rng-random,id=rng0,filename=/dev/urandom')
-
- def common_vm_setup(self, custom_kernel=None):
- self.require_accelerator("kvm")
- self.add_common_args()
- self.vm.add_args("-accel", "kvm")
-
- if custom_kernel is None:
- return
-
- kernel_url = self.distro.pxeboot_url + 'vmlinuz'
- kernel_hash = '5b6f6876e1b5bda314f93893271da0d5777b1f3c'
- initrd_url = self.distro.pxeboot_url + 'initrd.img'
- initrd_hash = 'dd0340a1b39bd28f88532babd4581c67649ec5b1'
- self.kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash)
- self.initrd_path = self.fetch_asset(initrd_url, asset_hash=initrd_hash)
-
- def run_and_check(self):
- if self.kernel_path:
- self.vm.add_args('-kernel', self.kernel_path,
- '-append', self.kernel_params,
- '-initrd', self.initrd_path)
- self.launch_and_wait()
- self.ssh_command('cat /proc/cmdline')
- self.ssh_command('dmesg | grep -e DMAR -e IOMMU')
- self.ssh_command('find /sys/kernel/iommu_groups/ -type l')
- self.ssh_command('dnf -y install numactl-devel')
-
- def test_intel_iommu(self):
- """
- :avocado: tags=intel_iommu_intremap
- """
-
- self.common_vm_setup(True)
- self.vm.add_args('-device', 'intel-iommu,intremap=on')
- self.vm.add_args('-machine', 'kernel_irqchip=split')
-
- self.kernel_params = (self.distro.default_kernel_params +
- ' quiet intel_iommu=on')
- self.run_and_check()
-
- def test_intel_iommu_strict(self):
- """
- :avocado: tags=intel_iommu_strict
- """
-
- self.common_vm_setup(True)
- self.vm.add_args('-device', 'intel-iommu,intremap=on')
- self.vm.add_args('-machine', 'kernel_irqchip=split')
- self.kernel_params = (self.distro.default_kernel_params +
- ' quiet intel_iommu=on,strict')
- self.run_and_check()
-
- def test_intel_iommu_strict_cm(self):
- """
- :avocado: tags=intel_iommu_strict_cm
- """
-
- self.common_vm_setup(True)
- self.vm.add_args('-device', 'intel-iommu,intremap=on,caching-mode=on')
- self.vm.add_args('-machine', 'kernel_irqchip=split')
- self.kernel_params = (self.distro.default_kernel_params +
- ' quiet intel_iommu=on,strict')
- self.run_and_check()
-
- def test_intel_iommu_pt(self):
- """
- :avocado: tags=intel_iommu_pt
- """
-
- self.common_vm_setup(True)
- self.vm.add_args('-device', 'intel-iommu,intremap=on')
- self.vm.add_args('-machine', 'kernel_irqchip=split')
- self.kernel_params = (self.distro.default_kernel_params +
- ' quiet intel_iommu=on iommu=pt')
- self.run_and_check()
diff --git a/tests/functional/meson.build b/tests/functional/meson.build
index 1bc5ba5..24f7f8f 100644
--- a/tests/functional/meson.build
+++ b/tests/functional/meson.build
@@ -27,9 +27,11 @@ test_timeouts = {
'arm_collie' : 180,
'arm_cubieboard' : 360,
'arm_orangepi' : 540,
+ 'arm_quanta_gsj' : 240,
'arm_raspi2' : 120,
'arm_tuxrun' : 240,
'arm_sx1' : 360,
+ 'intel_iommu': 300,
'mips_malta' : 120,
'netdev_ethtool' : 180,
'ppc_40p' : 240,
@@ -85,10 +87,12 @@ tests_arm_system_thorough = [
'arm_emcraft_sf2',
'arm_integratorcp',
'arm_orangepi',
+ 'arm_quanta_gsj',
'arm_raspi2',
'arm_smdkc210',
'arm_sx1',
'arm_vexpress',
+ 'arm_virt',
'arm_tuxrun',
]
@@ -224,11 +228,13 @@ tests_x86_64_system_quick = [
tests_x86_64_system_thorough = [
'acpi_bits',
- 'x86_64_tuxrun',
+ 'intel_iommu',
'linux_initrd',
'multiprocess',
'netdev_ethtool',
'virtio_gpu',
+ 'x86_64_hotplug_cpu',
+ 'x86_64_tuxrun',
]
tests_xtensa_system_thorough = [
diff --git a/tests/functional/qemu_test/__init__.py b/tests/functional/qemu_test/__init__.py
index 67f87be..da18302 100644
--- a/tests/functional/qemu_test/__init__.py
+++ b/tests/functional/qemu_test/__init__.py
@@ -8,8 +8,13 @@
from .asset import Asset
from .config import BUILD_DIR
-from .cmd import has_cmd, has_cmds, run_cmd, is_readable_executable_file, \
+from .cmd import is_readable_executable_file, \
interrupt_interactive_console_until_pattern, wait_for_console_pattern, \
- exec_command, exec_command_and_wait_for_pattern, get_qemu_img
+ exec_command, exec_command_and_wait_for_pattern, get_qemu_img, which
from .testcase import QemuBaseTest, QemuUserTest, QemuSystemTest
from .linuxkernel import LinuxKernelTest
+from .decorators import skipIfMissingCommands, skipIfNotMachine, \
+ skipFlakyTest, skipUntrustedTest, skipBigDataTest, \
+ skipIfMissingImports
+from .archive import archive_extract
+from .uncompress import uncompress
diff --git a/tests/functional/qemu_test/archive.py b/tests/functional/qemu_test/archive.py
new file mode 100644
index 0000000..c803fda
--- /dev/null
+++ b/tests/functional/qemu_test/archive.py
@@ -0,0 +1,117 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Utilities for python-based QEMU tests
+#
+# Copyright 2024 Red Hat, Inc.
+#
+# Authors:
+# Thomas Huth <thuth@redhat.com>
+
+import os
+from subprocess import check_call, run, DEVNULL
+import tarfile
+from urllib.parse import urlparse
+import zipfile
+
+from .asset import Asset
+
+
+def tar_extract(archive, dest_dir, member=None):
+ with tarfile.open(archive) as tf:
+ if hasattr(tarfile, 'data_filter'):
+ tf.extraction_filter = getattr(tarfile, 'data_filter',
+ (lambda member, path: member))
+ if member:
+ tf.extract(member=member, path=dest_dir)
+ else:
+ tf.extractall(path=dest_dir)
+
+def cpio_extract(archive, output_path):
+ cwd = os.getcwd()
+ os.chdir(output_path)
+ # Not passing 'check=True' as cpio exits with non-zero
+ # status if the archive contains any device nodes :-(
+ if type(archive) == str:
+ run(['cpio', '-i', '-F', archive],
+ stdout=DEVNULL, stderr=DEVNULL)
+ else:
+ run(['cpio', '-i'],
+ input=archive.read(),
+ stdout=DEVNULL, stderr=DEVNULL)
+ os.chdir(cwd)
+
+def zip_extract(archive, dest_dir, member=None):
+ with zipfile.ZipFile(archive, 'r') as zf:
+ if member:
+ zf.extract(member=member, path=dest_dir)
+ else:
+ zf.extractall(path=dest_dir)
+
+def deb_extract(archive, dest_dir, member=None):
+ cwd = os.getcwd()
+ os.chdir(dest_dir)
+ try:
+ proc = run(['ar', 't', archive],
+ check=True, capture_output=True, encoding='utf8')
+ file_path = proc.stdout.split()[2]
+ check_call(['ar', 'x', archive, file_path],
+ stdout=DEVNULL, stderr=DEVNULL)
+ tar_extract(file_path, dest_dir, member)
+ finally:
+ os.chdir(cwd)
+
+'''
+@params archive: filename, Asset, or file-like object to extract
+@params dest_dir: target directory to extract into
+@params member: optional member file to limit extraction to
+
+Extracts @archive into @dest_dir. All files are extracted
+unless @member specifies a limit.
+
+If @format is None, heuristics will be applied to guess the format
+from the filename or Asset URL. @format must be non-None if @archive
+is a file-like object.
+'''
+def archive_extract(archive, dest_dir, format=None, member=None):
+ if format is None:
+ format = guess_archive_format(archive)
+ if type(archive) == Asset:
+ archive = str(archive)
+
+ if format == "tar":
+ tar_extract(archive, dest_dir, member)
+ elif format == "zip":
+ zip_extract(archive, dest_dir, member)
+ elif format == "cpio":
+ if member is not None:
+ raise Exception("Unable to filter cpio extraction")
+ cpio_extract(archive, dest_dir)
+ elif format == "deb":
+ if type(archive) != str:
+ raise Exception("Unable to use file-like object with deb archives")
+ deb_extract(archive, dest_dir, "./" + member)
+ else:
+ raise Exception(f"Unknown archive format {format}")
+
+'''
+@params archive: filename, or Asset to guess
+
+Guess the format of @compressed, raising an exception if
+no format can be determined
+'''
+def guess_archive_format(archive):
+ if type(archive) == Asset:
+ archive = urlparse(archive.url).path
+ elif type(archive) != str:
+ raise Exception(f"Unable to guess archive format for {archive}")
+
+ if ".tar." in archive or archive.endswith("tgz"):
+ return "tar"
+ elif archive.endswith(".zip"):
+ return "zip"
+ elif archive.endswith(".cpio"):
+ return "cpio"
+ elif archive.endswith(".deb") or archive.endswith(".udeb"):
+ return "deb"
+ else:
+ raise Exception(f"Unknown archive format for {archive}")
diff --git a/tests/functional/qemu_test/asset.py b/tests/functional/qemu_test/asset.py
index f126cd5..f073069 100644
--- a/tests/functional/qemu_test/asset.py
+++ b/tests/functional/qemu_test/asset.py
@@ -9,13 +9,13 @@ import hashlib
import logging
import os
import stat
-import subprocess
import sys
import unittest
import urllib.request
from time import sleep
from pathlib import Path
from shutil import copyfileobj
+from urllib.error import HTTPError
# Instances of this class must be declared as class level variables
@@ -40,6 +40,9 @@ class Asset:
return "Asset: url=%s hash=%s cache=%s" % (
self.url, self.hash, self.cache_file)
+ def __str__(self):
+ return str(self.cache_file)
+
def _check(self, cache_file):
if self.hash is None:
return True
@@ -63,6 +66,12 @@ class Asset:
def valid(self):
return self.cache_file.exists() and self._check(self.cache_file)
+ def fetchable(self):
+ return not os.environ.get("QEMU_TEST_NO_DOWNLOAD", False)
+
+ def available(self):
+ return self.valid() or self.fetchable()
+
def _wait_for_other_download(self, tmp_cache_file):
# Another thread already seems to download the asset, so wait until
# it is done, while also checking the size to see whether it is stuck
@@ -101,7 +110,7 @@ class Asset:
self.cache_file, self.url)
return str(self.cache_file)
- if os.environ.get("QEMU_TEST_NO_DOWNLOAD", False):
+ if not self.fetchable():
raise Exception("Asset cache is invalid and downloads disabled")
self.log.info("Downloading %s to %s...", self.url, self.cache_file)
@@ -162,7 +171,18 @@ class Asset:
for name, asset in vars(test.__class__).items():
if name.startswith("ASSET_") and type(asset) == Asset:
log.info("Attempting to cache '%s'" % asset)
- asset.fetch()
+ try:
+ asset.fetch()
+ except HTTPError as e:
+ # Treat 404 as fatal, since it is highly likely to
+ # indicate a broken test rather than a transient
+ # server or networking problem
+ if e.code == 404:
+ raise
+
+ log.debug(f"HTTP error {e.code} from {asset.url} " +
+ "skipping asset precache")
+
log.removeHandler(handler)
def precache_suite(suite):
diff --git a/tests/functional/qemu_test/cmd.py b/tests/functional/qemu_test/cmd.py
index 11c8334..dc5f422 100644
--- a/tests/functional/qemu_test/cmd.py
+++ b/tests/functional/qemu_test/cmd.py
@@ -14,66 +14,18 @@
import logging
import os
import os.path
-import subprocess
-from .config import BUILD_DIR
-
-def has_cmd(name, args=None):
- """
- This function is for use in a @skipUnless decorator, e.g.:
-
- @skipUnless(*has_cmd('sudo -n', ('sudo', '-n', 'true')))
- def test_something_that_needs_sudo(self):
- ...
- """
-
- if args is None:
- args = ('which', name)
-
- try:
- _, stderr, exitcode = run_cmd(args)
- except Exception as e:
- exitcode = -1
- stderr = str(e)
-
- if exitcode != 0:
- cmd_line = ' '.join(args)
- err = f'{name} required, but "{cmd_line}" failed: {stderr.strip()}'
- return (False, err)
- else:
- return (True, '')
-
-def has_cmds(*cmds):
+def which(tool):
+ """ looks up the full path for @tool, returns None if not found
+ or if @tool does not have executable permissions.
"""
- This function is for use in a @skipUnless decorator and
- allows checking for the availability of multiple commands, e.g.:
-
- @skipUnless(*has_cmds(('cmd1', ('cmd1', '--some-parameter')),
- 'cmd2', 'cmd3'))
- def test_something_that_needs_cmd1_and_cmd2(self):
- ...
- """
-
- for cmd in cmds:
- if isinstance(cmd, str):
- cmd = (cmd,)
-
- ok, errstr = has_cmd(*cmd)
- if not ok:
- return (False, errstr)
-
- return (True, '')
-
-def run_cmd(args):
- subp = subprocess.Popen(args,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- universal_newlines=True)
- stdout, stderr = subp.communicate()
- ret = subp.returncode
-
- return (stdout, stderr, ret)
+ paths=os.getenv('PATH')
+ for p in paths.split(os.path.pathsep):
+ p = os.path.join(p, tool)
+ if os.access(p, os.X_OK):
+ return p
+ return None
def is_readable_executable_file(path):
return os.path.isfile(path) and os.access(path, os.R_OK | os.X_OK)
@@ -241,10 +193,10 @@ def get_qemu_img(test):
# If qemu-img has been built, use it, otherwise the system wide one
# will be used.
- qemu_img = os.path.join(BUILD_DIR, 'qemu-img')
+ qemu_img = test.build_file('qemu-img')
if os.path.exists(qemu_img):
return qemu_img
- (has_system_qemu_img, errmsg) = has_cmd('qemu-img')
- if has_system_qemu_img:
- return 'qemu-img'
- test.skipTest(errmsg)
+ qemu_img = which('qemu-img')
+ if qemu_img is not None:
+ return qemu_img
+ test.skipTest(f"qemu-img not found in build dir or '$PATH'")
diff --git a/tests/functional/qemu_test/decorators.py b/tests/functional/qemu_test/decorators.py
new file mode 100644
index 0000000..df088bc
--- /dev/null
+++ b/tests/functional/qemu_test/decorators.py
@@ -0,0 +1,107 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Decorators useful in functional tests
+
+import os
+import platform
+from unittest import skipUnless
+
+from .cmd import which
+
+'''
+Decorator to skip execution of a test if the list
+of command binaries is not available in $PATH.
+Example:
+
+ @skipIfMissingCommands("mkisofs", "losetup")
+'''
+def skipIfMissingCommands(*args):
+ def has_cmds(cmdlist):
+ for cmd in cmdlist:
+ if not which(cmd):
+ return False
+ return True
+
+ return skipUnless(lambda: has_cmds(args),
+ 'required command(s) "%s" not installed' %
+ ", ".join(args))
+
+'''
+Decorator to skip execution of a test if the current
+host machine does not match one of the permitted
+machines.
+Example
+
+ @skipIfNotMachine("x86_64", "aarch64")
+'''
+def skipIfNotMachine(*args):
+ return skipUnless(lambda: platform.machine() in args,
+ 'not running on one of the required machine(s) "%s"' %
+ ", ".join(args))
+
+'''
+Decorator to skip execution of flaky tests, unless
+the $QEMU_TEST_FLAKY_TESTS environment variable is set.
+A bug URL must be provided that documents the observed
+failure behaviour, so it can be tracked & re-evaluated
+in future.
+
+Historical tests may be providing "None" as the bug_url
+but this should not be done for new test.
+
+Example:
+
+ @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/NNN")
+'''
+def skipFlakyTest(bug_url):
+ if bug_url is None:
+ bug_url = "FIXME: reproduce flaky test and file bug report or remove"
+ return skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'),
+ f'Test is unstable: {bug_url}')
+
+'''
+Decorator to skip execution of tests which are likely
+to execute untrusted commands on the host, or commands
+which process untrusted code, unless the
+$QEMU_TEST_ALLOW_UNTRUSTED_CODE env var is set.
+Example:
+
+ @skipUntrustedTest()
+'''
+def skipUntrustedTest():
+ return skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'),
+ 'Test runs untrusted code / processes untrusted data')
+
+'''
+Decorator to skip execution of tests which need large
+data storage (over around 500MB-1GB mark) on the host,
+unless the $QEMU_TEST_ALLOW_LARGE_STORAGE environment
+variable is set
+
+Example:
+
+ @skipBigDataTest()
+'''
+def skipBigDataTest():
+ return skipUnless(os.getenv('QEMU_TEST_ALLOW_LARGE_STORAGE'),
+ 'Test requires large host storage space')
+
+'''
+Decorator to skip execution of a test if the list
+of python imports is not available.
+Example:
+
+ @skipIfMissingImports("numpy", "cv2")
+'''
+def skipIfMissingImports(*args):
+ def has_imports(importlist):
+ for impname in importlist:
+ try:
+ import impname
+ except ImportError:
+ return False
+ return True
+
+ return skipUnless(lambda: has_imports(args),
+ 'required import(s) "%s" not installed' %
+ ", ".join(args))
diff --git a/tests/functional/qemu_test/linuxkernel.py b/tests/functional/qemu_test/linuxkernel.py
index 2b5b9a5..2c95981 100644
--- a/tests/functional/qemu_test/linuxkernel.py
+++ b/tests/functional/qemu_test/linuxkernel.py
@@ -3,11 +3,9 @@
# 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 os
-
from .testcase import QemuSystemTest
-from .cmd import run_cmd, wait_for_console_pattern
-from .utils import archive_extract
+from .cmd import wait_for_console_pattern
+
class LinuxKernelTest(QemuSystemTest):
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
@@ -28,26 +26,3 @@ class LinuxKernelTest(QemuSystemTest):
self.vm.launch()
if wait_for:
self.wait_for_console_pattern(wait_for)
-
- def extract_from_deb(self, deb_path, path):
- """
- Extracts a file from a deb package into the test workdir
-
- :param deb_path: path to the deb archive
- :param path: path within the deb archive of the file to be extracted
- :returns: path of the extracted file
- """
- cwd = os.getcwd()
- os.chdir(self.workdir)
- (stdout, stderr, ret) = run_cmd(['ar', 't', deb_path])
- file_path = stdout.split()[2]
- run_cmd(['ar', 'x', deb_path, file_path])
- archive_extract(file_path, self.workdir)
- os.chdir(cwd)
- # Return complete path to extracted file. Because callers to
- # extract_from_deb() specify 'path' with a leading slash, it is
- # necessary to use os.path.relpath() as otherwise os.path.join()
- # interprets it as an absolute path and drops the self.workdir part.
- return os.path.normpath(os.path.join(self.workdir,
- os.path.relpath(path, '/')))
-
diff --git a/tests/functional/qemu_test/tesseract.py b/tests/functional/qemu_test/tesseract.py
index db44102..ede6c65 100644
--- a/tests/functional/qemu_test/tesseract.py
+++ b/tests/functional/qemu_test/tesseract.py
@@ -5,30 +5,19 @@
# 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 re
import logging
+from subprocess import run
-from . import has_cmd, run_cmd
-
-def tesseract_available(expected_version):
- (has_tesseract, _) = has_cmd('tesseract')
- if not has_tesseract:
- return False
- (stdout, stderr, ret) = run_cmd([ 'tesseract', '--version'])
- if ret:
- return False
- version = stdout.split()[1]
- return int(version.split('.')[0]) >= expected_version
def tesseract_ocr(image_path, tesseract_args=''):
console_logger = logging.getLogger('console')
console_logger.debug(image_path)
- (stdout, stderr, ret) = run_cmd(['tesseract', image_path,
- 'stdout'])
- if ret:
+ proc = run(['tesseract', image_path, 'stdout'],
+ capture_output=True, encoding='utf8')
+ if proc.returncode:
return None
lines = []
- for line in stdout.split('\n'):
+ for line in proc.stdout.split('\n'):
sline = line.strip()
if len(sline):
console_logger.debug(sline)
diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py
index 90ae59e..869f394 100644
--- a/tests/functional/qemu_test/testcase.py
+++ b/tests/functional/qemu_test/testcase.py
@@ -13,19 +13,22 @@
import logging
import os
+from pathlib import Path
import pycotap
import shutil
-import subprocess
+from subprocess import run
import sys
+import tempfile
import unittest
import uuid
from qemu.machine import QEMUMachine
from qemu.utils import kvm_available, tcg_available
+from .archive import archive_extract
from .asset import Asset
-from .cmd import run_cmd
from .config import BUILD_DIR
+from .uncompress import uncompress
class QemuBaseTest(unittest.TestCase):
@@ -37,17 +40,169 @@ class QemuBaseTest(unittest.TestCase):
log = None
logdir = None
+ '''
+ @params compressed: filename, Asset, or file-like object to uncompress
+ @params format: optional compression format (gzip, lzma)
+
+ Uncompresses @compressed into the scratch directory.
+
+ If @format is None, heuristics will be applied to guess the format
+ from the filename or Asset URL. @format must be non-None if @uncompressed
+ is a file-like object.
+
+ Returns the fully qualified path to the uncompressed file
+ '''
+ def uncompress(self, compressed, format=None):
+ self.log.debug(f"Uncompress {compressed} format={format}")
+ if type(compressed) == Asset:
+ compressed.fetch()
+
+ (name, ext) = os.path.splitext(str(compressed))
+ uncompressed = self.scratch_file(os.path.basename(name))
+
+ uncompress(compressed, uncompressed, format)
+
+ return uncompressed
+
+ '''
+ @params archive: filename, Asset, or file-like object to extract
+ @params format: optional archive format (tar, zip, deb, cpio)
+ @params sub_dir: optional sub-directory to extract into
+ @params member: optional member file to limit extraction to
+
+ Extracts @archive into the scratch directory, or a directory beneath
+ named by @sub_dir. All files are extracted unless @member specifies
+ a limit.
+
+ If @format is None, heuristics will be applied to guess the format
+ from the filename or Asset URL. @format must be non-None if @archive
+ is a file-like object.
+
+ If @member is non-None, returns the fully qualified path to @member
+ '''
+ def archive_extract(self, archive, format=None, sub_dir=None, member=None):
+ self.log.debug(f"Extract {archive} format={format}" +
+ f"sub_dir={sub_dir} member={member}")
+ if type(archive) == Asset:
+ archive.fetch()
+ if sub_dir is None:
+ archive_extract(archive, self.scratch_file(), format, member)
+ else:
+ archive_extract(archive, self.scratch_file(sub_dir),
+ format, member)
+
+ if member is not None:
+ return self.scratch_file(member)
+ return None
+
+ '''
+ Create a temporary directory suitable for storing UNIX
+ socket paths.
+
+ Returns: a tempfile.TemporaryDirectory instance
+ '''
+ def socket_dir(self):
+ if self.socketdir is None:
+ self.socketdir = tempfile.TemporaryDirectory(
+ prefix="qemu_func_test_sock_")
+ return self.socketdir
+
+ '''
+ @params args list of zero or more subdirectories or file
+
+ Construct a path for accessing a data file located
+ relative to the source directory that is the root for
+ functional tests.
+
+ @args may be an empty list to reference the root dir
+ itself, may be a single element to reference a file in
+ the root directory, or may be multiple elements to
+ reference a file nested below. The path components
+ will be joined using the platform appropriate path
+ separator.
+
+ Returns: string representing a file path
+ '''
+ def data_file(self, *args):
+ return str(Path(Path(__file__).parent.parent, *args))
+
+ '''
+ @params args list of zero or more subdirectories or file
+
+ Construct a path for accessing a data file located
+ relative to the build directory root.
+
+ @args may be an empty list to reference the build dir
+ itself, may be a single element to reference a file in
+ the build directory, or may be multiple elements to
+ reference a file nested below. The path components
+ will be joined using the platform appropriate path
+ separator.
+
+ Returns: string representing a file path
+ '''
+ def build_file(self, *args):
+ return str(Path(BUILD_DIR, *args))
+
+ '''
+ @params args list of zero or more subdirectories or file
+
+ Construct a path for accessing/creating a scratch file
+ located relative to a temporary directory dedicated to
+ this test case. The directory and its contents will be
+ purged upon completion of the test.
+
+ @args may be an empty list to reference the scratch dir
+ itself, may be a single element to reference a file in
+ the scratch directory, or may be multiple elements to
+ reference a file nested below. The path components
+ will be joined using the platform appropriate path
+ separator.
+
+ Returns: string representing a file path
+ '''
+ def scratch_file(self, *args):
+ return str(Path(self.workdir, *args))
+
+ '''
+ @params args list of zero or more subdirectories or file
+
+ Construct a path for accessing/creating a log file
+ located relative to a temporary directory dedicated to
+ this test case. The directory and its log files will be
+ preserved upon completion of the test.
+
+ @args may be an empty list to reference the log dir
+ itself, may be a single element to reference a file in
+ the log directory, or may be multiple elements to
+ reference a file nested below. The path components
+ will be joined using the platform appropriate path
+ separator.
+
+ Returns: string representing a file path
+ '''
+ def log_file(self, *args):
+ return str(Path(self.outputdir, *args))
+
+ def assets_available(self):
+ for name, asset in vars(self.__class__).items():
+ if name.startswith("ASSET_") and type(asset) == Asset:
+ if not asset.available():
+ self.log.debug(f"Asset {asset.url} not available")
+ return False
+ return True
+
def setUp(self, bin_prefix):
self.assertIsNotNone(self.qemu_bin, 'QEMU_TEST_QEMU_BINARY must be set')
self.arch = self.qemu_bin.split('-')[-1]
+ self.socketdir = None
- self.outputdir = os.path.join(BUILD_DIR, 'tests', 'functional',
- self.arch, self.id())
+ self.outputdir = self.build_file('tests', 'functional',
+ self.arch, self.id())
self.workdir = os.path.join(self.outputdir, 'scratch')
os.makedirs(self.workdir, exist_ok=True)
- self.logdir = self.outputdir
- self.log_filename = os.path.join(self.logdir, 'base.log')
+ self.log_filename = self.log_file('base.log')
self.log = logging.getLogger('qemu-test')
self.log.setLevel(logging.DEBUG)
self._log_fh = logging.FileHandler(self.log_filename, mode='w')
@@ -62,9 +217,15 @@ class QemuBaseTest(unittest.TestCase):
self.machinelog.setLevel(logging.DEBUG)
self.machinelog.addHandler(self._log_fh)
+ if not self.assets_available():
+ self.skipTest('One or more assets is not available')
+
def tearDown(self):
if "QEMU_TEST_KEEP_SCRATCH" not in os.environ:
shutil.rmtree(self.workdir)
+ if self.socketdir is not None:
+ shutil.rmtree(self.socketdir.name)
+ self.socketdir = None
self.machinelog.removeHandler(self._log_fh)
self.log.removeHandler(self._log_fh)
@@ -100,11 +261,11 @@ class QemuUserTest(QemuBaseTest):
self._ldpath.append(os.path.abspath(ldpath))
def run_cmd(self, bin_path, args=[]):
- return subprocess.run([self.qemu_bin]
- + ["-L %s" % ldpath for ldpath in self._ldpath]
- + [bin_path]
- + args,
- text=True, capture_output=True)
+ return run([self.qemu_bin]
+ + ["-L %s" % ldpath for ldpath in self._ldpath]
+ + [bin_path]
+ + args,
+ text=True, capture_output=True)
class QemuSystemTest(QemuBaseTest):
"""Facilitates system emulation tests."""
@@ -120,7 +281,7 @@ class QemuSystemTest(QemuBaseTest):
console_log = logging.getLogger('console')
console_log.setLevel(logging.DEBUG)
- self.console_log_name = os.path.join(self.logdir, 'console.log')
+ self.console_log_name = self.log_file('console.log')
self._console_log_fh = logging.FileHandler(self.console_log_name,
mode='w')
self._console_log_fh.setLevel(logging.DEBUG)
@@ -131,7 +292,9 @@ class QemuSystemTest(QemuBaseTest):
def set_machine(self, machinename):
# TODO: We should use QMP to get the list of available machines
if not self._machinehelp:
- self._machinehelp = run_cmd([self.qemu_bin, '-M', 'help'])[0];
+ self._machinehelp = run(
+ [self.qemu_bin, '-M', 'help'],
+ capture_output=True, check=True, encoding='utf8').stdout
if self._machinehelp.find(machinename) < 0:
self.skipTest('no support for machine ' + machinename)
self.machine = machinename
@@ -159,22 +322,24 @@ class QemuSystemTest(QemuBaseTest):
"available" % accelerator)
def require_netdev(self, netdevname):
- netdevhelp = run_cmd([self.qemu_bin,
- '-M', 'none', '-netdev', 'help'])[0];
- if netdevhelp.find('\n' + netdevname + '\n') < 0:
+ help = run([self.qemu_bin,
+ '-M', 'none', '-netdev', 'help'],
+ capture_output=True, check=True, encoding='utf8').stdout;
+ if help.find('\n' + netdevname + '\n') < 0:
self.skipTest('no support for " + netdevname + " networking')
def require_device(self, devicename):
- devhelp = run_cmd([self.qemu_bin,
- '-M', 'none', '-device', 'help'])[0];
- if devhelp.find(devicename) < 0:
+ help = run([self.qemu_bin,
+ '-M', 'none', '-device', 'help'],
+ capture_output=True, check=True, encoding='utf8').stdout;
+ if help.find(devicename) < 0:
self.skipTest('no support for device ' + devicename)
def _new_vm(self, name, *args):
vm = QEMUMachine(self.qemu_bin,
name=name,
base_temp_dir=self.workdir,
- log_dir=self.logdir)
+ log_dir=self.log_file())
self.log.debug('QEMUMachine "%s" created', name)
self.log.debug('QEMUMachine "%s" temp_dir: %s', name, vm.temp_dir)
diff --git a/tests/functional/qemu_test/tuxruntest.py b/tests/functional/qemu_test/tuxruntest.py
index ab3b27d..7227a83 100644
--- a/tests/functional/qemu_test/tuxruntest.py
+++ b/tests/functional/qemu_test/tuxruntest.py
@@ -11,12 +11,12 @@
import os
import stat
-import time
+from subprocess import check_call, DEVNULL
from qemu_test import QemuSystemTest
-from qemu_test import exec_command, exec_command_and_wait_for_pattern
+from qemu_test import exec_command_and_wait_for_pattern
from qemu_test import wait_for_console_pattern
-from qemu_test import has_cmd, run_cmd, get_qemu_img
+from qemu_test import which, get_qemu_img
class TuxRunBaselineTest(QemuSystemTest):
@@ -39,10 +39,8 @@ class TuxRunBaselineTest(QemuSystemTest):
super().setUp()
# We need zstd for all the tuxrun tests
- (has_zstd, msg) = has_cmd('zstd')
- if has_zstd is False:
- self.skipTest(msg)
- self.zstd = 'zstd'
+ if which('zstd') is None:
+ self.skipTest("zstd not found in $PATH")
# Pre-init TuxRun specific settings: Most machines work with
# reasonable defaults but we sometimes need to tweak the
@@ -77,10 +75,11 @@ class TuxRunBaselineTest(QemuSystemTest):
kernel_image = kernel_asset.fetch()
disk_image_zst = rootfs_asset.fetch()
- disk_image = self.workdir + "/rootfs.ext4"
+ disk_image = self.scratch_file("rootfs.ext4")
- run_cmd([self.zstd, "-f", "-d", disk_image_zst,
- "-o", disk_image])
+ check_call(['zstd', "-f", "-d", disk_image_zst,
+ "-o", disk_image],
+ stdout=DEVNULL, stderr=DEVNULL)
# zstd copies source archive permissions for the output
# file, so must make this writable for QEMU
os.chmod(disk_image, stat.S_IRUSR | stat.S_IWUSR)
diff --git a/tests/functional/qemu_test/uncompress.py b/tests/functional/qemu_test/uncompress.py
new file mode 100644
index 0000000..6d02ded
--- /dev/null
+++ b/tests/functional/qemu_test/uncompress.py
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Utilities for python-based QEMU tests
+#
+# Copyright 2024 Red Hat, Inc.
+#
+# Authors:
+# Thomas Huth <thuth@redhat.com>
+
+import gzip
+import lzma
+import os
+import shutil
+from urllib.parse import urlparse
+
+from .asset import Asset
+
+
+def gzip_uncompress(gz_path, output_path):
+ if os.path.exists(output_path):
+ return
+ with gzip.open(gz_path, 'rb') as gz_in:
+ try:
+ with open(output_path, 'wb') as raw_out:
+ shutil.copyfileobj(gz_in, raw_out)
+ except:
+ os.remove(output_path)
+ raise
+
+def lzma_uncompress(xz_path, output_path):
+ if os.path.exists(output_path):
+ return
+ with lzma.open(xz_path, 'rb') as lzma_in:
+ try:
+ with open(output_path, 'wb') as raw_out:
+ shutil.copyfileobj(lzma_in, raw_out)
+ except:
+ os.remove(output_path)
+ raise
+
+'''
+@params compressed: filename, Asset, or file-like object to uncompress
+@params uncompressed: filename to uncompress into
+@params format: optional compression format (gzip, lzma)
+
+Uncompresses @compressed into @uncompressed
+
+If @format is None, heuristics will be applied to guess the format
+from the filename or Asset URL. @format must be non-None if @uncompressed
+is a file-like object.
+
+Returns the fully qualified path to the uncompessed file
+'''
+def uncompress(compressed, uncompressed, format=None):
+ if format is None:
+ format = guess_uncompress_format(compressed)
+
+ if format == "xz":
+ lzma_uncompress(str(compressed), uncompressed)
+ elif format == "gz":
+ gzip_uncompress(str(compressed), uncompressed)
+ else:
+ raise Exception(f"Unknown compression format {format}")
+
+'''
+@params compressed: filename, Asset, or file-like object to guess
+
+Guess the format of @compressed, raising an exception if
+no format can be determined
+'''
+def guess_uncompress_format(compressed):
+ if type(compressed) == Asset:
+ compressed = urlparse(compressed.url).path
+ elif type(compressed) != str:
+ raise Exception(f"Unable to guess compression cformat for {compressed}")
+
+ (name, ext) = os.path.splitext(compressed)
+ if ext == ".xz":
+ return "xz"
+ elif ext == ".gz":
+ return "gz"
+ else:
+ raise Exception(f"Unknown compression format for {compressed}")
diff --git a/tests/functional/qemu_test/utils.py b/tests/functional/qemu_test/utils.py
index 1bf1c41..e7c8de8 100644
--- a/tests/functional/qemu_test/utils.py
+++ b/tests/functional/qemu_test/utils.py
@@ -8,12 +8,14 @@
# 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 gzip
-import lzma
import os
-import shutil
-import subprocess
-import tarfile
+
+from qemu.utils import get_info_usernet_hostfwd_port
+
+
+def get_usernet_hostfwd_port(vm):
+ res = vm.cmd('human-monitor-command', command_line='info usernet')
+ return get_info_usernet_hostfwd_port(res)
"""
Round up to next power of 2
@@ -35,43 +37,3 @@ def image_pow2ceil_expand(path):
if size != size_aligned:
with open(path, 'ab+') as fd:
fd.truncate(size_aligned)
-
-def archive_extract(archive, dest_dir, member=None):
- with tarfile.open(archive) as tf:
- if hasattr(tarfile, 'data_filter'):
- tf.extraction_filter = getattr(tarfile, 'data_filter',
- (lambda member, path: member))
- if member:
- tf.extract(member=member, path=dest_dir)
- else:
- tf.extractall(path=dest_dir)
-
-def gzip_uncompress(gz_path, output_path):
- if os.path.exists(output_path):
- return
- with gzip.open(gz_path, 'rb') as gz_in:
- try:
- with open(output_path, 'wb') as raw_out:
- shutil.copyfileobj(gz_in, raw_out)
- except:
- os.remove(output_path)
- raise
-
-def lzma_uncompress(xz_path, output_path):
- if os.path.exists(output_path):
- return
- with lzma.open(xz_path, 'rb') as lzma_in:
- try:
- with open(output_path, 'wb') as raw_out:
- shutil.copyfileobj(lzma_in, raw_out)
- except:
- os.remove(output_path)
- raise
-
-def cpio_extract(cpio_handle, output_path):
- cwd = os.getcwd()
- os.chdir(output_path)
- subprocess.run(['cpio', '-i'],
- input=cpio_handle.read(),
- stderr=subprocess.DEVNULL)
- os.chdir(cwd)
diff --git a/tests/functional/test_aarch64_aspeed.py b/tests/functional/test_aarch64_aspeed.py
index 59916ef..141d863 100644..100755
--- a/tests/functional/test_aarch64_aspeed.py
+++ b/tests/functional/test_aarch64_aspeed.py
@@ -6,13 +6,12 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import sys
import os
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
from qemu_test import exec_command_and_wait_for_pattern
-from qemu_test.utils import archive_extract
+
class AST2x00MachineSDK(QemuSystemTest):
@@ -35,30 +34,31 @@ class AST2x00MachineSDK(QemuSystemTest):
def test_aarch64_ast2700_evb_sdk_v09_02(self):
self.set_machine('ast2700-evb')
- image_path = self.ASSET_SDK_V902_AST2700.fetch()
- archive_extract(image_path, self.workdir)
+ self.archive_extract(self.ASSET_SDK_V902_AST2700)
num_cpu = 4
- image_dir = self.workdir + '/ast2700-default/'
- uboot_size = os.path.getsize(image_dir + 'u-boot-nodtb.bin')
+ uboot_size = os.path.getsize(self.scratch_file('ast2700-default',
+ 'u-boot-nodtb.bin'))
uboot_dtb_load_addr = hex(0x400000000 + uboot_size)
load_images_list = [
{
'addr': '0x400000000',
- 'file': image_dir + 'u-boot-nodtb.bin'
+ 'file': self.scratch_file('ast2700-default',
+ 'u-boot-nodtb.bin')
},
{
'addr': str(uboot_dtb_load_addr),
- 'file': image_dir + 'u-boot.dtb'
+ 'file': self.scratch_file('ast2700-default', 'u-boot.dtb')
},
{
'addr': '0x430000000',
- 'file': image_dir + 'bl31.bin'
+ 'file': self.scratch_file('ast2700-default', 'bl31.bin')
},
{
'addr': '0x430080000',
- 'file': image_dir + 'optee/tee-raw.bin'
+ 'file': self.scratch_file('ast2700-default', 'optee',
+ 'tee-raw.bin')
}
]
@@ -75,7 +75,8 @@ class AST2x00MachineSDK(QemuSystemTest):
self.vm.add_args('-smp', str(num_cpu))
self.vm.add_args('-device',
'tmp105,bus=aspeed.i2c.bus.1,address=0x4d,id=tmp-test')
- self.do_test_aarch64_aspeed_sdk_start(image_dir + 'image-bmc')
+ self.do_test_aarch64_aspeed_sdk_start(
+ self.scratch_file('ast2700-default', 'image-bmc'))
wait_for_console_pattern(self, 'ast2700-default login:')
diff --git a/tests/functional/test_aarch64_raspi3.py b/tests/functional/test_aarch64_raspi3.py
index 369f95a..74f6630 100755
--- a/tests/functional/test_aarch64_raspi3.py
+++ b/tests/functional/test_aarch64_raspi3.py
@@ -7,9 +7,6 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import os
-from zipfile import ZipFile
-
from qemu_test import LinuxKernelTest, Asset
@@ -22,11 +19,7 @@ class Aarch64Raspi3Machine(LinuxKernelTest):
def test_aarch64_raspi3_atf(self):
efi_name = 'RPI_EFI.fd'
- zip_path = self.ASSET_RPI3_UEFI.fetch()
-
- with ZipFile(zip_path, 'r') as zf:
- zf.extract(efi_name, path=self.workdir)
- efi_fd = os.path.join(self.workdir, efi_name)
+ efi_fd = self.archive_extract(self.ASSET_RPI3_UEFI, member=efi_name)
self.set_machine('raspi3b')
self.vm.set_console(console_index=1)
diff --git a/tests/functional/test_aarch64_raspi4.py b/tests/functional/test_aarch64_raspi4.py
index e5c9f77..7a4302b 100755
--- a/tests/functional/test_aarch64_raspi4.py
+++ b/tests/functional/test_aarch64_raspi4.py
@@ -5,11 +5,8 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import os
-
from qemu_test import LinuxKernelTest, Asset
from qemu_test import exec_command_and_wait_for_pattern
-from qemu_test.utils import gzip_uncompress
class Aarch64Raspi4Machine(LinuxKernelTest):
@@ -32,9 +29,10 @@ class Aarch64Raspi4Machine(LinuxKernelTest):
'7c0b16d1853772f6f4c3ca63e789b3b9ff4936efac9c8a01fb0c98c05c7a7648')
def test_arm_raspi4(self):
- deb_path = self.ASSET_KERNEL_20190215.fetch()
- kernel_path = self.extract_from_deb(deb_path, '/boot/kernel8.img')
- dtb_path = self.extract_from_deb(deb_path, '/boot/bcm2711-rpi-4-b.dtb')
+ kernel_path = self.archive_extract(self.ASSET_KERNEL_20190215,
+ member='boot/kernel8.img')
+ dtb_path = self.archive_extract(self.ASSET_KERNEL_20190215,
+ member='boot/bcm2711-rpi-4-b.dtb')
self.set_machine('raspi4b')
self.vm.set_console()
@@ -60,12 +58,11 @@ class Aarch64Raspi4Machine(LinuxKernelTest):
def test_arm_raspi4_initrd(self):
- deb_path = self.ASSET_KERNEL_20190215.fetch()
- kernel_path = self.extract_from_deb(deb_path, '/boot/kernel8.img')
- dtb_path = self.extract_from_deb(deb_path, '/boot/bcm2711-rpi-4-b.dtb')
- initrd_path_gz = self.ASSET_INITRD.fetch()
- initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
- gzip_uncompress(initrd_path_gz, initrd_path)
+ kernel_path = self.archive_extract(self.ASSET_KERNEL_20190215,
+ member='boot/kernel8.img')
+ dtb_path = self.archive_extract(self.ASSET_KERNEL_20190215,
+ member='boot/bcm2711-rpi-4-b.dtb')
+ initrd_path = self.uncompress(self.ASSET_INITRD)
self.set_machine('raspi4b')
self.vm.set_console()
diff --git a/tests/functional/test_aarch64_sbsaref.py b/tests/functional/test_aarch64_sbsaref.py
index 52507af..99cfb6f 100755
--- a/tests/functional/test_aarch64_sbsaref.py
+++ b/tests/functional/test_aarch64_sbsaref.py
@@ -8,12 +8,10 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import os
-
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
from qemu_test import interrupt_interactive_console_until_pattern
-from qemu_test.utils import lzma_uncompress
+
def fetch_firmware(test):
"""
@@ -31,14 +29,10 @@ def fetch_firmware(test):
"""
# Secure BootRom (TF-A code)
- fs0_xz_path = Aarch64SbsarefMachine.ASSET_FLASH0.fetch()
- fs0_path = os.path.join(test.workdir, "SBSA_FLASH0.fd")
- lzma_uncompress(fs0_xz_path, fs0_path)
+ fs0_path = test.uncompress(Aarch64SbsarefMachine.ASSET_FLASH0)
# Non-secure rom (UEFI and EFI variables)
- fs1_xz_path = Aarch64SbsarefMachine.ASSET_FLASH1.fetch()
- fs1_path = os.path.join(test.workdir, "SBSA_FLASH1.fd")
- lzma_uncompress(fs1_xz_path, fs1_path)
+ fs1_path = test.uncompress(Aarch64SbsarefMachine.ASSET_FLASH1)
for path in [fs0_path, fs1_path]:
with open(path, "ab+") as fd:
diff --git a/tests/functional/test_aarch64_sbsaref_alpine.py b/tests/functional/test_aarch64_sbsaref_alpine.py
index ebc29b2..6dbc90f 100755
--- a/tests/functional/test_aarch64_sbsaref_alpine.py
+++ b/tests/functional/test_aarch64_sbsaref_alpine.py
@@ -12,7 +12,6 @@ import os
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
-from qemu_test import interrupt_interactive_console_until_pattern
from unittest import skipUnless
from test_aarch64_sbsaref import fetch_firmware
diff --git a/tests/functional/test_aarch64_sbsaref_freebsd.py b/tests/functional/test_aarch64_sbsaref_freebsd.py
index 80298dd..77ba2ba 100755
--- a/tests/functional/test_aarch64_sbsaref_freebsd.py
+++ b/tests/functional/test_aarch64_sbsaref_freebsd.py
@@ -12,7 +12,6 @@ import os
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
-from qemu_test import interrupt_interactive_console_until_pattern
from unittest import skipUnless
from test_aarch64_sbsaref import fetch_firmware
diff --git a/tests/functional/test_aarch64_virt.py b/tests/functional/test_aarch64_virt.py
index c967da4..08576b0 100755
--- a/tests/functional/test_aarch64_virt.py
+++ b/tests/functional/test_aarch64_virt.py
@@ -11,13 +11,12 @@
# SPDX-License-Identifier: GPL-2.0-or-later
import time
-import os
import logging
+from subprocess import check_call, DEVNULL
-from qemu_test import BUILD_DIR
from qemu_test import QemuSystemTest, Asset
from qemu_test import exec_command, wait_for_console_pattern
-from qemu_test import get_qemu_img, run_cmd
+from qemu_test import get_qemu_img
class Aarch64VirtMachine(QemuSystemTest):
@@ -54,8 +53,8 @@ class Aarch64VirtMachine(QemuSystemTest):
"mte=on,"
"gic-version=max,iommu=smmuv3")
self.vm.add_args("-smp", "2", "-m", "1024")
- self.vm.add_args('-bios', os.path.join(BUILD_DIR, 'pc-bios',
- 'edk2-aarch64-code.fd'))
+ self.vm.add_args('-bios', self.build_file('pc-bios',
+ 'edk2-aarch64-code.fd'))
self.vm.add_args("-drive", f"file={iso_path},media=cdrom,format=raw")
self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0')
self.vm.add_args('-object', 'rng-random,id=rng0,filename=/dev/urandom')
@@ -96,9 +95,10 @@ class Aarch64VirtMachine(QemuSystemTest):
# Also add a scratch block device
logger.info('creating scratch qcow2 image')
- image_path = os.path.join(self.workdir, 'scratch.qcow2')
+ image_path = self.scratch_file('scratch.qcow2')
qemu_img = get_qemu_img(self)
- run_cmd([qemu_img, 'create', '-f', 'qcow2', image_path, '8M'])
+ check_call([qemu_img, 'create', '-f', 'qcow2', image_path, '8M'],
+ stdout=DEVNULL, stderr=DEVNULL)
# Add the device
self.vm.add_args('-blockdev',
diff --git a/tests/functional/test_acpi_bits.py b/tests/functional/test_acpi_bits.py
index 63e2c53..20da435 100755
--- a/tests/functional/test_acpi_bits.py
+++ b/tests/functional/test_acpi_bits.py
@@ -31,56 +31,24 @@ including an upgraded acpica. The fork is located here:
https://gitlab.com/qemu-project/biosbits-bits .
"""
-import logging
import os
-import platform
import re
import shutil
import subprocess
-import tarfile
-import tempfile
-import zipfile
-from pathlib import Path
from typing import (
List,
Optional,
Sequence,
)
from qemu.machine import QEMUMachine
-from unittest import skipIf
-from qemu_test import QemuSystemTest, Asset
+from qemu_test import (QemuSystemTest, Asset, skipIfMissingCommands,
+ skipIfNotMachine)
-deps = ["xorriso", "mformat"] # dependent tools needed in the test setup/box.
-supported_platforms = ['x86_64'] # supported test platforms.
# default timeout of 120 secs is sometimes not enough for bits test.
BITS_TIMEOUT = 200
-def which(tool):
- """ looks up the full path for @tool, returns None if not found
- or if @tool does not have executable permissions.
- """
- paths=os.getenv('PATH')
- for p in paths.split(os.path.pathsep):
- p = os.path.join(p, tool)
- if os.path.exists(p) and os.access(p, os.X_OK):
- return p
- return None
-
-def missing_deps():
- """ returns True if any of the test dependent tools are absent.
- """
- for dep in deps:
- if which(dep) is None:
- return True
- return False
-
-def supported_platform():
- """ checks if the test is running on a supported platform.
- """
- return platform.machine() in supported_platforms
-
class QEMUBitsMachine(QEMUMachine): # pylint: disable=too-few-public-methods
"""
A QEMU VM, with isa-debugcon enabled and bits iso passed
@@ -123,9 +91,8 @@ class QEMUBitsMachine(QEMUMachine): # pylint: disable=too-few-public-methods
"""return the base argument to QEMU binary"""
return self._base_args
-@skipIf(not supported_platform() or missing_deps(),
- 'unsupported platform or dependencies (%s) not installed' \
- % ','.join(deps))
+@skipIfMissingCommands("xorriso", "mformat")
+@skipIfNotMachine("x86_64")
class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attributes
"""
ACPI and SMBIOS tests using biosbits.
@@ -149,7 +116,6 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._vm = None
- self._baseDir = None
self._debugcon_addr = '0x403'
self._debugcon_log = 'debugcon-log.txt'
@@ -164,29 +130,24 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute
def copy_bits_config(self):
""" copies the bios bits config file into bits.
"""
- config_file = 'bits-cfg.txt'
- bits_config_dir = os.path.join(self._baseDir, 'acpi-bits',
- 'bits-config')
- target_config_dir = os.path.join(self.workdir,
- 'bits-%d' %self.BITS_INTERNAL_VER,
- 'boot')
- self.assertTrue(os.path.exists(bits_config_dir))
+ bits_config_file = self.data_file('acpi-bits',
+ 'bits-config',
+ 'bits-cfg.txt')
+ target_config_dir = self.scratch_file('bits-%d' %
+ self.BITS_INTERNAL_VER,
+ 'boot')
+ self.assertTrue(os.path.exists(bits_config_file))
self.assertTrue(os.path.exists(target_config_dir))
- self.assertTrue(os.access(os.path.join(bits_config_dir,
- config_file), os.R_OK))
- shutil.copy2(os.path.join(bits_config_dir, config_file),
- target_config_dir)
+ shutil.copy2(bits_config_file, target_config_dir)
self.logger.info('copied config file %s to %s',
- config_file, target_config_dir)
+ bits_config_file, target_config_dir)
def copy_test_scripts(self):
"""copies the python test scripts into bits. """
- bits_test_dir = os.path.join(self._baseDir, 'acpi-bits',
- 'bits-tests')
- target_test_dir = os.path.join(self.workdir,
- 'bits-%d' %self.BITS_INTERNAL_VER,
- 'boot', 'python')
+ bits_test_dir = self.data_file('acpi-bits', 'bits-tests')
+ target_test_dir = self.scratch_file('bits-%d' % self.BITS_INTERNAL_VER,
+ 'boot', 'python')
self.assertTrue(os.path.exists(bits_test_dir))
self.assertTrue(os.path.exists(target_test_dir))
@@ -223,8 +184,8 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute
the directory where we have extracted our pre-built bits grub
tarball.
"""
- grub_x86_64_mods = os.path.join(self.workdir, 'grub-inst-x86_64-efi')
- grub_i386_mods = os.path.join(self.workdir, 'grub-inst')
+ grub_x86_64_mods = self.scratch_file('grub-inst-x86_64-efi')
+ grub_i386_mods = self.scratch_file('grub-inst')
self.assertTrue(os.path.exists(grub_x86_64_mods))
self.assertTrue(os.path.exists(grub_i386_mods))
@@ -245,13 +206,11 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute
""" Uses grub-mkrescue to generate a fresh bits iso with the python
test scripts
"""
- bits_dir = os.path.join(self.workdir,
- 'bits-%d' %self.BITS_INTERNAL_VER)
- iso_file = os.path.join(self.workdir,
- 'bits-%d.iso' %self.BITS_INTERNAL_VER)
- mkrescue_script = os.path.join(self.workdir,
- 'grub-inst-x86_64-efi', 'bin',
- 'grub-mkrescue')
+ bits_dir = self.scratch_file('bits-%d' % self.BITS_INTERNAL_VER)
+ iso_file = self.scratch_file('bits-%d.iso' % self.BITS_INTERNAL_VER)
+ mkrescue_script = self.scratch_file('grub-inst-x86_64-efi',
+ 'bin',
+ 'grub-mkrescue')
self.assertTrue(os.access(mkrescue_script,
os.R_OK | os.W_OK | os.X_OK))
@@ -286,33 +245,25 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute
super().setUp()
self.logger = self.log
- self._baseDir = Path(__file__).parent
-
- prebuiltDir = os.path.join(self.workdir, 'prebuilt')
+ prebuiltDir = self.scratch_file('prebuilt')
if not os.path.isdir(prebuiltDir):
os.mkdir(prebuiltDir, mode=0o775)
- bits_zip_file = os.path.join(prebuiltDir, 'bits-%d-%s.zip'
- %(self.BITS_INTERNAL_VER,
- self.BITS_COMMIT_HASH))
- grub_tar_file = os.path.join(prebuiltDir,
- 'bits-%d-%s-grub.tar.gz'
- %(self.BITS_INTERNAL_VER,
- self.BITS_COMMIT_HASH))
-
- bitsLocalArtLoc = self.ASSET_BITS.fetch()
- self.logger.info("downloaded bits artifacts to %s", bitsLocalArtLoc)
+ bits_zip_file = self.scratch_file('prebuilt',
+ 'bits-%d-%s.zip'
+ %(self.BITS_INTERNAL_VER,
+ self.BITS_COMMIT_HASH))
+ grub_tar_file = self.scratch_file('prebuilt',
+ 'bits-%d-%s-grub.tar.gz'
+ %(self.BITS_INTERNAL_VER,
+ self.BITS_COMMIT_HASH))
# extract the bits artifact in the temp working directory
- with zipfile.ZipFile(bitsLocalArtLoc, 'r') as zref:
- zref.extractall(prebuiltDir)
+ self.archive_extract(self.ASSET_BITS, sub_dir='prebuilt', format='zip')
# extract the bits software in the temp working directory
- with zipfile.ZipFile(bits_zip_file, 'r') as zref:
- zref.extractall(self.workdir)
-
- with tarfile.open(grub_tar_file, 'r', encoding='utf-8') as tarball:
- tarball.extractall(self.workdir)
+ self.archive_extract(bits_zip_file)
+ self.archive_extract(grub_tar_file)
self.copy_test_scripts()
self.copy_bits_config()
@@ -322,7 +273,7 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute
"""parse the log generated by running bits tests and
check for failures.
"""
- debugconf = os.path.join(self.workdir, self._debugcon_log)
+ debugconf = self.scratch_file(self._debugcon_log)
log = ""
with open(debugconf, 'r', encoding='utf-8') as filehandle:
log = filehandle.read()
@@ -354,8 +305,7 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute
"""The main test case implementation."""
self.set_machine('pc')
- iso_file = os.path.join(self.workdir,
- 'bits-%d.iso' %self.BITS_INTERNAL_VER)
+ iso_file = self.scratch_file('bits-%d.iso' % self.BITS_INTERNAL_VER)
self.assertTrue(os.access(iso_file, os.R_OK))
diff --git a/tests/functional/test_alpha_clipper.py b/tests/functional/test_alpha_clipper.py
index c1fbf0e..c5d7181 100755
--- a/tests/functional/test_alpha_clipper.py
+++ b/tests/functional/test_alpha_clipper.py
@@ -5,10 +5,7 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import os
-
from qemu_test import LinuxKernelTest, Asset
-from qemu_test.utils import gzip_uncompress
class AlphaClipperTest(LinuxKernelTest):
@@ -22,8 +19,7 @@ class AlphaClipperTest(LinuxKernelTest):
self.set_machine('clipper')
kernel_path = self.ASSET_KERNEL.fetch()
- uncompressed_kernel = os.path.join(self.workdir, 'vmlinux')
- gzip_uncompress(kernel_path, uncompressed_kernel)
+ uncompressed_kernel = self.uncompress(self.ASSET_KERNEL, format="gz")
self.vm.set_console()
kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0'
diff --git a/tests/functional/test_arm_aspeed_ast1030.py b/tests/functional/test_arm_aspeed_ast1030.py
index 380a76e..d45d9f7 100644..100755
--- a/tests/functional/test_arm_aspeed_ast1030.py
+++ b/tests/functional/test_arm_aspeed_ast1030.py
@@ -6,11 +6,9 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import os
-
from qemu_test import LinuxKernelTest, Asset
from qemu_test import exec_command_and_wait_for_pattern
-from zipfile import ZipFile
+
class AST1030Machine(LinuxKernelTest):
@@ -22,12 +20,9 @@ class AST1030Machine(LinuxKernelTest):
def test_ast1030_zephyros_1_04(self):
self.set_machine('ast1030-evb')
- zip_file = self.ASSET_ZEPHYR_1_04.fetch()
-
kernel_name = "ast1030-evb-demo/zephyr.elf"
- with ZipFile(zip_file, 'r') as zf:
- zf.extract(kernel_name, path=self.workdir)
- kernel_file = os.path.join(self.workdir, kernel_name)
+ kernel_file = self.archive_extract(
+ self.ASSET_ZEPHYR_1_04, member=kernel_name)
self.vm.set_console()
self.vm.add_args('-kernel', kernel_file, '-nographic')
@@ -44,12 +39,9 @@ class AST1030Machine(LinuxKernelTest):
def test_ast1030_zephyros_1_07(self):
self.set_machine('ast1030-evb')
- zip_file = self.ASSET_ZEPHYR_1_07.fetch()
-
kernel_name = "ast1030-evb-demo/zephyr.bin"
- with ZipFile(zip_file, 'r') as zf:
- zf.extract(kernel_name, path=self.workdir)
- kernel_file = os.path.join(self.workdir, kernel_name)
+ kernel_file = self.archive_extract(
+ self.ASSET_ZEPHYR_1_07, member=kernel_name)
self.vm.set_console()
self.vm.add_args('-kernel', kernel_file, '-nographic')
diff --git a/tests/functional/test_arm_aspeed_ast2500.py b/tests/functional/test_arm_aspeed_ast2500.py
index 79baf37..743fc46 100644..100755
--- a/tests/functional/test_arm_aspeed_ast2500.py
+++ b/tests/functional/test_arm_aspeed_ast2500.py
@@ -7,7 +7,7 @@
from qemu_test import Asset
from aspeed import AspeedTest
from qemu_test import exec_command_and_wait_for_pattern
-from qemu_test.utils import archive_extract
+
class AST2500Machine(AspeedTest):
@@ -45,12 +45,10 @@ class AST2500Machine(AspeedTest):
def test_arm_ast2500_evb_sdk(self):
self.set_machine('ast2500-evb')
- image_path = self.ASSET_SDK_V806_AST2500.fetch()
-
- archive_extract(image_path, self.workdir)
+ self.archive_extract(self.ASSET_SDK_V806_AST2500)
self.do_test_arm_aspeed_sdk_start(
- self.workdir + '/ast2500-default/image-bmc')
+ self.scratch_file("ast2500-default", "image-bmc"))
self.wait_for_console_pattern('ast2500-default login:')
diff --git a/tests/functional/test_arm_aspeed_ast2600.py b/tests/functional/test_arm_aspeed_ast2600.py
index 74d025e..2164012 100644..100755
--- a/tests/functional/test_arm_aspeed_ast2600.py
+++ b/tests/functional/test_arm_aspeed_ast2600.py
@@ -11,10 +11,8 @@ import subprocess
from qemu_test import Asset
from aspeed import AspeedTest
-from qemu_test import exec_command_and_wait_for_pattern
-from qemu_test import has_cmd
-from qemu_test.utils import archive_extract
-from unittest import skipUnless
+from qemu_test import exec_command_and_wait_for_pattern, skipIfMissingCommands
+
class AST2600Machine(AspeedTest):
@@ -68,7 +66,7 @@ class AST2600Machine(AspeedTest):
'images/ast2600-evb/buildroot-2023.02-tpm/flash.img'),
'a46009ae8a5403a0826d607215e731a8c68d27c14c41e55331706b8f9c7bd997')
- @skipUnless(*has_cmd('swtpm'))
+ @skipIfMissingCommands('swtpm')
def test_arm_ast2600_evb_buildroot_tpm(self):
self.set_machine('ast2600-evb')
@@ -106,16 +104,14 @@ class AST2600Machine(AspeedTest):
def test_arm_ast2600_evb_sdk(self):
self.set_machine('ast2600-evb')
- image_path = self.ASSET_SDK_V806_AST2600_A2.fetch()
-
- archive_extract(image_path, self.workdir)
+ self.archive_extract(self.ASSET_SDK_V806_AST2600_A2)
self.vm.add_args('-device',
'tmp105,bus=aspeed.i2c.bus.5,address=0x4d,id=tmp-test');
self.vm.add_args('-device',
'ds1338,bus=aspeed.i2c.bus.5,address=0x32');
self.do_test_arm_aspeed_sdk_start(
- self.workdir + '/ast2600-a2/image-bmc')
+ self.scratch_file("ast2600-a2", "image-bmc"))
self.wait_for_console_pattern('ast2600-a2 login:')
diff --git a/tests/functional/test_arm_aspeed_palmetto.py b/tests/functional/test_arm_aspeed_palmetto.py
index 6588c02..6588c02 100644..100755
--- a/tests/functional/test_arm_aspeed_palmetto.py
+++ b/tests/functional/test_arm_aspeed_palmetto.py
diff --git a/tests/functional/test_arm_aspeed_rainier.py b/tests/functional/test_arm_aspeed_rainier.py
index b856aea..602d619 100644..100755
--- a/tests/functional/test_arm_aspeed_rainier.py
+++ b/tests/functional/test_arm_aspeed_rainier.py
@@ -43,11 +43,12 @@ class RainierMachine(AspeedTest):
def test_arm_debian_kernel_boot(self):
self.set_machine('rainier-bmc')
- deb_path = self.ASSET_DEBIAN_LINUX_ARMHF_DEB.fetch()
-
- kernel_path = self.extract_from_deb(deb_path, '/boot/vmlinuz-5.17.0-2-armmp')
- dtb_path = self.extract_from_deb(deb_path,
- '/usr/lib/linux-image-5.17.0-2-armmp/aspeed-bmc-ibm-rainier.dtb')
+ kernel_path = self.archive_extract(
+ self.ASSET_DEBIAN_LINUX_ARMHF_DEB,
+ member='boot/vmlinuz-5.17.0-2-armmp')
+ dtb_path = self.archive_extract(
+ self.ASSET_DEBIAN_LINUX_ARMHF_DEB,
+ member='usr/lib/linux-image-5.17.0-2-armmp/aspeed-bmc-ibm-rainier.dtb')
self.vm.set_console()
self.vm.add_args('-kernel', kernel_path,
diff --git a/tests/functional/test_arm_aspeed_romulus.py b/tests/functional/test_arm_aspeed_romulus.py
index 747b616..747b616 100644..100755
--- a/tests/functional/test_arm_aspeed_romulus.py
+++ b/tests/functional/test_arm_aspeed_romulus.py
diff --git a/tests/functional/test_arm_bflt.py b/tests/functional/test_arm_bflt.py
index 281925d..f273fc8 100755
--- a/tests/functional/test_arm_bflt.py
+++ b/tests/functional/test_arm_bflt.py
@@ -6,13 +6,10 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import os
import bz2
from qemu_test import QemuUserTest, Asset
-from qemu_test import has_cmd
-from qemu_test.utils import cpio_extract
-from unittest import skipUnless
+from qemu_test import skipIfMissingCommands, skipUntrustedTest
class LoadBFLT(QemuUserTest):
@@ -21,15 +18,15 @@ class LoadBFLT(QemuUserTest):
('https://elinux.org/images/5/51/Stm32_mini_rootfs.cpio.bz2'),
'eefb788e4980c9e8d6c9d60ce7d15d4da6bf4fbc6a80f487673824600d5ba9cc')
- @skipUnless(*has_cmd('cpio'))
- @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ @skipIfMissingCommands('cpio')
+ @skipUntrustedTest()
def test_stm32(self):
# See https://elinux.org/STM32#User_Space
rootfs_path_bz2 = self.ASSET_ROOTFS.fetch()
- busybox_path = os.path.join(self.workdir, "bin/busybox")
+ busybox_path = self.scratch_file("bin", "busybox")
with bz2.open(rootfs_path_bz2, 'rb') as cpio_handle:
- cpio_extract(cpio_handle, self.workdir)
+ self.archive_extract(cpio_handle, format="cpio")
res = self.run_cmd(busybox_path)
ver = 'BusyBox v1.24.0.git (2015-02-03 22:17:13 CET) multi-call binary.'
diff --git a/tests/functional/test_arm_bpim2u.py b/tests/functional/test_arm_bpim2u.py
index 35ea58d..12cd359 100755
--- a/tests/functional/test_arm_bpim2u.py
+++ b/tests/functional/test_arm_bpim2u.py
@@ -9,9 +9,9 @@ import os
from qemu_test import LinuxKernelTest, exec_command_and_wait_for_pattern
from qemu_test import Asset, interrupt_interactive_console_until_pattern
-from qemu_test.utils import archive_extract, gzip_uncompress, lzma_uncompress
+from qemu_test import skipBigDataTest
from qemu_test.utils import image_pow2ceil_expand
-from unittest import skipUnless
+
class BananaPiMachine(LinuxKernelTest):
@@ -38,12 +38,11 @@ class BananaPiMachine(LinuxKernelTest):
def test_arm_bpim2u(self):
self.set_machine('bpim2u')
- deb_path = self.ASSET_DEB.fetch()
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-6.6.16-current-sunxi')
- dtb_path = ('/usr/lib/linux-image-6.6.16-current-sunxi/'
+ kernel_path = self.archive_extract(
+ self.ASSET_DEB, member='boot/vmlinuz-6.6.16-current-sunxi')
+ dtb_path = ('usr/lib/linux-image-6.6.16-current-sunxi/'
'sun8i-r40-bananapi-m2-ultra.dtb')
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
+ dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path)
self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
@@ -60,15 +59,12 @@ class BananaPiMachine(LinuxKernelTest):
def test_arm_bpim2u_initrd(self):
self.set_machine('bpim2u')
- deb_path = self.ASSET_DEB.fetch()
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-6.6.16-current-sunxi')
- dtb_path = ('/usr/lib/linux-image-6.6.16-current-sunxi/'
+ kernel_path = self.archive_extract(
+ self.ASSET_DEB, member='boot/vmlinuz-6.6.16-current-sunxi')
+ dtb_path = ('usr/lib/linux-image-6.6.16-current-sunxi/'
'sun8i-r40-bananapi-m2-ultra.dtb')
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
- initrd_path_gz = self.ASSET_INITRD.fetch()
- initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
- gzip_uncompress(initrd_path_gz, initrd_path)
+ dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path)
+ initrd_path = self.uncompress(self.ASSET_INITRD)
self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
@@ -99,14 +95,12 @@ class BananaPiMachine(LinuxKernelTest):
self.require_netdev('user')
deb_path = self.ASSET_DEB.fetch()
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-6.6.16-current-sunxi')
- dtb_path = ('/usr/lib/linux-image-6.6.16-current-sunxi/'
+ kernel_path = self.archive_extract(
+ self.ASSET_DEB, member='boot/vmlinuz-6.6.16-current-sunxi')
+ dtb_path = ('usr/lib/linux-image-6.6.16-current-sunxi/'
'sun8i-r40-bananapi-m2-ultra.dtb')
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
- rootfs_path_xz = self.ASSET_ROOTFS.fetch()
- rootfs_path = os.path.join(self.workdir, 'rootfs.cpio')
- lzma_uncompress(rootfs_path_xz, rootfs_path)
+ dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path)
+ rootfs_path = self.uncompress(self.ASSET_ROOTFS)
image_pow2ceil_expand(rootfs_path)
self.vm.set_console()
@@ -143,14 +137,12 @@ class BananaPiMachine(LinuxKernelTest):
os.remove(dtb_path)
os.remove(rootfs_path)
- @skipUnless(os.getenv('QEMU_TEST_ALLOW_LARGE_STORAGE'), 'storage limited')
+ @skipBigDataTest()
def test_arm_bpim2u_openwrt_22_03_3(self):
self.set_machine('bpim2u')
# This test download a 8.9 MiB compressed image and expand it
# to 127 MiB.
- image_path_gz = self.ASSET_SD_IMAGE.fetch()
- image_path = os.path.join(self.workdir, 'sdcard.img')
- gzip_uncompress(image_path_gz, image_path)
+ image_path = self.uncompress(self.ASSET_SD_IMAGE)
image_pow2ceil_expand(image_path)
self.vm.set_console()
diff --git a/tests/functional/test_arm_canona1100.py b/tests/functional/test_arm_canona1100.py
index 65f1228..21a1a59 100755
--- a/tests/functional/test_arm_canona1100.py
+++ b/tests/functional/test_arm_canona1100.py
@@ -12,7 +12,7 @@
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
-from qemu_test.utils import archive_extract
+
class CanonA1100Machine(QemuSystemTest):
"""Boots the barebox firmware and checks that the console is operational"""
@@ -26,12 +26,10 @@ class CanonA1100Machine(QemuSystemTest):
def test_arm_canona1100(self):
self.set_machine('canon-a1100')
- file_path = self.ASSET_BIOS.fetch()
- archive_extract(file_path, dest_dir=self.workdir,
- member="day18/barebox.canon-a1100.bin")
+ bios = self.archive_extract(self.ASSET_BIOS,
+ member="day18/barebox.canon-a1100.bin")
self.vm.set_console()
- self.vm.add_args('-bios',
- self.workdir + '/day18/barebox.canon-a1100.bin')
+ self.vm.add_args('-bios', bios)
self.vm.launch()
wait_for_console_pattern(self, 'running /env/bin/init')
diff --git a/tests/functional/test_arm_collie.py b/tests/functional/test_arm_collie.py
index 7e144a0..fe1be3d 100755
--- a/tests/functional/test_arm_collie.py
+++ b/tests/functional/test_arm_collie.py
@@ -6,7 +6,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import LinuxKernelTest, Asset
-from qemu_test.utils import archive_extract
+
class CollieTest(LinuxKernelTest):
diff --git a/tests/functional/test_arm_cubieboard.py b/tests/functional/test_arm_cubieboard.py
index 2b33a1b..423db71 100755
--- a/tests/functional/test_arm_cubieboard.py
+++ b/tests/functional/test_arm_cubieboard.py
@@ -5,12 +5,12 @@
# SPDX-License-Identifier: GPL-2.0-or-later
import os
-import shutil
from qemu_test import LinuxKernelTest, Asset, exec_command_and_wait_for_pattern
from qemu_test import interrupt_interactive_console_until_pattern
-from qemu_test.utils import gzip_uncompress, image_pow2ceil_expand
-from unittest import skipUnless
+from qemu_test import skipBigDataTest
+from qemu_test.utils import image_pow2ceil_expand
+
class CubieboardMachine(LinuxKernelTest):
@@ -38,14 +38,12 @@ class CubieboardMachine(LinuxKernelTest):
def test_arm_cubieboard_initrd(self):
self.set_machine('cubieboard')
- deb_path = self.ASSET_DEB.fetch()
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-6.6.16-current-sunxi')
- dtb_path = '/usr/lib/linux-image-6.6.16-current-sunxi/sun4i-a10-cubieboard.dtb'
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
- initrd_path_gz = self.ASSET_INITRD.fetch()
- initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
- gzip_uncompress(initrd_path_gz, initrd_path)
+ kernel_path = self.archive_extract(
+ self.ASSET_DEB, member='boot/vmlinuz-6.6.16-current-sunxi')
+ dtb_path = ('usr/lib/linux-image-6.6.16-current-sunxi/' +
+ 'sun4i-a10-cubieboard.dtb')
+ dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path)
+ initrd_path = self.uncompress(self.ASSET_INITRD)
self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
@@ -71,15 +69,13 @@ class CubieboardMachine(LinuxKernelTest):
def test_arm_cubieboard_sata(self):
self.set_machine('cubieboard')
- deb_path = self.ASSET_DEB.fetch()
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-6.6.16-current-sunxi')
- dtb_path = '/usr/lib/linux-image-6.6.16-current-sunxi/sun4i-a10-cubieboard.dtb'
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
+ kernel_path = self.archive_extract(
+ self.ASSET_DEB, member='boot/vmlinuz-6.6.16-current-sunxi')
+ dtb_path = ('usr/lib/linux-image-6.6.16-current-sunxi/' +
+ 'sun4i-a10-cubieboard.dtb')
+ dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path)
- rootfs_path_gz = self.ASSET_SATA_ROOTFS.fetch()
- rootfs_path = os.path.join(self.workdir, 'rootfs.cpio')
- gzip_uncompress(rootfs_path_gz, rootfs_path)
+ rootfs_path = self.uncompress(self.ASSET_SATA_ROOTFS)
self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
@@ -106,14 +102,12 @@ class CubieboardMachine(LinuxKernelTest):
# Wait for VM to shut down gracefully
self.vm.wait()
- @skipUnless(os.getenv('AVOCADO_ALLOW_LARGE_STORAGE'), 'storage limited')
+ @skipBigDataTest()
def test_arm_cubieboard_openwrt_22_03_2(self):
# This test download a 7.5 MiB compressed image and expand it
# to 126 MiB.
self.set_machine('cubieboard')
- image_path_gz = self.ASSET_OPENWRT.fetch()
- image_path = os.path.join(self.workdir, 'sdcard.img')
- gzip_uncompress(image_path_gz, image_path)
+ image_path = self.uncompress(self.ASSET_OPENWRT)
image_pow2ceil_expand(image_path)
self.vm.set_console()
diff --git a/tests/functional/test_arm_emcraft_sf2.py b/tests/functional/test_arm_emcraft_sf2.py
index ada4dfd..f9f3f06 100755
--- a/tests/functional/test_arm_emcraft_sf2.py
+++ b/tests/functional/test_arm_emcraft_sf2.py
@@ -28,7 +28,7 @@ class EmcraftSf2Machine(LinuxKernelTest):
uboot_path = self.ASSET_UBOOT.fetch()
spi_path = self.ASSET_SPI.fetch()
- spi_path_rw = os.path.join(self.workdir, 'spi.bin')
+ spi_path_rw = self.scratch_file('spi.bin')
shutil.copy(spi_path, spi_path_rw)
os.chmod(spi_path_rw, 0o600)
diff --git a/tests/functional/test_arm_integratorcp.py b/tests/functional/test_arm_integratorcp.py
index 0fe083f..a85b339 100755
--- a/tests/functional/test_arm_integratorcp.py
+++ b/tests/functional/test_arm_integratorcp.py
@@ -12,25 +12,11 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import os
import logging
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
-from unittest import skipUnless
-
-
-NUMPY_AVAILABLE = True
-try:
- import numpy as np
-except ImportError:
- NUMPY_AVAILABLE = False
-
-CV2_AVAILABLE = True
-try:
- import cv2
-except ImportError:
- CV2_AVAILABLE = False
+from qemu_test import skipIfMissingImports, skipUntrustedTest
class IntegratorMachine(QemuSystemTest):
@@ -63,7 +49,7 @@ class IntegratorMachine(QemuSystemTest):
'-append', 'printk.time=0 console=ttyAMA0')
self.vm.launch()
- @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ @skipUntrustedTest()
def test_integratorcp_console(self):
"""
Boots the Linux kernel and checks that the console is operational
@@ -71,14 +57,16 @@ class IntegratorMachine(QemuSystemTest):
self.boot_integratorcp()
wait_for_console_pattern(self, 'Log in as root')
- @skipUnless(NUMPY_AVAILABLE, 'Python NumPy not installed')
- @skipUnless(CV2_AVAILABLE, 'Python OpenCV not installed')
- @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ @skipIfMissingImports("numpy", "cv2")
+ @skipUntrustedTest()
def test_framebuffer_tux_logo(self):
"""
Boot Linux and verify the Tux logo is displayed on the framebuffer.
"""
- screendump_path = os.path.join(self.workdir, "screendump.pbm")
+ import numpy as np
+ import cv2
+
+ screendump_path = self.scratch_file("screendump.pbm")
tuxlogo_path = self.ASSET_TUXLOGO.fetch()
self.boot_integratorcp()
diff --git a/tests/functional/test_arm_orangepi.py b/tests/functional/test_arm_orangepi.py
index 6d57223..18ee502 100755
--- a/tests/functional/test_arm_orangepi.py
+++ b/tests/functional/test_arm_orangepi.py
@@ -10,10 +10,9 @@ import shutil
from qemu_test import LinuxKernelTest, exec_command_and_wait_for_pattern
from qemu_test import Asset, interrupt_interactive_console_until_pattern
-from qemu_test import wait_for_console_pattern
-from qemu_test.utils import archive_extract, gzip_uncompress, lzma_uncompress
+from qemu_test import wait_for_console_pattern, skipBigDataTest
from qemu_test.utils import image_pow2ceil_expand
-from unittest import skipUnless
+
class BananaPiMachine(LinuxKernelTest):
@@ -50,11 +49,11 @@ class BananaPiMachine(LinuxKernelTest):
def test_arm_orangepi(self):
self.set_machine('orangepi-pc')
- deb_path = self.ASSET_DEB.fetch()
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-6.6.16-current-sunxi')
- dtb_path = '/usr/lib/linux-image-6.6.16-current-sunxi/sun8i-h3-orangepi-pc.dtb'
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
+ kernel_path = self.archive_extract(
+ self.ASSET_DEB, member='boot/vmlinuz-6.6.16-current-sunxi')
+ dtb_path = ('usr/lib/linux-image-6.6.16-current-sunxi/' +
+ 'sun8i-h3-orangepi-pc.dtb')
+ dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path)
self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
@@ -71,14 +70,12 @@ class BananaPiMachine(LinuxKernelTest):
def test_arm_orangepi_initrd(self):
self.set_machine('orangepi-pc')
- deb_path = self.ASSET_DEB.fetch()
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-6.6.16-current-sunxi')
- dtb_path = '/usr/lib/linux-image-6.6.16-current-sunxi/sun8i-h3-orangepi-pc.dtb'
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
- initrd_path_gz = self.ASSET_INITRD.fetch()
- initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
- gzip_uncompress(initrd_path_gz, initrd_path)
+ kernel_path = self.archive_extract(
+ self.ASSET_DEB, member='boot/vmlinuz-6.6.16-current-sunxi')
+ dtb_path = ('usr/lib/linux-image-6.6.16-current-sunxi/' +
+ 'sun8i-h3-orangepi-pc.dtb')
+ dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path)
+ initrd_path = self.uncompress(self.ASSET_INITRD)
self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
@@ -107,14 +104,12 @@ class BananaPiMachine(LinuxKernelTest):
def test_arm_orangepi_sd(self):
self.set_machine('orangepi-pc')
self.require_netdev('user')
- deb_path = self.ASSET_DEB.fetch()
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-6.6.16-current-sunxi')
- dtb_path = '/usr/lib/linux-image-6.6.16-current-sunxi/sun8i-h3-orangepi-pc.dtb'
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
- rootfs_path_xz = self.ASSET_ROOTFS.fetch()
- rootfs_path = os.path.join(self.workdir, 'rootfs.cpio')
- lzma_uncompress(rootfs_path_xz, rootfs_path)
+ kernel_path = self.archive_extract(
+ self.ASSET_DEB, member='boot/vmlinuz-6.6.16-current-sunxi')
+ dtb_path = ('usr/lib/linux-image-6.6.16-current-sunxi/' +
+ 'sun8i-h3-orangepi-pc.dtb')
+ dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path)
+ rootfs_path = self.uncompress(self.ASSET_ROOTFS)
image_pow2ceil_expand(rootfs_path)
self.vm.set_console()
@@ -149,15 +144,13 @@ class BananaPiMachine(LinuxKernelTest):
os.remove(dtb_path)
os.remove(rootfs_path)
- @skipUnless(os.getenv('QEMU_TEST_ALLOW_LARGE_STORAGE'), 'storage limited')
+ @skipBigDataTest()
def test_arm_orangepi_armbian(self):
self.set_machine('orangepi-pc')
# This test download a 275 MiB compressed image and expand it
# to 1036 MiB, but the underlying filesystem is 1552 MiB...
# As we expand it to 2 GiB we are safe.
- image_path_xz = self.ASSET_ARMBIAN.fetch()
- image_path = os.path.join(self.workdir, 'armbian.img')
- lzma_uncompress(image_path_xz, image_path)
+ image_path = self.uncompress(self.ASSET_ARMBIAN)
image_pow2ceil_expand(image_path)
self.vm.set_console()
@@ -185,20 +178,17 @@ class BananaPiMachine(LinuxKernelTest):
'to <orangepipc>')
self.wait_for_console_pattern('Starting Load Kernel Modules...')
- @skipUnless(os.getenv('QEMU_TEST_ALLOW_LARGE_STORAGE'), 'storage limited')
+ @skipBigDataTest()
def test_arm_orangepi_uboot_netbsd9(self):
self.set_machine('orangepi-pc')
# This test download a 304MB compressed image and expand it to 2GB
- deb_path = self.ASSET_UBOOT.fetch()
# We use the common OrangePi PC 'plus' build of U-Boot for our secondary
# program loader (SPL). We will then set the path to the more specific
# OrangePi "PC" device tree blob with 'setenv fdtfile' in U-Boot prompt,
# before to boot NetBSD.
- uboot_path = '/usr/lib/u-boot/orangepi_plus/u-boot-sunxi-with-spl.bin'
- uboot_path = self.extract_from_deb(deb_path, uboot_path)
- image_path_gz = self.ASSET_NETBSD.fetch()
- image_path = os.path.join(self.workdir, 'armv7.img')
- gzip_uncompress(image_path_gz, image_path)
+ uboot_path = 'usr/lib/u-boot/orangepi_plus/u-boot-sunxi-with-spl.bin'
+ uboot_path = self.archive_extract(self.ASSET_UBOOT, member=uboot_path)
+ image_path = self.uncompress(self.ASSET_NETBSD)
image_pow2ceil_expand(image_path)
image_drive_args = 'if=sd,format=raw,snapshot=on,file=' + image_path
diff --git a/tests/functional/test_arm_quanta_gsj.py b/tests/functional/test_arm_quanta_gsj.py
new file mode 100755
index 0000000..7aa5209
--- /dev/null
+++ b/tests/functional/test_arm_quanta_gsj.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+
+from qemu_test import LinuxKernelTest, Asset, exec_command_and_wait_for_pattern
+from qemu_test import interrupt_interactive_console_until_pattern
+from unittest import skipUnless
+
+class EmcraftSf2Machine(LinuxKernelTest):
+
+ ASSET_IMAGE = Asset(
+ ('https://github.com/hskinnemoen/openbmc/releases/download/'
+ '20200711-gsj-qemu-0/obmc-phosphor-image-gsj.static.mtd.gz'),
+ 'eccd4e375cde53034c84aece5c511932cacf838d9fd3f63da368a511757da72b')
+
+ ASSET_INITRD = Asset(
+ ('https://github.com/hskinnemoen/openbmc/releases/download/'
+ '20200711-gsj-qemu-0/obmc-phosphor-initramfs-gsj.cpio.xz'),
+ '37b05009fc54db1434beac12bd7ff99a2e751a2f032ee18d9042f991dd0cdeaa')
+
+ ASSET_KERNEL = Asset(
+ ('https://github.com/hskinnemoen/openbmc/releases/download/'
+ '20200711-gsj-qemu-0/uImage-gsj.bin'),
+ 'ce6d6b37bff46c74fc7b1e90da10a431cc37a62cdb35ec199fa73473d0790110')
+
+ ASSET_DTB = Asset(
+ ('https://github.com/hskinnemoen/openbmc/releases/download/'
+ '20200711-gsj-qemu-0/nuvoton-npcm730-gsj.dtb'),
+ '3249b2da787d4b9ad4e61f315b160abfceb87b5e1895a7ce898ce7f40c8d4045')
+
+ @skipUnless(os.getenv('QEMU_TEST_TIMEOUT_EXPECTED'), 'Test might timeout')
+ def test_arm_quanta_gsj(self):
+ self.set_machine('quanta-gsj')
+ image_path = self.uncompress(ASSET_IMAGE, 'obmc.mtd', format='gz')
+
+ self.vm.set_console()
+ drive_args = 'file=' + image_path + ',if=mtd,bus=0,unit=0'
+ self.vm.add_args('-drive', drive_args)
+ self.vm.launch()
+
+ # Disable drivers and services that stall for a long time during boot,
+ # to avoid running past the 90-second timeout. These may be removed
+ # as the corresponding device support is added.
+ kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + (
+ 'console=${console} '
+ 'mem=${mem} '
+ 'initcall_blacklist=npcm_i2c_bus_driver_init '
+ 'systemd.mask=systemd-random-seed.service '
+ 'systemd.mask=dropbearkey.service '
+ )
+
+ self.wait_for_console_pattern('> BootBlock by Nuvoton')
+ self.wait_for_console_pattern('>Device: Poleg BMC NPCM730')
+ self.wait_for_console_pattern('>Skip DDR init.')
+ self.wait_for_console_pattern('U-Boot ')
+ interrupt_interactive_console_until_pattern(
+ self, 'Hit any key to stop autoboot:', 'U-Boot>')
+ exec_command_and_wait_for_pattern(
+ self, "setenv bootargs ${bootargs} " + kernel_command_line,
+ 'U-Boot>')
+ exec_command_and_wait_for_pattern(
+ self, 'run romboot', 'Booting Kernel from flash')
+ self.wait_for_console_pattern('Booting Linux on physical CPU 0x0')
+ self.wait_for_console_pattern('CPU1: thread -1, cpu 1, socket 0')
+ self.wait_for_console_pattern('OpenBMC Project Reference Distro')
+ self.wait_for_console_pattern('gsj login:')
+
+ def test_arm_quanta_gsj_initrd(self):
+ self.set_machine('quanta-gsj')
+ initrd_path = self.ASSET_INITRD.fetch()
+ kernel_path = self.ASSET_KERNEL.fetch()
+ dtb_path = self.ASSET_DTB.fetch()
+
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyS0,115200n8 '
+ 'earlycon=uart8250,mmio32,0xf0001000')
+ self.vm.add_args('-kernel', kernel_path,
+ '-initrd', initrd_path,
+ '-dtb', dtb_path,
+ '-append', kernel_command_line)
+ self.vm.launch()
+
+ self.wait_for_console_pattern('Booting Linux on physical CPU 0x0')
+ self.wait_for_console_pattern('CPU1: thread -1, cpu 1, socket 0')
+ self.wait_for_console_pattern(
+ 'Give root password for system maintenance')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_arm_raspi2.py b/tests/functional/test_arm_raspi2.py
index 3bf079d..d3c7aaa 100755
--- a/tests/functional/test_arm_raspi2.py
+++ b/tests/functional/test_arm_raspi2.py
@@ -7,11 +7,8 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import os
-
from qemu_test import LinuxKernelTest, Asset
from qemu_test import exec_command_and_wait_for_pattern
-from qemu_test.utils import gzip_uncompress
class ArmRaspi2Machine(LinuxKernelTest):
@@ -37,9 +34,10 @@ class ArmRaspi2Machine(LinuxKernelTest):
serial_kernel_cmdline = {
0: 'earlycon=pl011,0x3f201000 console=ttyAMA0',
}
- deb_path = self.ASSET_KERNEL_20190215.fetch()
- kernel_path = self.extract_from_deb(deb_path, '/boot/kernel7.img')
- dtb_path = self.extract_from_deb(deb_path, '/boot/bcm2709-rpi-2-b.dtb')
+ kernel_path = self.archive_extract(self.ASSET_KERNEL_20190215,
+ member='boot/kernel7.img')
+ dtb_path = self.archive_extract(self.ASSET_KERNEL_20190215,
+ member='boot/bcm2709-rpi-2-b.dtb')
self.set_machine('raspi2b')
self.vm.set_console()
@@ -61,12 +59,11 @@ class ArmRaspi2Machine(LinuxKernelTest):
self.do_test_arm_raspi2(0)
def test_arm_raspi2_initrd(self):
- deb_path = self.ASSET_KERNEL_20190215.fetch()
- kernel_path = self.extract_from_deb(deb_path, '/boot/kernel7.img')
- dtb_path = self.extract_from_deb(deb_path, '/boot/bcm2709-rpi-2-b.dtb')
- initrd_path_gz = self.ASSET_INITRD.fetch()
- initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
- gzip_uncompress(initrd_path_gz, initrd_path)
+ kernel_path = self.archive_extract(self.ASSET_KERNEL_20190215,
+ member='boot/kernel7.img')
+ dtb_path = self.archive_extract(self.ASSET_KERNEL_20190215,
+ member='boot/bcm2709-rpi-2-b.dtb')
+ initrd_path = self.uncompress(self.ASSET_INITRD)
self.set_machine('raspi2b')
self.vm.set_console()
diff --git a/tests/functional/test_arm_smdkc210.py b/tests/functional/test_arm_smdkc210.py
index 967752f..0fda45c 100755
--- a/tests/functional/test_arm_smdkc210.py
+++ b/tests/functional/test_arm_smdkc210.py
@@ -5,10 +5,9 @@
# SPDX-License-Identifier: GPL-2.0-or-later
import os
-import shutil
-from qemu_test import LinuxKernelTest, Asset, exec_command_and_wait_for_pattern
-from qemu_test.utils import gzip_uncompress
+from qemu_test import LinuxKernelTest, Asset
+
class Smdkc210Machine(LinuxKernelTest):
@@ -26,15 +25,12 @@ class Smdkc210Machine(LinuxKernelTest):
def test_arm_exynos4210_initrd(self):
self.set_machine('smdkc210')
- deb_path = self.ASSET_DEB.fetch()
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinuz-4.19.0-6-armmp')
- dtb_path = '/usr/lib/linux-image-4.19.0-6-armmp/exynos4210-smdkv310.dtb'
- dtb_path = self.extract_from_deb(deb_path, dtb_path)
+ kernel_path = self.archive_extract(self.ASSET_DEB,
+ member='boot/vmlinuz-4.19.0-6-armmp')
+ dtb_path = 'usr/lib/linux-image-4.19.0-6-armmp/exynos4210-smdkv310.dtb'
+ dtb_path = self.archive_extract(self.ASSET_DEB, member=dtb_path)
- initrd_path_gz = self.ASSET_ROOTFS.fetch()
- initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
- gzip_uncompress(initrd_path_gz, initrd_path)
+ initrd_path = self.uncompress(self.ASSET_ROOTFS)
self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
diff --git a/tests/functional/test_arm_sx1.py b/tests/functional/test_arm_sx1.py
index 2292317..b85bfaa 100755
--- a/tests/functional/test_arm_sx1.py
+++ b/tests/functional/test_arm_sx1.py
@@ -14,7 +14,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import LinuxKernelTest, Asset
-from qemu_test.utils import archive_extract
+
class SX1Test(LinuxKernelTest):
diff --git a/tests/functional/test_arm_vexpress.py b/tests/functional/test_arm_vexpress.py
index 6bd6290..6b11552 100755
--- a/tests/functional/test_arm_vexpress.py
+++ b/tests/functional/test_arm_vexpress.py
@@ -6,7 +6,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import LinuxKernelTest, Asset
-from qemu_test.utils import archive_extract
+
class VExpressTest(LinuxKernelTest):
@@ -16,10 +16,10 @@ class VExpressTest(LinuxKernelTest):
def test_arm_vexpressa9(self):
self.set_machine('vexpress-a9')
- file_path = self.ASSET_DAY16.fetch()
- archive_extract(file_path, self.workdir)
- self.launch_kernel(self.workdir + '/day16/winter.zImage',
- dtb=self.workdir + '/day16/vexpress-v2p-ca9.dtb',
+ self.archive_extract(self.ASSET_DAY16)
+ self.launch_kernel(self.scratch_file('day16', 'winter.zImage'),
+ dtb=self.scratch_file('day16',
+ 'vexpress-v2p-ca9.dtb'),
wait_for='QEMU advent calendar')
if __name__ == '__main__':
diff --git a/tests/functional/test_arm_virt.py b/tests/functional/test_arm_virt.py
new file mode 100755
index 0000000..7b65491
--- /dev/null
+++ b/tests/functional/test_arm_virt.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python3
+#
+# Functional test that boots a Linux kernel and checks the console
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+from qemu_test import LinuxKernelTest, Asset
+
+class ArmVirtMachine(LinuxKernelTest):
+
+ ASSET_KERNEL = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/'
+ 'releases/29/Everything/armhfp/os/images/pxeboot/vmlinuz'),
+ '18dd5f1a9a28bd539f9d047f7c0677211bae528e8712b40ca5a229a4ad8e2591')
+
+ def test_arm_virt(self):
+ self.set_machine('virt')
+ kernel_path = self.ASSET_KERNEL.fetch()
+
+ self.vm.set_console()
+ kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+ 'console=ttyAMA0')
+ self.vm.add_args('-kernel', kernel_path,
+ '-append', kernel_command_line)
+ self.vm.launch()
+ console_pattern = 'Kernel command line: %s' % kernel_command_line
+ self.wait_for_console_pattern(console_pattern)
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_info_usernet.py b/tests/functional/test_info_usernet.py
index cd37524..e8cbc37 100755
--- a/tests/functional/test_info_usernet.py
+++ b/tests/functional/test_info_usernet.py
@@ -11,8 +11,7 @@
# later. See the COPYING file in the top-level directory.
from qemu_test import QemuSystemTest
-
-from qemu.utils import get_info_usernet_hostfwd_port
+from qemu_test.utils import get_usernet_hostfwd_port
class InfoUsernet(QemuSystemTest):
@@ -22,9 +21,8 @@ class InfoUsernet(QemuSystemTest):
self.set_machine('none')
self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22')
self.vm.launch()
- res = self.vm.cmd('human-monitor-command',
- command_line='info usernet')
- port = get_info_usernet_hostfwd_port(res)
+
+ port = get_usernet_hostfwd_port(self.vm)
self.assertIsNotNone(port,
('"info usernet" output content does not seem to '
'contain the redirected port'))
diff --git a/tests/functional/test_intel_iommu.py b/tests/functional/test_intel_iommu.py
new file mode 100755
index 0000000..a9e8f82
--- /dev/null
+++ b/tests/functional/test_intel_iommu.py
@@ -0,0 +1,175 @@
+#!/usr/bin/env python3
+#
+# INTEL_IOMMU Functional tests
+#
+# Copyright (c) 2021 Red Hat, Inc.
+#
+# Author:
+# Eric Auger <eric.auger@redhat.com>
+#
+# 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
+
+from qemu_test import LinuxKernelTest, Asset, exec_command_and_wait_for_pattern
+from qemu_test.utils import get_usernet_hostfwd_port
+
+
+class IntelIOMMU(LinuxKernelTest):
+
+ ASSET_KERNEL = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
+ '/31/Server/x86_64/os/images/pxeboot/vmlinuz'),
+ 'd4738d03dbbe083ca610d0821d0a8f1488bebbdccef54ce33e3adb35fda00129')
+
+ ASSET_INITRD = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
+ '/31/Server/x86_64/os/images/pxeboot/initrd.img'),
+ '277cd6c7adf77c7e63d73bbb2cded8ef9e2d3a2f100000e92ff1f8396513cd8b')
+
+ ASSET_DISKIMAGE = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
+ '/31/Cloud/x86_64/images/Fedora-Cloud-Base-31-1.9.x86_64.qcow2'),
+ 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0')
+
+ DEFAULT_KERNEL_PARAMS = ('root=/dev/vda1 console=ttyS0 net.ifnames=0 '
+ 'quiet rd.rescue ')
+ GUEST_PORT = 8080
+ IOMMU_ADDON = ',iommu_platform=on,disable-modern=off,disable-legacy=on'
+ kernel_path = None
+ initrd_path = None
+ kernel_params = None
+
+ def add_common_args(self, path):
+ self.vm.add_args('-drive', f'file={path},if=none,id=drv0,snapshot=on')
+ self.vm.add_args('-device', 'virtio-blk-pci,bus=pcie.0,' +
+ 'drive=drv0,id=virtio-disk0,bootindex=1,'
+ 'werror=stop,rerror=stop' + self.IOMMU_ADDON)
+ self.vm.add_args('-device', 'virtio-gpu-pci' + self.IOMMU_ADDON)
+
+ self.vm.add_args('-netdev',
+ 'user,id=n1,hostfwd=tcp:127.0.0.1:0-:%d' %
+ self.GUEST_PORT)
+ self.vm.add_args('-device',
+ 'virtio-net-pci,netdev=n1' + self.IOMMU_ADDON)
+
+ self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0')
+ self.vm.add_args('-object',
+ 'rng-random,id=rng0,filename=/dev/urandom')
+ self.vm.add_args("-m", "1G")
+ self.vm.add_args("-accel", "kvm")
+
+ def common_vm_setup(self):
+ self.set_machine('q35')
+ self.require_accelerator("kvm")
+ self.require_netdev('user')
+
+ self.kernel_path = self.ASSET_KERNEL.fetch()
+ self.initrd_path = self.ASSET_INITRD.fetch()
+ image_path = self.ASSET_DISKIMAGE.fetch()
+ self.add_common_args(image_path)
+ self.kernel_params = self.DEFAULT_KERNEL_PARAMS
+
+ def run_and_check(self):
+ if self.kernel_path:
+ self.vm.add_args('-kernel', self.kernel_path,
+ '-append', self.kernel_params,
+ '-initrd', self.initrd_path)
+ self.vm.set_console()
+ self.vm.launch()
+ self.wait_for_console_pattern('Entering emergency mode.')
+ prompt = '# '
+ self.wait_for_console_pattern(prompt)
+
+ # Copy a file (checked later), umount afterwards to drop disk cache:
+ exec_command_and_wait_for_pattern(self, 'mount /dev/vda1 /sysroot',
+ prompt)
+ filename = '/boot/initramfs-5.3.7-301.fc31.x86_64.img'
+ exec_command_and_wait_for_pattern(self, (f'cp /sysroot{filename}'
+ ' /sysroot/root/data'),
+ prompt)
+ exec_command_and_wait_for_pattern(self, 'umount /sysroot', prompt)
+
+ # Switch from initrd to the cloud image filesystem:
+ exec_command_and_wait_for_pattern(self, 'mount /dev/vda1 /sysroot',
+ prompt)
+ exec_command_and_wait_for_pattern(self,
+ ('for d in dev proc sys run ; do '
+ 'mount -o bind /$d /sysroot/$d ; done'), prompt)
+ exec_command_and_wait_for_pattern(self, 'chroot /sysroot', prompt)
+
+ # Checking for IOMMU enablement:
+ self.log.info("Checking whether IOMMU has been enabled...")
+ exec_command_and_wait_for_pattern(self, 'cat /proc/cmdline',
+ 'intel_iommu=on')
+ self.wait_for_console_pattern(prompt)
+ exec_command_and_wait_for_pattern(self, 'dmesg | grep DMAR:',
+ 'IOMMU enabled')
+ self.wait_for_console_pattern(prompt)
+ exec_command_and_wait_for_pattern(self,
+ 'find /sys/kernel/iommu_groups/ -type l',
+ 'devices/0000:00:')
+ self.wait_for_console_pattern(prompt)
+
+ # Check hard disk device via sha256sum:
+ self.log.info("Checking hard disk...")
+ hashsum = '0dc7472f879be70b2f3daae279e3ae47175ffe249691e7d97f47222b65b8a720'
+ exec_command_and_wait_for_pattern(self, 'sha256sum ' + filename,
+ hashsum)
+ self.wait_for_console_pattern(prompt)
+ exec_command_and_wait_for_pattern(self, 'sha256sum /root/data',
+ hashsum)
+ self.wait_for_console_pattern(prompt)
+
+ # Check virtio-net via HTTP:
+ exec_command_and_wait_for_pattern(self, 'dhclient eth0', prompt)
+ exec_command_and_wait_for_pattern(self,
+ f'python3 -m http.server {self.GUEST_PORT} & sleep 1',
+ f'Serving HTTP on 0.0.0.0 port {self.GUEST_PORT}')
+ 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)
+
+ def test_intel_iommu(self):
+ self.common_vm_setup()
+ self.vm.add_args('-device', 'intel-iommu,intremap=on')
+ self.vm.add_args('-machine', 'kernel_irqchip=split')
+ self.kernel_params += 'intel_iommu=on'
+ self.run_and_check()
+
+ def test_intel_iommu_strict(self):
+ self.common_vm_setup()
+ self.vm.add_args('-device', 'intel-iommu,intremap=on')
+ self.vm.add_args('-machine', 'kernel_irqchip=split')
+ self.kernel_params += 'intel_iommu=on,strict'
+ self.run_and_check()
+
+ def test_intel_iommu_strict_cm(self):
+ self.common_vm_setup()
+ self.vm.add_args('-device', 'intel-iommu,intremap=on,caching-mode=on')
+ self.vm.add_args('-machine', 'kernel_irqchip=split')
+ self.kernel_params += 'intel_iommu=on,strict'
+ self.run_and_check()
+
+ def test_intel_iommu_pt(self):
+ self.common_vm_setup()
+ self.vm.add_args('-device', 'intel-iommu,intremap=on')
+ self.vm.add_args('-machine', 'kernel_irqchip=split')
+ self.kernel_params += 'intel_iommu=on iommu=pt'
+ self.run_and_check()
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_linux_initrd.py b/tests/functional/test_linux_initrd.py
index c71a59d..2207f83 100755
--- a/tests/functional/test_linux_initrd.py
+++ b/tests/functional/test_linux_initrd.py
@@ -10,12 +10,10 @@
# 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 os
import logging
import tempfile
-from qemu_test import QemuSystemTest, Asset
-from unittest import skipUnless
+from qemu_test import QemuSystemTest, Asset, skipFlakyTest
class LinuxInitrd(QemuSystemTest):
@@ -60,7 +58,8 @@ class LinuxInitrd(QemuSystemTest):
max_size + 1)
self.assertRegex(self.vm.get_log(), expected_msg)
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
+ # XXX file tracking bug
+ @skipFlakyTest(bug_url=None)
def test_with_2gib_file_should_work_with_linux_v4_16(self):
"""
QEMU has supported up to 4 GiB initrd for recent kernel
diff --git a/tests/functional/test_m68k_mcf5208evb.py b/tests/functional/test_m68k_mcf5208evb.py
index fb178fd..c7d1998 100755
--- a/tests/functional/test_m68k_mcf5208evb.py
+++ b/tests/functional/test_m68k_mcf5208evb.py
@@ -6,7 +6,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import LinuxKernelTest, Asset
-from qemu_test.utils import archive_extract
+
class Mcf5208EvbTest(LinuxKernelTest):
@@ -16,10 +16,10 @@ class Mcf5208EvbTest(LinuxKernelTest):
def test_m68k_mcf5208evb(self):
self.set_machine('mcf5208evb')
- file_path = self.ASSET_DAY07.fetch()
- archive_extract(file_path, self.workdir)
+ self.archive_extract(self.ASSET_DAY07)
self.vm.set_console()
- self.vm.add_args('-kernel', self.workdir + '/day07/sanity-clause.elf')
+ self.vm.add_args('-kernel',
+ self.scratch_file('day07', 'sanity-clause.elf'))
self.vm.launch()
self.wait_for_console_pattern('QEMU advent calendar')
diff --git a/tests/functional/test_m68k_nextcube.py b/tests/functional/test_m68k_nextcube.py
index 0124622..ff773a7 100755
--- a/tests/functional/test_m68k_nextcube.py
+++ b/tests/functional/test_m68k_nextcube.py
@@ -7,19 +7,11 @@
# 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 os
import time
from qemu_test import QemuSystemTest, Asset
-from unittest import skipUnless
-
-from qemu_test.tesseract import tesseract_available, tesseract_ocr
-
-PIL_AVAILABLE = True
-try:
- from PIL import Image
-except ImportError:
- PIL_AVAILABLE = False
+from qemu_test import skipIfMissingImports, skipIfMissingCommands
+from qemu_test.tesseract import tesseract_ocr
class NextCubeMachine(QemuSystemTest):
@@ -43,23 +35,21 @@ class NextCubeMachine(QemuSystemTest):
self.vm.cmd('human-monitor-command',
command_line='screendump %s' % screenshot_path)
- @skipUnless(PIL_AVAILABLE, 'Python PIL not installed')
+ @skipIfMissingImports("PIL")
def test_bootrom_framebuffer_size(self):
self.set_machine('next-cube')
- screenshot_path = os.path.join(self.workdir, "dump.ppm")
+ screenshot_path = self.scratch_file("dump.ppm")
self.check_bootrom_framebuffer(screenshot_path)
+ from PIL import Image
width, height = Image.open(screenshot_path).size
self.assertEqual(width, 1120)
self.assertEqual(height, 832)
- # Tesseract 4 adds a new OCR engine based on LSTM neural networks. The
- # new version is faster and more accurate than version 3. The drawback is
- # that it is still alpha-level software.
- @skipUnless(tesseract_available(4), 'tesseract OCR tool not available')
+ @skipIfMissingCommands('tesseract')
def test_bootrom_framebuffer_ocr_with_tesseract(self):
self.set_machine('next-cube')
- screenshot_path = os.path.join(self.workdir, "dump.ppm")
+ screenshot_path = self.scratch_file("dump.ppm")
self.check_bootrom_framebuffer(screenshot_path)
lines = tesseract_ocr(screenshot_path)
text = '\n'.join(lines)
diff --git a/tests/functional/test_m68k_q800.py b/tests/functional/test_m68k_q800.py
index 3b17244..400b7ae 100755
--- a/tests/functional/test_m68k_q800.py
+++ b/tests/functional/test_m68k_q800.py
@@ -18,9 +18,8 @@ class Q800MachineTest(LinuxKernelTest):
def test_m68k_q800(self):
self.set_machine('q800')
- deb_path = self.ASSET_KERNEL.fetch()
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-5.3.0-1-m68k')
+ kernel_path = self.archive_extract(self.ASSET_KERNEL,
+ member='boot/vmlinux-5.3.0-1-m68k')
self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
diff --git a/tests/functional/test_microblaze_s3adsp1800.py b/tests/functional/test_microblaze_s3adsp1800.py
index d2be310..2c4464b 100755
--- a/tests/functional/test_microblaze_s3adsp1800.py
+++ b/tests/functional/test_microblaze_s3adsp1800.py
@@ -7,10 +7,9 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from qemu_test import exec_command, exec_command_and_wait_for_pattern
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
-from qemu_test.utils import archive_extract
+
class MicroblazeMachine(QemuSystemTest):
@@ -23,10 +22,10 @@ class MicroblazeMachine(QemuSystemTest):
def test_microblaze_s3adsp1800(self):
self.set_machine('petalogix-s3adsp1800')
- file_path = self.ASSET_IMAGE.fetch()
- archive_extract(file_path, self.workdir)
+ self.archive_extract(self.ASSET_IMAGE)
self.vm.set_console()
- self.vm.add_args('-kernel', self.workdir + '/day17/ballerina.bin')
+ self.vm.add_args('-kernel',
+ self.scratch_file('day17', 'ballerina.bin'))
self.vm.launch()
wait_for_console_pattern(self, 'This architecture does not have '
'kernel memory protection')
diff --git a/tests/functional/test_microblazeel_s3adsp1800.py b/tests/functional/test_microblazeel_s3adsp1800.py
index faa3927..c382afe 100755
--- a/tests/functional/test_microblazeel_s3adsp1800.py
+++ b/tests/functional/test_microblazeel_s3adsp1800.py
@@ -11,7 +11,7 @@ import time
from qemu_test import exec_command, exec_command_and_wait_for_pattern
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
-from qemu_test.utils import archive_extract
+
class MicroblazeelMachine(QemuSystemTest):
@@ -24,11 +24,11 @@ class MicroblazeelMachine(QemuSystemTest):
def test_microblazeel_s3adsp1800(self):
self.require_netdev('user')
self.set_machine('petalogix-s3adsp1800')
- file_path = self.ASSET_IMAGE.fetch()
- archive_extract(file_path, self.workdir)
+ self.archive_extract(self.ASSET_IMAGE)
self.vm.set_console()
- self.vm.add_args('-kernel', self.workdir + '/day13/xmaton.bin')
- self.vm.add_args('-nic', 'user,tftp=' + self.workdir + '/day13/')
+ self.vm.add_args('-kernel', self.scratch_file('day13', 'xmaton.bin'))
+ tftproot = self.scratch_file('day13')
+ self.vm.add_args('-nic', f'user,tftp={tftproot}')
self.vm.launch()
wait_for_console_pattern(self, 'QEMU Advent Calendar 2023')
time.sleep(0.1)
diff --git a/tests/functional/test_mips64el_fuloong2e.py b/tests/functional/test_mips64el_fuloong2e.py
index a32d5f9..35e500b 100755
--- a/tests/functional/test_mips64el_fuloong2e.py
+++ b/tests/functional/test_mips64el_fuloong2e.py
@@ -13,7 +13,7 @@ import os
import subprocess
from qemu_test import LinuxKernelTest, Asset
-from qemu_test import wait_for_console_pattern
+from qemu_test import wait_for_console_pattern, skipUntrustedTest
from unittest import skipUnless
class MipsFuloong2e(LinuxKernelTest):
@@ -26,9 +26,9 @@ class MipsFuloong2e(LinuxKernelTest):
'2a70f15b397f4ced632b0c15cb22660394190644146d804d60a4796eefbe1f50')
def test_linux_kernel_3_16(self):
- deb_path = self.ASSET_KERNEL.fetch()
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-3.16.0-6-loongson-2e')
+ kernel_path = self.archive_extract(
+ self.ASSET_KERNEL,
+ member='boot/vmlinux-3.16.0-6-loongson-2e')
self.set_machine('fuloong2e')
self.vm.set_console()
@@ -39,7 +39,7 @@ class MipsFuloong2e(LinuxKernelTest):
console_pattern = 'Kernel command line: %s' % kernel_command_line
self.wait_for_console_pattern(console_pattern)
- @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ @skipUntrustedTest()
@skipUnless(os.getenv('RESCUE_YL_PATH'), 'RESCUE_YL_PATH not available')
def test_linux_kernel_2_6_27_isa_serial(self):
# Recovery system for the Yeeloong laptop
diff --git a/tests/functional/test_mips64el_loongson3v.py b/tests/functional/test_mips64el_loongson3v.py
index e57ec54..f85371e 100755
--- a/tests/functional/test_mips64el_loongson3v.py
+++ b/tests/functional/test_mips64el_loongson3v.py
@@ -9,11 +9,9 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import os
-
-from unittest import skipUnless
from qemu_test import QemuSystemTest, Asset
-from qemu_test import wait_for_console_pattern
+from qemu_test import wait_for_console_pattern, skipUntrustedTest
+
class MipsLoongson3v(QemuSystemTest):
timeout = 60
@@ -23,7 +21,7 @@ class MipsLoongson3v(QemuSystemTest):
'releases/download/20210112/pmon-3avirt.bin'),
'fcdf6bb2cb7885a4a62f31fcb0d5e368bac7b6cea28f40c6dfa678af22fea20a')
- @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ @skipUntrustedTest()
def test_pmon_serial_console(self):
self.set_machine('loongson3-virt')
diff --git a/tests/functional/test_mips64el_malta.py b/tests/functional/test_mips64el_malta.py
index 6d1195d..a8da15a 100755
--- a/tests/functional/test_mips64el_malta.py
+++ b/tests/functional/test_mips64el_malta.py
@@ -14,20 +14,7 @@ import logging
from qemu_test import LinuxKernelTest, Asset
from qemu_test import exec_command_and_wait_for_pattern
-from qemu_test.utils import gzip_uncompress
-from unittest import skipUnless
-
-NUMPY_AVAILABLE = True
-try:
- import numpy as np
-except ImportError:
- NUMPY_AVAILABLE = False
-
-CV2_AVAILABLE = True
-try:
- import cv2
-except ImportError:
- CV2_AVAILABLE = False
+from qemu_test import skipIfMissingImports, skipFlakyTest, skipUntrustedTest
class MaltaMachineConsole(LinuxKernelTest):
@@ -51,9 +38,9 @@ class MaltaMachineConsole(LinuxKernelTest):
[2] https://kernel-team.pages.debian.net/kernel-handbook/
ch-common-tasks.html#s-common-official
"""
- deb_path = self.ASSET_KERNEL_2_63_2.fetch()
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-2.6.32-5-5kc-malta')
+ kernel_path = self.archive_extract(
+ self.ASSET_KERNEL_2_63_2,
+ member='boot/vmlinux-2.6.32-5-5kc-malta')
self.set_machine('malta')
self.vm.set_console()
@@ -76,12 +63,10 @@ class MaltaMachineConsole(LinuxKernelTest):
'rootfs.mipsel64r1.cpio.gz'),
'75ba10cd35fb44e32948eeb26974f061b703c81c4ba2fab1ebcacf1d1bec3b61')
- @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ @skipUntrustedTest()
def test_mips64el_malta_5KEc_cpio(self):
kernel_path = self.ASSET_KERNEL_3_19_3.fetch()
- initrd_path_gz = self.ASSET_CPIO_R1.fetch()
- initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
- gzip_uncompress(initrd_path_gz, initrd_path)
+ initrd_path = self.uncompress(self.ASSET_CPIO_R1)
self.set_machine('malta')
self.vm.set_console()
@@ -106,8 +91,7 @@ class MaltaMachineConsole(LinuxKernelTest):
self.vm.wait()
-@skipUnless(NUMPY_AVAILABLE, 'Python NumPy not installed')
-@skipUnless(CV2_AVAILABLE, 'Python OpenCV not installed')
+@skipIfMissingImports('numpy', 'cv2')
class MaltaMachineFramebuffer(LinuxKernelTest):
timeout = 30
@@ -126,11 +110,13 @@ class MaltaMachineFramebuffer(LinuxKernelTest):
"""
Boot Linux kernel and check Tux logo is displayed on the framebuffer.
"""
- screendump_path = os.path.join(self.workdir, 'screendump.pbm')
- kernel_path_gz = self.ASSET_KERNEL_4_7_0.fetch()
- kernel_path = self.workdir + "/vmlinux"
- gzip_uncompress(kernel_path_gz, kernel_path)
+ import numpy as np
+ import cv2
+
+ screendump_path = self.scratch_file('screendump.pbm')
+
+ kernel_path = self.uncompress(self.ASSET_KERNEL_4_7_0)
tuxlogo_path = self.ASSET_TUXLOGO.fetch()
@@ -171,11 +157,12 @@ class MaltaMachineFramebuffer(LinuxKernelTest):
def test_mips_malta_i6400_framebuffer_logo_1core(self):
self.do_test_i6400_framebuffer_logo(1)
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
+ # XXX file tracking bug
+ @skipFlakyTest(bug_url=None)
def test_mips_malta_i6400_framebuffer_logo_7cores(self):
self.do_test_i6400_framebuffer_logo(7)
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
+ @skipFlakyTest(bug_url=None)
def test_mips_malta_i6400_framebuffer_logo_8cores(self):
self.do_test_i6400_framebuffer_logo(8)
diff --git a/tests/functional/test_mips_malta.py b/tests/functional/test_mips_malta.py
index a012081..3b15038 100755
--- a/tests/functional/test_mips_malta.py
+++ b/tests/functional/test_mips_malta.py
@@ -6,11 +6,8 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import os
-
from qemu_test import LinuxKernelTest, Asset
from qemu_test import exec_command_and_wait_for_pattern
-from qemu_test.utils import gzip_uncompress
class MaltaMachineConsole(LinuxKernelTest):
@@ -22,9 +19,9 @@ class MaltaMachineConsole(LinuxKernelTest):
'16ca524148afb0626f483163e5edf352bc1ab0e4fc7b9f9d473252762f2c7a43')
def test_mips_malta(self):
- deb_path = self.ASSET_KERNEL_2_63_2.fetch()
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-2.6.32-5-4kc-malta')
+ kernel_path = self.archive_extract(
+ self.ASSET_KERNEL_2_63_2,
+ member='boot/vmlinux-2.6.32-5-4kc-malta')
self.set_machine('malta')
self.vm.set_console()
@@ -48,12 +45,10 @@ class MaltaMachineConsole(LinuxKernelTest):
'dcfe3a7fe3200da3a00d176b95caaa086495eb158f2bff64afc67d7e1eb2cddc')
def test_mips_malta_cpio(self):
- deb_path = self.ASSET_KERNEL_4_5_0.fetch()
- kernel_path = self.extract_from_deb(deb_path,
- '/boot/vmlinux-4.5.0-2-4kc-malta')
- initrd_path_gz = self.ASSET_INITRD.fetch()
- initrd_path = os.path.join(self.workdir, 'rootfs.cpio')
- gzip_uncompress(initrd_path_gz, initrd_path)
+ kernel_path = self.archive_extract(
+ self.ASSET_KERNEL_4_5_0,
+ member='boot/vmlinux-4.5.0-2-4kc-malta')
+ initrd_path = self.uncompress(self.ASSET_INITRD)
self.set_machine('malta')
self.vm.set_console()
diff --git a/tests/functional/test_mipsel_malta.py b/tests/functional/test_mipsel_malta.py
index b8dfddd..fe9c3a1 100755
--- a/tests/functional/test_mipsel_malta.py
+++ b/tests/functional/test_mipsel_malta.py
@@ -9,13 +9,9 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import os
-
from qemu_test import QemuSystemTest, LinuxKernelTest, Asset
from qemu_test import interrupt_interactive_console_until_pattern
from qemu_test import wait_for_console_pattern
-from qemu_test.utils import lzma_uncompress
-from zipfile import ZipFile
class MaltaMachineConsole(LinuxKernelTest):
@@ -36,9 +32,8 @@ class MaltaMachineConsole(LinuxKernelTest):
'generic_nano32r6el_page64k_dbg.xz'),
'ce21ff4b07a981ecb8a39db2876616f5a2473eb2ab459c6f67465b9914b0c6b6')
- def do_test_mips_malta32el_nanomips(self, kernel_path_xz):
- kernel_path = os.path.join(self.workdir, 'kernel')
- lzma_uncompress(kernel_path_xz, kernel_path)
+ def do_test_mips_malta32el_nanomips(self, kernel):
+ kernel_path = self.uncompress(kernel)
self.set_machine('malta')
self.vm.set_console()
@@ -54,16 +49,13 @@ class MaltaMachineConsole(LinuxKernelTest):
self.wait_for_console_pattern(console_pattern)
def test_mips_malta32el_nanomips_4k(self):
- kernel_path_xz = self.ASSET_KERNEL_4K.fetch()
- self.do_test_mips_malta32el_nanomips(kernel_path_xz)
+ self.do_test_mips_malta32el_nanomips(self.ASSET_KERNEL_4K)
def test_mips_malta32el_nanomips_16k_up(self):
- kernel_path_xz = self.ASSET_KERNEL_16K.fetch()
- self.do_test_mips_malta32el_nanomips(kernel_path_xz)
+ self.do_test_mips_malta32el_nanomips(self.ASSET_KERNEL_16K)
def test_mips_malta32el_nanomips_64k_dbg(self):
- kernel_path_xz = self.ASSET_KERNEL_16K.fetch()
- self.do_test_mips_malta32el_nanomips(kernel_path_xz)
+ self.do_test_mips_malta32el_nanomips(self.ASSET_KERNEL_64K)
class MaltaMachineYAMON(QemuSystemTest):
@@ -75,10 +67,8 @@ class MaltaMachineYAMON(QemuSystemTest):
def test_mipsel_malta_yamon(self):
yamon_bin = 'yamon-02.22.bin'
- zip_path = self.ASSET_YAMON_ROM.fetch()
- with ZipFile(zip_path, 'r') as zf:
- zf.extract(yamon_bin, path=self.workdir)
- yamon_path = os.path.join(self.workdir, yamon_bin)
+ self.archive_extract(self.ASSET_YAMON_ROM)
+ yamon_path = self.scratch_file(yamon_bin)
self.set_machine('malta')
self.vm.set_console()
diff --git a/tests/functional/test_or1k_sim.py b/tests/functional/test_or1k_sim.py
index 5b68b6b..f9f0b69 100755
--- a/tests/functional/test_or1k_sim.py
+++ b/tests/functional/test_or1k_sim.py
@@ -6,7 +6,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import LinuxKernelTest, Asset
-from qemu_test.utils import archive_extract
+
class OpenRISC1kSimTest(LinuxKernelTest):
@@ -16,10 +16,9 @@ class OpenRISC1kSimTest(LinuxKernelTest):
def test_or1k_sim(self):
self.set_machine('or1k-sim')
- file_path = self.ASSET_DAY20.fetch()
- archive_extract(file_path, self.workdir)
+ self.archive_extract(self.ASSET_DAY20)
self.vm.set_console()
- self.vm.add_args('-kernel', self.workdir + '/day20/vmlinux')
+ self.vm.add_args('-kernel', self.scratch_file('day20', 'vmlinux'))
self.vm.launch()
self.wait_for_console_pattern('QEMU advent calendar')
diff --git a/tests/functional/test_ppc64_e500.py b/tests/functional/test_ppc64_e500.py
index f1af923..b92fe0b 100755
--- a/tests/functional/test_ppc64_e500.py
+++ b/tests/functional/test_ppc64_e500.py
@@ -5,7 +5,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import LinuxKernelTest, Asset
-from qemu_test.utils import archive_extract
+
class E500Test(LinuxKernelTest):
@@ -16,9 +16,8 @@ class E500Test(LinuxKernelTest):
def test_ppc64_e500(self):
self.set_machine('ppce500')
self.cpu = 'e5500'
- file_path = self.ASSET_DAY19.fetch()
- archive_extract(file_path, self.workdir)
- self.launch_kernel(self.workdir + '/day19/uImage',
+ self.archive_extract(self.ASSET_DAY19)
+ self.launch_kernel(self.scratch_file('day19', 'uImage'),
wait_for='QEMU advent calendar')
if __name__ == '__main__':
diff --git a/tests/functional/test_ppc64_hv.py b/tests/functional/test_ppc64_hv.py
index d97b62e..037dfdf 100755
--- a/tests/functional/test_ppc64_hv.py
+++ b/tests/functional/test_ppc64_hv.py
@@ -9,35 +9,14 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from unittest import skipIf, skipUnless
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern, exec_command
+from qemu_test import skipIfMissingCommands, skipBigDataTest
import os
import time
import subprocess
from datetime import datetime
-deps = ["xorriso"] # dependent tools needed in the test setup/box.
-
-def which(tool):
- """ looks up the full path for @tool, returns None if not found
- or if @tool does not have executable permissions.
- """
- paths=os.getenv('PATH')
- for p in paths.split(os.path.pathsep):
- p = os.path.join(p, tool)
- if os.path.exists(p) and os.access(p, os.X_OK):
- return p
- return None
-
-def missing_deps():
- """ returns True if any of the test dependent tools are absent.
- """
- for dep in deps:
- if which(dep) is None:
- return True
- return False
-
# Alpine is a light weight distro that supports QEMU. These tests boot
# that on the machine then run a QEMU guest inside it in KVM mode,
# that runs the same Alpine distro image.
@@ -45,8 +24,8 @@ def missing_deps():
# large download, but it may be more polite to create qcow2 image with
# QEMU already installed and use that.
# XXX: The order of these tests seems to matter, see git blame.
-@skipIf(missing_deps(), 'dependencies (%s) not installed' % ','.join(deps))
-@skipUnless(os.getenv('QEMU_TEST_ALLOW_LARGE_STORAGE'), 'storage limited')
+@skipIfMissingCommands("xorriso")
+@skipBigDataTest()
class HypervisorTest(QemuSystemTest):
timeout = 1000
@@ -67,23 +46,15 @@ class HypervisorTest(QemuSystemTest):
:param path: path within the iso file of the file to be extracted
:returns: path of the extracted file
"""
- filename = os.path.basename(path)
-
- cwd = os.getcwd()
- os.chdir(self.workdir)
+ filename = self.scratch_file(os.path.basename(path))
cmd = "xorriso -osirrox on -indev %s -cpx %s %s" % (iso, path, filename)
subprocess.run(cmd.split(),
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
os.chmod(filename, 0o600)
- os.chdir(cwd)
- # Return complete path to extracted file. Because callers to
- # extract_from_iso() specify 'path' with a leading slash, it is
- # necessary to use os.path.relpath() as otherwise os.path.join()
- # interprets it as an absolute path and drops the self.workdir part.
- return os.path.normpath(os.path.join(self.workdir, filename))
+ return filename
def setUp(self):
super().setUp()
diff --git a/tests/functional/test_ppc64_tuxrun.py b/tests/functional/test_ppc64_tuxrun.py
index 03b47e0..8a98d18 100755
--- a/tests/functional/test_ppc64_tuxrun.py
+++ b/tests/functional/test_ppc64_tuxrun.py
@@ -11,9 +11,10 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
+from subprocess import check_call, DEVNULL
import tempfile
-from qemu_test import run_cmd, Asset
+from qemu_test import Asset
from qemu_test.tuxruntest import TuxRunBaselineTest
class TuxRunPPC64Test(TuxRunBaselineTest):
@@ -70,7 +71,9 @@ class TuxRunPPC64Test(TuxRunBaselineTest):
# Create a temporary qcow2 and launch the test-case
with tempfile.NamedTemporaryFile(prefix=prefix,
suffix='.qcow2') as qcow2:
- run_cmd([self.qemu_img, 'create', '-f', 'qcow2', qcow2.name, ' 1G'])
+ check_call([self.qemu_img, 'create', '-f', 'qcow2',
+ qcow2.name, ' 1G'],
+ stdout=DEVNULL, stderr=DEVNULL)
self.vm.add_args('-drive', 'file=' + qcow2.name +
',format=qcow2,if=none,id='
diff --git a/tests/functional/test_ppc_40p.py b/tests/functional/test_ppc_40p.py
index 67bcdae..7a74e0c 100755
--- a/tests/functional/test_ppc_40p.py
+++ b/tests/functional/test_ppc_40p.py
@@ -7,11 +7,8 @@
# 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 os
-
-from unittest import skipUnless
from qemu_test import QemuSystemTest, Asset
-from qemu_test import wait_for_console_pattern
+from qemu_test import wait_for_console_pattern, skipUntrustedTest
class IbmPrep40pMachine(QemuSystemTest):
@@ -37,7 +34,7 @@ class IbmPrep40pMachine(QemuSystemTest):
# All rights reserved.
# U.S. Government Users Restricted Rights - Use, duplication or disclosure
# restricted by GSA ADP Schedule Contract with IBM Corp.
- @skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 'untrusted code')
+ @skipUntrustedTest()
def test_factory_firmware_and_netbsd(self):
self.set_machine('40p')
self.require_accelerator("tcg")
diff --git a/tests/functional/test_ppc_amiga.py b/tests/functional/test_ppc_amiga.py
index b793b5c..8600e2e 100755
--- a/tests/functional/test_ppc_amiga.py
+++ b/tests/functional/test_ppc_amiga.py
@@ -10,8 +10,8 @@
import subprocess
from qemu_test import QemuSystemTest, Asset
-from qemu_test import wait_for_console_pattern, run_cmd
-from zipfile import ZipFile
+from qemu_test import wait_for_console_pattern
+
class AmigaOneMachine(QemuSystemTest):
@@ -26,16 +26,16 @@ class AmigaOneMachine(QemuSystemTest):
self.require_accelerator("tcg")
self.set_machine('amigaone')
tar_name = 'A1Firmware_Floppy_05-Mar-2005.zip'
- zip_file = self.ASSET_IMAGE.fetch()
- with ZipFile(zip_file, 'r') as zf:
- zf.extractall(path=self.workdir)
- bios_fh = open(self.workdir + "/u-boot-amigaone.bin", "wb")
- subprocess.run(['tail', '-c', '524288',
- self.workdir + "/floppy_edition/updater.image"],
- stdout=bios_fh)
+ self.archive_extract(self.ASSET_IMAGE, format="zip")
+ bios = self.scratch_file("u-boot-amigaone.bin")
+ with open(bios, "wb") as bios_fh:
+ subprocess.run(['tail', '-c', '524288',
+ self.scratch_file("floppy_edition",
+ "updater.image")],
+ stdout=bios_fh)
self.vm.set_console()
- self.vm.add_args('-bios', self.workdir + '/u-boot-amigaone.bin')
+ self.vm.add_args('-bios', bios)
self.vm.launch()
wait_for_console_pattern(self, 'FLASH:')
diff --git a/tests/functional/test_ppc_bamboo.py b/tests/functional/test_ppc_bamboo.py
index e72cbde..fddcc24 100755
--- a/tests/functional/test_ppc_bamboo.py
+++ b/tests/functional/test_ppc_bamboo.py
@@ -7,11 +7,11 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from qemu_test.utils import archive_extract
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
from qemu_test import exec_command_and_wait_for_pattern
+
class BambooMachine(QemuSystemTest):
timeout = 90
@@ -25,13 +25,14 @@ class BambooMachine(QemuSystemTest):
self.set_machine('bamboo')
self.require_accelerator("tcg")
self.require_netdev('user')
- file_path = self.ASSET_IMAGE.fetch()
- archive_extract(file_path, self.workdir)
+ self.archive_extract(self.ASSET_IMAGE)
self.vm.set_console()
- self.vm.add_args('-kernel', self.workdir +
- '/system-image-powerpc-440fp/linux',
- '-initrd', self.workdir +
- '/system-image-powerpc-440fp/rootfs.cpio.gz',
+ self.vm.add_args('-kernel',
+ self.scratch_file('system-image-powerpc-440fp',
+ 'linux'),
+ '-initrd',
+ self.scratch_file('system-image-powerpc-440fp',
+ 'rootfs.cpio.gz'),
'-nic', 'user,model=rtl8139,restrict=on')
self.vm.launch()
wait_for_console_pattern(self, 'Type exit when done')
diff --git a/tests/functional/test_ppc_mac.py b/tests/functional/test_ppc_mac.py
index 3f45e37..9e4bc1a 100755
--- a/tests/functional/test_ppc_mac.py
+++ b/tests/functional/test_ppc_mac.py
@@ -5,7 +5,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import LinuxKernelTest, Asset
-from qemu_test.utils import archive_extract
+
class MacTest(LinuxKernelTest):
@@ -19,11 +19,9 @@ class MacTest(LinuxKernelTest):
# we're running kvm_hv or kvm_pr. For now let's disable this test
# if we don't have TCG support.
self.require_accelerator("tcg")
-
- file_path = self.ASSET_DAY15.fetch()
- archive_extract(file_path, self.workdir)
+ self.archive_extract(self.ASSET_DAY15)
self.vm.add_args('-M', 'graphics=off')
- self.launch_kernel(self.workdir + '/day15/invaders.elf',
+ self.launch_kernel(self.scratch_file('day15', 'invaders.elf'),
wait_for='QEMU advent calendar')
def test_ppc_g3beige(self):
diff --git a/tests/functional/test_ppc_mpc8544ds.py b/tests/functional/test_ppc_mpc8544ds.py
index 2b3f089..0715410 100755
--- a/tests/functional/test_ppc_mpc8544ds.py
+++ b/tests/functional/test_ppc_mpc8544ds.py
@@ -7,10 +7,10 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from qemu_test.utils import archive_extract
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
+
class Mpc8544dsMachine(QemuSystemTest):
timeout = 90
@@ -25,10 +25,10 @@ class Mpc8544dsMachine(QemuSystemTest):
def test_ppc_mpc8544ds(self):
self.require_accelerator("tcg")
self.set_machine('mpc8544ds')
- file_path = self.ASSET_IMAGE.fetch()
- archive_extract(file_path, self.workdir, member='creek/creek.bin')
+ kernel_file = self.archive_extract(self.ASSET_IMAGE,
+ member='creek/creek.bin')
self.vm.set_console()
- self.vm.add_args('-kernel', self.workdir + '/creek/creek.bin')
+ self.vm.add_args('-kernel', kernel_file)
self.vm.launch()
wait_for_console_pattern(self, 'QEMU advent calendar 2020',
self.panic_message)
diff --git a/tests/functional/test_ppc_virtex_ml507.py b/tests/functional/test_ppc_virtex_ml507.py
index ffa9a06..8fe4354 100755
--- a/tests/functional/test_ppc_virtex_ml507.py
+++ b/tests/functional/test_ppc_virtex_ml507.py
@@ -7,10 +7,10 @@
# This work is licensed under the terms of the GNU GPL, version 2 or
# later. See the COPYING file in the top-level directory.
-from qemu_test.utils import archive_extract
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
+
class VirtexMl507Machine(QemuSystemTest):
timeout = 90
@@ -25,11 +25,11 @@ class VirtexMl507Machine(QemuSystemTest):
def test_ppc_virtex_ml507(self):
self.require_accelerator("tcg")
self.set_machine('virtex-ml507')
- file_path = self.ASSET_IMAGE.fetch()
- archive_extract(file_path, self.workdir)
+ self.archive_extract(self.ASSET_IMAGE)
self.vm.set_console()
- self.vm.add_args('-kernel', self.workdir + '/hippo/hippo.linux',
- '-dtb', self.workdir + '/hippo/virtex440-ml507.dtb',
+ self.vm.add_args('-kernel', self.scratch_file('hippo', 'hippo.linux'),
+ '-dtb', self.scratch_file('hippo',
+ 'virtex440-ml507.dtb'),
'-m', '512')
self.vm.launch()
wait_for_console_pattern(self, 'QEMU advent calendar 2020',
diff --git a/tests/functional/test_rx_gdbsim.py b/tests/functional/test_rx_gdbsim.py
index 5687f75..20623aa 100755
--- a/tests/functional/test_rx_gdbsim.py
+++ b/tests/functional/test_rx_gdbsim.py
@@ -10,13 +10,9 @@
# 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 os
-
-from unittest import skipUnless
from qemu_test import QemuSystemTest, Asset
from qemu_test import exec_command_and_wait_for_pattern
-from qemu_test import wait_for_console_pattern
-from qemu_test.utils import gzip_uncompress
+from qemu_test import wait_for_console_pattern, skipFlakyTest
class RxGdbSimMachine(QemuSystemTest):
@@ -40,9 +36,7 @@ class RxGdbSimMachine(QemuSystemTest):
"""
self.set_machine('gdbsim-r5f562n8')
- uboot_path_gz = self.ASSET_UBOOT.fetch()
- uboot_path = os.path.join(self.workdir, 'u-boot.bin')
- gzip_uncompress(uboot_path_gz, uboot_path)
+ uboot_path = self.uncompress(self.ASSET_UBOOT)
self.vm.set_console()
self.vm.add_args('-bios', uboot_path,
@@ -52,9 +46,10 @@ class RxGdbSimMachine(QemuSystemTest):
wait_for_console_pattern(self, uboot_version)
gcc_version = 'rx-unknown-linux-gcc (GCC) 9.0.0 20181105 (experimental)'
# FIXME limit baudrate on chardev, else we type too fast
+ # https://gitlab.com/qemu-project/qemu/-/issues/2691
#exec_command_and_wait_for_pattern(self, 'version', gcc_version)
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
+ @skipFlakyTest(bug_url="https://gitlab.com/qemu-project/qemu/-/issues/2691")
def test_linux_sash(self):
"""
Boots a Linux kernel and checks that the console is operational.
diff --git a/tests/functional/test_s390x_ccw_virtio.py b/tests/functional/test_s390x_ccw_virtio.py
index f7acd90..453711a 100755
--- a/tests/functional/test_s390x_ccw_virtio.py
+++ b/tests/functional/test_s390x_ccw_virtio.py
@@ -17,7 +17,7 @@ import tempfile
from qemu_test import QemuSystemTest, Asset
from qemu_test import exec_command_and_wait_for_pattern
from qemu_test import wait_for_console_pattern
-from qemu_test.utils import lzma_uncompress
+
class S390CCWVirtioMachine(QemuSystemTest):
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
@@ -174,9 +174,7 @@ class S390CCWVirtioMachine(QemuSystemTest):
kernel_path = self.ASSET_F31_KERNEL.fetch()
- initrd_path_xz = self.ASSET_F31_INITRD.fetch()
- initrd_path = os.path.join(self.workdir, 'initrd-raw.img')
- lzma_uncompress(initrd_path_xz, initrd_path)
+ initrd_path = self.uncompress(self.ASSET_F31_INITRD, format="xz")
self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + ' audit=0 '
diff --git a/tests/functional/test_s390x_topology.py b/tests/functional/test_s390x_topology.py
index c54c7a8..eefd972 100755
--- a/tests/functional/test_s390x_topology.py
+++ b/tests/functional/test_s390x_topology.py
@@ -10,13 +10,10 @@
# 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 os
-
from qemu_test import QemuSystemTest, Asset
from qemu_test import exec_command
from qemu_test import exec_command_and_wait_for_pattern
from qemu_test import wait_for_console_pattern
-from qemu_test.utils import lzma_uncompress
class S390CPUTopology(QemuSystemTest):
@@ -88,9 +85,7 @@ class S390CPUTopology(QemuSystemTest):
"""
self.require_accelerator("kvm")
kernel_path = self.ASSET_F35_KERNEL.fetch()
- initrd_path_xz = self.ASSET_F35_INITRD.fetch()
- initrd_path = os.path.join(self.workdir, 'initrd-raw.img')
- lzma_uncompress(initrd_path_xz, initrd_path)
+ initrd_path = self.uncompress(self.ASSET_F35_INITRD, format="xz")
self.vm.set_console()
kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE
diff --git a/tests/functional/test_sh4_r2d.py b/tests/functional/test_sh4_r2d.py
index c3cfff7..03a64837 100755
--- a/tests/functional/test_sh4_r2d.py
+++ b/tests/functional/test_sh4_r2d.py
@@ -4,11 +4,8 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import os
+from qemu_test import LinuxKernelTest, Asset, skipFlakyTest
-from qemu_test import LinuxKernelTest, Asset
-from qemu_test.utils import archive_extract
-from unittest import skipUnless
class R2dTest(LinuxKernelTest):
@@ -18,13 +15,14 @@ class R2dTest(LinuxKernelTest):
# This test has a 6-10% failure rate on various hosts that look
# like issues with a buggy kernel.
- @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable')
+ # XXX file tracking bug
+ @skipFlakyTest(bug_url=None)
def test_r2d(self):
self.set_machine('r2d')
- file_path = self.ASSET_DAY09.fetch()
- archive_extract(file_path, self.workdir)
+ self.archive_extract(self.ASSET_DAY09)
self.vm.add_args('-append', 'console=ttySC1')
- self.launch_kernel(self.workdir + '/day09/zImage', console_index=1,
+ self.launch_kernel(self.scratch_file('day09', 'zImage'),
+ console_index=1,
wait_for='QEMU advent calendar')
if __name__ == '__main__':
diff --git a/tests/functional/test_sh4eb_r2d.py b/tests/functional/test_sh4eb_r2d.py
index cd46007..473093b 100755
--- a/tests/functional/test_sh4eb_r2d.py
+++ b/tests/functional/test_sh4eb_r2d.py
@@ -4,12 +4,9 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
-import os
-import shutil
-
from qemu_test import LinuxKernelTest, Asset
from qemu_test import exec_command_and_wait_for_pattern
-from qemu_test.utils import archive_extract
+
class R2dEBTest(LinuxKernelTest):
@@ -19,14 +16,13 @@ class R2dEBTest(LinuxKernelTest):
def test_sh4eb_r2d(self):
self.set_machine('r2d')
- file_path = self.ASSET_TGZ.fetch()
- archive_extract(file_path, self.workdir)
+ self.archive_extract(self.ASSET_TGZ)
self.vm.add_args('-append', 'console=ttySC1 noiotrap')
- self.launch_kernel(os.path.join(self.workdir, 'sh4eb/linux-kernel'),
- initrd=os.path.join(self.workdir, 'sh4eb/initramfs.cpio.gz'),
+ self.launch_kernel(self.scratch_file('sh4eb', 'linux-kernel'),
+ initrd=self.scratch_file('sh4eb',
+ 'initramfs.cpio.gz'),
console_index=1, wait_for='Type exit when done')
exec_command_and_wait_for_pattern(self, 'exit', 'Restarting system')
- shutil.rmtree(os.path.join(self.workdir, 'sh4eb'))
if __name__ == '__main__':
LinuxKernelTest.main()
diff --git a/tests/functional/test_sparc64_sun4u.py b/tests/functional/test_sparc64_sun4u.py
index 32e245f..27ac289 100755
--- a/tests/functional/test_sparc64_sun4u.py
+++ b/tests/functional/test_sparc64_sun4u.py
@@ -10,11 +10,9 @@
# 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 os
-
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
-from qemu_test.utils import archive_extract
+
class Sun4uMachine(QemuSystemTest):
"""Boots the Linux kernel and checks that the console is operational"""
@@ -28,11 +26,10 @@ class Sun4uMachine(QemuSystemTest):
def test_sparc64_sun4u(self):
self.set_machine('sun4u')
- file_path = self.ASSET_IMAGE.fetch()
- kernel_name = 'day23/vmlinux'
- archive_extract(file_path, self.workdir, kernel_name)
+ kernel_file = self.archive_extract(self.ASSET_IMAGE,
+ member='day23/vmlinux')
self.vm.set_console()
- self.vm.add_args('-kernel', os.path.join(self.workdir, kernel_name),
+ self.vm.add_args('-kernel', kernel_file,
'-append', 'printk.time=0')
self.vm.launch()
wait_for_console_pattern(self, 'Starting logging: OK')
diff --git a/tests/functional/test_sparc_sun4m.py b/tests/functional/test_sparc_sun4m.py
index 573f852..7cd28eb 100755
--- a/tests/functional/test_sparc_sun4m.py
+++ b/tests/functional/test_sparc_sun4m.py
@@ -6,7 +6,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import LinuxKernelTest, Asset
-from qemu_test.utils import archive_extract
+
class Sun4mTest(LinuxKernelTest):
@@ -16,9 +16,8 @@ class Sun4mTest(LinuxKernelTest):
def test_sparc_ss20(self):
self.set_machine('SS-20')
- file_path = self.ASSET_DAY11.fetch()
- archive_extract(file_path, self.workdir)
- self.launch_kernel(self.workdir + '/day11/zImage.elf',
+ self.archive_extract(self.ASSET_DAY11)
+ self.launch_kernel(self.scratch_file('day11', 'zImage.elf'),
wait_for='QEMU advent calendar')
if __name__ == '__main__':
diff --git a/tests/functional/test_virtio_gpu.py b/tests/functional/test_virtio_gpu.py
index d502748..81c9156 100755
--- a/tests/functional/test_virtio_gpu.py
+++ b/tests/functional/test_virtio_gpu.py
@@ -6,25 +6,19 @@
# later. See the COPYING file in the top-level directory.
-from qemu_test import BUILD_DIR
from qemu_test import QemuSystemTest, Asset
from qemu_test import wait_for_console_pattern
from qemu_test import exec_command_and_wait_for_pattern
from qemu_test import is_readable_executable_file
-from qemu.utils import kvm_available
import os
import socket
import subprocess
-def pick_default_vug_bin():
- relative_path = "./contrib/vhost-user-gpu/vhost-user-gpu"
- if is_readable_executable_file(relative_path):
- return relative_path
-
- bld_dir_path = os.path.join(BUILD_DIR, relative_path)
+def pick_default_vug_bin(test):
+ bld_dir_path = test.build_file("contrib", "vhost-user-gpu", "vhost-user-gpu")
if is_readable_executable_file(bld_dir_path):
return bld_dir_path
@@ -87,7 +81,7 @@ class VirtioGPUx86(QemuSystemTest):
# FIXME: should check presence of vhost-user-gpu, virgl, memfd etc
self.require_accelerator('kvm')
- vug = pick_default_vug_bin()
+ vug = pick_default_vug_bin(self)
if not vug:
self.skipTest("Could not find vhost-user-gpu")
@@ -101,9 +95,7 @@ class VirtioGPUx86(QemuSystemTest):
os.set_inheritable(qemu_sock.fileno(), True)
os.set_inheritable(vug_sock.fileno(), True)
- self._vug_log_path = os.path.join(
- self.logdir, "vhost-user-gpu.log"
- )
+ self._vug_log_path = self.log_file("vhost-user-gpu.log")
self._vug_log_file = open(self._vug_log_path, "wb")
self.log.info('Complete vhost-user-gpu.log file can be '
'found at %s', self._vug_log_path)
diff --git a/tests/functional/test_x86_64_hotplug_cpu.py b/tests/functional/test_x86_64_hotplug_cpu.py
new file mode 100755
index 0000000..b1d5156
--- /dev/null
+++ b/tests/functional/test_x86_64_hotplug_cpu.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python3
+#
+# Functional test that hotplugs a CPU and checks it on a Linux guest
+#
+# Copyright (c) 2021 Red Hat, Inc.
+#
+# Author:
+# Cleber Rosa <crosa@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or
+# later. See the COPYING file in the top-level directory.
+
+from qemu_test import LinuxKernelTest, Asset, exec_command_and_wait_for_pattern
+
+
+class HotPlugCPU(LinuxKernelTest):
+
+ ASSET_KERNEL = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
+ '/31/Server/x86_64/os/images/pxeboot/vmlinuz'),
+ 'd4738d03dbbe083ca610d0821d0a8f1488bebbdccef54ce33e3adb35fda00129')
+
+ ASSET_INITRD = Asset(
+ ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases'
+ '/31/Server/x86_64/os/images/pxeboot/initrd.img'),
+ '277cd6c7adf77c7e63d73bbb2cded8ef9e2d3a2f100000e92ff1f8396513cd8b')
+
+ def test_hotplug(self):
+
+ self.require_accelerator('kvm')
+ self.vm.add_args('-accel', 'kvm')
+ self.vm.add_args('-cpu', 'Haswell')
+ self.vm.add_args('-smp', '1,sockets=1,cores=2,threads=1,maxcpus=2')
+ self.vm.add_args('-m', '1G')
+ self.vm.add_args('-append', 'console=ttyS0 rd.rescue')
+
+ self.launch_kernel(self.ASSET_KERNEL.fetch(),
+ self.ASSET_INITRD.fetch(),
+ wait_for='Entering emergency mode.')
+ prompt = '# '
+ self.wait_for_console_pattern(prompt)
+
+ exec_command_and_wait_for_pattern(self,
+ 'cd /sys/devices/system/cpu/cpu0',
+ 'cpu0#')
+ exec_command_and_wait_for_pattern(self,
+ 'cd /sys/devices/system/cpu/cpu1',
+ 'No such file or directory')
+
+ self.vm.cmd('device_add',
+ driver='Haswell-x86_64-cpu',
+ id='c1',
+ socket_id=0,
+ core_id=1,
+ thread_id=0)
+ self.wait_for_console_pattern('CPU1 has been hot-added')
+
+ exec_command_and_wait_for_pattern(self,
+ 'cd /sys/devices/system/cpu/cpu1',
+ 'cpu1#')
+
+ self.vm.cmd('device_del', id='c1')
+
+ exec_command_and_wait_for_pattern(self,
+ 'cd /sys/devices/system/cpu/cpu1',
+ 'No such file or directory')
+
+if __name__ == '__main__':
+ LinuxKernelTest.main()
diff --git a/tests/functional/test_xtensa_lx60.py b/tests/functional/test_xtensa_lx60.py
index d4ad92d..147c920 100755
--- a/tests/functional/test_xtensa_lx60.py
+++ b/tests/functional/test_xtensa_lx60.py
@@ -6,7 +6,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from qemu_test import LinuxKernelTest, Asset
-from qemu_test.utils import archive_extract
+
class XTensaLX60Test(LinuxKernelTest):
@@ -17,9 +17,9 @@ class XTensaLX60Test(LinuxKernelTest):
def test_xtensa_lx60(self):
self.set_machine('lx60')
self.cpu = 'dc233c'
- file_path = self.ASSET_DAY02.fetch()
- archive_extract(file_path, self.workdir)
- self.launch_kernel(self.workdir + '/day02/santas-sleigh-ride.elf',
+ self.archive_extract(self.ASSET_DAY02)
+ self.launch_kernel(self.scratch_file('day02',
+ 'santas-sleigh-ride.elf'),
wait_for='QEMU advent calendar')
if __name__ == '__main__':