Imported Upstream version 3.1.0
[debian/amanda] / installcheck / Amanda_Taper_Scan_traditional.pl
1 # Copyright (c) 2010 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 => 9;
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_traditional";
44 my $tapelist = "$Installcheck::TMP/tapelist";
45
46 # vtape support
47
48 sub reset_taperoot {
49     my ($nslots) = @_;
50
51     if (-d $taperoot) {
52         rmtree($taperoot);
53     }
54     mkpath($taperoot);
55
56     for my $slot (1 .. $nslots) {
57         mkdir("$taperoot/slot$slot")
58             or die("Could not mkdir: $!");
59     }
60
61     # clear out the tapefile
62     open(my $fh, ">", $tapelist) or die("opening tapelist: $!");
63 }
64
65 sub label_slot {
66     my ($slot, $label, $stamp, $reuse, $update_tapelist) = @_;
67
68     my $drivedir = "$taperoot/tmp";
69     -d $drivedir and rmtree($drivedir);
70     mkpath($drivedir);
71     symlink("$taperoot/slot$slot", "$drivedir/data");
72
73     my $dev = Amanda::Device->new("file:$drivedir");
74     die $dev->error_or_status() unless $dev->status == $DEVICE_STATUS_SUCCESS;
75
76     if (defined $label){
77         if (!$dev->start($ACCESS_WRITE, $label, $stamp)) {
78             die $dev->error_or_status();
79         }
80     } else {
81         $dev->erase();
82     }
83
84     rmtree($drivedir);
85
86     if ($update_tapelist) {
87         # tapelist uses '0' for new tapes; devices use 'X'..
88         $stamp = '0' if ($stamp eq 'X');
89         open(my $fh, ">>", $tapelist) or die("opening tapelist: $!");
90         print $fh "$stamp $label $reuse\n";
91         close($fh);
92     }
93 }
94
95 # run the mainloop around a scan
96 sub run_scan {
97     my ($ts) = @_;
98     my ($error, $res, $label, $mode);
99
100     my $result_cb = make_cb(result_cb => sub {
101         ($error, $res, $label, $mode) = @_;
102
103         if ($res) {
104             $res->release(finished_cb => sub {
105                 Amanda::MainLoop::quit();
106             });
107         } else {
108             Amanda::MainLoop::quit();
109         }
110     });
111
112     $ts->scan(result_cb => $result_cb);
113     Amanda::MainLoop::run();
114     return $error, $label, $mode;
115 }
116
117 # set the current slot on the changer
118 sub set_current_slot {
119     my ($slot) = @_;
120
121     unlink("$taperoot/data");
122     symlink("slot$slot", "$taperoot/data");
123 }
124
125 # set up and load a config
126 my $testconf = Installcheck::Config->new();
127 $testconf->add_param("tapelist", "\"$tapelist\"");
128 $testconf->add_param("labelstr", "\"TEST-[0-9]+\"");
129 $testconf->write();
130 my $cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF');
131 if ($cfg_result != $CFGERR_OK) {
132     my ($level, @errors) = Amanda::Config::config_errors();
133     die(join "\n", @errors);
134 }
135
136 reset_taperoot(5);
137 label_slot(1, "TEST-1", "20090424173001", "reuse", 1);
138 label_slot(2, "TEST-2", "20090424173002", "reuse", 1);
139 label_slot(3, "TEST-3", "20090424173003", "reuse", 1);
140
141 my $chg;
142 my $taperscan;
143 my @results;
144
145 # set up a traditional taperscan
146 $taperscan = Amanda::Taper::Scan->new(
147     algorithm => "traditional",
148     tapecycle => 4,
149     changer => Amanda::Changer->new("chg-disk:$taperoot"));
150 @results = run_scan($taperscan);
151 is_deeply([ @results ],
152           [ "No acceptable volumes found", undef, undef ],
153           "no reusable tapes -> error")
154           or diag(Dumper(\@results));
155
156 $taperscan = Amanda::Taper::Scan->new(
157     algorithm => "traditional",
158     tapecycle => 3,
159     changer => Amanda::Changer->new("chg-disk:$taperoot"));
160 @results = run_scan($taperscan);
161 is_deeply([ @results ],
162           [ undef, "TEST-1", $ACCESS_WRITE ],
163           "finds the best reusable tape")
164           or diag(Dumper(\@results));
165
166 $chg = Amanda::Changer->new("chg-disk:$taperoot");
167 $chg->{'support_fast_search'} = 0; # no fast search -> skip stage 1
168 set_current_slot(2); # slot 2 is acceptable, so it should be returned
169 $taperscan = Amanda::Taper::Scan->new(
170     algorithm => "traditional",
171     tapecycle => 1,
172     changer => $chg);
173 @results = run_scan($taperscan);
174 is_deeply([ @results ],
175           [ undef, "TEST-2", $ACCESS_WRITE ],
176           "finds the first reusable tape when fast_search is false")
177           or diag(Dumper(\@results));
178
179 label_slot(1); # remove TEST-1
180 label_slot(4, "TEST-4", "20090424183004", "reuse", 1);
181 set_current_slot(1);
182 $taperscan = Amanda::Taper::Scan->new(
183     algorithm => "traditional",
184     tapecycle => 2,
185     changer => Amanda::Changer->new("chg-disk:$taperoot"));
186 @results = run_scan($taperscan);
187 is_deeply([ @results ],
188           [ undef, "TEST-2", $ACCESS_WRITE ],
189           "uses the first usable tape it finds when oldest is missing")
190           or diag(Dumper(\@results));
191
192 set_current_slot(3);
193 $taperscan = Amanda::Taper::Scan->new(
194     algorithm => "traditional",
195     tapecycle => 2,
196     changer => Amanda::Changer->new("chg-disk:$taperoot"));
197 @results = run_scan($taperscan);
198 is_deeply([ @results ],
199           [ undef, "TEST-3", $ACCESS_WRITE ],
200           "starts sequential scan at 'current'")
201           or diag(Dumper(\@results));
202
203 set_current_slot(5);
204 $taperscan = Amanda::Taper::Scan->new(
205     algorithm => "traditional",
206     tapecycle => 2,
207     autolabel => { 'template'     => "TEST-%",
208                    'empty'        => 1,
209                    'volume_error' => 1},
210     changer => Amanda::Changer->new("chg-disk:$taperoot"));
211 @results = run_scan($taperscan);
212 is_deeply([ @results ],
213           [ undef, "TEST-5", $ACCESS_WRITE ],
214           "labels new tapes in blank slots")
215           or diag(Dumper(\@results));
216
217 set_current_slot(6);
218 $taperscan = Amanda::Taper::Scan->new(
219     algorithm => "traditional",
220     tapecycle => 1,
221     autolabel => { },
222     changer => Amanda::Changer->new("chg-disk:$taperoot"));
223 @results = run_scan($taperscan);
224 is_deeply([ @results ],
225           [ undef, "TEST-2", $ACCESS_WRITE ],
226           "handles an invalid current slot by going to the next")
227           or diag(Dumper(\@results));
228
229 # simulate "amlabel"
230 label_slot(1, "TEST-6", "X", "reuse", 1);
231 set_current_slot(2);
232 $taperscan = Amanda::Taper::Scan->new(
233     algorithm => "traditional",
234     tapecycle => 2,
235     changer => Amanda::Changer->new("chg-disk:$taperoot"));
236 @results = run_scan($taperscan);
237 is_deeply([ @results ],
238           [ undef, "TEST-2", $ACCESS_WRITE ],
239           "scans for volumes, even with a newly labeled volume available")
240           or diag(Dumper(\@results));
241
242 # test skipping no-reuse tapes
243 reset_taperoot(5);
244 label_slot(1, "TEST-1", "20090424173001", "no-reuse", 1);
245 label_slot(2, "TEST-2", "20090424173002", "reuse", 1);
246 label_slot(3, "TEST-3", "20090424173003", "reuse", 1);
247 label_slot(4, "TEST-4", "20090424173004", "reuse", 1);
248 set_current_slot(1);
249
250 $taperscan = Amanda::Taper::Scan->new(
251     algorithm => "traditional",
252     tapecycle => 2,
253     changer => Amanda::Changer->new("chg-disk:$taperoot"));
254 @results = run_scan($taperscan);
255 is_deeply([ @results ],
256           [ undef, "TEST-2", $ACCESS_WRITE ],
257           "skips a no-reuse volume")
258           or diag(Dumper(\@results));
259
260 rmtree($taperoot);
261 unlink($tapelist);