Imported Upstream version 3.3.3
[debian/amanda] / installcheck / amfetchdump.pl
1 # Copyright (c) 2008-2012 Zmanda, Inc.  All Rights Reserved.
2 #
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful, but
9 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11 # for more details.
12 #
13 # You should have received a copy of the GNU General Public License along
14 # with this program; if not, write to the Free Software Foundation, Inc.,
15 # 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 #
17 # Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300
18 # Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
19
20 use Test::More tests => 33;
21
22 use lib "@amperldir@";
23 use Installcheck;
24 use Installcheck::Config;
25 use Installcheck::Run qw(run run_get run_err $diskname);
26 use Installcheck::Dumpcache;
27 use File::Path qw(rmtree mkpath);
28 use Amanda::Paths;
29 use Amanda::Header;
30 use Amanda::Debug;
31 use Cwd;
32 use warnings;
33 use strict;
34 no strict 'subs';
35
36 unless ($Installcheck::Run::have_expect) {
37     SKIP: {
38         skip("Expect.pm not available", Test::More->builder->expected_tests);
39     }
40     exit 0;
41 }
42
43 ## NOTE:
44 #
45 # Not all features of amfetchdump can be tested without a lot of extra work:
46 # --header-fd: Expect doesn't pass through nonstandard fd's
47 # -p: Expect would have to deal with the dumpfile data, which it won't like
48
49 my $testconf;
50 my $dumpok;
51 my @filenames;
52 my $exp;
53 my @results;
54 my $fok;
55 my $last_file_size;
56
57 my $testdir = "$Installcheck::TMP/amfetchdump-installcheck/files";
58 rmtree($testdir);
59 mkpath($testdir);
60
61 my $origdir = getcwd;
62 chdir($testdir);
63
64 Amanda::Debug::dbopen("installcheck");
65 Installcheck::log_test_output();
66
67 sub cleandir {
68     for my $filename (<$testdir/*>) {
69         unlink($filename);
70     }
71 }
72
73 sub got_files {
74     my ($count, $msg) = @_;
75     my $ok = 1;
76
77     my @filenames = <localhost.*>;
78
79     # check for .tmp files and empty files
80     for my $fn (@filenames) {
81         if ($fn =~ /\.tmp$/ || -z "$testdir/$fn") {
82             $ok = 0;
83         }
84     }
85
86     if (scalar @filenames != $count) {
87         diag("expected $count files");
88         $ok = 0;
89     }
90
91     # capture file size if there's only one file
92     if (@filenames == 1) {
93         $last_file_size = -s $filenames[0];
94     }
95
96     ok($ok, $msg) or diag(`ls -l $testdir`);
97 }
98
99 Installcheck::Dumpcache::load("basic");
100
101 like(run_err('amfetchdump', 'TESTCONF'),
102     qr{^Usage:},
103     "'amfetchdump TESTCONF' gives usage message on stderr");
104
105 like(run_err('amfetchdump', '-b', '65536', 'TESTCONF', 'localhost'),
106     qr{ERROR: The -b option is no longer},
107     "-b option gives a warning stderr");
108
109 ##
110 # plain vanilla
111
112 cleandir();
113
114 $exp = Installcheck::Run::run_expect('amfetchdump', 'TESTCONF', 'localhost');
115 $exp->log_stdout(0);
116
117 @results = ();
118 $exp->expect(60,
119     [ qr{1 (tape|volume)\(s\) needed for restoration}, sub {
120         push @results, "tape-count";
121         exp_continue;
122     } ],
123     [ qr{The following (tapes|volumes) are needed: TESTCONF01}, sub {
124         push @results, "tapes-needed";
125         exp_continue;
126     } ],
127     [ qr{amfetchdump: 1: restoring split dumpfile: date [[:digit:]]+ host localhost disk .*},
128     sub {
129         push @results, "restoring";
130         exp_continue;
131     } ],
132     [ 'Press enter when ready', sub {
133         push @results, "press-enter";
134         $exp->send("\n");
135         exp_continue;
136     }, ],
137     [ 'eof', sub {
138         push @results, "eof";
139     }, ],
140 );
141 is_deeply([ @results ], [ "tape-count", "tapes-needed", "press-enter", "restoring", "eof" ],
142           "simple restore follows the correct steps");
143
144 got_files(1, "..and restored file is present in testdir");
145
146 ##
147 # -a (assume)
148
149 cleandir();
150
151 ok(run('amfetchdump', '-a', '-l', 'TESTCONF', 'localhost'),
152     "run with -a and -l successful");
153
154 got_files(1, "..and restored file is present in testdir ($last_file_size bytes)");
155 my $uncomp_size = $last_file_size;
156
157 ##
158 # -C (should make output file smaller)
159
160 cleandir();
161
162 ok(run('amfetchdump', '-a', '-C', 'TESTCONF', 'localhost'),
163     "run with -a and -C successful");
164
165 got_files(1, "..and restored file is present in testdir");
166
167 ok($last_file_size < $uncomp_size,
168     "..and is smaller than previous run ($last_file_size bytes)");
169
170 ##
171 # -O
172
173 cleandir();
174 chdir($Installcheck::TMP);
175
176 $exp = Installcheck::Run::run_expect('amfetchdump', '-O', $testdir, 'TESTCONF', 'localhost');
177 $exp->log_stdout(0);
178
179 @results = ();
180 $exp->expect(60,
181     [ qr{1 (tape|volume)\(s\) needed for restoration}, sub {
182         push @results, "tape-count";
183         exp_continue;
184     } ],
185     [ qr{The following (tapes|volumes) are needed: TESTCONF01}, sub {
186         push @results, "tapes-needed";
187         exp_continue;
188     } ],
189     [ qr{amfetchdump: 1: restoring split dumpfile: date [[:digit:]]+ host localhost disk .*},
190     sub {
191         push @results, "restoring";
192         exp_continue;
193     } ],
194     [ 'Press enter when ready', sub {
195         push @results, "press-enter";
196         $exp->send("\n");
197         exp_continue;
198     }, ],
199     [ 'eof', sub {
200         push @results, "eof";
201     }, ],
202 );
203 is_deeply([ @results ], [ "tape-count", "tapes-needed", "press-enter", "restoring", "eof" ],
204           "restore with -O follows the correct steps");
205
206 chdir($testdir);
207 got_files(1, "..and restored file is present in testdir");
208
209 ##
210 # -h
211
212 cleandir();
213
214 $exp = Installcheck::Run::run_expect('amfetchdump', '-h', 'TESTCONF', 'localhost');
215 $exp->log_stdout(0);
216
217 @results = ();
218 $exp->expect(60,
219     [ qr{1 (tape|volume)\(s\) needed for restoration}, sub {
220         push @results, "tape-count";
221         exp_continue;
222     } ],
223     [ qr{The following (tapes|volumes) are needed: TESTCONF01}, sub {
224         push @results, "tapes-needed";
225         exp_continue;
226     } ],
227     [ qr{amfetchdump: 1: restoring split dumpfile: date [[:digit:]]+ host localhost disk .*},
228     sub {
229         push @results, "restoring";
230         exp_continue;
231     } ],
232     [ 'Press enter when ready', sub {
233         push @results, "press-enter";
234         $exp->send("\n");
235         exp_continue;
236     }, ],
237     [ 'eof', sub {
238         push @results, "eof";
239     }, ],
240 );
241 is_deeply([ @results ], [ "tape-count", "tapes-needed", "press-enter", "restoring", "eof" ],
242           "restore with -h follows the correct steps");
243
244 $fok = got_files(1, "..and restored file is present in testdir");
245
246 # check that it starts with a header
247 if ($fok) {
248     my @filenames = <localhost.*>;
249     open(my $fh, "<", $filenames[0]) or die "error opening: $!";
250     sysread($fh, my $hdr_dat, 32768) or die "error reading: $!";
251     close($fh);
252     my $hdr = Amanda::Header->from_string($hdr_dat);
253     is($hdr->{type}+0, $Amanda::Header::F_SPLIT_DUMPFILE,
254         "..dumpfile begins with a split dumpfile header");
255 } else {
256     fail();
257 }
258
259 ##
260 # --header-file
261
262 cleandir();
263
264 $exp = Installcheck::Run::run_expect('amfetchdump', '--header-file', 'hdr',
265                                         'TESTCONF', 'localhost');
266 $exp->log_stdout(0);
267
268 @results = ();
269 $exp->expect(60,
270     [ qr{1 (tape|volume)\(s\) needed for restoration}, sub {
271         push @results, "tape-count";
272         exp_continue;
273     } ],
274     [ qr{The following (tapes|volumes) are needed: TESTCONF01}, sub {
275         push @results, "tapes-needed";
276         exp_continue;
277     } ],
278     [ qr{amfetchdump: 1: restoring split dumpfile: date [[:digit:]]+ host localhost disk .*},
279     sub {
280         push @results, "restoring";
281         exp_continue;
282     } ],
283     [ 'Press enter when ready', sub {
284         push @results, "press-enter";
285         $exp->send("\n");
286         exp_continue;
287     }, ],
288     [ 'eof', sub {
289         push @results, "eof";
290     }, ],
291 );
292 is_deeply([ @results ], [ "tape-count", "tapes-needed", "press-enter", "restoring", "eof" ],
293           "restore with --header-file follows the correct steps");
294
295 $fok = got_files(1, "..and restored file is present in testdir");
296
297 # check that it starts with a header
298 if ($fok) {
299     my @filenames = <localhost.*>;
300     open(my $fh, "<", "$testdir/hdr") or die "error opening: $!";
301     sysread($fh, my $hdr_dat, 32768) or die "error reading: $!";
302     close($fh);
303     my $hdr = Amanda::Header->from_string($hdr_dat);
304     is($hdr->{type}+0, $Amanda::Header::F_SPLIT_DUMPFILE,
305         "..and the header file contains the right header");
306 } else {
307     fail();
308 }
309
310 ##
311 # -d and prompting for volumes one at a time
312
313 cleandir();
314
315 my $vfsdev = 'file:' . Installcheck::Run::vtape_dir();
316 Installcheck::Run::load_vtape(3); # wrong vtape
317 $exp = Installcheck::Run::run_expect('amfetchdump', '-d', $vfsdev,
318                                         'TESTCONF', 'localhost');
319 $exp->log_stdout(0);
320
321 @results = ();
322 $exp->expect(60,
323     [ qr{1 (tape|volume)\(s\) needed for restoration}, sub {
324         push @results, "tape-count";
325         exp_continue;
326     } ],
327     [ qr{The following (tapes|volumes) are needed: TESTCONF01}, sub {
328         push @results, "tapes-needed";
329         exp_continue;
330     } ],
331     [ 'Press enter when ready', sub {
332         push @results, "press-enter";
333         $exp->send("\n");
334         exp_continue;
335     }, ],
336     [ qr{Insert (tape|volume) labeled '?TESTCONF01'? in .*\n.*to abort}, sub {
337         push @results, "insert-tape";
338         Installcheck::Run::load_vtape(1); # right vtape
339         $exp->send("\n");
340         exp_continue;
341     }, ],
342     [ qr{amfetchdump: 1: restoring split dumpfile: date [[:digit:]]+ host localhost disk .*},
343     sub {
344         push @results, "restoring";
345         exp_continue;
346     } ],
347     [ 'eof', sub {
348         push @results, "eof";
349     }, ],
350 );
351 is_deeply([ @results ], [ "tape-count", "tapes-needed", "press-enter",
352                           "insert-tape", "restoring", "eof" ],
353           "restore with an explicit device follows the correct steps, prompting for each");
354
355 got_files(1, "..and restored file is present in testdir");
356
357 ##
358 # -n (using a multipart dump)
359
360 Installcheck::Dumpcache::load("parts");
361 cleandir();
362
363 $exp = Installcheck::Run::run_expect('amfetchdump', '-n', 'TESTCONF', 'localhost');
364 $exp->log_stdout(0);
365
366 @results = ();
367 $exp->expect(60,
368     [ qr{1 (tape|volume)\(s\) needed for restoration}, sub {
369         push @results, "tape-count";
370         exp_continue;
371     } ],
372     [ qr{The following (tapes|volumes) are needed: TESTCONF01}, sub {
373         push @results, "tapes-needed";
374         exp_continue;
375     } ],
376     [ qr{amfetchdump: (\d+): restoring split dumpfile: date [[:digit:]]+ host localhost disk .*},
377     sub {
378         push @results, "restoring";
379         exp_continue;
380     } ],
381     [ 'Press enter when ready', sub {
382         push @results, "press-enter";
383         $exp->send("\n");
384         exp_continue;
385     }, ],
386     [ 'eof', sub {
387         push @results, "eof";
388     }, ],
389 );
390 is_deeply([ @results ], [ "tape-count", "tapes-needed", "press-enter",
391                           ("restoring",)x9, "eof" ],
392           "restore with -n follows the correct steps");
393
394 got_files(9, "..and restored file is present in testdir");
395
396 ##
397 # -l, no options, and -c for compressed dumps
398
399 Installcheck::Dumpcache::load("compress");
400 cleandir();
401
402 ok(run('amfetchdump', '-a', 'TESTCONF', 'localhost'),
403     "run with -a successful (should uncompress)");
404
405 got_files(1, "..and restored file is present in testdir ($last_file_size bytes)");
406 $uncomp_size = $last_file_size;
407
408 cleandir();
409
410 ok(run('amfetchdump', '-a', '-l', 'TESTCONF', 'localhost'),
411     "run with -a and -l successful (should not uncompress)");
412
413 got_files(1, "..and restored file is present in testdir");
414
415 ok($last_file_size < $uncomp_size,
416     "..and is smaller than previous run ($last_file_size bytes)");
417
418 cleandir();
419
420 ok(run('amfetchdump', '-a', '-c', 'TESTCONF', 'localhost'),
421     "run with -a and -c successful (should not uncompress)");
422
423 got_files(1, "..and restored file is present in testdir");
424
425 ok($last_file_size < $uncomp_size,
426     "..and is smaller than previous run ($last_file_size bytes)");
427
428 Installcheck::Dumpcache::load("multi");
429 cleandir();
430
431 $exp = Installcheck::Run::run_expect('amfetchdump', 'TESTCONF', 'localhost');
432 $exp->log_stdout(0);
433
434 @results = ();
435 $exp->expect(60,
436     [ qr{2 (tape|volume)\(s\) needed for restoration}, sub {
437         push @results, "tape-count";
438         exp_continue;
439     } ],
440     [ qr{The following (tapes|volumes) are needed: TESTCONF01 TESTCONF02.*}, sub {
441         push @results, "tapes-needed";
442         exp_continue;
443     } ],
444     [ qr{2 holding file\(s\) needed for restoration}, sub {
445         push @results, "holding-count";
446         exp_continue;
447     } ],
448     [ qr{Reading .*\nFILE: date [[:digit:]]+ host localhost disk .*},
449     sub {
450         push @results, "reading";
451         exp_continue;
452     } ],
453     [ 'Press enter when ready', sub {
454         push @results, "press-enter";
455         $exp->send("\n");
456         exp_continue;
457     }, ],
458     [ 'eof', sub {
459         push @results, "eof";
460     }, ],
461 );
462 is_deeply([ @results ], [ "tape-count", "tapes-needed", "holding-count",
463                           "press-enter", "reading", "reading", "eof" ],
464           "restore from holding follows the correct steps");
465
466 got_files(6, "..and all restored files are present in testdir");
467
468
469 SKIP: {
470     skip "Expect not installed or not built with ndmp and server", 2 unless
471         Amanda::Util::built_with_component("ndmp") and
472         Amanda::Util::built_with_component("server") and
473         $Installcheck::Run::have_expect;
474
475
476     Installcheck::Dumpcache::load("ndmp");
477     my $ndmp = Installcheck::Mock::NdmpServer->new(no_reset => 1);
478     $ndmp->edit_config();
479
480     cleandir();
481
482     $exp = Installcheck::Run::run_expect('amfetchdump', 'TESTCONF', 'localhost');
483     $exp->log_stdout(0);
484
485     @results = ();
486     $exp->expect(60,
487         [ qr{1 (tape|volume)\(s\) needed for restoration}, sub {
488             push @results, "tape-count";
489             exp_continue;
490         } ],
491         [ qr{The following (tapes|volumes) are needed: TESTCONF01}, sub {
492             push @results, "tapes-needed";
493             exp_continue;
494         } ],
495         [ qr{amfetchdump: 1: restoring split dumpfile: date [[:digit:]]+ host localhost disk .*},
496         sub {
497             push @results, "restoring";
498             exp_continue;
499         } ],
500         [ 'Press enter when ready', sub {
501             push @results, "press-enter";
502             $exp->send("\n");
503             exp_continue;
504         }, ],
505         [ 'eof', sub {
506             push @results, "eof";
507         }, ],
508     );
509     is_deeply([ @results ], [ "tape-count", "tapes-needed", "press-enter", "restoring", "eof" ],
510               "ndmp restore follows the correct steps");
511
512     got_files(1, "..and restored file is present in testdir");
513 }
514
515 chdir("$testdir/..");
516 rmtree($testdir);