Imported Upstream version 3.3.3
[debian/amanda] / installcheck / Amanda_Taper_Scan_traditional.pl
1 # Copyright (c) 2010-2012 Zmanda Inc.  All Rights Reserved.
2 #
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful, but
9 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11 # for more details.
12 #
13 # You should have received a copy of the GNU General Public License along
14 # with this program; if not, write to the Free Software Foundation, Inc.,
15 # 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 #
17 # Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300
18 # Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
19
20 use Test::More tests => 9;
21 use File::Path;
22 use Data::Dumper;
23 use strict;
24 use warnings;
25
26 use lib "@amperldir@";
27 use Installcheck;
28 use Installcheck::Config;
29 use Installcheck::Changer;
30 use Amanda::Device qw( :constants );
31 use Amanda::Debug;
32 use Amanda::MainLoop;
33 use Amanda::Config qw( :init :getconf config_dir_relative );
34 use Amanda::Changer;
35 use Amanda::Taper::Scan;
36
37 # set up debugging so debug output doesn't interfere with test results
38 Amanda::Debug::dbopen("installcheck");
39 Installcheck::log_test_output();
40
41 # and disable Debug's die() and warn() overrides
42 Amanda::Debug::disable_die_override();
43
44 my $taperoot = "$Installcheck::TMP/Amanda_Taper_Scan_traditional";
45 my $tapelist_filename = "$Installcheck::TMP/tapelist";
46 my $tapelist = Amanda::Tapelist->new($tapelist_filename);
47
48 # vtape support
49
50 sub reset_taperoot {
51     my ($nslots) = @_;
52
53     if (-d $taperoot) {
54         rmtree($taperoot);
55     }
56     mkpath($taperoot);
57
58     for my $slot (1 .. $nslots) {
59         mkdir("$taperoot/slot$slot")
60             or die("Could not mkdir: $!");
61     }
62
63     # clear out the tapefile
64     open(my $fh, ">", $tapelist_filename) or die("opening tapelist_filename: $!");
65 }
66
67 sub label_slot {
68     my ($slot, $label, $stamp, $reuse, $update_tapelist) = @_;
69
70     my $drivedir = "$taperoot/tmp";
71     -d $drivedir and rmtree($drivedir);
72     mkpath($drivedir);
73     symlink("$taperoot/slot$slot", "$drivedir/data");
74
75     my $dev = Amanda::Device->new("file:$drivedir");
76     die $dev->error_or_status() unless $dev->status == $DEVICE_STATUS_SUCCESS;
77
78     if (defined $label){
79         if (!$dev->start($ACCESS_WRITE, $label, $stamp)) {
80             die $dev->error_or_status();
81         }
82     } else {
83         $dev->erase();
84     }
85
86     rmtree($drivedir);
87
88     if ($update_tapelist) {
89         # tapelist uses '0' for new tapes; devices use 'X'..
90         $stamp = '0' if ($stamp eq 'X');
91         open(my $fh, ">>", $tapelist_filename) or die("opening tapelist_filename: $!");
92         print $fh "$stamp $label $reuse\n";
93         close($fh);
94     }
95 }
96
97 # run the mainloop around a scan
98 sub run_scan {
99     my ($ts) = @_;
100     my ($error, $res, $label, $mode);
101
102     my $result_cb = make_cb(result_cb => sub {
103         ($error, $res, $label, $mode) = @_;
104
105         if ($res) {
106             $res->release(finished_cb => sub {
107                 Amanda::MainLoop::quit();
108             });
109         } else {
110             Amanda::MainLoop::quit();
111         }
112     });
113
114     $ts->scan(result_cb => $result_cb);
115     Amanda::MainLoop::run();
116     return $error, $label, $mode;
117 }
118
119 # set the current slot on the changer
120 sub set_current_slot {
121     my ($slot) = @_;
122
123     unlink("$taperoot/data");
124     symlink("slot$slot", "$taperoot/data");
125 }
126
127 # set up and load a config
128 my $testconf = Installcheck::Config->new();
129 $testconf->add_param("tapelist", "\"$tapelist\"");
130 $testconf->add_param("labelstr", "\"TEST-[0-9]+\"");
131 $testconf->write();
132 my $cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF');
133 if ($cfg_result != $CFGERR_OK) {
134     my ($level, @errors) = Amanda::Config::config_errors();
135     die(join "\n", @errors);
136 }
137
138 reset_taperoot(5);
139 label_slot(1, "TEST-1", "20090424173001", "reuse", 1);
140 label_slot(2, "TEST-2", "20090424173002", "reuse", 1);
141 label_slot(3, "TEST-3", "20090424173003", "reuse", 1);
142
143 my $chg;
144 my $taperscan;
145 my @results;
146
147 # set up a traditional taperscan
148 $chg = Amanda::Changer->new("chg-disk:$taperoot", tapelist => $tapelist);
149 $taperscan = Amanda::Taper::Scan->new(
150     tapelist  => $tapelist,
151     algorithm => "traditional",
152     tapecycle => 4,
153     changer => $chg);
154 @results = run_scan($taperscan);
155 is_deeply([ @results ],
156           [ "No acceptable volumes found", undef, undef ],
157           "no reusable tapes -> error")
158           or diag(Dumper(\@results));
159 $taperscan->quit();
160
161 $chg = Amanda::Changer->new("chg-disk:$taperoot", tapelist => $tapelist);
162 $taperscan = Amanda::Taper::Scan->new(
163     tapelist  => $tapelist,
164     algorithm => "traditional",
165     tapecycle => 3,
166     changer => $chg);
167 @results = run_scan($taperscan);
168 is_deeply([ @results ],
169           [ undef, "TEST-1", $ACCESS_WRITE ],
170           "finds the best reusable tape")
171           or diag(Dumper(\@results));
172 $taperscan->quit();
173
174 $chg = Amanda::Changer->new("chg-disk:$taperoot", tapelist => $tapelist);
175 $chg->{'support_fast_search'} = 0; # no fast search -> skip stage 1
176 set_current_slot(2); # slot 2 is acceptable, so it should be returned
177 $taperscan = Amanda::Taper::Scan->new(
178     tapelist  => $tapelist,
179     algorithm => "traditional",
180     tapecycle => 1,
181     changer => $chg);
182 @results = run_scan($taperscan);
183 is_deeply([ @results ],
184           [ undef, "TEST-2", $ACCESS_WRITE ],
185           "finds the first reusable tape when fast_search is false")
186           or diag(Dumper(\@results));
187 $taperscan->quit();
188
189 $chg = Amanda::Changer->new("chg-disk:$taperoot", tapelist => $tapelist);
190 $chg->{'support_fast_search'} = 1;
191
192 label_slot(1); # remove TEST-1
193 label_slot(4, "TEST-4", "20090424183004", "reuse", 1);
194 set_current_slot(1);
195 $taperscan = Amanda::Taper::Scan->new(
196     tapelist  => $tapelist,
197     algorithm => "traditional",
198     tapecycle => 2,
199     changer => $chg);
200 @results = run_scan($taperscan);
201 is_deeply([ @results ],
202           [ undef, "TEST-2", $ACCESS_WRITE ],
203           "uses the first usable tape it finds when oldest is missing")
204           or diag(Dumper(\@results));
205 $taperscan->quit();
206
207 $chg = Amanda::Changer->new("chg-disk:$taperoot", tapelist => $tapelist);
208
209 set_current_slot(3);
210 $taperscan = Amanda::Taper::Scan->new(
211     tapelist  => $tapelist,
212     algorithm => "traditional",
213     tapecycle => 2,
214     changer => $chg);
215 @results = run_scan($taperscan);
216 is_deeply([ @results ],
217           [ undef, "TEST-3", $ACCESS_WRITE ],
218           "starts sequential scan at 'current'")
219           or diag(Dumper(\@results));
220 $taperscan->quit();
221
222 $chg = Amanda::Changer->new("chg-disk:$taperoot",
223                         tapelist => $tapelist,
224                         autolabel => { 'template'     => "TEST-%",
225                                        'empty'        => 1,
226                                        'volume_error' => 1});
227 $taperscan = Amanda::Taper::Scan->new(
228     tapelist  => $tapelist,
229     algorithm => "traditional",
230     tapecycle => 2,
231     changer => $chg);
232 set_current_slot(5);
233 @results = run_scan($taperscan);
234 is_deeply([ @results ],
235           [ undef, "TEST-5", $ACCESS_WRITE ],
236           "labels new tapes in blank slots")
237           or diag(Dumper(\@results));
238 $taperscan->quit();
239
240 $chg = Amanda::Changer->new("chg-disk:$taperoot",
241                         tapelist => $tapelist,
242                         autolabel => { });
243 $taperscan = Amanda::Taper::Scan->new(
244     tapelist  => $tapelist,
245     algorithm => "traditional",
246     tapecycle => 1,
247     changer => $chg);
248 set_current_slot(6);
249 @results = run_scan($taperscan);
250 is_deeply([ @results ],
251           [ undef, "TEST-2", $ACCESS_WRITE ],
252           "handles an invalid current slot by going to the next")
253           or diag(Dumper(\@results));
254 $taperscan->quit();
255
256 $chg = Amanda::Changer->new("chg-disk:$taperoot",
257                         tapelist => $tapelist);
258 # simulate "amlabel"
259 label_slot(1, "TEST-6", "X", "reuse", 1);
260 $taperscan = Amanda::Taper::Scan->new(
261     tapelist  => $tapelist,
262     algorithm => "traditional",
263     tapecycle => 2,
264     changer => $chg);
265 set_current_slot(2);
266 @results = run_scan($taperscan);
267 is_deeply([ @results ],
268           [ undef, "TEST-2", $ACCESS_WRITE ],
269           "scans for volumes, even with a newly labeled volume available")
270           or diag(Dumper(\@results));
271
272 # test skipping no-reuse tapes
273 reset_taperoot(5);
274 label_slot(1, "TEST-1", "20090424173001", "no-reuse", 1);
275 label_slot(2, "TEST-2", "20090424173002", "reuse", 1);
276 label_slot(3, "TEST-3", "20090424173003", "reuse", 1);
277 label_slot(4, "TEST-4", "20090424173004", "reuse", 1);
278 $taperscan->quit();
279
280 $chg = Amanda::Changer->new("chg-disk:$taperoot", tapelist => $tapelist);
281 set_current_slot(1);
282
283 $taperscan = Amanda::Taper::Scan->new(
284     tapelist  => $tapelist,
285     algorithm => "traditional",
286     tapecycle => 2,
287     changer => $chg);
288 @results = run_scan($taperscan);
289 is_deeply([ @results ],
290           [ undef, "TEST-2", $ACCESS_WRITE ],
291           "skips a no-reuse volume")
292           or diag(Dumper(\@results));
293 $taperscan->quit();
294
295 rmtree($taperoot);
296 unlink($tapelist);