d525fd6b313fa9d2e74848dd31faf5aa51650fb5
[debian/amanda] / installcheck / Amanda_Changer.pl
1 # Copyright (c) 2006 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, 505 N Mathlida Ave, Suite 120
17 # Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
18
19 use Test::More qw(no_plan);
20 use Amconfig;
21 use File::Path;
22 use strict;
23
24 use lib "@amperldir@";
25 use Amanda::Paths;
26 use Amanda::Device;
27 use Amanda::Debug;
28 use Amanda::Config qw( :init :getconf config_dir_relative );
29 use Amanda::Changer;
30
31 # set up debugging so debug output doesn't interfere with test results
32 Amanda::Debug::dbopen("installcheck");
33
34 my $changer_filename = "$AMANDA_TMPDIR/chg-test";
35
36 sub setup_changer {
37     my ($changer_script) = @_;
38
39     open my $chg_test, ">", $changer_filename or die("Could not create test changer");
40     
41     $changer_script =~ s/\$AMANDA_TMPDIR/$AMANDA_TMPDIR/g;
42
43     print $chg_test "#! /bin/sh\n";
44     print $chg_test $changer_script;
45
46     close $chg_test;
47     chmod 0755, $changer_filename;
48 }
49
50 # set up and load a simple config with a tpchanger
51 my $testconf = Amconfig->new();
52 $testconf->add_param('tpchanger', "\"$changer_filename\"");
53 $testconf->write();
54 config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF') or die("Could not load test config");
55
56 # some variables we'll need
57 my ($error, $slot, $device);
58
59 # OK, let's get started with some simple stuff
60 setup_changer <<'EOC';
61 case "${1}" in
62     -slot)
63         case "${2}" in
64             1) echo "1 fake:1"; exit 0;;
65             2) echo "<ignored> slot 2 is empty"; exit 1;;
66             3) echo "<error> oh noes!"; exit 2;;
67             4) echo "1"; exit 0;; # test missing 'device' portion
68         esac;;
69     -reset) echo "reset ignored";;
70     -eject) echo "eject ignored";;
71     -clean) echo "clean ignored";;
72     -label)
73         case "${2}" in
74             foo?bar) echo "1 ok"; exit 0;;
75             *) echo "<error> bad label"; exit 1;;
76         esac;;
77     -info) echo "7 10 1 1"; exit 0;;
78     -search) 
79         case "${2}" in
80             TAPE?01) echo "5 fakedev"; exit 0;;
81             *) echo "<error> not found"; exit 2;;
82         esac;;
83 esac
84 EOC
85
86 is_deeply([ Amanda::Changer::loadslot(1) ], [0, "1", "fake:1"],
87     "A successful loadslot() returns the right stuff");
88
89 ($error, $slot, $device) = Amanda::Changer::loadslot(2);
90 is($error, "slot 2 is empty", "A loadslot() with a benign error returns the right stuff");
91
92 eval { Amanda::Changer::loadslot(3); };
93 like($@, qr/.*oh noes!.*/, "A loadslot() with a serious error croaks");
94
95 is_deeply([ Amanda::Changer::loadslot(4) ], [0, "1", undef],
96     "a response without a device string returns undef");
97
98 is_deeply([ Amanda::Changer::reset() ], [ 0, "reset" ],
99     "reset() calls tapechanger -reset");
100 is_deeply([ Amanda::Changer::eject() ], [ 0, "eject" ],
101     "eject() calls tapechanger -eject");
102 is_deeply([ Amanda::Changer::clean() ], [ 0, "clean" ],
103     "clean() calls tapechanger -clean");
104
105 is_deeply([ Amanda::Changer::label("foo bar") ], [ 0 ],
106     "label('foo bar') calls tapechanger -label 'foo bar' (note spaces)");
107
108 is_deeply([ Amanda::Changer::query() ], [ 0, 7, 10, 1, 1 ],
109     "query() returns the correct values for a 4-value changer script");
110
111 is_deeply([ Amanda::Changer::find("TAPE 01") ], [ 0, "5", "fakedev" ],
112     "find on a searchable changer invokes -search");
113
114 eval { Amanda::Changer::find("TAPE 02") };
115 ok($@, "A searchable changer croaks when the label can't be found");
116
117 # Now a simple changer that returns three values for -info
118 setup_changer <<'EOC';
119 case "${1}" in
120     -info) echo "11 13 0"; exit 0;;
121 esac
122 EOC
123
124 is_deeply([ Amanda::Changer::query() ], [ 0, 11, 13, 0, 0 ],
125     "query() returns the correct values for a 4-value changer script");
126
127 # set up 5 vtapes
128 for (my $i = 0; $i < 5; $i++) {
129     my $vtapedir = "$AMANDA_TMPDIR/chg-test-tapes/$i/data";
130     if (-e $vtapedir) {
131         rmtree($vtapedir) 
132             or die("Could not remove '$vtapedir'");
133     }
134     mkpath($vtapedir)
135         or die("Could not create '$vtapedir'");
136 }
137
138 # label three of them (slot 2 is empty; slot 4 is unlabeled)
139 for (my $i = 0; $i < 5; $i++) {
140     next if $i == 2 || $i == 4;
141     my $dev = Amanda::Device->new("file:$AMANDA_TMPDIR/chg-test-tapes/$i")
142         or die("Could not open device");
143     $dev->start($Amanda::Device::ACCESS_WRITE, "TAPE$i", "19780615010203") 
144         or die("Could not write label");
145     $dev->finish();
146 }
147
148 # And finally a "stateful" changer that can support "scan" and "find"
149 setup_changer <<'EOC';
150 STATEFILE="$AMANDA_TMPDIR/chg-test-state"
151 SLOT=0
152 [ -f "$STATEFILE" ] && . "$STATEFILE"
153
154 case "${1}" in
155     -slot)
156         case "${2}" in
157             current) ;;
158             0|1|2|3|4|5) SLOT="${2}";;
159             next|advance) SLOT=`expr $SLOT + 1`;;
160             prev) SLOT=`expr $SLOT - 1`;;
161             first) SLOT=0;;
162             last) SLOT=4;;
163         esac
164
165         # normalize 0 <= $SLOT  < 5
166         while [ "$SLOT" -ge 5 ]; do SLOT=`expr $SLOT - 5`; done
167         while [ "$SLOT" -lt 0 ]; do SLOT=`expr $SLOT + 5`; done
168
169         # signal an empty slot for slot 2
170         if [ "$SLOT" = 2 ]; then
171             echo "$SLOT slot $SLOT is empty"
172             EXIT=1
173         else
174             echo "$SLOT" "file:$AMANDA_TMPDIR/chg-test-tapes/$SLOT"
175         fi
176         ;;
177     -info) echo "$SLOT 5 1 0";;
178 esac
179
180 echo SLOT=$SLOT > $STATEFILE
181 exit $EXIT
182 EOC
183
184 ($error, $slot, $device) = Amanda::Changer::loadslot(0);
185 if ($error) { die("Error loading slot 0: $error"); }
186 is_deeply([ Amanda::Changer::find("TAPE3") ], [0, "3", "file:$AMANDA_TMPDIR/chg-test-tapes/3"],
187     "Finds a tape after skipping an empty slot");
188
189 ($error, $slot, $device) = Amanda::Changer::loadslot(3);
190 if ($error) { die("Error loading slot 3: $error"); }
191 is_deeply([ Amanda::Changer::find("TAPE1") ], [0, "1", "file:$AMANDA_TMPDIR/chg-test-tapes/1"],
192     "Finds a tape after skipping an unlabeled but filled slot");
193
194 my @scanresults;
195 sub cb {
196     fail("called too many times") if (!@scanresults);
197     my $expected = shift @scanresults;
198     my $descr = pop @$expected;
199     my $done = pop @$expected;
200     is_deeply([ @_ ], $expected, $descr);
201     return 1;
202 }
203
204 # scan the whole changer
205 ($error, $slot, $device) = Amanda::Changer::loadslot(0);
206 if ($error) { die("Error loading slot 0: $error"); }
207 @scanresults = (
208     [ "0", "file:$AMANDA_TMPDIR/chg-test-tapes/0", 0, 0, "scan starts with slot 0" ],
209     [ "1", "file:$AMANDA_TMPDIR/chg-test-tapes/1", 0, 0, "next in slot 1" ],
210     [ undef, undef, "slot 2 is empty",                0, "slot 2 is empty" ],
211     [ "3", "file:$AMANDA_TMPDIR/chg-test-tapes/3", 0, 0, "next in slot 3" ],
212     [ "4", "file:$AMANDA_TMPDIR/chg-test-tapes/4", 0, 0, "next in slot 4" ],
213 );
214 Amanda::Changer::scan(\&cb);
215
216 # make sure it stops when "done"
217 ($error, $slot, $device) = Amanda::Changer::loadslot(0);
218 if ($error) { die("Error loading slot 0: $error"); }
219 @scanresults = (
220     [ "0", "file:$AMANDA_TMPDIR/chg-test-tapes/0", 0, 1, "scan starts with slot 0" ],
221 );
222 Amanda::Changer::scan(\&cb);
223
224 # cleanup
225 unlink("$AMANDA_TMPDIR/chg-test");
226 unlink("$AMANDA_TMPDIR/chg-test-state");
227 rmtree("$AMANDA_TMPDIR/chg-test-tapes");