c8db6bf39e3017eaae5bfa3eaa2031acf75eaa84
[debian/amanda] / installcheck / Amanda_Changer_disk.pl
1 # Copyright (c) 2005-2008 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 Mathlida Ave, Suite 300
17 # Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
18
19 use Test::More tests => 14;
20 use File::Path;
21 use strict;
22
23 use lib "@amperldir@";
24 use Installcheck::Config;
25 use Amanda::Paths;
26 use Amanda::Device;
27 use Amanda::Debug;
28 use Amanda::MainLoop;
29 use Amanda::Config qw( :init :getconf config_dir_relative );
30 use Amanda::Changer;
31
32 # set up debugging so debug output doesn't interfere with test results
33 Amanda::Debug::dbopen("installcheck");
34
35 # and disable Debug's die() and warn() overrides
36 Amanda::Debug::disable_die_override();
37
38 my $taperoot = "$AMANDA_TMPDIR/Amanda_Changer_Disk_test";
39
40 sub reset_taperoot {
41     my ($nslots) = @_;
42
43     if (-d $taperoot) {
44         rmtree($taperoot);
45     }
46     mkpath($taperoot);
47
48     for my $slot (1 .. $nslots) {
49         mkdir("$taperoot/slot$slot")
50             or die("Could not mkdir: $!");
51     }
52 }
53
54 sub is_pointing_to {
55     my ($res, $slot, $msg) = @_;
56
57     my ($datalink) = ($res->{'device_name'} =~ /file:(.*)/);
58     $datalink .= "/data";
59     is(readlink($datalink), "../slot$slot", $msg);
60 }
61
62 # Build a configuration that specifies Amanda::Changer::Disk
63 my $testconf = Installcheck::Config->new();
64 $testconf->write();
65
66 my $cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF');
67 if ($cfg_result != $CFGERR_OK) {
68     my ($level, @errors) = Amanda::Config::config_errors();
69     die(join "\n", @errors);
70 }
71
72 reset_taperoot(5);
73 my $chg = Amanda::Changer->new("chg-disk:$taperoot");
74
75 {
76     my @slots = ( 1, 3, 5 );
77     my @reservations = ();
78     my $getres;
79
80     $getres = sub {
81         my $slot = pop @slots;
82
83         $chg->load(slot => $slot,
84                    set_current => ($slot == 5),
85                    res_cb => sub {
86             my ($err, $reservation) = @_;
87             ok(!$err, "no error loading slot $slot")
88                 or diag($err);
89
90             # keep this reservation
91             if ($reservation) {
92                 push @reservations, $reservation;
93             }
94
95             # and start on the next
96             if (@slots) {
97                 $getres->();
98                 return;
99             } else {
100                 # try to load an already-reserved slot
101                 $chg->load(slot => 3,
102                            res_cb => sub {
103                     my ($err, $reservation) = @_;
104                     ok($err, "error when requesting already-reserved slot");
105                     Amanda::MainLoop::quit();
106                 });
107             }
108         });
109     };
110
111     # start the loop
112     Amanda::MainLoop::call_later($getres);
113     Amanda::MainLoop::run();
114
115     # ditch the reservations and do it all again
116     @reservations = ();
117     @slots = ( 4, 2, 3 );
118     Amanda::MainLoop::call_later($getres);
119     Amanda::MainLoop::run();
120
121     @reservations = ();
122 }
123
124 # check "current" and "next" functionality
125 {
126     # load the "current" slot, which should be 3
127     my ($load_current, $check_current_cb, $check_next_cb, $reset_finished_cb, $check_reset_cb);
128
129     $load_current = sub {
130         $chg->load(slot => "current", res_cb => $check_current_cb);
131     };
132
133     $check_current_cb = sub {
134         my ($err, $res) = @_;
135         die $err if $err;
136
137         is_pointing_to($res, 5, "'current' is slot 5");
138
139         $chg->load(slot => $res->{'next_slot'}, res_cb => $check_next_cb);
140     };
141
142     $check_next_cb = sub {
143         my ($err, $res) = @_;
144         die $err if $err;
145
146         is_pointing_to($res, 1, "'next' from there is slot 1");
147
148         $chg->reset(finished_cb => $reset_finished_cb);
149     };
150
151     $reset_finished_cb = sub {
152         my ($err) = @_;
153         die $err if $err;
154
155         $chg->load(slot => "current", res_cb => $check_reset_cb);
156     };
157
158     $check_reset_cb = sub {
159         my ($err, $res) = @_;
160         die $err if $err;
161
162         is_pointing_to($res, 1, "after reset, 'current' is slot 1");
163
164         Amanda::MainLoop::quit();
165     };
166
167     Amanda::MainLoop::call_later($load_current);
168     Amanda::MainLoop::run();
169 }
170
171 # test loading slot "next"
172 {
173     my $load_next = sub {
174         $chg->load(slot => "next",
175             res_cb => sub {
176                 my ($err, $res) = @_;
177                 die $err if $err;
178
179                 is_pointing_to($res, 2, "loading slot 'next' loads the correct slot");
180
181                 Amanda::MainLoop::quit();
182             }
183         );
184     };
185
186     Amanda::MainLoop::call_later($load_next);
187     Amanda::MainLoop::run();
188 }
189
190 # check num_slots and loading by label
191 {
192     my ($get_info, $load_label, $check_load_cb) = @_;
193
194     $get_info = sub {
195         $chg->info(info_cb => $load_label, info => [ 'num_slots' ]);
196     };
197
198     $load_label = sub {
199         my $err = shift;
200         my %results = @_;
201         die($err) if defined($err);
202
203         is($results{'num_slots'}, 5, "info() returns the correct num_slots");
204
205         # note use of a glob metacharacter in the label name
206         $chg->load(label => "FOO?BAR", res_cb => $check_load_cb);
207     };
208
209     $check_load_cb = sub {
210         my ($err, $res) = @_;
211         die $err if $err;
212
213         is_pointing_to($res, 4, "labeled volume found in slot 4");
214
215         Amanda::MainLoop::quit();
216     };
217
218     # label slot 4, using our own symlink
219     mkpath("$taperoot/tmp");
220     symlink("../slot4", "$taperoot/tmp/data") or die "While symlinking: $!";
221     my $dev = Amanda::Device->new("file:$taperoot/tmp");
222     $dev->start($Amanda::Device::ACCESS_WRITE, "FOO?BAR", undef)
223         or die $dev->error_or_status();
224     $dev->finish()
225         or die $dev->error_or_status();
226     rmtree("$taperoot/tmp");
227
228     Amanda::MainLoop::call_later($get_info);
229     Amanda::MainLoop::run();
230 }