# Copyright (c) 2010-2012 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
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Contact information: Carbonite Inc., 756 N Pastoria Ave
# Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
use Test::More tests => 11;
use File::Path;
use Data::Dumper;
use strict;
use warnings;
use lib '@amperldir@';
use Installcheck::Run;
use Installcheck::Catalogs;
use Amanda::Config qw( :init :getconf config_dir_relative );
use Amanda::Changer;
use Amanda::Debug;
use Amanda::DB::Catalog;
use Amanda::Recovery::Planner;
use Amanda::MainLoop;
use Amanda::Header;
use Amanda::Xfer qw( :constants );
# disable Debug's die() and warn() overrides
Amanda::Debug::disable_die_override();
# put the debug messages somewhere
Amanda::Debug::dbopen("installcheck");
Installcheck::log_test_output();
my $testconf;
$testconf = Installcheck::Run::setup();
$testconf->write();
# install the 'bigdb' catalog to test against
my $cat = Installcheck::Catalogs::load("bigdb");
$cat->install();
my $cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF');
if ($cfg_result != $CFGERR_OK) {
my ($level, @errors) = Amanda::Config::config_errors();
die(join "\n", @errors);
}
##
## Tests!
###
sub make_plan_sync {
my $plan;
Amanda::Recovery::Planner::make_plan(@_,
labelstr => ".*",
debug => 1,
plan_cb => sub {
(my $err, $plan) = @_;
die "$err" if $err;
Amanda::MainLoop::quit();
});
Amanda::MainLoop::run();
return $plan;
}
sub ds {
return Amanda::Cmdline::dumpspec_t->new($_[0], $_[1], $_[2], $_[3], undef);
}
sub is_plan {
my ($got, $exp, $msg) = @_;
my $got_dumps = $got->{'dumps'};
# make an "abbreviated" version of the plan for comparison with the
# expected
my @got_abbrev;
for my $d (@$got_dumps) {
my @parts;
push @got_abbrev, [
$d->{'hostname'},
$d->{'diskname'},
$d->{'dump_timestamp'},
"$d->{'level'}"+0, # strip bigints
\@parts ];
for my $p (@{$d->{'parts'}}) {
next unless defined $p;
if (exists $p->{'holding_file'}) {
# extract the last two filename components, since the rest is variable
my $hf = $p->{'holding_file'};
$hf =~ s/^.*\/([^\/]*\/[^\/]*)$/$1/;
push @parts, $hf;
} else {
push @parts,
$p->{'label'},
"$p->{filenum}"+0; # strip bigints
}
}
}
is_deeply(\@got_abbrev, $exp, $msg)
or diag("got:\n" . Dumper(\@got_abbrev));
}
is_plan(make_plan_sync(
dumpspec => ds("no-box-at-all")),
[ ],
"empty plan for nonexistent host");
is_plan(make_plan_sync(
dumpspec => ds("oldbox", "^/opt")),
[
[ "oldbox", "/opt", "20080414144444", 0, [
'20080414144444/oldbox._opt',
],
],
],
"simple plan for a dump on holding disk");
is_plan(make_plan_sync(
dumpspec => ds("somebox", "^/lib", "200801")),
[
[ "somebox", "/lib", "20080111000000", 0, [
'Conf-001' => 1,
],
],
],
"simple plan for just one dump");
is_plan(make_plan_sync(
dumpspec => ds("somebox", "^/usr/bin")),
[
[ 'somebox', '/usr/bin', '20080313133333', 1, [
'Conf-003' => 1,
],
],
[ 'somebox', '/usr/bin', '20080515155555', 1, [
'Conf-006' => 1,
]
],
[ 'somebox', '/usr/bin', '20080616166666', 1, [
'Conf-007' => 1,
],
],
],
"plan for three dumps, in order by tape write time");
is_plan(make_plan_sync(
dumpspec => ds("otherbox", "^/lib")),
[
[ "otherbox", "/lib", "20080414144444", 1, [
'20080414144444/otherbox._lib',
],
],
[ 'otherbox', '/lib', '20080313133333', 0, [
'Conf-003' => 14,
],
],
[ "otherbox", "/lib", "20080511151555", 0, [
'Conf-006', 13,
],
],
],
"plan for three dumps, one on holding disk; holding dumps prioritized first");
is_plan(make_plan_sync(
dumpspecs => [
ds("somebox", "^/lib", "20080111"),
ds("somebox", "^/lib", "20080222"),
]),
[
[ "somebox", "/lib", "20080111000000", 0, [
'Conf-001' => 1,
],
],
[ 'somebox', '/lib', '20080222222222', 0, [
'Conf-002' => 1,
'Conf-002' => 2,
],
],
],
"plan for two dumps, one of them spanned, in order by tape write time");
is_plan(make_plan_sync(
dumpspec => ds("somebox", "^/lib", "200803"),
one_dump_per_part => 1),
[
[ "somebox", "/lib", "20080313133333", 0, [
'Conf-003' => 2,
],
],
[ "somebox", "/lib", "20080313133333", 0, [
'Conf-003' => 3,
],
],
[ "somebox", "/lib", "20080313133333", 0, [
'Conf-003' => 4,
],
],
[ "somebox", "/lib", "20080313133333", 0, [
'Conf-003' => 5,
],
],
[ "somebox", "/lib", "20080313133333", 0, [
'Conf-003' => 6,
],
],
[ "somebox", "/lib", "20080313133333", 0, [
'Conf-003' => 7,
],
],
[ "somebox", "/lib", "20080313133333", 0, [
'Conf-003' => 8,
],
],
[ "somebox", "/lib", "20080313133333", 0, [
'Conf-003' => 9,
],
],
[ "somebox", "/lib", "20080313133333", 0, [
'Conf-003' => 10,
],
],
[ "somebox", "/lib", "20080313133333", 0, [
'Conf-003' => 11,
],
],
],
"plan for a multipart dump, one_dump_per_part");
is_plan(make_plan_sync(
dumpspec => ds("oldbox", "^/opt", "20080414144444"),
holding_file => $cat->holding_filename('oldbox_opt_20080414144444_holding')),
[
[ "oldbox", "/opt", "20080414144444", 0, [
'20080414144444/oldbox._opt',
],
],
],
"make_plan creates an appropriate plan for an explicit holding-disk recovery");
is_plan(make_plan_sync(
holding_file => $cat->holding_filename('oldbox_opt_20080414144444_holding')),
[
[ "oldbox", "/opt", "20080414144444", 0, [
'20080414144444/oldbox._opt',
],
],
],
"same, without a dumpspec");
is_plan(make_plan_sync(
dumpspec => ds("somebox", "/lib", "20080515155555"),
filelist => [
'TESTCONF', 'Conf-006', [2, 3, 4, 5, 8, 9, 10, 11],
# (make_plan should fill in files 6 and 7)
]),
[
[ 'somebox', '/lib', '20080515155555', 0, [
'Conf-006' => 2,
'Conf-006' => 3,
'Conf-006' => 4,
'Conf-006' => 5,
'Conf-006' => 6,
'Conf-006' => 7,
'Conf-006' => 8,
'Conf-006' => 9,
'Conf-006' => 10,
'Conf-006' => 11,
],
],
],
"plan based on filelist, with a dumpspec");
is_plan(make_plan_sync(
filelist => [
'TESTCONF', 'Conf-006', [2, 3, 4, 5, 8, 9, 10, 11],
# (make_plan should fill in files 6 and 7)
]),
[
[ 'somebox', '/lib', '20080515155555', 0, [
'Conf-006' => 2,
'Conf-006' => 3,
'Conf-006' => 4,
'Conf-006' => 5,
'Conf-006' => 6,
'Conf-006' => 7,
'Conf-006' => 8,
'Conf-006' => 9,
'Conf-006' => 10,
'Conf-006' => 11,
],
],
],
"plan based on filelist, without a dumpspec");