From: Dominik Csapak <d.csapak@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH qemu-server v4 1/9] tests: factor out useful commandline mocks for reuse
Date: Fri, 23 Oct 2026 15:01:04 +0200 [thread overview]
Message-ID: <20261023130324.451252-2-d.csapak@proxmox.com> (raw)
In-Reply-To: <20261023130324.451252-1-d.csapak@proxmox.com>
we can reuse this in different test runners later (e.g. for
testing hot-plugging).
Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
src/test/Makefile | 4 +-
src/test/QemuServerTest/CommandLineMocks.pm | 542 ++++++++++++++++++++
src/test/run_config2command_tests.pl | 506 +-----------------
3 files changed, 553 insertions(+), 499 deletions(-)
create mode 100644 src/test/QemuServerTest/CommandLineMocks.pm
diff --git a/src/test/Makefile b/src/test/Makefile
index d6466ce8..8906be58 100644
--- a/src/test/Makefile
+++ b/src/test/Makefile
@@ -6,10 +6,10 @@ test_snapshot: run_snapshot_tests.pl
./run_snapshot_tests.pl
./test_get_replicatable_volumes.pl
-test_cfg_to_cmd: run_config2command_tests.pl cfg2cmd/*.conf
+test_cfg_to_cmd: run_config2command_tests.pl QemuServerTest/*.pm cfg2cmd/*.conf
perl -I../ ./run_config2command_tests.pl
-test_cfg_to_cmd_aarch64: run_config2command_tests.pl cfg2cmd/aarch64/*.conf
+test_cfg_to_cmd_aarch64: run_config2command_tests.pl QemuServerTest/*.pm cfg2cmd/aarch64/*.conf
perl -I../ ./run_config2command_tests.pl cfg2cmd/aarch64
test_qemu_img_convert: run_qemu_img_convert_tests.pl
diff --git a/src/test/QemuServerTest/CommandLineMocks.pm b/src/test/QemuServerTest/CommandLineMocks.pm
new file mode 100644
index 00000000..99442d7e
--- /dev/null
+++ b/src/test/QemuServerTest/CommandLineMocks.pm
@@ -0,0 +1,542 @@
+package QemuServerTest::CommandLineMocks;
+
+# Mocks for generating the QEMU command line of a VM config in tests, shared
+# between the test scripts for the command line itself and for hotplugging. The
+# environment (storage configuration, PCI devices, mappings, ...) is fixed,
+# while a few properties of the host can be set per test via set_test_env().
+# Also contains helpers that are useful and needed by multiple test harnesses.
+
+use v5.36;
+
+use JSON qw(decode_json);
+use Socket qw(AF_INET AF_INET6);
+use Test::MockModule;
+
+use PVE::INotify;
+use PVE::Mapping::PCI;
+use PVE::Mapping::USB;
+use PVE::ProcFSTools;
+use PVE::Storage::RBDPlugin;
+use PVE::Storage::ZFSPlugin;
+use PVE::Storage;
+use PVE::SysFSTools;
+use PVE::Tools;
+
+use PVE::QemuServer::CPUConfig;
+use PVE::QemuServer::Drive;
+use PVE::QemuServer::Helpers;
+use PVE::QemuServer::Memory;
+use PVE::QemuServer::OVMF;
+use PVE::QemuServer::PCI;
+use PVE::QemuServer;
+
+use base 'Exporter';
+
+our @EXPORT_OK = qw(
+ get_storage_config
+ get_test_qemu_version
+ set_test_env
+);
+
+# can be overwritten by individual tests
+my $real_qemu_version = PVE::QemuServer::Helpers::kvm_user_version();
+
+# the properties of the host for the current test, see set_test_env()
+my $test_env = {};
+
+my $storage_config = {
+ ids => {
+ local => {
+ content => {
+ images => 1,
+ iso => 1,
+ },
+ path => '/var/lib/vz',
+ type => 'dir',
+ shared => 0,
+ },
+ localsnapext => {
+ content => {
+ images => 1,
+ },
+ path => '/var/lib/vzsnapext',
+ type => 'dir',
+ shared => 0,
+ 'snapshot-as-volume-chain' => 1,
+ },
+ noimages => {
+ content => {
+ iso => 1,
+ },
+ path => '/var/lib/vz',
+ type => 'dir',
+ },
+ 'btrfs-store' => {
+ content => {
+ images => 1,
+ },
+ path => '/butter/bread',
+ type => 'btrfs',
+ },
+ 'cifs-store' => {
+ shared => 1,
+ path => '/mnt/pve/cifs-store',
+ username => 'guest',
+ server => '127.0.0.42',
+ type => 'cifs',
+ share => 'CIFShare',
+ content => {
+ images => 1,
+ iso => 1,
+ },
+ },
+ 'rbd-store' => {
+ monhost => '127.0.0.42,127.0.0.21,::1',
+ fsid => 'fc4181a6-56eb-4f68-b452-8ba1f381ca2a',
+ content => {
+ images => 1,
+ },
+ type => 'rbd',
+ pool => 'cpool',
+ username => 'admin',
+ shared => 1,
+ },
+ 'krbd-store' => {
+ monhost => '127.0.0.42,127.0.0.21,::1',
+ fsid => 'fc4181a6-56eb-4f68-b452-8ba1f381ca2a',
+ content => {
+ images => 1,
+ },
+ type => 'rbd',
+ pool => 'cpool',
+ username => 'admin',
+ shared => 1,
+ krbd => 1,
+ },
+ 'zfs-over-iscsi-store' => {
+ type => 'zfs',
+ iscsiprovider => "comstar",
+ lio_tpg => "tpg1",
+ portal => "127.0.0.1",
+ target => "iqn.2019-10.org.test:foobar",
+ pool => "tank",
+ content => {
+ images => 1,
+ },
+ },
+ 'lvm-store' => {
+ vgname => 'veegee',
+ type => 'lvm',
+ content => {
+ images => 1,
+ },
+ },
+ 'local-lvm' => {
+ vgname => 'pve',
+ bwlimit => 'restore=1024',
+ type => 'lvmthin',
+ thinpool => 'data',
+ content => {
+ images => 1,
+ },
+ },
+ },
+};
+
+my $pci_devs = [
+ "0000:00:02.0",
+ "0000:00:43.1",
+ "0000:00:f4.0",
+ "0000:00:ff.1",
+ "0000:0f:f2.0",
+ "0000:d0:13.0",
+ "0000:d0:15.1",
+ "0000:d0:15.2",
+ "0000:d0:17.0",
+ "0000:f0:42.0",
+ "0000:f0:43.0",
+ "0000:f0:43.1",
+ "1234:f0:43.1",
+ "0000:01:00.4",
+ "0000:01:00.5",
+ "0000:01:00.6",
+ "0000:07:10.0",
+ "0000:07:10.1",
+ "0000:07:10.4",
+];
+
+my $pci_map_config = {
+ ids => {
+ someGpu => {
+ type => 'pci',
+ mdev => 1,
+ map => [
+ 'node=localhost,path=0000:01:00.4,id=10de:2231,iommugroup=1',
+ 'node=localhost,path=0000:01:00.5,id=10de:2231,iommugroup=1',
+ 'node=localhost,path=0000:01:00.6,id=10de:2231,iommugroup=1',
+ ],
+ },
+ someNic => {
+ type => 'pci',
+ map => [
+ 'node=localhost,path=0000:07:10.0,id=8086:1520,iommugroup=2',
+ 'node=localhost,path=0000:07:10.1,id=8086:1520,iommugroup=2',
+ 'node=localhost,path=0000:07:10.4,id=8086:1520,iommugroup=2',
+ ],
+ },
+ },
+};
+
+my $usb_map_config = {};
+
+my $cpu_hw_capabilities = {
+ # Gathered from an AMD EPYC 9475F running kernel 6.11.11-2-pve
+ 'amd-turin-9005' =>
+ '{ "amd-sev": { "cbitpos": 51, "reduced-phys-bits": 6, "sev-support": true,'
+ . ' "sev-support-es": true, "sev-support-snp": true } }',
+ # TODO: others?
+};
+
+# Set the properties of the (mocked) host for the following test, fields are:
+# qemu_version: version of the installed QEMU binary (defaults to the real version)
+# host_arch: x86_64 | aarch64 (defaults to x86_64)
+# host-cpu-vendor: AuthenticAMD | GenuineIntel | etc. (defaults to GenuineIntel)
+# hw_capabilities: a CPU from $cpu_hw_capabilities above or a raw JSON string
+sub set_test_env($env) {
+ $test_env = $env;
+ $test_env->{qemu_version} //= $real_qemu_version // '2.12';
+ $test_env->{host_arch} //= 'x86_64';
+ $test_env->{'host-cpu-vendor'} //= 'GenuineIntel';
+}
+
+sub get_test_qemu_version() {
+ return $test_env->{qemu_version};
+}
+
+sub get_storage_config() {
+ return $storage_config;
+}
+
+# Use 'our' for the mocker objects, since they need to stay alive after loading. Using 'my' here
+# would free them after loading the module and negate the mocking.
+
+our $procfs_tools_module = Test::MockModule->new('PVE::ProcFSTools');
+$procfs_tools_module->mock(
+ read_cpuinfo => sub {
+ my $res = $procfs_tools_module->original('read_cpuinfo')->();
+ my $vendor = $test_env->{'host-cpu-vendor'};
+ $res->{vendor} = $vendor;
+ return $res;
+ },
+);
+
+our $qemu_server_module;
+$qemu_server_module = Test::MockModule->new('PVE::QemuServer');
+$qemu_server_module->mock(
+ kvm_user_version => sub {
+ return get_test_qemu_version();
+ },
+ kvm_version => sub {
+ return get_test_qemu_version();
+ },
+ kernel_has_vhost_net => sub {
+ return 1; # TODO: make this per-test configurable?
+ },
+ get_iscsi_initiator_name => sub {
+ return 'iqn.1993-08.org.debian:01:aabbccddeeff';
+ },
+ cleanup_pci_devices => {
+ # do nothing
+ },
+);
+
+our $qemu_server_ovmf_module = Test::MockModule->new("PVE::QemuServer::OVMF");
+$qemu_server_ovmf_module->mock(
+ file_exists => sub {
+ my ($path) = @_;
+ return 1;
+ },
+ file_get_size => sub {
+ my ($path) = @_;
+ if ($path =~ m/OVMF(32)?_(SEV_)?VARS_4M/) {
+ return 528 * 1024;
+ } elsif ($path =~ m/OVMF_VARS/) {
+ return 128 * 1024;
+ } elsif ($path =~ m/AAVMF_VARS/) {
+ return 64 * 1024 * 1024;
+ } elsif ($path =~ m/RISCV_VIRT_VARS/) {
+ return 32 * 1024 * 1024;
+ } else {
+ die "unknown ovmf vars image '$path' - implement me";
+ }
+ },
+);
+
+our $storage_module = Test::MockModule->new("PVE::Storage");
+$storage_module->mock(
+ activate_volumes => sub {
+ return;
+ },
+ deactivate_volumes => sub {
+ return;
+ },
+ volume_snapshot_info => sub {
+ my ($cfg, $volid) = @_;
+
+ my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
+
+ my $snapshots = {};
+ if ($storeid eq 'localsnapext') {
+ $snapshots = {
+ current => {
+ file => 'var/lib/vzsnapext/images/8006/vm-8006-disk-0.qcow2',
+ parent => 'snap2',
+ },
+ snap2 => {
+ file => '/var/lib/vzsnapext/images/8006/snap2-vm-8006-disk-0.qcow2',
+ parent => 'snap1',
+ },
+ snap1 => {
+ file => '/var/lib/vzsnapext/images/8006/snap1-vm-8006-disk-0.qcow2',
+ },
+ };
+ } elsif ($storeid eq 'lvm-store') {
+ $snapshots = {
+ current => {
+ file => '/dev/veegee/vm-8006-disk-0.qcow2',
+ parent => 'snap2',
+ },
+ snap2 => {
+ file => '/dev/veegee/snap2-vm-8006-disk-0.qcow2',
+ parent => 'snap1',
+ },
+ snap1 => {
+ file => '/dev/veegee/snap1-vm-8006-disk-0.qcow2',
+ },
+ };
+ }
+ return $snapshots;
+ },
+);
+
+our $file_stat_module = Test::MockModule->new("File::stat");
+$file_stat_module->mock(
+ stat => sub {
+ my ($path) = @_;
+ my $st = $file_stat_module->original('stat')->($0);
+ $st->[2] = 25008 if $path =~ m!/dev/!; # block device
+ return $st;
+ },
+);
+
+our $zfsplugin_module = Test::MockModule->new("PVE::Storage::ZFSPlugin");
+$zfsplugin_module->mock(
+ zfs_get_lu_name => sub {
+ return "foobar";
+ },
+ zfs_get_lun_number => sub {
+ return "0";
+ },
+);
+
+our $rbdplugin_module = Test::MockModule->new("PVE::Storage::RBDPlugin");
+$rbdplugin_module->mock(
+ rbd_volume_config_set => sub {
+ return;
+ },
+);
+
+our $qemu_server_helpers;
+$qemu_server_helpers = Test::MockModule->new('PVE::QemuServer::Helpers');
+$qemu_server_helpers->mock(
+ get_host_phys_address_bits => sub {
+ return 46;
+ },
+);
+
+our $qemu_server_memory;
+$qemu_server_memory = Test::MockModule->new('PVE::QemuServer::Memory');
+$qemu_server_memory->mock(
+ hugepages_chunk_size_supported => sub {
+ return 1;
+ },
+ host_numanode_exists => sub {
+ my ($id) = @_;
+ return 1;
+ },
+);
+
+our $pve_common_tools;
+$pve_common_tools = Test::MockModule->new('PVE::Tools');
+$pve_common_tools->mock(
+ next_vnc_port => sub {
+ my ($family, $address) = @_;
+
+ return '5900';
+ },
+ next_spice_port => sub {
+ my ($family, $address) = @_;
+
+ return '61000';
+ },
+ getaddrinfo_all => sub {
+ my ($hostname, @opts) = @_;
+ die "need stable hostname" if $hostname ne 'localhost';
+ return (
+ {
+ addr => Socket::pack_sockaddr_in(0, Socket::INADDR_LOOPBACK),
+ family => AF_INET, # IPv4
+ protocol => 6,
+ socktype => 1,
+ },
+ );
+ },
+ get_host_arch => sub {
+ return $test_env->{host_arch};
+ },
+);
+
+our $pve_common_file;
+$pve_common_file = Test::MockModule->new('PVE::File');
+$pve_common_file->mock(
+ file_copy => sub {
+ my ($filename, $dst, $max, $perm) = @_;
+ if ($dst =~ m|^/run/qemu-server/efidisk|) {
+ return;
+ }
+ return $pve_common_file->original('file_copy')->($filename, $dst, $max, $perm);
+ },
+);
+
+our $pve_cpuconfig;
+$pve_cpuconfig = Test::MockModule->new('PVE::QemuServer::CPUConfig');
+$pve_cpuconfig->mock(
+ load_custom_cpu_model_config => sub {
+ # mock custom CPU model config
+ return PVE::QemuServer::CPUConfig->parse_config(
+ "cpu-models.conf",
+ <<EOF,
+
+# "qemu64" is also a default CPU, used here to test that this doesn't matter
+cpu-model: qemu64
+ reported-model athlon
+ flags +aes;+avx;-kvm_pv_unhalt
+ hv-vendor-id testvend
+ phys-bits 40
+
+cpu-model: alldefault
+
+EOF
+ );
+ },
+ get_hw_capabilities => sub {
+ my $hw_capabilities_raw;
+ if (!defined($test_env->{hw_capabilities})) {
+ # default to barebone uncapable HW
+ $hw_capabilities_raw =
+ '{"amd-sev":{"cbitpos":0,"reduced-phys-bits":0,"sev-support":false,'
+ . '"sev-support-es":false,"sev-support-snp":false}}';
+ } elsif (my $cpu_hw_caps = $cpu_hw_capabilities->{ lc($test_env->{hw_capabilities}) }) {
+ $hw_capabilities_raw = $cpu_hw_caps;
+ } else {
+ $hw_capabilities_raw = $test_env->{hw_capabilities};
+ }
+
+ my $hw_capabilities = decode_json($hw_capabilities_raw);
+ return $hw_capabilities;
+ },
+);
+
+our $pve_common_network;
+$pve_common_network = Test::MockModule->new('PVE::Network');
+$pve_common_network->mock(
+ read_bridge_mtu => sub {
+ my ($bridge_name) = @_;
+
+ if ($bridge_name eq 'vxlan_bridge') {
+ return 1450;
+ }
+
+ return 1500;
+ },
+);
+
+our $pve_common_inotify;
+$pve_common_inotify = Test::MockModule->new('PVE::INotify');
+$pve_common_inotify->mock(
+ nodename => sub {
+ return 'localhost';
+ },
+);
+
+our $pve_common_sysfstools;
+$pve_common_sysfstools = Test::MockModule->new('PVE::SysFSTools');
+$pve_common_sysfstools->mock(
+ lspci => sub {
+ my ($filter, $verbose) = @_;
+
+ return [
+ map { { id => $_ } }
+ grep {
+ !defined($filter)
+ || (!ref($filter) && $_ =~ m/^(0000:)?\Q$filter\E/)
+ || (ref($filter) eq 'CODE' && $filter->({ id => $_ }))
+ } sort @$pci_devs
+ ];
+ },
+ pci_device_info => sub {
+ my ($path, $noerr) = @_;
+
+ if ($path =~ m/^0000:01:00/) {
+ return {
+ mdev => 1,
+ iommugroup => 1,
+ mdev => 1,
+ vendor => "0x10de",
+ device => "0x2231",
+ };
+ } elsif ($path =~ m/^0000:07:10/) {
+ return {
+ iommugroup => 2,
+ vendor => "0x8086",
+ device => "0x1520",
+ };
+ } else {
+ return {};
+ }
+ },
+);
+
+our $qemu_drive_module;
+$qemu_drive_module = Test::MockModule->new('PVE::QemuServer::Drive');
+$qemu_drive_module->mock(
+ get_cdrom_path => sub {
+ return "/dev/cdrom";
+ },
+);
+
+our $mapping_usb_module = Test::MockModule->new("PVE::Mapping::USB");
+$mapping_usb_module->mock(
+ config => sub {
+ return $usb_map_config;
+ },
+);
+
+our $mapping_pci_module = Test::MockModule->new("PVE::Mapping::PCI");
+$mapping_pci_module->mock(
+ config => sub {
+ return $pci_map_config;
+ },
+);
+
+our $pci_module = Test::MockModule->new("PVE::QemuServer::PCI");
+$pci_module->mock(
+ reserve_pci_usage => sub {
+ die "reserve_pci_usage should not be called for 'qm showcmd'\n";
+ },
+ create_nvidia_device => sub {
+ die "create_nvidia_device should not be called for 'qm showcmd'\n";
+ },
+);
+
+1;
diff --git a/src/test/run_config2command_tests.pl b/src/test/run_config2command_tests.pl
index 28f538d3..2c553260 100755
--- a/src/test/run_config2command_tests.pl
+++ b/src/test/run_config2command_tests.pl
@@ -2,184 +2,22 @@
use v5.36;
-use lib qw(..);
+use lib qw(.. .);
-use JSON qw(decode_json);
use Test::More;
use Test::MockModule;
-use Socket qw(AF_INET AF_INET6);
use PVE::File qw(file_get_contents file_set_contents);
-use PVE::Tools qw(run_command);
-use PVE::INotify;
-use PVE::SysFSTools;
-
use PVE::QemuConfig;
use PVE::QemuServer;
-use PVE::QemuServer::Drive;
-use PVE::QemuServer::Helpers;
use PVE::QemuServer::Monitor;
-use PVE::QemuServer::OVMF;
use PVE::QemuServer::QMPHelpers;
use PVE::QemuServer::CPUConfig;
use PVE::Storage;
-my $base_env = {
- storage_config => {
- ids => {
- local => {
- content => {
- images => 1,
- iso => 1,
- },
- path => '/var/lib/vz',
- type => 'dir',
- shared => 0,
- },
- localsnapext => {
- content => {
- images => 1,
- },
- path => '/var/lib/vzsnapext',
- type => 'dir',
- shared => 0,
- 'snapshot-as-volume-chain' => 1,
- },
- noimages => {
- content => {
- iso => 1,
- },
- path => '/var/lib/vz',
- type => 'dir',
- },
- 'btrfs-store' => {
- content => {
- images => 1,
- },
- path => '/butter/bread',
- type => 'btrfs',
- },
- 'cifs-store' => {
- shared => 1,
- path => '/mnt/pve/cifs-store',
- username => 'guest',
- server => '127.0.0.42',
- type => 'cifs',
- share => 'CIFShare',
- content => {
- images => 1,
- iso => 1,
- },
- },
- 'rbd-store' => {
- monhost => '127.0.0.42,127.0.0.21,::1',
- fsid => 'fc4181a6-56eb-4f68-b452-8ba1f381ca2a',
- content => {
- images => 1,
- },
- type => 'rbd',
- pool => 'cpool',
- username => 'admin',
- shared => 1,
- },
- 'krbd-store' => {
- monhost => '127.0.0.42,127.0.0.21,::1',
- fsid => 'fc4181a6-56eb-4f68-b452-8ba1f381ca2a',
- content => {
- images => 1,
- },
- type => 'rbd',
- pool => 'cpool',
- username => 'admin',
- shared => 1,
- krbd => 1,
- },
- 'zfs-over-iscsi-store' => {
- type => 'zfs',
- iscsiprovider => "comstar",
- lio_tpg => "tpg1",
- portal => "127.0.0.1",
- target => "iqn.2019-10.org.test:foobar",
- pool => "tank",
- content => {
- images => 1,
- },
- },
- 'lvm-store' => {
- vgname => 'veegee',
- type => 'lvm',
- content => {
- images => 1,
- },
- },
- 'local-lvm' => {
- vgname => 'pve',
- bwlimit => 'restore=1024',
- type => 'lvmthin',
- thinpool => 'data',
- content => {
- images => 1,
- },
- },
- },
- },
- vmid => 8006,
- real_qemu_version => PVE::QemuServer::Helpers::kvm_user_version(), # not yet mocked
-};
+use QemuServerTest::CommandLineMocks qw(get_storage_config get_test_qemu_version set_test_env);
-my $pci_devs = [
- "0000:00:02.0",
- "0000:00:43.1",
- "0000:00:f4.0",
- "0000:00:ff.1",
- "0000:0f:f2.0",
- "0000:d0:13.0",
- "0000:d0:15.1",
- "0000:d0:15.2",
- "0000:d0:17.0",
- "0000:f0:42.0",
- "0000:f0:43.0",
- "0000:f0:43.1",
- "1234:f0:43.1",
- "0000:01:00.4",
- "0000:01:00.5",
- "0000:01:00.6",
- "0000:07:10.0",
- "0000:07:10.1",
- "0000:07:10.4",
-];
-
-my $pci_map_config = {
- ids => {
- someGpu => {
- type => 'pci',
- mdev => 1,
- map => [
- 'node=localhost,path=0000:01:00.4,id=10de:2231,iommugroup=1',
- 'node=localhost,path=0000:01:00.5,id=10de:2231,iommugroup=1',
- 'node=localhost,path=0000:01:00.6,id=10de:2231,iommugroup=1',
- ],
- },
- someNic => {
- type => 'pci',
- map => [
- 'node=localhost,path=0000:07:10.0,id=8086:1520,iommugroup=2',
- 'node=localhost,path=0000:07:10.1,id=8086:1520,iommugroup=2',
- 'node=localhost,path=0000:07:10.4,id=8086:1520,iommugroup=2',
- ],
- },
- },
-};
-
-my $usb_map_config = {},
-
- my $cpu_hw_capabilities = {
- # Gathered from an AMD EPYC 9475F running kernel 6.11.11-2-pve
- 'amd-turin-9005' =>
- '{ "amd-sev": { "cbitpos": 51, "reduced-phys-bits": 6, "sev-support": true,'
- . ' "sev-support-es": true, "sev-support-snp": true } }',
- # TODO: others?
- };
+my $vmid = 8006;
my $current_test; # = {
# description => 'Test description', # if available
@@ -212,8 +50,6 @@ sub parse_test($config_fn) {
my $description = $config->{description} // '';
- $current_test->{'host-cpu-vendor'} = 'GenuineIntel';
-
while ($description =~ /^\h*(.*?)\h*$/gm) {
my $line = $1;
next if !$line || $line =~ /^#/;
@@ -244,140 +80,11 @@ sub parse_test($config_fn) {
}
$current_test->{testname} = $testname;
- PVE::QemuServer::CPUConfig::initialize_cpu_models();
-}
+ set_test_env($current_test);
-sub get_test_qemu_version {
- $current_test->{qemu_version} // $base_env->{real_qemu_version} // '2.12';
+ PVE::QemuServer::CPUConfig::initialize_cpu_models();
}
-my $procfs_tools_module = Test::MockModule->new('PVE::ProcFSTools');
-$procfs_tools_module->mock(
- read_cpuinfo => sub {
- my $res = $procfs_tools_module->original('read_cpuinfo')->();
- my $vendor = $current_test->{'host-cpu-vendor'}
- or die "internal error - host cpu vendor not set";
- $res->{vendor} = $vendor;
- return $res;
- },
-);
-
-my $qemu_server_module;
-$qemu_server_module = Test::MockModule->new('PVE::QemuServer');
-$qemu_server_module->mock(
- kvm_user_version => sub {
- return get_test_qemu_version();
- },
- kvm_version => sub {
- return get_test_qemu_version();
- },
- kernel_has_vhost_net => sub {
- return 1; # TODO: make this per-test configurable?
- },
- get_iscsi_initiator_name => sub {
- return 'iqn.1993-08.org.debian:01:aabbccddeeff';
- },
- cleanup_pci_devices => {
- # do nothing
- },
-);
-
-my $qemu_server_ovmf_module = Test::MockModule->new("PVE::QemuServer::OVMF");
-$qemu_server_ovmf_module->mock(
- file_exists => sub {
- my ($path) = @_;
- return 1;
- },
- file_get_size => sub {
- my ($path) = @_;
- if ($path =~ m/OVMF(32)?_(SEV_)?VARS_4M/) {
- return 528 * 1024;
- } elsif ($path =~ m/OVMF_VARS/) {
- return 128 * 1024;
- } elsif ($path =~ m/AAVMF_VARS/) {
- return 64 * 1024 * 1024;
- } elsif ($path =~ m/RISCV_VIRT_VARS/) {
- return 32 * 1024 * 1024;
- } else {
- die "unknown ovmf vars image '$path' - implement me";
- }
- },
-);
-
-my $storage_module = Test::MockModule->new("PVE::Storage");
-$storage_module->mock(
- activate_volumes => sub {
- return;
- },
- deactivate_volumes => sub {
- return;
- },
- volume_snapshot_info => sub {
- my ($cfg, $volid) = @_;
-
- my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
-
- my $snapshots = {};
- if ($storeid eq 'localsnapext') {
- $snapshots = {
- current => {
- file => 'var/lib/vzsnapext/images/8006/vm-8006-disk-0.qcow2',
- parent => 'snap2',
- },
- snap2 => {
- file => '/var/lib/vzsnapext/images/8006/snap2-vm-8006-disk-0.qcow2',
- parent => 'snap1',
- },
- snap1 => {
- file => '/var/lib/vzsnapext/images/8006/snap1-vm-8006-disk-0.qcow2',
- },
- };
- } elsif ($storeid eq 'lvm-store') {
- $snapshots = {
- current => {
- file => '/dev/veegee/vm-8006-disk-0.qcow2',
- parent => 'snap2',
- },
- snap2 => {
- file => '/dev/veegee/snap2-vm-8006-disk-0.qcow2',
- parent => 'snap1',
- },
- snap1 => {
- file => '/dev/veegee/snap1-vm-8006-disk-0.qcow2',
- },
- };
- }
- return $snapshots;
- },
-);
-
-my $file_stat_module = Test::MockModule->new("File::stat");
-$file_stat_module->mock(
- stat => sub {
- my ($path) = @_;
- my $st = $file_stat_module->original('stat')->('./run_config2command_tests.pl');
- $st->[2] = 25008 if $path =~ m!/dev/!; # block device
- return $st;
- },
-);
-
-my $zfsplugin_module = Test::MockModule->new("PVE::Storage::ZFSPlugin");
-$zfsplugin_module->mock(
- zfs_get_lu_name => sub {
- return "foobar";
- },
- zfs_get_lun_number => sub {
- return "0";
- },
-);
-
-my $rbdplugin_module = Test::MockModule->new("PVE::Storage::RBDPlugin");
-$rbdplugin_module->mock(
- rbd_volume_config_set => sub {
- return;
- },
-);
-
my $qemu_server_config;
$qemu_server_config = Test::MockModule->new('PVE::QemuConfig');
$qemu_server_config->mock(
@@ -388,185 +95,14 @@ $qemu_server_config->mock(
},
);
-my $qemu_server_helpers;
-$qemu_server_helpers = Test::MockModule->new('PVE::QemuServer::Helpers');
-$qemu_server_helpers->mock(
- get_host_phys_address_bits => sub {
- return 46;
- },
-);
-
-my $qemu_server_memory;
-$qemu_server_memory = Test::MockModule->new('PVE::QemuServer::Memory');
-$qemu_server_memory->mock(
- hugepages_chunk_size_supported => sub {
- return 1;
- },
- host_numanode_exists => sub {
- my ($id) = @_;
- return 1;
- },
-);
-
-my $pve_common_tools;
-$pve_common_tools = Test::MockModule->new('PVE::Tools');
-$pve_common_tools->mock(
- next_vnc_port => sub {
- my ($family, $address) = @_;
-
- return '5900';
- },
- next_spice_port => sub {
- my ($family, $address) = @_;
-
- return '61000';
- },
- getaddrinfo_all => sub {
- my ($hostname, @opts) = @_;
- die "need stable hostname" if $hostname ne 'localhost';
- return (
- {
- addr => Socket::pack_sockaddr_in(0, Socket::INADDR_LOOPBACK),
- family => AF_INET, # IPv4
- protocol => 6,
- socktype => 1,
- },
- );
- },
- get_host_arch => sub {
- return $current_test->{host_arch} // 'x86_64';
- },
-);
-
-my $pve_common_file;
-$pve_common_file = Test::MockModule->new('PVE::File');
-$pve_common_file->mock(
- file_copy => sub {
- my ($filename, $dst, $max, $perm) = @_;
- if ($dst =~ m|^/run/qemu-server/efidisk|) {
- return;
- }
- return $pve_common_file->original('file_copy')->($filename, $dst, $max, $perm);
- },
-);
-
-my $pve_cpuconfig;
-$pve_cpuconfig = Test::MockModule->new('PVE::QemuServer::CPUConfig');
-$pve_cpuconfig->mock(
- load_custom_cpu_model_config => sub {
- # mock custom CPU model config
- return PVE::QemuServer::CPUConfig->parse_config(
- "cpu-models.conf",
- <<EOF,
-
-# "qemu64" is also a default CPU, used here to test that this doesn't matter
-cpu-model: qemu64
- reported-model athlon
- flags +aes;+avx;-kvm_pv_unhalt
- hv-vendor-id testvend
- phys-bits 40
-
-cpu-model: alldefault
-
-EOF
- );
- },
- get_hw_capabilities => sub {
- my $hw_capabilities_raw;
- if (!defined($current_test->{hw_capabilities})) {
- # default to barebone uncapable HW
- $hw_capabilities_raw =
- '{"amd-sev":{"cbitpos":0,"reduced-phys-bits":0,"sev-support":false,'
- . '"sev-support-es":false,"sev-support-snp":false}}';
- } elsif (
- my $cpu_hw_caps = $cpu_hw_capabilities->{ lc($current_test->{hw_capabilities}) }
- ) {
- $hw_capabilities_raw = $cpu_hw_caps;
- } else {
- $hw_capabilities_raw = $current_test->{hw_capabilities};
- }
-
- my $hw_capabilities = decode_json($hw_capabilities_raw);
- return $hw_capabilities;
- },
-);
-
-my $pve_common_network;
-$pve_common_network = Test::MockModule->new('PVE::Network');
-$pve_common_network->mock(
- read_bridge_mtu => sub {
- my ($bridge_name) = @_;
-
- if ($bridge_name eq 'vxlan_bridge') {
- return 1450;
- }
-
- return 1500;
- },
-);
-
-my $pve_common_inotify;
-$pve_common_inotify = Test::MockModule->new('PVE::INotify');
-$pve_common_inotify->mock(
- nodename => sub {
- return 'localhost';
- },
-);
-
-my $pve_common_sysfstools;
-$pve_common_sysfstools = Test::MockModule->new('PVE::SysFSTools');
-$pve_common_sysfstools->mock(
- lspci => sub {
- my ($filter, $verbose) = @_;
-
- return [
- map { { id => $_ } }
- grep {
- !defined($filter)
- || (!ref($filter) && $_ =~ m/^(0000:)?\Q$filter\E/)
- || (ref($filter) eq 'CODE' && $filter->({ id => $_ }))
- } sort @$pci_devs
- ];
- },
- pci_device_info => sub {
- my ($path, $noerr) = @_;
-
- if ($path =~ m/^0000:01:00/) {
- return {
- mdev => 1,
- iommugroup => 1,
- mdev => 1,
- vendor => "0x10de",
- device => "0x2231",
- };
- } elsif ($path =~ m/^0000:07:10/) {
- return {
- iommugroup => 2,
- vendor => "0x8086",
- device => "0x1520",
- };
- } else {
- return {};
- }
- },
-);
-
-my $qemu_drive_module;
-$qemu_drive_module = Test::MockModule->new('PVE::QemuServer::Drive');
-$qemu_drive_module->mock(
- get_cdrom_path => sub {
- return "/dev/cdrom";
- },
-);
-
my $qemu_monitor_module;
$qemu_monitor_module = Test::MockModule->new('PVE::QemuServer::Monitor');
$qemu_monitor_module->mock(
mon_cmd => sub {
- my ($vmid, $cmd) = @_;
+ my ($id, $cmd) = @_;
- die "invalid vmid: $vmid (expected: $base_env->{vmid})"
- if $vmid != $base_env->{vmid};
+ die "invalid vmid: $id (expected: $vmid)"
+ if $id != $vmid;
if ($cmd eq 'query-version') {
my $ver = get_test_qemu_version();
@@ -584,30 +120,6 @@ $qemu_monitor_module->mock(
},
);
-my $mapping_usb_module = Test::MockModule->new("PVE::Mapping::USB");
-$mapping_usb_module->mock(
- config => sub {
- return $usb_map_config;
- },
-);
-
-my $mapping_pci_module = Test::MockModule->new("PVE::Mapping::PCI");
-$mapping_pci_module->mock(
- config => sub {
- return $pci_map_config;
- },
-);
-
-my $pci_module = Test::MockModule->new("PVE::QemuServer::PCI");
-$pci_module->mock(
- reserve_pci_usage => sub {
- die "reserve_pci_usage should not be called for 'qm showcmd'\n";
- },
- create_nvidia_device => sub {
- die "create_nvidia_device should not be called for 'qm showcmd'\n";
- },
-);
-
sub diff($a, $b) {
return if $a eq $b;
@@ -663,7 +175,7 @@ sub do_test($config_fn) {
my $testname = $current_test->{testname};
- my ($vmid, $storecfg) = $base_env->@{qw(vmid storage_config)};
+ my $storecfg = get_storage_config();
my $cmdline = eval { PVE::QemuServer::vm_commandline($storecfg, $vmid) };
my $err = $@;
--
2.47.3
next prev parent reply other threads:[~2026-10-23 13:04 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-23 13:01 [PATCH qemu-server v4 0/9] add hotplug tests and fix uncovered bugs Dominik Csapak
2026-10-23 13:01 ` Dominik Csapak [this message]
2026-10-23 13:01 ` [PATCH qemu-server v4 2/9] tests: factor out the diff generation Dominik Csapak
2026-10-23 13:01 ` [PATCH qemu-server v4 3/9] machine: factor out machine expanding Dominik Csapak
2026-10-23 13:01 ` [PATCH qemu-server v4 4/9] tests: hotplug: add initial hotplug test harness Dominik Csapak
2026-10-23 13:01 ` [PATCH qemu-server v4 5/9] tests: hotplug: add some test cases Dominik Csapak
2026-10-23 13:01 ` [PATCH qemu-server v4 6/9] tests: hotplug: add test case for adding scsi14 on qemu 11.1 Dominik Csapak
2026-10-23 13:01 ` [PATCH qemu-server v4 7/9] tests: hotplug: add cases for known defects Dominik Csapak
2026-10-23 13:01 ` [PATCH qemu-server v4 8/9] hotplug: fix hot unplugging tablet on aarch64 Dominik Csapak
2026-10-23 13:01 ` [PATCH qemu-server v4 9/9] hotplug: remove iothread if adding drive device failed Dominik Csapak
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261023130324.451252-2-d.csapak@proxmox.com \
--to=d.csapak@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox