]> git.proxmox.com Git - pve-storage.git/blame - test/prune_backups_test.pm
prune mark: correctly keep track of already included backups
[pve-storage.git] / test / prune_backups_test.pm
CommitLineData
8f26b391
FE
1package PVE::Storage::TestPruneBackups;
2
3use strict;
4use warnings;
5
6use lib qw(..);
7
8use PVE::Storage;
9use Test::More;
10use Test::MockModule;
11
12my $storeid = 'BackTest123';
13my @vmids = (1234, 9001);
14
15# only includes the information needed for prune_backups
16my $mocked_backups_lists = {};
17
18my $basetime = 1577881101; # 2020_01_01-12_18_21 UTC
19
20foreach my $vmid (@vmids) {
21 push @{$mocked_backups_lists->{default}}, (
22 {
23 'volid' => "$storeid:backup/vzdump-qemu-$vmid-2018_05_26-11_18_21.tar.zst",
24 'ctime' => $basetime - 585*24*60*60 - 60*60,
25 'vmid' => $vmid,
26 },
27 {
28 'volid' => "$storeid:backup/vzdump-qemu-$vmid-2019_12_31-11_18_21.tar.zst",
29 'ctime' => $basetime - 24*60*60 - 60*60,
30 'vmid' => $vmid,
31 },
32 {
33 'volid' => "$storeid:backup/vzdump-qemu-$vmid-2019_12_31-11_19_21.tar.zst",
34 'ctime' => $basetime - 24*60*60 - 60*60 + 60,
35 'vmid' => $vmid,
36 },
37 {
38 'volid' => "$storeid:backup/vzdump-qemu-$vmid-2020_01_01-11_18_21.tar.zst",
39 'ctime' => $basetime - 60*60,
40 'vmid' => $vmid,
41 },
42 {
43 'volid' => "$storeid:backup/vzdump-qemu-$vmid-2020_01_01-12_18_21.tar.zst",
44 'ctime' => $basetime,
45 'vmid' => $vmid,
46 },
47 {
48 'volid' => "$storeid:backup/vzdump-lxc-$vmid-2020_01_01-12_18_21.tar.zst",
49 'ctime' => $basetime,
50 'vmid' => $vmid,
51 },
52 {
53 'volid' => "$storeid:backup/vzdump-$vmid-renamed.tar.zst",
54 'ctime' => 1234,
55 'vmid' => $vmid,
56 },
57 );
58}
59push @{$mocked_backups_lists->{year1970}}, (
60 {
61 'volid' => "$storeid:backup/vzdump-lxc-321-1970_01_01-00_01_23.tar.zst",
62 'ctime' => 83,
63 'vmid' => 321,
64 },
65 {
66 'volid' => "$storeid:backup/vzdump-lxc-321-2070_01_01-00_01_00.tar.zst",
67 'ctime' => 60*60*24 * (365*100 + 25) + 60,
68 'vmid' => 321,
69 },
70);
71push @{$mocked_backups_lists->{novmid}}, (
72 {
73 'volid' => "$storeid:backup/vzdump-lxc-novmid.tar.gz",
74 'ctime' => 1234,
75 },
76);
10dfeb9e
FE
77push @{$mocked_backups_lists->{threeway}}, (
78 {
79 'volid' => "$storeid:backup/vzdump-qemu-7654-2019_12_25-12_18_21.tar.zst",
80 'ctime' => $basetime - 7*24*60*60,
81 'vmid' => 7654,
82 },
83 {
84 'volid' => "$storeid:backup/vzdump-qemu-7654-2019_12_31-12_18_21.tar.zst",
85 'ctime' => $basetime - 24*60*60,
86 'vmid' => 7654,
87 },
88 {
89 'volid' => "$storeid:backup/vzdump-qemu-7654-2020_01_01-12_18_21.tar.zst",
90 'ctime' => $basetime,
91 'vmid' => 7654,
92 },
93);
8f26b391
FE
94my $current_list;
95my $mock_plugin = Test::MockModule->new('PVE::Storage::Plugin');
96$mock_plugin->redefine(list_volumes => sub {
97 my ($class, $storeid, $scfg, $vmid, $content_types) = @_;
98
99 my $list = $mocked_backups_lists->{$current_list};
100
101 return $list if !defined($vmid);
102
103 return [ grep { $_->{vmid} eq $vmid } @{$list} ];
104});
105
106sub generate_expected {
107 my ($vmids, $type, $marks) = @_;
108
109 my @expected;
110 foreach my $vmid (@{$vmids}) {
111 push @expected, (
112 {
113 'volid' => "$storeid:backup/vzdump-qemu-$vmid-2018_05_26-11_18_21.tar.zst",
114 'type' => 'qemu',
115 'ctime' => $basetime - 585*24*60*60 - 60*60,
116 'mark' => $marks->[0],
117 'vmid' => $vmid,
118 },
119 {
120 'volid' => "$storeid:backup/vzdump-qemu-$vmid-2019_12_31-11_18_21.tar.zst",
121 'type' => 'qemu',
122 'ctime' => $basetime - 24*60*60 - 60*60,
123 'mark' => $marks->[1],
124 'vmid' => $vmid,
125 },
126 {
127 'volid' => "$storeid:backup/vzdump-qemu-$vmid-2019_12_31-11_19_21.tar.zst",
128 'type' => 'qemu',
129 'ctime' => $basetime - 24*60*60 - 60*60 + 60,
130 'mark' => $marks->[2],
131 'vmid' => $vmid,
132 },
133 {
134 'volid' => "$storeid:backup/vzdump-qemu-$vmid-2020_01_01-11_18_21.tar.zst",
135 'type' => 'qemu',
136 'ctime' => $basetime - 60*60,
137 'mark' => $marks->[3],
138 'vmid' => $vmid,
139 },
140 {
141 'volid' => "$storeid:backup/vzdump-qemu-$vmid-2020_01_01-12_18_21.tar.zst",
142 'type' => 'qemu',
143 'ctime' => $basetime,
144 'mark' => $marks->[4],
145 'vmid' => $vmid,
146 },
147 ) if !defined($type) || $type eq 'qemu';
148 push @expected, (
149 {
150 'volid' => "$storeid:backup/vzdump-lxc-$vmid-2020_01_01-12_18_21.tar.zst",
151 'type' => 'lxc',
152 'ctime' => $basetime,
153 'mark' => $marks->[5],
154 'vmid' => $vmid,
155 },
156 ) if !defined($type) || $type eq 'lxc';
157 push @expected, (
158 {
159 'volid' => "$storeid:backup/vzdump-$vmid-renamed.tar.zst",
160 'type' => 'unknown',
161 'ctime' => 1234,
162 'mark' => 'protected',
163 'vmid' => $vmid,
164 },
165 ) if !defined($type);
166 }
167 return [ sort { $a->{volid} cmp $b->{volid} } @expected ];
168}
169
170# an array of test cases, each test is comprised of the following keys:
171# description => to identify a single test
172# vmid => VMID or undef for all
173# type => 'qemu' or 'lxc' or undef for all
174# keep => options describing what to keep
175# list => backups list to use. defaults to 'default'
176# expected => what prune_backups should return
177#
178# most of them are created further below
179my $tests = [
180 {
181 description => 'last=3, multiple IDs',
182 keep => {
183 'keep-last' => 3,
184 },
185 expected => generate_expected(\@vmids, undef, ['remove', 'remove', 'keep', 'keep', 'keep', 'keep']),
186 },
187 {
188 description => 'weekly=2, one ID',
189 vmid => $vmids[0],
190 keep => {
191 'keep-weekly' => 2,
192 },
193 expected => generate_expected([$vmids[0]], undef, ['keep', 'remove', 'remove', 'remove', 'keep', 'keep']),
194 },
195 {
196 description => 'daily=weekly=monthly=1, multiple IDs',
197 keep => {
198 'keep-hourly' => 0,
199 'keep-daily' => 1,
200 'keep-weekly' => 1,
201 'keep-monthly' => 1,
202 },
203 expected => generate_expected(\@vmids, undef, ['keep', 'remove', 'keep', 'remove', 'keep', 'keep']),
204 },
205 {
206 description => 'hourly=4, one ID',
207 vmid => $vmids[0],
208 keep => {
209 'keep-hourly' => 4,
210 'keep-daily' => 0,
211 },
212 expected => generate_expected([$vmids[0]], undef, ['keep', 'remove', 'keep', 'keep', 'keep', 'keep']),
213 },
214 {
215 description => 'yearly=2, multiple IDs',
216 keep => {
217 'keep-hourly' => 0,
218 'keep-daily' => 0,
219 'keep-weekly' => 0,
220 'keep-monthly' => 0,
221 'keep-yearly' => 2,
222 },
223 expected => generate_expected(\@vmids, undef, ['remove', 'remove', 'keep', 'remove', 'keep', 'keep']),
224 },
225 {
226 description => 'last=2,hourly=2 one ID',
227 vmid => $vmids[0],
228 keep => {
229 'keep-last' => 2,
230 'keep-hourly' => 2,
231 },
232 expected => generate_expected([$vmids[0]], undef, ['keep', 'remove', 'keep', 'keep', 'keep', 'keep']),
233 },
234 {
235 description => 'last=1,monthly=2, multiple IDs',
236 keep => {
237 'keep-last' => 1,
238 'keep-monthly' => 2,
239 },
240 expected => generate_expected(\@vmids, undef, ['keep', 'remove', 'keep', 'remove', 'keep', 'keep']),
241 },
242 {
243 description => 'monthly=3, one ID',
244 vmid => $vmids[0],
245 keep => {
246 'keep-monthly' => 3,
247 },
248 expected => generate_expected([$vmids[0]], undef, ['keep', 'remove', 'keep', 'remove', 'keep', 'keep']),
249 },
250 {
251 description => 'last=daily=weekly=1, multiple IDs',
252 keep => {
253 'keep-last' => 1,
254 'keep-daily' => 1,
255 'keep-weekly' => 1,
256 },
257 expected => generate_expected(\@vmids, undef, ['keep', 'remove', 'keep', 'remove', 'keep', 'keep']),
258 },
f514181d
FE
259 {
260 description => 'last=daily=weekly=1, others zero, multiple IDs',
261 keep => {
262 'keep-hourly' => 0,
263 'keep-last' => 1,
264 'keep-daily' => 1,
265 'keep-weekly' => 1,
266 'keep-monthly' => 0,
267 'keep-yearly' => 0,
268 },
269 expected => generate_expected(\@vmids, undef, ['keep', 'remove', 'keep', 'remove', 'keep', 'keep']),
270 },
8f26b391
FE
271 {
272 description => 'daily=2, one ID',
273 vmid => $vmids[0],
274 keep => {
275 'keep-daily' => 2,
276 },
277 expected => generate_expected([$vmids[0]], undef, ['remove', 'remove', 'keep', 'remove', 'keep', 'keep']),
278 },
279 {
280 description => 'weekly=monthly=1, multiple IDs',
281 keep => {
282 'keep-weekly' => 1,
283 'keep-monthly' => 1,
284 },
285 expected => generate_expected(\@vmids, undef, ['keep', 'remove', 'remove', 'remove', 'keep', 'keep']),
286 },
287 {
288 description => 'weekly=yearly=1, one ID',
289 vmid => $vmids[0],
290 keep => {
291 'keep-weekly' => 1,
292 'keep-yearly' => 1,
293 },
294 expected => generate_expected([$vmids[0]], undef, ['keep', 'remove', 'remove', 'remove', 'keep', 'keep']),
295 },
296 {
297 description => 'weekly=yearly=1, one ID, type qemu',
298 vmid => $vmids[0],
299 type => 'qemu',
300 keep => {
301 'keep-weekly' => 1,
302 'keep-yearly' => 1,
303 },
304 expected => generate_expected([$vmids[0]], 'qemu', ['keep', 'remove', 'remove', 'remove', 'keep', '']),
305 },
306 {
307 description => 'week=yearly=1, one ID, type lxc',
308 vmid => $vmids[0],
309 type => 'lxc',
310 keep => {
311 'keep-last' => 1,
312 },
313 expected => generate_expected([$vmids[0]], 'lxc', ['', '', '', '', '', 'keep']),
314 },
315 {
316 description => 'yearly=1, year before 2000',
317 keep => {
318 'keep-yearly' => 1,
319 },
320 list => 'year1970',
321 expected => [
322 {
323 'volid' => "$storeid:backup/vzdump-lxc-321-1970_01_01-00_01_23.tar.zst",
324 'ctime' => 83,
325 'mark' => 'remove',
326 'type' => 'lxc',
327 'vmid' => 321,
328 },
329 {
330 'volid' => "$storeid:backup/vzdump-lxc-321-2070_01_01-00_01_00.tar.zst",
331 'ctime' => 60*60*24 * (365*100 + 25) + 60,
332 'mark' => 'keep',
333 'type' => 'lxc',
334 'vmid' => 321,
335 },
336 ],
337 },
338 {
339 description => 'last=1, ne ID, year before 2000',
340 keep => {
341 'keep-last' => 1,
342 },
343 list => 'novmid',
344 expected => [
345 {
346 'volid' => "$storeid:backup/vzdump-lxc-novmid.tar.gz",
347 'ctime' => 1234,
348 'mark' => 'protected',
349 'type' => 'lxc',
350 },
351 ],
352 },
f514181d
FE
353 {
354 description => 'all missing, multiple IDs',
355 keep => {},
356 expected => generate_expected(\@vmids, undef, ['keep', 'keep', 'keep', 'keep', 'keep', 'keep']),
357 },
358 {
359 description => 'all zero, multiple IDs',
360 keep => {
361 'keep-last' => 0,
362 'keep-hourly' => 0,
363 'keep-daily' => 0,
364 'keep-weekly' => 0,
365 'keep-monthyl' => 0,
366 'keep-yearly' => 0,
367 },
368 expected => generate_expected(\@vmids, undef, ['keep', 'keep', 'keep', 'keep', 'keep', 'keep']),
369 },
370 {
371 description => 'some zero, some missing, multiple IDs',
372 keep => {
373 'keep-last' => 0,
374 'keep-hourly' => 0,
375 'keep-daily' => 0,
376 'keep-monthyl' => 0,
377 'keep-yearly' => 0,
378 },
379 expected => generate_expected(\@vmids, undef, ['keep', 'keep', 'keep', 'keep', 'keep', 'keep']),
380 },
10dfeb9e
FE
381 {
382 description => 'daily=weekly=monthly=1',
383 keep => {
384 'keep-daily' => 1,
385 'keep-weekly' => 1,
386 'keep-monthly' => 1,
387 },
388 list => 'threeway',
389 expected => [
390 {
391 'volid' => "$storeid:backup/vzdump-qemu-7654-2019_12_25-12_18_21.tar.zst",
392 'ctime' => $basetime - 7*24*60*60,
393 'type' => 'qemu',
394 'vmid' => 7654,
395 'mark' => 'keep',
396 },
397 {
398 'volid' => "$storeid:backup/vzdump-qemu-7654-2019_12_31-12_18_21.tar.zst",
399 'ctime' => $basetime - 24*60*60,
400 'type' => 'qemu',
401 'vmid' => 7654,
402 'mark' => 'remove', # month is already covered by the backup kept by keep-weekly!
403 },
404 {
405 'volid' => "$storeid:backup/vzdump-qemu-7654-2020_01_01-12_18_21.tar.zst",
406 'ctime' => $basetime,
407 'type' => 'qemu',
408 'vmid' => 7654,
409 'mark' => 'keep',
410 },
411 ],
412 },
8f26b391
FE
413];
414
415plan tests => scalar @$tests;
416
417for my $tt (@$tests) {
418
419 my $got = eval {
420 $current_list = $tt->{list} // 'default';
421 my $res = PVE::Storage::Plugin->prune_backups($tt->{scfg}, $storeid, $tt->{keep}, $tt->{vmid}, $tt->{type}, 1);
422 return [ sort { $a->{volid} cmp $b->{volid} } @{$res} ];
423 };
424 $got = $@ if $@;
425
426 is_deeply($got, $tt->{expected}, $tt->{description}) || diag(explain($got));
427}
428
429done_testing();
430
4311;