1 # Copyright (c) 2005-2008 Zmanda Inc. All Rights Reserved.
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.
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
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
16 # Contact information: Zmanda Inc, 465 S Mathlida Ave, Suite 300
17 # Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
19 use Test::More tests => 22;
24 use lib "@amperldir@";
25 use Installcheck::Config;
26 use Installcheck::Run;
31 use Amanda::Config qw( :init :getconf config_dir_relative );
34 # set up debugging so debug output doesn't interfere with test results
35 Amanda::Debug::dbopen("installcheck");
37 # and disable Debug's die() and warn() overrides
38 Amanda::Debug::disable_die_override();
40 my $changer_filename = "$AMANDA_TMPDIR/chg-test";
41 my $result_file = "$AMANDA_TMPDIR/chg-test.result";
43 # Set up a 'test' changer; several of these are defined below.
45 my ($changer_script) = @_;
47 open my $chg_test, ">", $changer_filename or die("Could not create test changer");
49 $changer_script =~ s/\$AMANDA_TMPDIR/$AMANDA_TMPDIR/g;
51 print $chg_test "#! /bin/sh\n";
52 print $chg_test $changer_script;
55 chmod 0755, $changer_filename;
58 # slurp the $result_file
60 return '' unless (-r $result_file);
62 open(my $fh, "<", $result_file) or die("open $result_file: $!");
63 my $result = do { local $/; <$fh> };
69 # Functions to invoke the changer and later verify the result
77 Amanda::MainLoop::quit();
80 if (defined($expected_err_re)) {
81 like($err, $expected_err_re, $msg);
84 debug("Unexpected error: $err");
87 if (defined($expected_dev)) {
88 is($res->{'device_name'}, $expected_dev, $msg);
91 diag("Unexpected reservation");
96 sub check_finished_cb {
98 Amanda::MainLoop::quit();
101 if (defined($expected_err_re)) {
102 like($err, $expected_err_re, $msg);
105 diag("Unexpected error: $err");
108 if (!defined($expected_err_re)) {
112 diag("Unexpected success");
117 sub try_run_changer {
119 ($sub, $expected_err_re, $expected_dev, $msg) = @_;
121 Amanda::MainLoop::call_later($sub);
122 Amanda::MainLoop::run();
126 # OK, let's get started with some simple stuff
127 setup_changer <<'EOC';
131 1) echo "1 fake:1"; exit 0;;
132 2) echo "<ignored> slot 2 is empty"; exit 1;;
133 3) echo "1"; exit 0;; # test missing 'device' portion
136 echo "reset" > @AMANDA_TMPDIR@/chg-test.result
137 echo "reset ignored";;
139 echo "eject" > @AMANDA_TMPDIR@/chg-test.result
140 echo "eject ignored";;
142 echo "clean" > @AMANDA_TMPDIR@/chg-test.result
143 echo "clean ignored";;
146 foo?bar) echo "1 ok"; exit 0;;
147 *) echo "<error> bad label"; exit 1;;
149 -info) echo "7 10 1 1"; exit 0;;
152 TAPE?01) echo "5 fakedev"; exit 0;;
153 *) echo "<error> not found"; exit 1;;
158 # set up a config for this changer, implicitly using Amanda::Changer::Compat
160 $testconf = Installcheck::Config->new();
161 $testconf->add_param("tpchanger", "\"$changer_filename\"");
164 my $cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF');
165 if ($cfg_result != $CFGERR_OK) {
166 my ($level, @errors) = Amanda::Config::config_errors();
167 die(join "\n", @errors);
170 my $chg = Amanda::Changer->new();
172 sub { $chg->load(label => 'TAPE-01', res_cb => \&check_res_cb); },
173 undef, "fakedev", "search by label");
176 sub { $chg->load(label => 'TAPE-99', res_cb => \&check_res_cb); },
177 qr/^not found$/, undef, "search by label; nonexistent tape");
180 sub { $chg->load(slot => '1', res_cb => \&check_res_cb); },
181 undef, "fake:1", "search by slot");
184 sub { $chg->load(slot => '2', res_cb => \&check_res_cb); },
185 qr/^slot 2 is empty$/, undef, "search by slot; empty slot");
187 # TODO: what *should* happen here?
189 # sub { $chg->load(slot => '3', res_cb => \&check_res_cb); },
190 # undef, undef, "search by slot; invalid response");
193 sub { $chg->eject(finished_cb => \&check_finished_cb); },
194 undef, undef, "chg->eject doesn't fail");
195 like(slurp_result(), qr/eject/, ".. and calls chg-test -eject");
198 sub { $chg->reset(finished_cb => \&check_finished_cb); },
199 undef, undef, "chg->reset doesn't fail");
200 like(slurp_result(), qr/reset/, ".. and calls chg-test -reset");
203 sub { $chg->clean(finished_cb => \&check_finished_cb); },
204 undef, undef, "chg->clean doesn't fail");
205 like(slurp_result(), qr/clean/, ".. and calls chg-test -clean");
209 # make sure only one reservation can be held at once
213 my ($load_1, $load_2, $check_load_2, $check_eject);
216 $chg->load(slot => 1, res_cb => $load_2);
220 my ($err, $res) = @_;
223 # keep this in scope through the next load
226 $chg->load(slot => 2, res_cb => $check_load_2);
229 $check_load_2 = sub {
230 my ($err, $res) = @_;
232 like($err, qr/Changer is already reserved/,
233 "mulitple simultaneous reservations not alowed");
235 $first_res->release(eject => 1, finished_cb => $check_eject);
241 ok(!defined $err, "release with eject succeeds");
243 like(slurp_result(), qr/eject/, "..and calls chg-test -eject");
245 Amanda::MainLoop::quit();
248 Amanda::MainLoop::call_later($load_1);
249 Amanda::MainLoop::run();
254 # Installcheck::Run sets up the whole chg-disk thing for us
255 $testconf = Installcheck::Run->setup();
258 $cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF');
259 if ($cfg_result != $CFGERR_OK) {
260 my ($level, @errors) = Amanda::Config::config_errors();
261 die(join "\n", @errors);
264 $chg = Amanda::Changer->new();
267 my ($get_info, $load_current, $label_current, $load_next,
268 $release_next, $load_by_label, $check_by_label);
271 $chg->info(info_cb => $load_current, info => [ 'num_slots' ]);
274 $load_current = sub {
277 die($err) if defined($err);
279 is($results{'num_slots'}, 15, "info() returns the correct num_slots");
281 $chg->load(slot => "1", res_cb => $label_current);
284 $label_current = sub {
285 my ($err, $res) = @_;
288 pass("seek to current slot succeeded");
290 my $dev = Amanda::Device->new($res->{'device_name'});
291 $dev->start($Amanda::Device::ACCESS_WRITE, "TESTCONF18", undef)
292 or die $dev->error_or_status();
294 or die $dev->error_or_status();
296 is($res->{'this_slot'}, "1", "this slot is '1'");
297 is($res->{'next_slot'}, "next", "next slot is 'next'");
298 $res->set_label(label => "TESTCONF18", finished_cb => $load_next);
305 pass("set_label succeeded");
307 $chg->load(slot => "next", res_cb => $release_next);
310 $release_next = sub {
311 my ($err, $res) = @_;
314 pass("load 'next' succeeded");
316 $res->release(finished_cb => $load_by_label);
319 $load_by_label = sub {
323 pass("release loaded");
325 $chg->load(label => "TESTCONF18", res_cb => $check_by_label);
328 $check_by_label = sub {
329 my ($err, $res) = @_;
332 pass("load by label succeeded");
334 my $dev = Amanda::Device->new($res->{'device_name'});
335 $dev->read_label() == 0
336 or die $dev->error_or_status();
338 is($dev->volume_label(), "TESTCONF18",
339 "..and finds the right volume");
341 Amanda::MainLoop::quit();
344 Amanda::MainLoop::call_later($get_info);
345 Amanda::MainLoop::run();