diff --git a/docs/conf.py b/docs/conf.py index 164a8ee8b2..31bb9a3789 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -87,7 +87,7 @@ default_role = 'any' # General information about the project. project = u'QEMU' -copyright = u'2024, The QEMU Project Developers' +copyright = u'2025, The QEMU Project Developers' author = u'The QEMU Project Developers' # The version info for the project you're documenting, acts as replacement for diff --git a/include/qemu/help-texts.h b/include/qemu/help-texts.h index 353ab2ad8b..bc8fab9169 100644 --- a/include/qemu/help-texts.h +++ b/include/qemu/help-texts.h @@ -2,7 +2,7 @@ #define QEMU_HELP_TEXTS_H /* Copyright string for -version arguments, About dialogs, etc */ -#define QEMU_COPYRIGHT "Copyright (c) 2003-2024 " \ +#define QEMU_COPYRIGHT "Copyright (c) 2003-2025 " \ "Fabrice Bellard and the QEMU Project developers" /* Bug reporting information for --help arguments, About dialogs, etc */ diff --git a/tests/functional/meson.build b/tests/functional/meson.build index 24f7f8f2f1..a5087fcb34 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -224,6 +224,7 @@ tests_x86_64_system_quick = [ 'pc_cpu_hotplug_props', 'virtio_version', 'x86_cpu_model_versions', + 'vnc', ] tests_x86_64_system_thorough = [ diff --git a/tests/functional/qemu_test/ports.py b/tests/functional/qemu_test/ports.py new file mode 100644 index 0000000000..cc39939d48 --- /dev/null +++ b/tests/functional/qemu_test/ports.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +# +# Simple functional tests for VNC functionality +# +# Copyright 2018, 2024 Red Hat, Inc. +# +# 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 fcntl +import os +import socket +import sys +import tempfile + +from .config import BUILD_DIR +from typing import List + +class Ports(): + + PORTS_ADDR = '127.0.0.1' + PORTS_RANGE_SIZE = 1024 + PORTS_START = 49152 + ((os.getpid() * PORTS_RANGE_SIZE) % 16384) + PORTS_END = PORTS_START + PORTS_RANGE_SIZE + + def __enter__(self): + lock_file = os.path.join(BUILD_DIR, "tests", "functional", "port_lock") + self.lock_fh = os.open(lock_file, os.O_CREAT) + fcntl.flock(self.lock_fh, fcntl.LOCK_EX) + return self + + def __exit__(self, exc_type, exc_value, traceback): + fcntl.flock(self.lock_fh, fcntl.LOCK_UN) + os.close(self.lock_fh) + + def check_bind(self, port: int) -> bool: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + try: + sock.bind((self.PORTS_ADDR, port)) + except OSError: + return False + + return True + + def find_free_ports(self, count: int) -> List[int]: + result = [] + for port in range(self.PORTS_START, self.PORTS_END): + if self.check_bind(port): + result.append(port) + if len(result) >= count: + break + assert len(result) == count + return result + + def find_free_port(self) -> int: + return self.find_free_ports(1)[0] diff --git a/tests/functional/test_arm_quanta_gsj.py b/tests/functional/test_arm_quanta_gsj.py index 7aa5209bea..7b82e2185c 100755 --- a/tests/functional/test_arm_quanta_gsj.py +++ b/tests/functional/test_arm_quanta_gsj.py @@ -35,7 +35,7 @@ class EmcraftSf2Machine(LinuxKernelTest): @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') + image_path = self.uncompress(self.ASSET_IMAGE, format='gz') self.vm.set_console() drive_args = 'file=' + image_path + ',if=mtd,bus=0,unit=0' diff --git a/tests/functional/test_ppc64_hv.py b/tests/functional/test_ppc64_hv.py index 037dfdf87e..62f996adf6 100755 --- a/tests/functional/test_ppc64_hv.py +++ b/tests/functional/test_ppc64_hv.py @@ -12,6 +12,7 @@ from qemu_test import QemuSystemTest, Asset from qemu_test import wait_for_console_pattern, exec_command from qemu_test import skipIfMissingCommands, skipBigDataTest +from qemu_test import exec_command_and_wait_for_pattern import os import time import subprocess @@ -34,9 +35,9 @@ class HypervisorTest(QemuSystemTest): good_message = 'VFS: Cannot open root device' ASSET_ISO = Asset( - ('https://dl-cdn.alpinelinux.org/alpine/v3.18/' - 'releases/ppc64le/alpine-standard-3.18.4-ppc64le.iso'), - 'c26b8d3e17c2f3f0fed02b4b1296589c2390e6d5548610099af75300edd7b3ff') + ('https://dl-cdn.alpinelinux.org/alpine/v3.21/' + 'releases/ppc64le/alpine-standard-3.21.0-ppc64le.iso'), + '7651ab4e3027604535c0b36e86c901b4695bf8fe97b908f5b48590f6baae8f30') def extract_from_iso(self, iso, path): """ @@ -73,31 +74,29 @@ class HypervisorTest(QemuSystemTest): "id=drive0,read-only=true") self.vm.launch() - wait_for_console_pattern(self, 'Welcome to Alpine Linux 3.18') - exec_command(self, 'root') + ps1='localhost:~#' wait_for_console_pattern(self, 'localhost login:') - wait_for_console_pattern(self, 'You may change this message by editing /etc/motd.') + exec_command_and_wait_for_pattern(self, 'root', ps1) # If the time is wrong, SSL certificates can fail. - exec_command(self, 'date -s "' + datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S' + '"')) - exec_command(self, 'setup-alpine -qe') - wait_for_console_pattern(self, 'Updating repository indexes... done.') + exec_command_and_wait_for_pattern(self, 'date -s "' + datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S' + '"'), ps1) + ps1='alpine:~#' + exec_command_and_wait_for_pattern(self, 'setup-alpine -qe', ps1) + exec_command_and_wait_for_pattern(self, 'setup-apkrepos -c1', ps1) + exec_command_and_wait_for_pattern(self, 'apk update', ps1) + # Could upgrade here but it usually should not be necessary + # exec_command_and_wait_for_pattern(self, 'apk upgrade --available', ps1) def do_stop_alpine(self): - exec_command(self, 'poweroff') + exec_command(self, 'echo "TEST ME"') wait_for_console_pattern(self, 'alpine:~#') + exec_command(self, 'poweroff') + wait_for_console_pattern(self, 'reboot: Power down') self.vm.wait() def do_setup_kvm(self): - exec_command(self, 'echo http://dl-cdn.alpinelinux.org/alpine/v3.18/main > /etc/apk/repositories') - wait_for_console_pattern(self, 'alpine:~#') - exec_command(self, 'echo http://dl-cdn.alpinelinux.org/alpine/v3.18/community >> /etc/apk/repositories') - wait_for_console_pattern(self, 'alpine:~#') - exec_command(self, 'apk update') - wait_for_console_pattern(self, 'alpine:~#') - exec_command(self, 'apk add qemu-system-ppc64') - wait_for_console_pattern(self, 'alpine:~#') - exec_command(self, 'modprobe kvm-hv') - wait_for_console_pattern(self, 'alpine:~#') + ps1='alpine:~#' + exec_command_and_wait_for_pattern(self, 'apk add qemu-system-ppc64', ps1) + exec_command_and_wait_for_pattern(self, 'modprobe kvm-hv', ps1) # This uses the host's block device as the source file for guest block # device for install media. This is a bit hacky but allows reuse of the @@ -115,16 +114,13 @@ class HypervisorTest(QemuSystemTest): '-initrd /media/nvme0n1/boot/initramfs-lts ' '-kernel /media/nvme0n1/boot/vmlinuz-lts ' '-append \'usbcore.nousb ' + append + '\'') - # Alpine 3.18 kernel seems to crash in XHCI USB driver. - wait_for_console_pattern(self, 'Welcome to Alpine Linux 3.18') - exec_command(self, 'root') + # Alpine 3.21 kernel seems to crash in XHCI USB driver. + ps1='localhost:~#' wait_for_console_pattern(self, 'localhost login:') - wait_for_console_pattern(self, 'You may change this message by editing /etc/motd.') - exec_command(self, 'poweroff >& /dev/null') - wait_for_console_pattern(self, 'localhost:~#') + exec_command_and_wait_for_pattern(self, 'root', ps1) + exec_command(self, 'poweroff') wait_for_console_pattern(self, 'reboot: Power down') - time.sleep(1) - exec_command(self, '') + # Now wait for the host's prompt to come back wait_for_console_pattern(self, 'alpine:~#') def test_hv_pseries(self): diff --git a/tests/functional/test_rx_gdbsim.py b/tests/functional/test_rx_gdbsim.py index 20623aa51c..49245793e1 100755 --- a/tests/functional/test_rx_gdbsim.py +++ b/tests/functional/test_rx_gdbsim.py @@ -21,13 +21,16 @@ class RxGdbSimMachine(QemuSystemTest): KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 ' ASSET_UBOOT = Asset( - 'https://acc.dl.osdn.jp/users/23/23888/u-boot.bin.gz', - '7146567d669e91dbac166384b29aeba1715beb844c8551e904b86831bfd9d046') + ('https://github.com/philmd/qemu-testing-blob/raw/rx-gdbsim/rx/gdbsim/' + 'u-boot.bin'), + 'dd7dd4220cccf7aeb32227b26233bf39600db05c3f8e26005bcc2bf6c927207d') ASSET_DTB = Asset( - 'https://acc.dl.osdn.jp/users/23/23887/rx-virt.dtb', + ('https://github.com/philmd/qemu-testing-blob/raw/rx-gdbsim/rx/gdbsim/' + 'rx-gdbsim.dtb'), 'aa278d9c1907a4501741d7ee57e7f65c02dd1b3e0323b33c6d4247f1b32cf29a') ASSET_KERNEL = Asset( - 'http://acc.dl.osdn.jp/users/23/23845/zImage', + ('https://github.com/philmd/qemu-testing-blob/raw/rx-gdbsim/rx/gdbsim/' + 'zImage'), 'baa43205e74a7220ed8482188c5e9ce497226712abb7f4e7e4f825ce19ff9656') def test_uboot(self): @@ -36,7 +39,7 @@ class RxGdbSimMachine(QemuSystemTest): """ self.set_machine('gdbsim-r5f562n8') - uboot_path = self.uncompress(self.ASSET_UBOOT) + uboot_path = self.ASSET_UBOOT.fetch() self.vm.set_console() self.vm.add_args('-bios', uboot_path, diff --git a/tests/avocado/vnc.py b/tests/functional/test_vnc.py old mode 100644 new mode 100755 similarity index 74% rename from tests/avocado/vnc.py rename to tests/functional/test_vnc.py index 862c8996a8..1916be0103 --- a/tests/avocado/vnc.py +++ b/tests/functional/test_vnc.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 +# # Simple functional tests for VNC functionality # # Copyright (c) 2018 Red Hat, Inc. @@ -11,23 +13,10 @@ import socket from typing import List -from avocado_qemu import QemuSystemTest - +from qemu_test import QemuSystemTest +from qemu_test.ports import Ports VNC_ADDR = '127.0.0.1' -VNC_PORT_START = 32768 -VNC_PORT_END = VNC_PORT_START + 1024 - - -def check_bind(port: int) -> bool: - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: - try: - sock.bind((VNC_ADDR, port)) - except OSError: - return False - - return True - def check_connect(port: int) -> bool: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: @@ -38,27 +27,7 @@ def check_connect(port: int) -> bool: return True - -def find_free_ports(count: int) -> List[int]: - result = [] - for port in range(VNC_PORT_START, VNC_PORT_END): - if check_bind(port): - result.append(port) - if len(result) >= count: - break - assert len(result) == count - return result - - class Vnc(QemuSystemTest): - """ - :avocado: tags=vnc,quick - :avocado: tags=machine:none - """ - def test_no_vnc(self): - self.vm.add_args('-nodefaults', '-S') - self.vm.launch() - self.assertFalse(self.vm.qmp('query-vnc')['return']['enabled']) def test_no_vnc_change_password(self): self.vm.add_args('-nodefaults', '-S') @@ -73,7 +42,7 @@ class Vnc(QemuSystemTest): 'Could not set password') def test_change_password_requires_a_password(self): - self.vm.add_args('-nodefaults', '-S', '-vnc', ':0') + self.vm.add_args('-nodefaults', '-S', '-vnc', ':1,to=999') self.vm.launch() self.assertTrue(self.vm.qmp('query-vnc')['return']['enabled']) set_password_response = self.vm.qmp('change-vnc-password', @@ -85,14 +54,13 @@ class Vnc(QemuSystemTest): 'Could not set password') def test_change_password(self): - self.vm.add_args('-nodefaults', '-S', '-vnc', ':0,password=on') + self.vm.add_args('-nodefaults', '-S', '-vnc', ':1,to=999,password=on') self.vm.launch() self.assertTrue(self.vm.qmp('query-vnc')['return']['enabled']) self.vm.cmd('change-vnc-password', password='new_password') - def test_change_listen(self): - a, b, c = find_free_ports(3) + def do_test_change_listen(self, a, b, c): self.assertFalse(check_connect(a)) self.assertFalse(check_connect(b)) self.assertFalse(check_connect(c)) @@ -113,3 +81,12 @@ class Vnc(QemuSystemTest): self.assertFalse(check_connect(a)) self.assertTrue(check_connect(b)) self.assertTrue(check_connect(c)) + + def test_change_listen(self): + with Ports() as ports: + a, b, c = ports.find_free_ports(3) + self.do_test_change_listen(a, b, c) + + +if __name__ == '__main__': + QemuSystemTest.main()