Imported Upstream version 3.3.2
[debian/amanda] / installcheck / Amanda_Taper_Scan_lexical.pl
1 # Copyright (c) 2010-2012 Zmanda Inc.  All Rights Reserved.
2 #
3 # This program is free software; you can redistribute it and/or modify it
4 # under the terms of the GNU General Public License version 2 as published
5 # by the Free Software Foundation.
6 #
7 # This program is distributed in the hope that it will be useful, but
8 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
9 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
10 # for more details.
11 #
12 # You should have received a copy of the GNU General Public License along
13 # with this program; if not, write to the Free Software Foundation, Inc.,
14 # 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
15 #
16 # Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300
17 # Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
18
19 use Test::More tests => 27;
20 use File::Path;
21 use Data::Dumper;
22 use strict;
23 use warnings;
24
25 use lib "@amperldir@";
26 use Installcheck;
27 use Installcheck::Config;
28 use Installcheck::Changer;
29 use Amanda::Device qw( :constants );
30 use Amanda::Debug;
31 use Amanda::MainLoop;
32 use Amanda::Config qw( :init :getconf config_dir_relative );
33 use Amanda::Changer;
34 use Amanda::Taper::Scan;
35
36 # set up debugging so debug output doesn't interfere with test results
37 Amanda::Debug::dbopen("installcheck");
38 Installcheck::log_test_output();
39
40 # and disable Debug's die() and warn() overrides
41 Amanda::Debug::disable_die_override();
42
43 my $taperoot = "$Installcheck::TMP/Amanda_Taper_Scan_lexical";
44 my $tapelist_filename = "$Installcheck::TMP/tapelist";
45 `cat /dev/null > $Installcheck::TMP/tapelist`;
46 my $tapelist = Amanda::Tapelist->new($tapelist_filename);
47
48 # vtape support
49 my %slot_label;
50
51 sub reset_taperoot {
52     my ($nslots) = @_;
53
54     if (-d $taperoot) {
55         rmtree($taperoot);
56     }
57     mkpath($taperoot);
58
59     for my $slot (1 .. $nslots) {
60         mkdir("$taperoot/slot$slot")
61             or die("Could not mkdir: $!");
62     }
63
64     # clear out the tapefile
65     open(my $fh, ">", $tapelist_filename) or die("opening tapelist_filename: $!");
66     %slot_label = ();
67 }
68
69 sub label_slot {
70     my ($slot, $label, $stamp, $reuse, $update_tapelist) = @_;
71
72     my $drivedir = "$taperoot/tmp";
73     -d $drivedir and rmtree($drivedir);
74     mkpath($drivedir);
75     symlink("$taperoot/slot$slot", "$drivedir/data");
76
77     my $dev = Amanda::Device->new("file:$drivedir");
78     die $dev->error_or_status() unless $dev->status == $DEVICE_STATUS_SUCCESS;
79
80     if (defined $label){
81         if (!$dev->start($ACCESS_WRITE, $label, $stamp)) {
82             die $dev->error_or_status();
83         }
84     } else {
85         $dev->erase();
86     }
87
88     rmtree($drivedir);
89
90     if ($update_tapelist) {
91         if (exists $slot_label{$slot}) {
92             $tapelist->remove_tapelabel($slot_label{$slot});
93             delete $slot_label{$slot};
94         }
95         # tapelist uses '0' for new tapes; devices use 'X'..
96         $stamp = '0' if ($stamp eq 'X');
97         $reuse = $reuse ne 'no-reuse';
98         $tapelist->remove_tapelabel($label);
99         $tapelist->add_tapelabel($stamp, $label, "", $reuse);
100         $tapelist->write();
101         $slot_label{$slot} = $label;
102         #open(my $fh, ">>", $tapelist_filename) or die("opening tapelist_filename: $!");
103         #print $fh "$stamp $label $reuse\n";
104         #close($fh);
105     }
106 }
107
108 # run the mainloop around a scan
109 sub run_scan {
110     my ($ts) = @_;
111     my ($error, $res, $label, $mode);
112
113     my $result_cb = make_cb(result_cb => sub {
114         ($error, $res, $label, $mode) = @_;
115
116         $error = "$error" if defined $error;
117         if ($res) {
118             $res->release(finished_cb => sub {
119                 Amanda::MainLoop::quit();
120             });
121         } else {
122             Amanda::MainLoop::quit();
123         }
124     });
125
126     $ts->scan(result_cb => $result_cb);
127     Amanda::MainLoop::run();
128     return $error, $label, $mode;
129 }
130
131 # set the current slot on the changer
132 sub set_current_slot {
133     my ($slot) = @_;
134
135     unlink("$taperoot/data");
136     symlink("slot$slot", "$taperoot/data");
137 }
138
139 # set up and load a config
140 my $testconf = Installcheck::Config->new();
141 $testconf->add_param("tapelist", "\"$tapelist\"");
142 $testconf->add_param("labelstr", "\"TEST-[0-9]+\"");
143 $testconf->write();
144 my $cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF');
145 if ($cfg_result != $CFGERR_OK) {
146     my ($level, @errors) = Amanda::Config::config_errors();
147     die(join "\n", @errors);
148 }
149
150 reset_taperoot(6);
151 $tapelist->clear_tapelist();
152 $tapelist->write();
153 label_slot(1, "TEST-10", "20090424173011", "reuse", 1);
154 label_slot(2, "TEST-20", "20090424173022", "reuse", 1);
155 label_slot(3, "TEST-30", "20090424173033", "reuse", 1);
156
157 my $chg;
158 my $taperscan;
159 my @results;
160
161 # set up a lexical taperscan
162 $chg = Amanda::Changer->new("chg-disk:$taperoot", tapelist => $tapelist);
163 $taperscan = Amanda::Taper::Scan->new(
164     tapelist  => $tapelist,
165     algorithm => "lexical",
166     tapecycle => 4,
167     changer => $chg);
168 @results = run_scan($taperscan);
169 is_deeply([ @results ],
170           [ "No acceptable volumes found", undef, undef ],
171           "no reusable tapes -> error")
172           or diag(Dumper(\@results));
173 $taperscan->quit();
174
175 $chg = Amanda::Changer->new("chg-disk:$taperoot", tapelist => $tapelist);
176 $taperscan = Amanda::Taper::Scan->new(
177     tapelist  => $tapelist,
178     algorithm => "lexical",
179     tapecycle => 3,
180     changer => $chg);
181 @results = run_scan($taperscan);
182 is_deeply([ @results ],
183           [ undef, "TEST-10", $ACCESS_WRITE ],
184           "finds the best reusable tape")
185           or diag(Dumper(\@results));
186 $taperscan->quit();
187
188 $chg = Amanda::Changer->new("chg-disk:$taperoot", tapelist => $tapelist);
189 set_current_slot(2);
190 $taperscan = Amanda::Taper::Scan->new(
191     tapelist  => $tapelist,
192     algorithm => "lexical",
193     tapecycle => 1,
194     changer => $chg);
195 @results = run_scan($taperscan);
196 is_deeply([ @results ],
197           [ undef, "TEST-10", $ACCESS_WRITE ],
198           "finds the first reusable tape")
199           or diag(Dumper(\@results));
200 $taperscan->quit();
201
202 label_slot(4, "TEST-40", "20090424173030", "reuse", 1);
203 $chg = Amanda::Changer->new("chg-disk:$taperoot", tapelist => $tapelist);
204 $taperscan = Amanda::Taper::Scan->new(
205     tapelist  => $tapelist,
206     algorithm => "lexical",
207     tapecycle => 1,
208     changer => $chg);
209 @results = run_scan($taperscan);
210 is_deeply([ @results ],
211           [ undef, "TEST-40", $ACCESS_WRITE ],
212           "finds the first reusable tape")
213           or diag(Dumper(\@results));
214 $taperscan->quit();
215
216 label_slot(4, "TEST-40", "X", "reuse", 1);
217 label_slot(5, "TEST-35", "X", "reuse", 1);
218 $chg = Amanda::Changer->new("chg-disk:$taperoot", tapelist => $tapelist);
219 $taperscan = Amanda::Taper::Scan->new(
220     tapelist  => $tapelist,
221     algorithm => "lexical",
222     tapecycle => 2,
223     changer => $chg);
224 @results = run_scan($taperscan);
225 is_deeply([ @results ],
226           [ undef, "TEST-35", $ACCESS_WRITE ],
227           "finds the first reusable tape")
228           or diag(Dumper(\@results));
229 $taperscan->quit();
230
231 $chg = Amanda::Changer->new("chg-disk:$taperoot",
232                         tapelist => $tapelist,
233                         autolabel => { 'template'     => "TEST-%0",
234                                        'empty'        => 1,
235                                        'volume_error' => 1});
236 $taperscan = Amanda::Taper::Scan->new(
237     tapelist  => $tapelist,
238     algorithm => "lexical",
239     tapecycle => 2,
240     changer => $chg);
241 $taperscan->{'scan_conf'}->{'new_labeled'} = 'order';
242 $taperscan->{'scan_conf'}->{'new_volume'} = 'soon';
243 @results = run_scan($taperscan);
244 is_deeply([ @results ],
245           [ undef, "TEST-50", $ACCESS_WRITE ],
246           "labels new tapes in blank slots")
247           or diag(Dumper(\@results));
248 $taperscan->quit();
249
250 $chg = Amanda::Changer->new("chg-disk:$taperoot",
251                         tapelist => $tapelist);
252 $taperscan->{'scan_conf'}->{'new_labeled'} = 'order';
253 $taperscan->{'scan_conf'}->{'new_volume'} = 'soon';
254 # simulate "amlabel"
255 label_slot(1, "TEST-60", "X", "reuse", 1);
256 $taperscan = Amanda::Taper::Scan->new(
257     tapelist  => $tapelist,
258     algorithm => "lexical",
259     tapecycle => 2,
260     changer => $chg);
261 set_current_slot(2);
262 @results = run_scan($taperscan);
263 is_deeply([ @results ],
264           [ undef, "TEST-35", $ACCESS_WRITE ],
265           "scans for volumes, even with a newly labeled volume available")
266           or diag(Dumper(\@results));
267 $taperscan->quit();
268
269 # test new_labeled with autolabel
270 reset_taperoot(5);
271 $tapelist->clear_tapelist();
272 $tapelist->write();
273 label_slot(1, "TEST-10", "20090424173011", "reuse", 1);
274 label_slot(2, "TEST-20", "20090424173033", "reuse", 1);
275 label_slot(4, "TEST-30", "20090424173022", "reuse", 1);
276 label_slot(3, "TEST-15", "X", "reuse", 1);
277 label_slot(5, "TEST-25", "X", "reuse", 1);
278 set_current_slot(2);
279
280 $chg = Amanda::Changer->new("chg-disk:$taperoot", tapelist => $tapelist,
281                              autolabel => { 'template'     => "TEST-%0",
282                                             'empty'        => 1,
283                                             'volume_error' => 1});
284 set_current_slot(1);
285
286 $taperscan = Amanda::Taper::Scan->new(
287     tapelist  => $tapelist,
288     algorithm => "lexical",
289     tapecycle => 1,
290     changer => $chg);
291 $taperscan->{'scan_conf'}->{'new_labeled'} = 'soon';
292 $taperscan->{'scan_conf'}->{'new_volume'} = 'soon';
293 @results = run_scan($taperscan);
294 is_deeply([ @results ],
295           [ undef, "TEST-25", $ACCESS_WRITE ],
296           "autolabel soon")
297           or diag(Dumper(\@results));
298
299 $taperscan->{'scan_conf'}->{'new_labeled'} = 'order';
300 $taperscan->{'scan_conf'}->{'new_volume'} = 'order';
301 @results = run_scan($taperscan);
302 is_deeply([ @results ],
303           [ undef, "TEST-25", $ACCESS_WRITE ],
304           "autolabel order")
305           or diag(Dumper(\@results));
306
307 $taperscan->{'scan_conf'}->{'new_labeled'} = 'last';
308 $taperscan->{'scan_conf'}->{'new_volume'} = 'last';
309 @results = run_scan($taperscan);
310 is_deeply([ @results ],
311           [ undef, "TEST-30", $ACCESS_WRITE ],
312           "autolabel last")
313           or diag(Dumper(\@results));
314 $taperscan->quit();
315
316 # test new_labeled with autolabel
317 reset_taperoot(5);
318 $tapelist->clear_tapelist();
319 $tapelist->write();
320 label_slot(1, "TEST-10", "20090424173011", "reuse", 1);
321 label_slot(2, "TEST-20", "20090424173033", "reuse", 1);
322 label_slot(4, "TEST-30", "20090424173022", "reuse", 1);
323 label_slot(3, "TEST-15", "X", "reuse", 1);
324 set_current_slot(2);
325
326 $chg = Amanda::Changer->new("chg-disk:$taperoot", tapelist => $tapelist,
327                              autolabel => { 'template'     => "TEST-%0",
328                                             'empty'        => 1,
329                                             'volume_error' => 1});
330 set_current_slot(1);
331
332 $taperscan = Amanda::Taper::Scan->new(
333     tapelist  => $tapelist,
334     algorithm => "lexical",
335     tapecycle => 1,
336     changer => $chg);
337 $taperscan->{'scan_conf'}->{'new_labeled'} = 'soon';
338 $taperscan->{'scan_conf'}->{'new_volume'} = 'soon';
339 @results = run_scan($taperscan);
340 is_deeply([ @results ],
341           [ undef, "TEST-15", $ACCESS_WRITE ],
342           "autolabel soon")
343           or diag(Dumper(\@results));
344
345 $taperscan->{'scan_conf'}->{'new_labeled'} = 'order';
346 $taperscan->{'scan_conf'}->{'new_volume'} = 'order';
347 @results = run_scan($taperscan);
348 is_deeply([ @results ],
349           [ undef, "TEST-30", $ACCESS_WRITE ],
350           "autolabel order")
351           or diag(Dumper(\@results));
352
353 $taperscan->{'scan_conf'}->{'new_labeled'} = 'last';
354 $taperscan->{'scan_conf'}->{'new_volume'} = 'last';
355 @results = run_scan($taperscan);
356 is_deeply([ @results ],
357           [ undef, "TEST-30", $ACCESS_WRITE ],
358           "autolabel last")
359           or diag(Dumper(\@results));
360
361 $taperscan->{'scan_conf'}->{'new_labeled'} = 'last';
362 $taperscan->{'scan_conf'}->{'new_volume'} = 'order';
363 @results = run_scan($taperscan);
364 is_deeply([ @results ],
365           [ undef, "TEST-30", $ACCESS_WRITE ],
366           "autolabel last")
367           or diag(Dumper(\@results));
368
369 $taperscan->{'scan_conf'}->{'new_labeled'} = 'order';
370 $taperscan->{'scan_conf'}->{'new_volume'} = 'soon';
371 @results = run_scan($taperscan);
372 is_deeply([ @results ],
373           [ undef, "TEST-40", $ACCESS_WRITE ],
374           "autolabel last")
375           or diag(Dumper(\@results));
376 $taperscan->quit();
377
378 # test new_labeled with autolabel
379 reset_taperoot(5);
380 $tapelist->clear_tapelist();
381 $tapelist->write();
382 label_slot(1, "TEST-10", "20090424173011", "reuse", 1);
383 label_slot(2, "TEST-20", "20090424173022", "reuse", 1);
384 label_slot(4, "TEST-30", "20090424173033", "reuse", 1);
385 label_slot(3, "TEST-15", "X", "reuse", 1);
386 set_current_slot(2);
387
388 $chg = Amanda::Changer->new("chg-disk:$taperoot", tapelist => $tapelist,
389                              autolabel => { 'template'     => "TEST-%0",
390                                             'empty'        => 1,
391                                             'volume_error' => 1});
392 set_current_slot(1);
393
394 $taperscan = Amanda::Taper::Scan->new(
395     tapelist  => $tapelist,
396     algorithm => "lexical",
397     tapecycle => 1,
398     changer => $chg);
399 $taperscan->{'scan_conf'}->{'new_labeled'} = 'soon';
400 $taperscan->{'scan_conf'}->{'new_volume'} = 'soon';
401 @results = run_scan($taperscan);
402 is_deeply([ @results ],
403           [ undef, "TEST-15", $ACCESS_WRITE ],
404           "autolabel soon")
405           or diag(Dumper(\@results));
406
407 $taperscan->{'scan_conf'}->{'new_labeled'} = 'order';
408 $taperscan->{'scan_conf'}->{'new_volume'} = 'order';
409 @results = run_scan($taperscan);
410 is_deeply([ @results ],
411           [ undef, "TEST-40", $ACCESS_WRITE ],
412           "autolabel order")
413           or diag(Dumper(\@results));
414
415 $taperscan->{'scan_conf'}->{'new_labeled'} = 'last';
416 $taperscan->{'scan_conf'}->{'new_volume'} = 'last';
417 @results = run_scan($taperscan);
418 is_deeply([ @results ],
419           [ undef, "TEST-10", $ACCESS_WRITE ],
420           "autolabel last")
421           or diag(Dumper(\@results));
422
423 $taperscan->{'scan_conf'}->{'new_labeled'} = 'last';
424 $taperscan->{'scan_conf'}->{'new_volume'} = 'order';
425 @results = run_scan($taperscan);
426 is_deeply([ @results ],
427           [ undef, "TEST-40", $ACCESS_WRITE ],
428           "autolabel last")
429           or diag(Dumper(\@results));
430
431 $taperscan->{'scan_conf'}->{'new_labeled'} = 'order';
432 $taperscan->{'scan_conf'}->{'new_volume'} = 'soon';
433 @results = run_scan($taperscan);
434 is_deeply([ @results ],
435           [ undef, "TEST-40", $ACCESS_WRITE ],
436           "autolabel last")
437           or diag(Dumper(\@results));
438 $taperscan->quit();
439
440 # test new_volume with autolabel
441 reset_taperoot(5);
442 $tapelist->clear_tapelist();
443 $tapelist->write();
444 label_slot(1, "TEST-10", "20090424173011", "reuse", 1);
445 label_slot(2, "TEST-20", "20090424173033", "reuse", 1);
446 label_slot(4, "TEST-30", "20090424173022", "reuse", 1);
447 set_current_slot(2);
448
449 $chg = Amanda::Changer->new("chg-disk:$taperoot", tapelist => $tapelist,
450                              autolabel => { 'template'     => "TEST-%0",
451                                             'empty'        => 1,
452                                             'volume_error' => 1});
453 set_current_slot(1);
454
455 $taperscan = Amanda::Taper::Scan->new(
456     tapelist  => $tapelist,
457     algorithm => "lexical",
458     tapecycle => 1,
459     changer => $chg);
460 $taperscan->{'scan_conf'}->{'new_labeled'} = 'soon';
461 $taperscan->{'scan_conf'}->{'new_volume'} = 'soon';
462 @results = run_scan($taperscan);
463 is_deeply([ @results ],
464           [ undef, "TEST-40", $ACCESS_WRITE ],
465           "autolabel soon")
466           or diag(Dumper(\@results));
467
468 $taperscan->{'scan_conf'}->{'new_labeled'} = 'order';
469 $taperscan->{'scan_conf'}->{'new_volume'} = 'order';
470 @results = run_scan($taperscan);
471 is_deeply([ @results ],
472           [ undef, "TEST-30", $ACCESS_WRITE ],
473           "autolabel order")
474           or diag(Dumper(\@results));
475
476 $taperscan->{'scan_conf'}->{'new_labeled'} = 'last';
477 $taperscan->{'scan_conf'}->{'new_volume'} = 'last';
478 @results = run_scan($taperscan);
479 is_deeply([ @results ],
480           [ undef, "TEST-30", $ACCESS_WRITE ],
481           "autolabel last")
482           or diag(Dumper(\@results));
483 $taperscan->quit();
484
485 $chg = Amanda::Changer->new("chg-disk:$taperoot", tapelist => $tapelist,
486                              autolabel => { 'template'     => "TEST-%0",
487                                             'empty'        => 1,
488                                             'volume_error' => 1});
489 $taperscan = Amanda::Taper::Scan->new(
490     tapelist  => $tapelist,
491     algorithm => "lexical",
492     tapecycle => 4,
493     changer => $chg);
494 $taperscan->{'scan_conf'}->{'new_labeled'} = 'soon';
495 $taperscan->{'scan_conf'}->{'new_volume'} = 'soon';
496 @results = run_scan($taperscan);
497 is_deeply([ @results ],
498           [ undef, "TEST-40", $ACCESS_WRITE ],
499           "autolabel soon")
500           or diag(Dumper(\@results));
501
502 $taperscan->{'scan_conf'}->{'new_labeled'} = 'order';
503 $taperscan->{'scan_conf'}->{'new_volume'} = 'order';
504 @results = run_scan($taperscan);
505 is_deeply([ @results ],
506           [ undef, "TEST-40", $ACCESS_WRITE ],
507           "autolabel order")
508           or diag(Dumper(\@results));
509
510 $taperscan->{'scan_conf'}->{'new_labeled'} = 'last';
511 $taperscan->{'scan_conf'}->{'new_volume'} = 'last';
512 @results = run_scan($taperscan);
513 is_deeply([ @results ],
514           [ undef, "TEST-40", $ACCESS_WRITE ],
515           "autolabel last")
516           or diag(Dumper(\@results));
517 $taperscan->quit();
518
519 # test skipping no-reuse tapes
520 reset_taperoot(5);
521 $tapelist->clear_tapelist();
522 $tapelist->write();
523 label_slot(1, "TEST-1", "20090424173001", "no-reuse", 1);
524 label_slot(2, "TEST-2", "20090424173002", "reuse", 1);
525 label_slot(3, "TEST-3", "20090424173003", "reuse", 1);
526 label_slot(4, "TEST-4", "20090424173004", "reuse", 1);
527
528 $chg = Amanda::Changer->new("chg-disk:$taperoot", tapelist => $tapelist);
529 set_current_slot(1);
530
531 $taperscan = Amanda::Taper::Scan->new(
532     tapelist  => $tapelist,
533     algorithm => "lexical",
534     tapecycle => 2,
535     tapecycle => 1,
536     changer => $chg);
537 @results = run_scan($taperscan);
538 is_deeply([ @results ],
539           [ undef, "TEST-2", $ACCESS_WRITE ],
540           "skips a no-reuse volume")
541           or diag(Dumper(\@results));
542 $taperscan->quit();
543
544 rmtree($taperoot);
545 unlink($tapelist);