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