diff options
Diffstat (limited to 'tests/functional')
| -rw-r--r-- | tests/functional/meson.build | 1 | ||||
| -rw-r--r-- | tests/functional/qemu_test/ports.py | 56 | ||||
| -rwxr-xr-x | tests/functional/test_arm_quanta_gsj.py | 2 | ||||
| -rwxr-xr-x | tests/functional/test_ppc64_hv.py | 52 | ||||
| -rwxr-xr-x | tests/functional/test_rx_gdbsim.py | 13 | ||||
| -rwxr-xr-x | tests/functional/test_vnc.py | 92 |
6 files changed, 182 insertions, 34 deletions
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/functional/test_vnc.py b/tests/functional/test_vnc.py new file mode 100755 index 0000000000..1916be0103 --- /dev/null +++ b/tests/functional/test_vnc.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +# +# Simple functional tests for VNC functionality +# +# Copyright (c) 2018 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. + +import socket +from typing import List + +from qemu_test import QemuSystemTest +from qemu_test.ports import Ports + +VNC_ADDR = '127.0.0.1' + +def check_connect(port: int) -> bool: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + try: + sock.connect((VNC_ADDR, port)) + except ConnectionRefusedError: + return False + + return True + +class Vnc(QemuSystemTest): + + def test_no_vnc_change_password(self): + self.vm.add_args('-nodefaults', '-S') + self.vm.launch() + self.assertFalse(self.vm.qmp('query-vnc')['return']['enabled']) + set_password_response = self.vm.qmp('change-vnc-password', + password='new_password') + self.assertIn('error', set_password_response) + self.assertEqual(set_password_response['error']['class'], + 'GenericError') + self.assertEqual(set_password_response['error']['desc'], + 'Could not set password') + + def test_change_password_requires_a_password(self): + 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', + password='new_password') + self.assertIn('error', set_password_response) + self.assertEqual(set_password_response['error']['class'], + 'GenericError') + self.assertEqual(set_password_response['error']['desc'], + 'Could not set password') + + def test_change_password(self): + 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 do_test_change_listen(self, a, b, c): + self.assertFalse(check_connect(a)) + self.assertFalse(check_connect(b)) + self.assertFalse(check_connect(c)) + + self.vm.add_args('-nodefaults', '-S', '-vnc', f'{VNC_ADDR}:{a - 5900}') + self.vm.launch() + self.assertEqual(self.vm.qmp('query-vnc')['return']['service'], str(a)) + self.assertTrue(check_connect(a)) + self.assertFalse(check_connect(b)) + self.assertFalse(check_connect(c)) + + self.vm.cmd('display-update', type='vnc', + addresses=[{'type': 'inet', 'host': VNC_ADDR, + 'port': str(b)}, + {'type': 'inet', 'host': VNC_ADDR, + 'port': str(c)}]) + self.assertEqual(self.vm.qmp('query-vnc')['return']['service'], str(b)) + 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() |