public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
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





  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
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal