]> git.proxmox.com Git - pve-storage.git/commitdiff
test: list_volumes
authorAlwin Antreich <a.antreich@proxmox.com>
Tue, 28 Apr 2020 13:58:17 +0000 (15:58 +0200)
committerFabian Grünbichler <f.gruenbichler@proxmox.com>
Thu, 30 Apr 2020 16:37:19 +0000 (18:37 +0200)
Test to reduce the potential for accidental breakage on regex changes.

Co-Authored-by: Dominic Jaeger <d.jaeger@proxmox.com>
Signed-off-by: Alwin Antreich <a.antreich@proxmox.com>
test/list_volumes_test.pm [new file with mode: 0644]
test/run_plugin_tests.pl

diff --git a/test/list_volumes_test.pm b/test/list_volumes_test.pm
new file mode 100644 (file)
index 0000000..a215617
--- /dev/null
@@ -0,0 +1,519 @@
+package PVE::Storage::TestListVolumes;
+
+use strict;
+use warnings;
+
+use lib qw(..);
+
+use PVE::Storage;
+use PVE::Cluster;
+use PVE::Tools qw(run_command);
+
+use Test::More;
+use Test::MockModule;
+
+use Cwd;
+use File::Basename;
+use File::Path qw(make_path remove_tree);
+use File::stat qw();
+use File::Temp;
+use Storable qw(dclone);
+
+use constant DEFAULT_SIZE => 131072; # 128 kiB
+use constant DEFAULT_USED => 262144; # 256 kiB
+use constant DEFAULT_CTIME => 1234567890;
+
+# get_vmlist() return values
+my $mocked_vmlist = {
+    'version' => 1,
+    'ids' => {
+       '16110' => {
+           'node'    => 'x42',
+           'type'    => 'qemu',
+           'version' => 4,
+       },
+       '16112' => {
+           'node'    => 'x42',
+           'type'    => 'lxc',
+           'version' => 7,
+       },
+       '16114' => {
+           'node'    => 'x42',
+           'type'    => 'qemu',
+           'version' => 2,
+       },
+       '16113' => {
+           'node'    => 'x42',
+           'type'    => 'qemu',
+           'version' => 5,
+       },
+       '16115' => {
+           'node'    => 'x42',
+           'type'    => 'qemu',
+           'version' => 1,
+       },
+       '9004' => {
+           'node'    => 'x42',
+           'type'    => 'qemu',
+           'version' => 6,
+       }
+    }
+};
+
+my $storage_dir = File::Temp->newdir();
+my $scfg = {
+    'type'     => 'dir',
+    'maxfiles' => 0,
+    'path'     => $storage_dir,
+    'shared'   => 0,
+    'content'  => {
+       'iso'      => 1,
+       'rootdir'  => 1,
+       'vztmpl'   => 1,
+       'images'   => 1,
+       'snippets' => 1,
+       'backup'   => 1,
+    },
+};
+
+# The test cases are comprised of an arry of hashes with the following keys:
+# description => displayed on error by Test::More
+# vmid        => used for image matches by list_volume
+# files       => array of files for qemu-img to create
+# expected    => returned result hash
+#                (content, ctime, format, parent, size, used, vimd, volid)
+my @tests = (
+    {
+       description => 'VMID: 16110, VM, qcow2, backup, snippets',
+       vmid => '16110',
+       files => [
+           "$storage_dir/images/16110/vm-16110-disk-0.qcow2",
+           "$storage_dir/images/16110/vm-16110-disk-1.raw",
+           "$storage_dir/images/16110/vm-16110-disk-2.vmdk",
+           "$storage_dir/dump/vzdump-qemu-16110-2020_03_30-21_11_40.vma.gz",
+           "$storage_dir/dump/vzdump-qemu-16110-2020_03_30-21_12_45.vma.lzo",
+           "$storage_dir/dump/vzdump-qemu-16110-2020_03_30-21_13_55.vma",
+           "$storage_dir/snippets/userconfig.yaml",
+           "$storage_dir/snippets/hookscript.pl",
+       ],
+       expected => [
+           {
+               'content' => 'images',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'qcow2',
+               'parent'  => undef,
+               'size'    => DEFAULT_SIZE,
+               'used'    => DEFAULT_USED,
+               'vmid'    => '16110',
+               'volid'   => 'local:16110/vm-16110-disk-0.qcow2',
+           },
+           {
+               'content' => 'images',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'raw',
+               'parent'  => undef,
+               'size'    => DEFAULT_SIZE,
+               'used'    => DEFAULT_USED,
+               'vmid'    => '16110',
+               'volid'   => 'local:16110/vm-16110-disk-1.raw',
+           },
+           {
+               'content' => 'images',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'vmdk',
+               'parent'  => undef,
+               'size'    => DEFAULT_SIZE,
+               'used'    => DEFAULT_USED,
+               'vmid'    => '16110',
+               'volid'   => 'local:16110/vm-16110-disk-2.vmdk',
+           },
+           {
+               'content' => 'backup',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'vma.gz',
+               'size'    => DEFAULT_SIZE,
+               'vmid'    => '16110',
+               'volid'   => 'local:backup/vzdump-qemu-16110-2020_03_30-21_11_40.vma.gz',
+           },
+           {
+               'content' => 'backup',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'vma.lzo',
+               'size'    => DEFAULT_SIZE,
+               'vmid'    => '16110',
+               'volid'   => 'local:backup/vzdump-qemu-16110-2020_03_30-21_12_45.vma.lzo',
+           },
+           {
+               'content' => 'backup',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'vma',
+               'size'    => DEFAULT_SIZE,
+               'vmid'    => '16110',
+               'volid'   => 'local:backup/vzdump-qemu-16110-2020_03_30-21_13_55.vma',
+           },
+           {
+               'content' => 'snippets',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'snippet',
+               'size'    => DEFAULT_SIZE,
+               'volid'   => 'local:snippets/hookscript.pl',
+           },
+           {
+               'content' => 'snippets',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'snippet',
+               'size'    => DEFAULT_SIZE,
+               'volid'   => 'local:snippets/userconfig.yaml',
+           },
+       ],
+    },
+    {
+       description => 'VMID: 16112, lxc, raw, backup',
+       vmid => '16112',
+       files => [
+           "$storage_dir/images/16112/vm-16112-disk-0.raw",
+           "$storage_dir/dump/vzdump-lxc-16112-2020_03_30-21_39_30.tar.lzo",
+           "$storage_dir/dump/vzdump-lxc-16112-2020_03_30-21_49_30.tar.gz",
+           "$storage_dir/dump/vzdump-lxc-16112-2020_03_30-21_59_30.tgz",
+       ],
+       expected => [
+           {
+               'content' => 'rootdir',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'raw',
+               'parent'  => undef,
+               'size'    => DEFAULT_SIZE,
+               'used'    => DEFAULT_USED,
+               'vmid'    => '16112',
+               'volid'   => 'local:16112/vm-16112-disk-0.raw',
+           },
+           {
+               'content' => 'backup',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'tar.lzo',
+               'size'    => DEFAULT_SIZE,
+               'vmid'    => '16112',
+               'volid'   => 'local:backup/vzdump-lxc-16112-2020_03_30-21_39_30.tar.lzo',
+           },
+           {
+               'content' => 'backup',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'tar.gz',
+               'size'    => DEFAULT_SIZE,
+               'vmid'    => '16112',
+               'volid'   => 'local:backup/vzdump-lxc-16112-2020_03_30-21_49_30.tar.gz',
+           },
+           {
+               'content' => 'backup',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'tgz',
+               'size'    => DEFAULT_SIZE,
+               'vmid'    => '16112',
+               'volid'   => 'local:backup/vzdump-lxc-16112-2020_03_30-21_59_30.tgz',
+           },
+       ],
+    },
+    {
+       description => 'VMID: 16114, VM, qcow2, linked clone',
+       vmid => '16114',
+       files => [
+           "$storage_dir/images/16114/vm-16114-disk-0.qcow2",
+           "$storage_dir/images/16114/vm-16114-disk-1.qcow2",
+       ],
+       parent => [
+           "../9004/base-9004-disk-0.qcow2",
+           "../9004/base-9004-disk-1.qcow2",
+       ],
+       expected => [
+           {
+               'content' => 'images',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'qcow2',
+               'parent'  => '../9004/base-9004-disk-0.qcow2',
+               'size'    => DEFAULT_SIZE,
+               'used'    => DEFAULT_USED,
+               'vmid'    => '16114',
+               'volid'   => 'local:9004/base-9004-disk-0.qcow2/16114/vm-16114-disk-0.qcow2',
+           },
+           {
+               'content' => 'images',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'qcow2',
+               'parent'  => '../9004/base-9004-disk-1.qcow2',
+               'size'    => DEFAULT_SIZE,
+               'used'    => DEFAULT_USED,
+               'vmid'    => '16114',
+               'volid'   => 'local:9004/base-9004-disk-1.qcow2/16114/vm-16114-disk-1.qcow2',
+           },
+       ],
+    },
+    {
+       description => 'VMID: 9004, VM, template, qcow2',
+       vmid => '9004',
+       files => [
+           "$storage_dir/images/9004/base-9004-disk-0.qcow2",
+           "$storage_dir/images/9004/base-9004-disk-1.qcow2",
+       ],
+       expected => [
+           {
+               'content' => 'images',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'qcow2',
+               'parent'  => undef,
+               'size'    => DEFAULT_SIZE,
+               'used'    => DEFAULT_USED,
+               'vmid'    => '9004',
+               'volid'   => 'local:9004/base-9004-disk-0.qcow2',
+           },
+           {
+               'content' => 'images',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'qcow2',
+               'parent'  => undef,
+               'size'    => DEFAULT_SIZE,
+               'used'    => DEFAULT_USED,
+               'vmid'    => '9004',
+               'volid'   => 'local:9004/base-9004-disk-1.qcow2',
+           },
+       ],
+    },
+    {
+       description => 'VMID: none, templates, snippets, backup',
+       vmid => undef,
+       files => [
+           "$storage_dir/dump/vzdump-lxc-19253-2020_02_03-19_57_43.tar.gz",
+           "$storage_dir/dump/vzdump-lxc-19254-2019_01_21-19_29_19.tar",
+           "$storage_dir/template/iso/archlinux-2020.02.01-x86_64.iso",
+           "$storage_dir/template/iso/debian-8.11.1-amd64-DVD-1.iso",
+           "$storage_dir/template/iso/debian-9.12.0-amd64-netinst.iso",
+           "$storage_dir/template/iso/proxmox-ve_6.1-1.iso",
+           "$storage_dir/template/cache/archlinux-base_20190924-1_amd64.tar.gz",
+           "$storage_dir/template/cache/debian-10.0-standard_10.0-1_amd64.tar.gz",
+           "$storage_dir/template/cache/alpine-3.10-default_20190626_amd64.tar.xz",
+           "$storage_dir/snippets/userconfig.yaml",
+           "$storage_dir/snippets/hookscript.pl",
+           "$storage_dir/private/1234/", # fileparse needs / at the end
+           "$storage_dir/private/1234/subvol-1234-disk-0.subvol/", # fileparse needs / at the end
+       ],
+       expected => [
+           {
+               'content' => 'vztmpl',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'txz',
+               'size'    => DEFAULT_SIZE,
+               'volid'   => 'local:vztmpl/alpine-3.10-default_20190626_amd64.tar.xz',
+           },
+           {
+               'content' => 'vztmpl',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'tgz',
+               'size'    => DEFAULT_SIZE,
+               'volid'   => 'local:vztmpl/archlinux-base_20190924-1_amd64.tar.gz',
+           },
+           {
+               'content' => 'vztmpl',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'tgz',
+               'size'    => DEFAULT_SIZE,
+               'volid'   => 'local:vztmpl/debian-10.0-standard_10.0-1_amd64.tar.gz',
+           },
+           {
+               'content' => 'iso',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'iso',
+               'size'    => DEFAULT_SIZE,
+               'volid'   => 'local:iso/archlinux-2020.02.01-x86_64.iso',
+           },
+           {
+               'content' => 'iso',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'iso',
+               'size'    => DEFAULT_SIZE,
+               'volid'   => 'local:iso/debian-8.11.1-amd64-DVD-1.iso',
+           },
+           {
+               'content' => 'iso',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'iso',
+               'size'    => DEFAULT_SIZE,
+               'volid'   => 'local:iso/debian-9.12.0-amd64-netinst.iso',
+           },
+           {
+               'content' => 'iso',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'iso',
+               'size'    => DEFAULT_SIZE,
+               'volid'   => 'local:iso/proxmox-ve_6.1-1.iso',
+           },
+           {
+               'content' => 'backup',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'tar.gz',
+               'size'    => DEFAULT_SIZE,
+               'vmid'    => '19253',
+               'volid'   => 'local:backup/vzdump-lxc-19253-2020_02_03-19_57_43.tar.gz',
+           },
+           {
+               'content' => 'backup',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'tar',
+               'size'    => DEFAULT_SIZE,
+               'vmid'    => '19254',
+               'volid'   => 'local:backup/vzdump-lxc-19254-2019_01_21-19_29_19.tar',
+           },
+           {
+               'content' => 'snippets',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'snippet',
+               'size'    => DEFAULT_SIZE,
+               'volid'   => 'local:snippets/hookscript.pl',
+           },
+           {
+               'content' => 'snippets',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'snippet',
+               'size'    => DEFAULT_SIZE,
+               'volid'   => 'local:snippets/userconfig.yaml',
+           },
+       ],
+    },
+    {
+       description => 'VMID: none, parent, non-matching',
+       # string instead of vmid in folder
+       #"$storage_dir/images/ssss/base-4321-disk-0.qcow2/1234/vm-1234-disk-0.qcow2",
+       vmid => undef,
+       files => [
+           "$storage_dir/images/1234/vm-1234-disk-0.qcow2",
+       ],
+       parent => [
+           "../ssss/base-4321-disk-0.qcow2",
+       ],
+       expected => [
+           {
+               'content' => 'images',
+               'ctime'   => DEFAULT_CTIME,
+               'format'  => 'qcow2',
+               'parent'  => '../ssss/base-4321-disk-0.qcow2',
+               'size'    => DEFAULT_SIZE,
+               'used'    => DEFAULT_USED,
+               'vmid'    => '1234',
+               'volid'   => 'local:1234/vm-1234-disk-0.qcow2',
+           }
+       ],
+    },
+    {
+       description => 'VMID: none, non-matching',
+       # failed matches
+       vmid => undef,
+       files => [
+           "$storage_dir/images/ssss/base-4321-disk-0.raw",
+           "$storage_dir/images/ssss/vm-1234-disk-0.qcow2",
+           "$storage_dir/template/iso/yet-again-a-installation-disk.dvd",
+           "$storage_dir/template/cache/debian-10.0-standard_10.0-1_amd64.zip.gz",
+           "$storage_dir/template/cache/debian-10.0-standard_10.0-1_amd64.tar.bz2",
+           "$storage_dir/private/subvol-19254-disk-0/19254",
+           "$storage_dir/dump/vzdump-openvz-16112-2020_03_30-21_39_30.tar.bz2",
+           "$storage_dir/dump/vzdump-openvz-16112-2020_03_30-21_39_30.zip.gz",
+           "$storage_dir/dump/vzdump-openvz-16112-2020_03_30-21_39_30.tgz.lzo",
+           "$storage_dir/dump/vzdump-qemu-16110-2020_03_30-21_12_40.vma.xz",
+           "$storage_dir/dump/vzdump-qemu-16110-2020_03_30-21_12_40.vms.gz",
+       ],
+       expected => [], # returns empty list
+    },
+);
+
+
+# provide static vmlist for tests
+my $mock_cluster = Test::MockModule->new('PVE::Cluster', no_auto => 1);
+$mock_cluster->redefine(get_vmlist => sub { return $mocked_vmlist; });
+
+# populate is File::stat's method to fill all information from CORE::stat into
+# an blessed array.
+my $mock_stat = Test::MockModule->new('File::stat', no_auto => 1);
+$mock_stat->redefine(populate => sub {
+       my (@st) = @_;
+       $st[7] = DEFAULT_SIZE;
+       $st[10] = DEFAULT_CTIME;
+
+       my $result = $mock_stat->original('populate')->(@st);
+
+       return $result;
+});
+
+# override info provided by qemu-img in file_size_info
+my $mock_fsi = Test::MockModule->new('PVE::Storage::Plugin', no_auto => 1);
+$mock_fsi->redefine(file_size_info => sub {
+       my ($filename, $timeout) = @_;
+       my ($size, $format, $used, $parent, $ctime) = $mock_fsi->original('file_size_info')->($filename, $timeout);
+
+       $size = DEFAULT_SIZE;
+       $used = DEFAULT_USED;
+
+       return wantarray ? ($size, $format, $used, $parent, $ctime) : $size;
+});
+
+my $plan = scalar @tests;
+plan tests => $plan + 1;
+
+{
+    # don't accidentally modify vmlist, see bug report
+    # https://pve.proxmox.com/pipermail/pve-devel/2020-January/041096.html
+    my $scfg_with_type = { path => $storage_dir, type => 'dir' };
+    my $original_vmlist = { ids => {} };
+    my $tested_vmlist = dclone($original_vmlist);
+
+    PVE::Storage::Plugin->list_volumes('sid', $scfg_with_type, undef, ['images']);
+
+    is_deeply ($tested_vmlist, $original_vmlist,
+       'PVE::Cluster::vmlist remains unmodified')
+    || diag ("Expected vmlist to remain\n", explain($original_vmlist),
+       "but it turned to\n", explain($tested_vmlist));
+}
+
+
+{
+    my $sid = 'local';
+    my $types = [ 'rootdir', 'images', 'vztmpl', 'iso', 'backup', 'snippets' ];
+    my @suffixes = ( 'qcow2', 'raw', 'vmdk', 'vhdx' );
+
+    # run through test cases
+    foreach my $tt (@tests) {
+       my $vmid = $tt->{vmid};
+       my $files = $tt->{files};
+       my $expected = $tt->{expected};
+       my $description = $tt->{description};
+       my $parent = $tt->{parent};
+
+       # prepare environment
+       my $num = 0; #parent disks
+       for my $file (@$files) {
+           my ($name, $dir, $suffix) = fileparse($file, @suffixes);
+
+           make_path($dir, { verbose => 1, mode => 0755 });
+
+           if ($name) {
+               # using qemu-img to also be able to represent the backing device
+               my @cmd = ( '/usr/bin/qemu-img', 'create', "$file", DEFAULT_SIZE );
+               push @cmd, ( '-f', $suffix ) if $suffix;
+               push @cmd, ( '-u', '-b', @$parent[$num] ) if $parent;
+               $num++;
+
+               run_command([@cmd]);
+           }
+       }
+
+       my $got;
+       eval { $got = PVE::Storage::Plugin->list_volumes($sid, $scfg, $vmid, $types) };
+       $got = $@ if $@;
+
+       is_deeply($got, $expected, $description) || diag(explain($got));
+
+       # clean up after each test case, otherwise
+       # we get wrong results from leftover files
+       remove_tree($storage_dir, { verbose => 1 });
+    }
+}
+
+done_testing();
+
+1;
index 6f5ea010b58621ef96410a16baff90f577d75c21..be8657a4d4831ca6ce44df8db59173a3d6f36eab 100755 (executable)
@@ -6,7 +6,11 @@ use warnings;
 use TAP::Harness;
 
 my $harness = TAP::Harness->new( { verbosity => -1 });
-my $res = $harness->runtests("archive_info_test.pm", "parse_volname_test.pm");
+my $res = $harness->runtests(
+    "archive_info_test.pm",
+    "parse_volname_test.pm",
+    "list_volumes_test.pm",
+);
 
 exit -1 if !$res || $res->{failed} || $res->{parse_errors};