]> git.proxmox.com Git - pve-storage.git/blame - test/list_volumes_test.pm
Fix: #2124 storage: add zstd support
[pve-storage.git] / test / list_volumes_test.pm
CommitLineData
6a27e817
AA
1package PVE::Storage::TestListVolumes;
2
3use strict;
4use warnings;
5
6use lib qw(..);
7
8use PVE::Storage;
9use PVE::Cluster;
10use PVE::Tools qw(run_command);
11
12use Test::More;
13use Test::MockModule;
14
15use Cwd;
16use File::Basename;
17use File::Path qw(make_path remove_tree);
18use File::stat qw();
19use File::Temp;
20use Storable qw(dclone);
21
22use constant DEFAULT_SIZE => 131072; # 128 kiB
23use constant DEFAULT_USED => 262144; # 256 kiB
24use constant DEFAULT_CTIME => 1234567890;
25
26# get_vmlist() return values
27my $mocked_vmlist = {
28 'version' => 1,
29 'ids' => {
30 '16110' => {
31 'node' => 'x42',
32 'type' => 'qemu',
33 'version' => 4,
34 },
35 '16112' => {
36 'node' => 'x42',
37 'type' => 'lxc',
38 'version' => 7,
39 },
40 '16114' => {
41 'node' => 'x42',
42 'type' => 'qemu',
43 'version' => 2,
44 },
45 '16113' => {
46 'node' => 'x42',
47 'type' => 'qemu',
48 'version' => 5,
49 },
50 '16115' => {
51 'node' => 'x42',
52 'type' => 'qemu',
53 'version' => 1,
54 },
55 '9004' => {
56 'node' => 'x42',
57 'type' => 'qemu',
58 'version' => 6,
59 }
60 }
61};
62
63my $storage_dir = File::Temp->newdir();
64my $scfg = {
65 'type' => 'dir',
66 'maxfiles' => 0,
67 'path' => $storage_dir,
68 'shared' => 0,
69 'content' => {
70 'iso' => 1,
71 'rootdir' => 1,
72 'vztmpl' => 1,
73 'images' => 1,
74 'snippets' => 1,
75 'backup' => 1,
76 },
77};
78
79# The test cases are comprised of an arry of hashes with the following keys:
80# description => displayed on error by Test::More
81# vmid => used for image matches by list_volume
82# files => array of files for qemu-img to create
83# expected => returned result hash
84# (content, ctime, format, parent, size, used, vimd, volid)
85my @tests = (
86 {
87 description => 'VMID: 16110, VM, qcow2, backup, snippets',
88 vmid => '16110',
89 files => [
90 "$storage_dir/images/16110/vm-16110-disk-0.qcow2",
91 "$storage_dir/images/16110/vm-16110-disk-1.raw",
92 "$storage_dir/images/16110/vm-16110-disk-2.vmdk",
93 "$storage_dir/dump/vzdump-qemu-16110-2020_03_30-21_11_40.vma.gz",
94 "$storage_dir/dump/vzdump-qemu-16110-2020_03_30-21_12_45.vma.lzo",
95 "$storage_dir/dump/vzdump-qemu-16110-2020_03_30-21_13_55.vma",
014d36db 96 "$storage_dir/dump/vzdump-qemu-16110-2020_03_30-21_13_55.vma.zst",
6a27e817
AA
97 "$storage_dir/snippets/userconfig.yaml",
98 "$storage_dir/snippets/hookscript.pl",
99 ],
100 expected => [
101 {
102 'content' => 'images',
103 'ctime' => DEFAULT_CTIME,
104 'format' => 'qcow2',
105 'parent' => undef,
106 'size' => DEFAULT_SIZE,
107 'used' => DEFAULT_USED,
108 'vmid' => '16110',
109 'volid' => 'local:16110/vm-16110-disk-0.qcow2',
110 },
111 {
112 'content' => 'images',
113 'ctime' => DEFAULT_CTIME,
114 'format' => 'raw',
115 'parent' => undef,
116 'size' => DEFAULT_SIZE,
117 'used' => DEFAULT_USED,
118 'vmid' => '16110',
119 'volid' => 'local:16110/vm-16110-disk-1.raw',
120 },
121 {
122 'content' => 'images',
123 'ctime' => DEFAULT_CTIME,
124 'format' => 'vmdk',
125 'parent' => undef,
126 'size' => DEFAULT_SIZE,
127 'used' => DEFAULT_USED,
128 'vmid' => '16110',
129 'volid' => 'local:16110/vm-16110-disk-2.vmdk',
130 },
131 {
132 'content' => 'backup',
40c795e7 133 'ctime' => 1585595500,
6a27e817
AA
134 'format' => 'vma.gz',
135 'size' => DEFAULT_SIZE,
136 'vmid' => '16110',
137 'volid' => 'local:backup/vzdump-qemu-16110-2020_03_30-21_11_40.vma.gz',
138 },
139 {
140 'content' => 'backup',
40c795e7 141 'ctime' => 1585595565,
6a27e817
AA
142 'format' => 'vma.lzo',
143 'size' => DEFAULT_SIZE,
144 'vmid' => '16110',
145 'volid' => 'local:backup/vzdump-qemu-16110-2020_03_30-21_12_45.vma.lzo',
146 },
147 {
148 'content' => 'backup',
40c795e7 149 'ctime' => 1585595635,
6a27e817
AA
150 'format' => 'vma',
151 'size' => DEFAULT_SIZE,
152 'vmid' => '16110',
153 'volid' => 'local:backup/vzdump-qemu-16110-2020_03_30-21_13_55.vma',
154 },
014d36db
AA
155 {
156 'content' => 'backup',
157 'ctime' => 1585595635,
158 'format' => 'vma.zst',
159 'size' => DEFAULT_SIZE,
160 'vmid' => '16110',
161 'volid' => 'local:backup/vzdump-qemu-16110-2020_03_30-21_13_55.vma.zst',
162 },
6a27e817
AA
163 {
164 'content' => 'snippets',
165 'ctime' => DEFAULT_CTIME,
166 'format' => 'snippet',
167 'size' => DEFAULT_SIZE,
168 'volid' => 'local:snippets/hookscript.pl',
169 },
170 {
171 'content' => 'snippets',
172 'ctime' => DEFAULT_CTIME,
173 'format' => 'snippet',
174 'size' => DEFAULT_SIZE,
175 'volid' => 'local:snippets/userconfig.yaml',
176 },
177 ],
178 },
179 {
180 description => 'VMID: 16112, lxc, raw, backup',
181 vmid => '16112',
182 files => [
183 "$storage_dir/images/16112/vm-16112-disk-0.raw",
184 "$storage_dir/dump/vzdump-lxc-16112-2020_03_30-21_39_30.tar.lzo",
185 "$storage_dir/dump/vzdump-lxc-16112-2020_03_30-21_49_30.tar.gz",
014d36db 186 "$storage_dir/dump/vzdump-lxc-16112-2020_03_30-21_49_30.tar.zst",
6a27e817
AA
187 "$storage_dir/dump/vzdump-lxc-16112-2020_03_30-21_59_30.tgz",
188 ],
189 expected => [
190 {
191 'content' => 'rootdir',
192 'ctime' => DEFAULT_CTIME,
193 'format' => 'raw',
194 'parent' => undef,
195 'size' => DEFAULT_SIZE,
196 'used' => DEFAULT_USED,
197 'vmid' => '16112',
198 'volid' => 'local:16112/vm-16112-disk-0.raw',
199 },
200 {
201 'content' => 'backup',
40c795e7 202 'ctime' => 1585597170,
6a27e817
AA
203 'format' => 'tar.lzo',
204 'size' => DEFAULT_SIZE,
205 'vmid' => '16112',
206 'volid' => 'local:backup/vzdump-lxc-16112-2020_03_30-21_39_30.tar.lzo',
207 },
208 {
209 'content' => 'backup',
40c795e7 210 'ctime' => 1585597770,
6a27e817
AA
211 'format' => 'tar.gz',
212 'size' => DEFAULT_SIZE,
213 'vmid' => '16112',
214 'volid' => 'local:backup/vzdump-lxc-16112-2020_03_30-21_49_30.tar.gz',
215 },
014d36db
AA
216 {
217 'content' => 'backup',
218 'ctime' => 1585597770,
219 'format' => 'tar.zst',
220 'size' => DEFAULT_SIZE,
221 'vmid' => '16112',
222 'volid' => 'local:backup/vzdump-lxc-16112-2020_03_30-21_49_30.tar.zst',
223 },
6a27e817
AA
224 {
225 'content' => 'backup',
40c795e7 226 'ctime' => 1585598370,
6a27e817
AA
227 'format' => 'tgz',
228 'size' => DEFAULT_SIZE,
229 'vmid' => '16112',
230 'volid' => 'local:backup/vzdump-lxc-16112-2020_03_30-21_59_30.tgz',
231 },
232 ],
233 },
234 {
235 description => 'VMID: 16114, VM, qcow2, linked clone',
236 vmid => '16114',
237 files => [
238 "$storage_dir/images/16114/vm-16114-disk-0.qcow2",
239 "$storage_dir/images/16114/vm-16114-disk-1.qcow2",
240 ],
241 parent => [
242 "../9004/base-9004-disk-0.qcow2",
243 "../9004/base-9004-disk-1.qcow2",
244 ],
245 expected => [
246 {
247 'content' => 'images',
248 'ctime' => DEFAULT_CTIME,
249 'format' => 'qcow2',
250 'parent' => '../9004/base-9004-disk-0.qcow2',
251 'size' => DEFAULT_SIZE,
252 'used' => DEFAULT_USED,
253 'vmid' => '16114',
254 'volid' => 'local:9004/base-9004-disk-0.qcow2/16114/vm-16114-disk-0.qcow2',
255 },
256 {
257 'content' => 'images',
258 'ctime' => DEFAULT_CTIME,
259 'format' => 'qcow2',
260 'parent' => '../9004/base-9004-disk-1.qcow2',
261 'size' => DEFAULT_SIZE,
262 'used' => DEFAULT_USED,
263 'vmid' => '16114',
264 'volid' => 'local:9004/base-9004-disk-1.qcow2/16114/vm-16114-disk-1.qcow2',
265 },
266 ],
267 },
268 {
269 description => 'VMID: 9004, VM, template, qcow2',
270 vmid => '9004',
271 files => [
272 "$storage_dir/images/9004/base-9004-disk-0.qcow2",
273 "$storage_dir/images/9004/base-9004-disk-1.qcow2",
274 ],
275 expected => [
276 {
277 'content' => 'images',
278 'ctime' => DEFAULT_CTIME,
279 'format' => 'qcow2',
280 'parent' => undef,
281 'size' => DEFAULT_SIZE,
282 'used' => DEFAULT_USED,
283 'vmid' => '9004',
284 'volid' => 'local:9004/base-9004-disk-0.qcow2',
285 },
286 {
287 'content' => 'images',
288 'ctime' => DEFAULT_CTIME,
289 'format' => 'qcow2',
290 'parent' => undef,
291 'size' => DEFAULT_SIZE,
292 'used' => DEFAULT_USED,
293 'vmid' => '9004',
294 'volid' => 'local:9004/base-9004-disk-1.qcow2',
295 },
296 ],
297 },
298 {
299 description => 'VMID: none, templates, snippets, backup',
300 vmid => undef,
301 files => [
302 "$storage_dir/dump/vzdump-lxc-19253-2020_02_03-19_57_43.tar.gz",
303 "$storage_dir/dump/vzdump-lxc-19254-2019_01_21-19_29_19.tar",
304 "$storage_dir/template/iso/archlinux-2020.02.01-x86_64.iso",
305 "$storage_dir/template/iso/debian-8.11.1-amd64-DVD-1.iso",
306 "$storage_dir/template/iso/debian-9.12.0-amd64-netinst.iso",
307 "$storage_dir/template/iso/proxmox-ve_6.1-1.iso",
308 "$storage_dir/template/cache/archlinux-base_20190924-1_amd64.tar.gz",
309 "$storage_dir/template/cache/debian-10.0-standard_10.0-1_amd64.tar.gz",
310 "$storage_dir/template/cache/alpine-3.10-default_20190626_amd64.tar.xz",
311 "$storage_dir/snippets/userconfig.yaml",
312 "$storage_dir/snippets/hookscript.pl",
313 "$storage_dir/private/1234/", # fileparse needs / at the end
314 "$storage_dir/private/1234/subvol-1234-disk-0.subvol/", # fileparse needs / at the end
315 ],
316 expected => [
317 {
318 'content' => 'vztmpl',
319 'ctime' => DEFAULT_CTIME,
320 'format' => 'txz',
321 'size' => DEFAULT_SIZE,
322 'volid' => 'local:vztmpl/alpine-3.10-default_20190626_amd64.tar.xz',
323 },
324 {
325 'content' => 'vztmpl',
326 'ctime' => DEFAULT_CTIME,
327 'format' => 'tgz',
328 'size' => DEFAULT_SIZE,
329 'volid' => 'local:vztmpl/archlinux-base_20190924-1_amd64.tar.gz',
330 },
331 {
332 'content' => 'vztmpl',
333 'ctime' => DEFAULT_CTIME,
334 'format' => 'tgz',
335 'size' => DEFAULT_SIZE,
336 'volid' => 'local:vztmpl/debian-10.0-standard_10.0-1_amd64.tar.gz',
337 },
338 {
339 'content' => 'iso',
340 'ctime' => DEFAULT_CTIME,
341 'format' => 'iso',
342 'size' => DEFAULT_SIZE,
343 'volid' => 'local:iso/archlinux-2020.02.01-x86_64.iso',
344 },
345 {
346 'content' => 'iso',
347 'ctime' => DEFAULT_CTIME,
348 'format' => 'iso',
349 'size' => DEFAULT_SIZE,
350 'volid' => 'local:iso/debian-8.11.1-amd64-DVD-1.iso',
351 },
352 {
353 'content' => 'iso',
354 'ctime' => DEFAULT_CTIME,
355 'format' => 'iso',
356 'size' => DEFAULT_SIZE,
357 'volid' => 'local:iso/debian-9.12.0-amd64-netinst.iso',
358 },
359 {
360 'content' => 'iso',
361 'ctime' => DEFAULT_CTIME,
362 'format' => 'iso',
363 'size' => DEFAULT_SIZE,
364 'volid' => 'local:iso/proxmox-ve_6.1-1.iso',
365 },
366 {
367 'content' => 'backup',
40c795e7 368 'ctime' => 1580756263,
6a27e817
AA
369 'format' => 'tar.gz',
370 'size' => DEFAULT_SIZE,
371 'vmid' => '19253',
372 'volid' => 'local:backup/vzdump-lxc-19253-2020_02_03-19_57_43.tar.gz',
373 },
374 {
375 'content' => 'backup',
40c795e7 376 'ctime' => 1548095359,
6a27e817
AA
377 'format' => 'tar',
378 'size' => DEFAULT_SIZE,
379 'vmid' => '19254',
380 'volid' => 'local:backup/vzdump-lxc-19254-2019_01_21-19_29_19.tar',
381 },
382 {
383 'content' => 'snippets',
384 'ctime' => DEFAULT_CTIME,
385 'format' => 'snippet',
386 'size' => DEFAULT_SIZE,
387 'volid' => 'local:snippets/hookscript.pl',
388 },
389 {
390 'content' => 'snippets',
391 'ctime' => DEFAULT_CTIME,
392 'format' => 'snippet',
393 'size' => DEFAULT_SIZE,
394 'volid' => 'local:snippets/userconfig.yaml',
395 },
396 ],
397 },
398 {
399 description => 'VMID: none, parent, non-matching',
400 # string instead of vmid in folder
401 #"$storage_dir/images/ssss/base-4321-disk-0.qcow2/1234/vm-1234-disk-0.qcow2",
402 vmid => undef,
403 files => [
404 "$storage_dir/images/1234/vm-1234-disk-0.qcow2",
405 ],
406 parent => [
407 "../ssss/base-4321-disk-0.qcow2",
408 ],
409 expected => [
410 {
411 'content' => 'images',
412 'ctime' => DEFAULT_CTIME,
413 'format' => 'qcow2',
414 'parent' => '../ssss/base-4321-disk-0.qcow2',
415 'size' => DEFAULT_SIZE,
416 'used' => DEFAULT_USED,
417 'vmid' => '1234',
418 'volid' => 'local:1234/vm-1234-disk-0.qcow2',
419 }
420 ],
421 },
422 {
423 description => 'VMID: none, non-matching',
424 # failed matches
425 vmid => undef,
426 files => [
427 "$storage_dir/images/ssss/base-4321-disk-0.raw",
428 "$storage_dir/images/ssss/vm-1234-disk-0.qcow2",
429 "$storage_dir/template/iso/yet-again-a-installation-disk.dvd",
430 "$storage_dir/template/cache/debian-10.0-standard_10.0-1_amd64.zip.gz",
431 "$storage_dir/template/cache/debian-10.0-standard_10.0-1_amd64.tar.bz2",
432 "$storage_dir/private/subvol-19254-disk-0/19254",
433 "$storage_dir/dump/vzdump-openvz-16112-2020_03_30-21_39_30.tar.bz2",
434 "$storage_dir/dump/vzdump-openvz-16112-2020_03_30-21_39_30.zip.gz",
435 "$storage_dir/dump/vzdump-openvz-16112-2020_03_30-21_39_30.tgz.lzo",
436 "$storage_dir/dump/vzdump-qemu-16110-2020_03_30-21_12_40.vma.xz",
437 "$storage_dir/dump/vzdump-qemu-16110-2020_03_30-21_12_40.vms.gz",
438 ],
439 expected => [], # returns empty list
440 },
441);
442
443
444# provide static vmlist for tests
445my $mock_cluster = Test::MockModule->new('PVE::Cluster', no_auto => 1);
446$mock_cluster->redefine(get_vmlist => sub { return $mocked_vmlist; });
447
448# populate is File::stat's method to fill all information from CORE::stat into
449# an blessed array.
450my $mock_stat = Test::MockModule->new('File::stat', no_auto => 1);
451$mock_stat->redefine(populate => sub {
452 my (@st) = @_;
453 $st[7] = DEFAULT_SIZE;
454 $st[10] = DEFAULT_CTIME;
455
456 my $result = $mock_stat->original('populate')->(@st);
457
458 return $result;
459});
460
461# override info provided by qemu-img in file_size_info
462my $mock_fsi = Test::MockModule->new('PVE::Storage::Plugin', no_auto => 1);
463$mock_fsi->redefine(file_size_info => sub {
464 my ($filename, $timeout) = @_;
465 my ($size, $format, $used, $parent, $ctime) = $mock_fsi->original('file_size_info')->($filename, $timeout);
466
467 $size = DEFAULT_SIZE;
468 $used = DEFAULT_USED;
469
470 return wantarray ? ($size, $format, $used, $parent, $ctime) : $size;
471});
472
473my $plan = scalar @tests;
474plan tests => $plan + 1;
475
476{
477 # don't accidentally modify vmlist, see bug report
478 # https://pve.proxmox.com/pipermail/pve-devel/2020-January/041096.html
479 my $scfg_with_type = { path => $storage_dir, type => 'dir' };
480 my $original_vmlist = { ids => {} };
481 my $tested_vmlist = dclone($original_vmlist);
482
483 PVE::Storage::Plugin->list_volumes('sid', $scfg_with_type, undef, ['images']);
484
485 is_deeply ($tested_vmlist, $original_vmlist,
486 'PVE::Cluster::vmlist remains unmodified')
487 || diag ("Expected vmlist to remain\n", explain($original_vmlist),
488 "but it turned to\n", explain($tested_vmlist));
489}
490
491
492{
493 my $sid = 'local';
494 my $types = [ 'rootdir', 'images', 'vztmpl', 'iso', 'backup', 'snippets' ];
495 my @suffixes = ( 'qcow2', 'raw', 'vmdk', 'vhdx' );
496
497 # run through test cases
498 foreach my $tt (@tests) {
499 my $vmid = $tt->{vmid};
500 my $files = $tt->{files};
501 my $expected = $tt->{expected};
502 my $description = $tt->{description};
503 my $parent = $tt->{parent};
504
505 # prepare environment
506 my $num = 0; #parent disks
507 for my $file (@$files) {
508 my ($name, $dir, $suffix) = fileparse($file, @suffixes);
509
510 make_path($dir, { verbose => 1, mode => 0755 });
511
512 if ($name) {
513 # using qemu-img to also be able to represent the backing device
514 my @cmd = ( '/usr/bin/qemu-img', 'create', "$file", DEFAULT_SIZE );
515 push @cmd, ( '-f', $suffix ) if $suffix;
516 push @cmd, ( '-u', '-b', @$parent[$num] ) if $parent;
517 $num++;
518
519 run_command([@cmd]);
520 }
521 }
522
523 my $got;
524 eval { $got = PVE::Storage::Plugin->list_volumes($sid, $scfg, $vmid, $types) };
525 $got = $@ if $@;
526
527 is_deeply($got, $expected, $description) || diag(explain($got));
528
529 # clean up after each test case, otherwise
530 # we get wrong results from leftover files
531 remove_tree($storage_dir, { verbose => 1 });
532 }
533}
534
535done_testing();
536
5371;