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