X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=installcheck%2FAmanda_Changer_disk.pl;h=993ee6f004390390b044b7577ac7597136da28db;hb=fd48f3e498442f0cbff5f3606c7c403d0566150e;hp=c8db6bf39e3017eaae5bfa3eaa2031acf75eaa84;hpb=96f35b20267e8b1a1c846d476f27fcd330e0b018;p=debian%2Famanda diff --git a/installcheck/Amanda_Changer_disk.pl b/installcheck/Amanda_Changer_disk.pl index c8db6bf..993ee6f 100644 --- a/installcheck/Amanda_Changer_disk.pl +++ b/installcheck/Amanda_Changer_disk.pl @@ -1,4 +1,4 @@ -# Copyright (c) 2005-2008 Zmanda Inc. All Rights Reserved. +# Copyright (c) 2008, 2009, 2010 Zmanda, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License version 2 as published @@ -13,17 +13,20 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # -# Contact information: Zmanda Inc, 465 S Mathlida Ave, Suite 300 +# Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300 # Sunnyvale, CA 94086, USA, or: http://www.zmanda.com -use Test::More tests => 14; +use Test::More tests => 18; use File::Path; use strict; +use warnings; use lib "@amperldir@"; +use Installcheck; use Installcheck::Config; +use Installcheck::Changer; use Amanda::Paths; -use Amanda::Device; +use Amanda::Device qw( :constants ); use Amanda::Debug; use Amanda::MainLoop; use Amanda::Config qw( :init :getconf config_dir_relative ); @@ -31,11 +34,12 @@ use Amanda::Changer; # set up debugging so debug output doesn't interfere with test results Amanda::Debug::dbopen("installcheck"); +Installcheck::log_test_output(); # and disable Debug's die() and warn() overrides Amanda::Debug::disable_die_override(); -my $taperoot = "$AMANDA_TMPDIR/Amanda_Changer_Disk_test"; +my $taperoot = "$Installcheck::TMP/Amanda_Changer_Disk_test"; sub reset_taperoot { my ($nslots) = @_; @@ -54,7 +58,7 @@ sub reset_taperoot { sub is_pointing_to { my ($res, $slot, $msg) = @_; - my ($datalink) = ($res->{'device_name'} =~ /file:(.*)/); + my ($datalink) = ($res->{'device'}->device_name =~ /file:(.*)/); $datalink .= "/data"; is(readlink($datalink), "../slot$slot", $msg); } @@ -70,120 +74,263 @@ if ($cfg_result != $CFGERR_OK) { } reset_taperoot(5); -my $chg = Amanda::Changer->new("chg-disk:$taperoot"); -{ - my @slots = ( 1, 3, 5 ); +# first try an error +my $chg = Amanda::Changer->new("chg-disk:$taperoot/foo"); +chg_err_like($chg, + { message => qr/directory '.*' does not exist/, + type => 'fatal' }, + "detects nonexistent directory"); + +$chg = Amanda::Changer->new("chg-disk:$taperoot"); +die($chg) if $chg->isa("Amanda::Changer::Error"); + +sub test_reserved { + my ($finished_cb, @slots) = @_; my @reservations = (); - my $getres; + my $slot; - $getres = sub { - my $slot = pop @slots; + my $steps = define_steps + cb_ref => \$finished_cb; + + step getres => sub { + $slot = pop @slots; + if (!defined $slot) { + return $steps->{'tryreserved'}->(); + } $chg->load(slot => $slot, set_current => ($slot == 5), + res_cb => make_cb($steps->{'loaded'})); + }; + + step loaded => sub { + my ($err, $reservation) = @_; + ok(!$err, "no error loading slot $slot") + or diag($err); + + # keep this reservation + if ($reservation) { + push @reservations, $reservation; + } + + # and start on the next + $steps->{'getres'}->(); + }; + + step tryreserved => sub { + # try to load an already-reserved slot + $chg->load(slot => 3, res_cb => sub { my ($err, $reservation) = @_; - ok(!$err, "no error loading slot $slot") - or diag($err); + chg_err_like($err, + { message => qr/Slot 3 is already in use by drive/, + type => 'failed', + reason => 'volinuse' }, + "error when requesting already-reserved slot"); + $steps->{'release'}->(); + }); + }; - # keep this reservation - if ($reservation) { - push @reservations, $reservation; - } + step release => sub { + my $res = pop @reservations; + if (!defined $res) { + return Amanda::MainLoop::quit(); + } - # and start on the next - if (@slots) { - $getres->(); - return; - } else { - # try to load an already-reserved slot - $chg->load(slot => 3, - res_cb => sub { - my ($err, $reservation) = @_; - ok($err, "error when requesting already-reserved slot"); - Amanda::MainLoop::quit(); - }); - } + $res->release(finished_cb => sub { + my ($err) = @_; + die $err if $err; + $steps->{'release'}->(); }); }; +} - # start the loop - Amanda::MainLoop::call_later($getres); - Amanda::MainLoop::run(); +# start the loop +test_reserved(\&Amanda::MainLoop::quit, 1, 3, 5); +Amanda::MainLoop::run(); - # ditch the reservations and do it all again - @reservations = (); - @slots = ( 4, 2, 3 ); - Amanda::MainLoop::call_later($getres); - Amanda::MainLoop::run(); +# and try it with some different slots, just to see +test_reserved(\&Amanda::MainLoop::quit, 4, 2, 3); +Amanda::MainLoop::run(); - @reservations = (); -} +# check relative slot ("current" and "next") functionality +sub test_relative_slot { + my ($finished_cb) = @_; + my $slot; -# check "current" and "next" functionality -{ - # load the "current" slot, which should be 3 - my ($load_current, $check_current_cb, $check_next_cb, $reset_finished_cb, $check_reset_cb); + my $steps = define_steps + cb_ref => \$finished_cb; - $load_current = sub { - $chg->load(slot => "current", res_cb => $check_current_cb); + # load the "current" slot, which should be 3 + step load_current => sub { + $chg->load(relative_slot => "current", res_cb => $steps->{'check_current_cb'}); }; - $check_current_cb = sub { + step check_current_cb => sub { my ($err, $res) = @_; die $err if $err; is_pointing_to($res, 5, "'current' is slot 5"); + $slot = $res->{'this_slot'}; - $chg->load(slot => $res->{'next_slot'}, res_cb => $check_next_cb); + $res->release(finished_cb => $steps->{'released1'}); }; - $check_next_cb = sub { + step released1 => sub { + my ($err) = @_; + die $err if $err; + + $chg->load(relative_slot => 'next', slot => $slot, + res_cb => $steps->{'check_next_cb'}); + }; + + step check_next_cb => sub { my ($err, $res) = @_; die $err if $err; is_pointing_to($res, 1, "'next' from there is slot 1"); - $chg->reset(finished_cb => $reset_finished_cb); + $res->release(finished_cb => $steps->{'released2'}); }; - $reset_finished_cb = sub { + step released2 => sub { + my ($err) = @_; + die $err if $err; + + $chg->reset(finished_cb => $steps->{'reset_finished_cb'}); + }; + + step reset_finished_cb => sub { my ($err) = @_; die $err if $err; - $chg->load(slot => "current", res_cb => $check_reset_cb); + $chg->load(relative_slot => "current", res_cb => $steps->{'check_reset_cb'}); }; - $check_reset_cb = sub { + step check_reset_cb => sub { my ($err, $res) = @_; die $err if $err; is_pointing_to($res, 1, "after reset, 'current' is slot 1"); - Amanda::MainLoop::quit(); + $res->release(finished_cb => $steps->{'released3'}); }; - Amanda::MainLoop::call_later($load_current); - Amanda::MainLoop::run(); + step released3 => sub { + my ($err) = @_; + die $err if $err; + + $finished_cb->(); + }; } +test_relative_slot(\&Amanda::MainLoop::quit); +Amanda::MainLoop::run(); -# test loading slot "next" -{ - my $load_next = sub { - $chg->load(slot => "next", +# test loading relative_slot "next" +sub test_relative_next { + my ($finished_cb) = @_; + + my $steps = define_steps + cb_ref => \$finished_cb; + + step load_next => sub { + $chg->load(relative_slot => "next", res_cb => sub { my ($err, $res) = @_; die $err if $err; - is_pointing_to($res, 2, "loading slot 'next' loads the correct slot"); + is_pointing_to($res, 2, "loading relative slot 'next' loads the correct slot"); - Amanda::MainLoop::quit(); + $steps->{'release'}->($res); } ); }; - Amanda::MainLoop::call_later($load_next); + step release => sub { + my ($res) = @_; + + $res->release(finished_cb => sub { + my ($err) = @_; + die $err if $err; + + $finished_cb->(); + }); + }; +} +test_relative_next(\&Amanda::MainLoop::quit); +Amanda::MainLoop::run(); + +# scan the changer using except_slots +sub test_except_slots { + my ($finished_cb) = @_; + my $slot; + my %except_slots; + + my $steps = define_steps + cb_ref => \$finished_cb; + + step start => sub { + $chg->load(slot => "5", except_slots => { %except_slots }, + res_cb => $steps->{'loaded'}); + }; + + step loaded => sub { + my ($err, $res) = @_; + if ($err) { + if ($err->notfound) { + # this means the scan is done + return $steps->{'quit'}->(); + } elsif ($err->volinuse and defined $err->{'slot'}) { + $slot = $err->{'slot'}; + } else { + die $err; + } + } else { + $slot = $res->{'this_slot'}; + } + + $except_slots{$slot} = 1; + + if ($res) { + $res->release(finished_cb => $steps->{'released'}); + } else { + $steps->{'released'}->(); + } + }; + + step released => sub { + my ($err) = @_; + die $err if $err; + + $chg->load(relative_slot => 'next', slot => $slot, + except_slots => { %except_slots }, + res_cb => $steps->{'loaded'}); + }; + + step quit => sub { + is_deeply({ %except_slots }, { 5=>1, 1=>1, 2=>1, 3=>1, 4=>1 }, + "scanning with except_slots works"); + $finished_cb->(); + }; +} +test_except_slots(\&Amanda::MainLoop::quit); +Amanda::MainLoop::run(); + +# eject is not implemented +{ + my $try_eject = make_cb('try_eject' => sub { + $chg->eject(finished_cb => make_cb(sub { + my ($err, $res) = @_; + chg_err_like($err, + { type => 'failed', reason => 'notimpl' }, + "eject returns a failed/notimpl error"); + + Amanda::MainLoop::quit(); + })); + }); + + $try_eject->(); Amanda::MainLoop::run(); } @@ -191,29 +338,36 @@ my $chg = Amanda::Changer->new("chg-disk:$taperoot"); { my ($get_info, $load_label, $check_load_cb) = @_; - $get_info = sub { - $chg->info(info_cb => $load_label, info => [ 'num_slots' ]); - }; + $get_info = make_cb('get_info' => sub { + $chg->info(info_cb => $load_label, info => [ 'num_slots', 'fast_search' ]); + }); - $load_label = sub { + $load_label = make_cb('load_label' => sub { my $err = shift; my %results = @_; die($err) if defined($err); - is($results{'num_slots'}, 5, "info() returns the correct num_slots"); + is_deeply({ %results }, + { num_slots => 5, fast_search => 1 }, + "info() returns the correct num_slots and fast_search"); # note use of a glob metacharacter in the label name $chg->load(label => "FOO?BAR", res_cb => $check_load_cb); - }; + }); - $check_load_cb = sub { + $check_load_cb = make_cb('check_load_cb' => sub { my ($err, $res) = @_; die $err if $err; is_pointing_to($res, 4, "labeled volume found in slot 4"); - Amanda::MainLoop::quit(); - }; + $res->release(finished_cb => sub { + my ($err) = @_; + die $err if $err; + + Amanda::MainLoop::quit(); + }); + }); # label slot 4, using our own symlink mkpath("$taperoot/tmp"); @@ -225,6 +379,46 @@ my $chg = Amanda::Changer->new("chg-disk:$taperoot"); or die $dev->error_or_status(); rmtree("$taperoot/tmp"); - Amanda::MainLoop::call_later($get_info); + $get_info->(); + Amanda::MainLoop::run(); +} + +# inventory is pretty cool +{ + my $try_inventory = make_cb('try_inventory' => sub { + $chg->inventory(inventory_cb => make_cb(sub { + my ($err, $inv) = @_; + die $err if $err; + + is_deeply($inv, [ + { slot => 1, state => Amanda::Changer::SLOT_FULL, + device_status => $DEVICE_STATUS_SUCCESS, + f_type => $Amanda::Header::F_EMPTY, label => undef, + reserved => 0, current => 1}, + { slot => 2, state => Amanda::Changer::SLOT_FULL, + device_status => $DEVICE_STATUS_SUCCESS, + f_type => $Amanda::Header::F_EMPTY, label => undef, + reserved => 0 }, + { slot => 3, state => Amanda::Changer::SLOT_FULL, + device_status => $DEVICE_STATUS_SUCCESS, + f_type => $Amanda::Header::F_EMPTY, label => undef, + reserved => 0 }, + { slot => 4, state => Amanda::Changer::SLOT_FULL, + device_status => $DEVICE_STATUS_SUCCESS, + f_type => $Amanda::Header::F_TAPESTART, label => "FOO?BAR", + reserved => 0 }, + { slot => 5, state => Amanda::Changer::SLOT_FULL, + device_status => $DEVICE_STATUS_SUCCESS, + f_type => $Amanda::Header::F_EMPTY, label => undef, + reserved => 0 }, + ], "inventory finds the labeled tape"); + + Amanda::MainLoop::quit(); + })); + }); + + $try_inventory->(); Amanda::MainLoop::run(); } + +rmtree($taperoot);