From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [IPv6:2a0f:8001:1:32::40]) by lore.proxmox.com (Postfix) with ESMTPS id 92DEC1FF0AF for ; Fri, 23 Oct 2026 15:04:32 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 35EDA21676; Fri, 23 Oct 2026 15:04:19 +0200 (CEST) From: Dominik Csapak 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 Message-ID: <20261023130324.451252-2-d.csapak@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20261023130324.451252-1-d.csapak@proxmox.com> References: <20261023130324.451252-1-d.csapak@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.347 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: LQOVSIJJ6VNDV7WTBUN77WW3VBFJZZQQ X-Message-ID-Hash: LQOVSIJJ6VNDV7WTBUN77WW3VBFJZZQQ X-MailFrom: d.csapak@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: we can reuse this in different test runners later (e.g. for testing hot-plugging). Signed-off-by: Dominik Csapak --- 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", + < 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", - < 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