# Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300
# Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
-use Test::More tests => 37;
+use Test::More tests => 46;
use File::Path;
use Data::Dumper;
use strict;
+use warnings;
use lib "@amperldir@";
use Installcheck;
}
SKIP: {
- skip "not built with server", 17 unless Amanda::Util::built_with_component("server");
+ skip "not built with server", 25 unless Amanda::Util::built_with_component("server");
my $disk_cache_dir = "$Installcheck::TMP";
my $RANDOM_SEED = 0xFACADE;
$xfer = Amanda::Xfer->new([
Amanda::Xfer::Source::Random->new(1024*1024, $RANDOM_SEED),
- Amanda::Xfer::Dest::Device->new($device, $device->block_size() * 10),
+ Amanda::Xfer::Dest::Device->new($device, 0),
]);
$xfer->start($quit_cb);
$device = Amanda::Device->new("file:" . Installcheck::Run::load_vtape($vtape_num++));
die("Could not open VFS device: " . $device->error())
unless ($device->status() == $Amanda::Device::DEVICE_STATUS_SUCCESS);
- $device->start($Amanda::Device::ACCESS_WRITE, "TESTCONF01", "20080102030405");
$device->property_set("MAX_VOLUME_USAGE", 1024*1024*2.5);
+ $device->property_set("LEOM", $params{'disable_leom'}? 0 : 1);
+ $device->start($Amanda::Device::ACCESS_WRITE, "TESTCONF01", "20080102030405");
my $dest = $dest_sub->($device);
# and create the xfer
$xfer = Amanda::Xfer->new([ $src, $dest ]);
my $start_new_part = sub {
- my ($successful, $eof, $partnum) = @_;
+ my ($successful, $eof, $partnum, $eom) = @_;
if (exists $params{'cancel_after_partnum'}
and $params{'cancel_after_partnum'} == $partnum) {
return;
}
- if (!$device || !$successful) {
+ if (!$device || $eom) {
# set up a device and start writing a part to it
$device->finish() if $device;
$device = Amanda::Device->new("file:" . Installcheck::Run::load_vtape($vtape_num++));
die("Could not open VFS device: " . $device->error())
unless ($device->status() == $Amanda::Device::DEVICE_STATUS_SUCCESS);
$dest->use_device($device);
- $device->start($Amanda::Device::ACCESS_WRITE, "TESTCONF01", "20080102030405");
+ $device->property_set("LEOM", $params{'disable_leom'}? 0 : 1);
$device->property_set("MAX_VOLUME_USAGE", 1024*1024*2.5);
+ $device->start($Amanda::Device::ACCESS_WRITE, "TESTCONF01", "20080102030405");
}
# bail out if we shouldn't retry this part
die $msg->{'elt'} . " failed: " . $msg->{'message'};
} elsif ($msg->{'type'} == $XMSG_PART_DONE) {
push @messages, "PART-" . $msg->{'partnum'} . '-' . ($msg->{'successful'}? "OK" : "FAILED");
- $start_new_part->($msg->{'successful'}, $msg->{'eof'}, $msg->{'partnum'});
+ push @messages, "EOM" if $msg->{'eom'};
+ $start_new_part->($msg->{'successful'}, $msg->{'eof'}, $msg->{'partnum'}, $msg->{'eom'});
} elsif ($msg->{'type'} == $XMSG_DONE) {
push @messages, "DONE";
Amanda::MainLoop::quit();
return "$holding_base/file0";
}
- # run this test in each of a few different cache permutations
+ # first, test the simpler Splitter class
test_taper_dest(
- Amanda::Xfer::Source::Random->new(1024*1024*4.1, $RANDOM_SEED),
+ Amanda::Xfer::Source::Random->new(1024*1951, $RANDOM_SEED),
+ sub {
+ my ($first_dev) = @_;
+ Amanda::Xfer::Dest::Taper::Splitter->new($first_dev, 128*1024,
+ 520*1024, 0);
+ },
+ [ "PART-1-OK", "PART-2-OK", "PART-3-OK", "PART-4-OK",
+ "DONE" ],
+ "Amanda::Xfer::Dest::Taper::Splitter - simple splitting");
+ test_recovery_source(
+ Amanda::Xfer::Dest::Null->new($RANDOM_SEED),
+ [ 1 => [ 1, 2, 3, 4 ], ],
+ [
+ 'READY',
+ 'PART',
+ 'KB-544',
+ 'PART',
+ 'KB-544',
+ 'PART',
+ 'KB-544',
+ 'PART',
+ 'KB-319',
+ 'DONE'
+ ]);
+
+ test_taper_dest(
+ Amanda::Xfer::Source::Random->new(1024*1024*3.1, $RANDOM_SEED),
+ sub {
+ my ($first_dev) = @_;
+ Amanda::Xfer::Dest::Taper::Splitter->new($first_dev, 128*1024,
+ 1024*1024, 0);
+ },
+ [ "PART-1-OK", "PART-2-OK", "PART-3-OK", "EOM",
+ "PART-4-OK",
+ "DONE" ],
+ "Amanda::Xfer::Dest::Taper::Splitter - splitting and spanning with LEOM");
+ test_recovery_source(
+ Amanda::Xfer::Dest::Null->new($RANDOM_SEED),
+ [ 1 => [ 1, 2, 3 ], 2 => [ 1, ], ],
+ [
+ 'READY',
+ 'PART',
+ 'KB-1024',
+ 'PART',
+ 'KB-1024',
+ 'PART',
+ 'KB-288',
+ 'PART',
+ 'KB-838',
+ 'DONE'
+ ]);
+
+ test_taper_dest(
+ Amanda::Xfer::Source::Random->new(1024*1024*1.5, $RANDOM_SEED),
+ sub {
+ my ($first_dev) = @_;
+ Amanda::Xfer::Dest::Taper::Splitter->new($first_dev, 128*1024,
+ 0, 0);
+ },
+ [ "PART-1-OK",
+ "DONE" ],
+ "Amanda::Xfer::Dest::Taper::Splitter - no splitting");
+ test_recovery_source(
+ Amanda::Xfer::Dest::Null->new($RANDOM_SEED),
+ [ 1 => [ 1, ], ],
+ [
+ 'READY',
+ 'PART',
+ 'KB-1536',
+ 'DONE'
+ ]);
+
+ test_taper_dest(
+ Amanda::Xfer::Source::Random->new(1024*1024*3.1, $RANDOM_SEED),
sub {
my ($first_dev) = @_;
Amanda::Xfer::Dest::Taper::Splitter->new($first_dev, 128*1024,
+ 2368*1024, 0);
+ },
+ [ "PART-1-OK", "PART-2-OK", "EOM",
+ "PART-3-OK",
+ "DONE" ],
+ "Amanda::Xfer::Dest::Taper::Splitter - LEOM hits in file 2 header");
+ test_recovery_source(
+ Amanda::Xfer::Dest::Null->new($RANDOM_SEED),
+ [ 1 => [ 1, 2 ], 2 => [ 1, ], ],
+ [
+ 'READY',
+ 'PART',
+ 'KB-2368',
+ 'PART',
+ 'KB-0', # this wouldn't be in the catalog, but it's on the vtape
+ 'PART',
+ 'KB-806',
+ 'DONE'
+ ]);
+
+ test_taper_dest(
+ Amanda::Xfer::Source::Random->new(1024*1024*3.1, $RANDOM_SEED),
+ sub {
+ my ($first_dev) = @_;
+ Amanda::Xfer::Dest::Taper::Splitter->new($first_dev, 128*1024,
+ 2368*1024, 0);
+ },
+ [ "PART-1-OK", "PART-2-FAILED", "EOM",
+ "NOT-RETRYING", "CANCELLED", "DONE" ],
+ "Amanda::Xfer::Dest::Taper::Splitter - LEOM fails, PEOM => failure",
+ disable_leom => 1, do_not_retry => 1);
+
+ # run A::X::Dest::Taper::Cacher test in each of a few different cache permutations
+ test_taper_dest(
+ Amanda::Xfer::Source::Random->new(1024*1024*4.1, $RANDOM_SEED),
+ sub {
+ my ($first_dev) = @_;
+ Amanda::Xfer::Dest::Taper::Cacher->new($first_dev, 128*1024,
1024*1024, 1, undef),
},
- [ "PART-1-OK", "PART-2-OK", "PART-3-FAILED",
+ [ "PART-1-OK", "PART-2-OK", "PART-3-FAILED", "EOM",
"PART-3-OK", "PART-4-OK", "PART-5-OK",
"DONE" ],
- "mem cache");
+ "Amanda::Xfer::Dest::Taper::Cacher - mem cache");
test_recovery_source(
Amanda::Xfer::Dest::Null->new($RANDOM_SEED),
[ 1 => [ 1, 2 ], 2 => [ 1, 2, 3 ], ],
Amanda::Xfer::Source::Random->new(1024*1024*4.1, $RANDOM_SEED),
sub {
my ($first_dev) = @_;
- Amanda::Xfer::Dest::Taper::Splitter->new($first_dev, 128*1024,
+ Amanda::Xfer::Dest::Taper::Cacher->new($first_dev, 128*1024,
1024*1024, 0, $disk_cache_dir),
},
- [ "PART-1-OK", "PART-2-OK", "PART-3-FAILED",
+ [ "PART-1-OK", "PART-2-OK", "PART-3-FAILED", "EOM",
"PART-3-OK", "PART-4-OK", "PART-5-OK",
"DONE" ],
- "disk cache");
+ "Amanda::Xfer::Dest::Taper::Cacher - disk cache");
test_recovery_source(
Amanda::Xfer::Dest::Null->new($RANDOM_SEED),
[ 1 => [ 1, 2 ], 2 => [ 1, 2, 3 ], ],
Amanda::Xfer::Source::Random->new(1024*1024*2, $RANDOM_SEED),
sub {
my ($first_dev) = @_;
- Amanda::Xfer::Dest::Taper::Splitter->new($first_dev, 128*1024,
+ Amanda::Xfer::Dest::Taper::Cacher->new($first_dev, 128*1024,
1024*1024, 0, undef),
},
[ "PART-1-OK", "PART-2-OK", "PART-3-OK",
"DONE" ],
- "no cache (no failed parts; exact multiple of part size)");
+ "Amanda::Xfer::Dest::Taper::Cacher - no cache (no failed parts; exact multiple of part size)");
test_recovery_source(
Amanda::Xfer::Dest::Null->new($RANDOM_SEED),
[ 1 => [ 1, 2, 3 ], ],
Amanda::Xfer::Source::Random->new(1024*1024*2, $RANDOM_SEED),
sub {
my ($first_dev) = @_;
- Amanda::Xfer::Dest::Taper::Splitter->new($first_dev, 128*1024, 0, 0, undef),
+ Amanda::Xfer::Dest::Taper::Cacher->new($first_dev, 128*1024, 0, 0, undef),
},
[ "PART-1-OK", "DONE" ],
- "no splitting (fits on volume)");
+ "Amanda::Xfer::Dest::Taper::Cacher - no splitting (fits on volume)");
test_recovery_source(
Amanda::Xfer::Dest::Null->new($RANDOM_SEED),
[ 1 => [ 1 ], ],
Amanda::Xfer::Source::Random->new(1024*1024*4.1, $RANDOM_SEED),
sub {
my ($first_dev) = @_;
- Amanda::Xfer::Dest::Taper::Splitter->new($first_dev, 128*1024, 0, 0, undef),
+ Amanda::Xfer::Dest::Taper::Cacher->new($first_dev, 128*1024, 0, 0, undef),
},
- [ "PART-1-FAILED", "NOT-RETRYING", "CANCELLED", "DONE" ],
- "no splitting (doesn't fit on volume -> fails)",
+ [ "PART-1-FAILED", "EOM",
+ "NOT-RETRYING", "CANCELLED", "DONE" ],
+ "Amanda::Xfer::Dest::Taper::Cacher - no splitting (doesn't fit on volume -> fails)",
do_not_retry => 1);
test_taper_dest(
Amanda::Xfer::Source::Random->new(1024*1024*4.1, $RANDOM_SEED),
sub {
my ($first_dev) = @_;
- Amanda::Xfer::Dest::Taper::Splitter->new($first_dev, 128*1024,
+ Amanda::Xfer::Dest::Taper::Cacher->new($first_dev, 128*1024,
1024*1024, 0, $disk_cache_dir),
},
- [ "PART-1-OK", "PART-2-OK", "PART-3-FAILED",
+ [ "PART-1-OK", "PART-2-OK", "PART-3-FAILED", "EOM",
"PART-3-OK", "PART-4-OK", "CANCEL",
"CANCELLED", "DONE" ],
- "cancellation after success",
+ "Amanda::Xfer::Dest::Taper::Cacher - cancellation after success",
cancel_after_partnum => 4);
# set up a few holding chunks and read from those
+
$holding_file = make_holding_files(3);
+
test_taper_dest(
Amanda::Xfer::Source::Holding->new($holding_file),
sub {
my ($first_dev) = @_;
Amanda::Xfer::Dest::Taper::Splitter->new($first_dev, 128*1024,
- 1024*1024, 0, undef),
+ 1024*1024, 1);
},
- [ "PART-1-OK", "PART-2-OK", "PART-3-FAILED",
- "PART-3-OK", "PART-4-OK", "PART-5-FAILED",
+ [ "PART-1-OK", "PART-2-OK", "PART-3-FAILED", "EOM",
+ "PART-3-OK", "PART-4-OK", "PART-5-FAILED", "EOM",
"PART-5-OK", "PART-6-OK", "PART-7-OK",
"DONE" ],
- "Amanda::Xfer::Source::Holding acts as a source and supplies cache_inform");
+ "Amanda::Xfer::Dest::Taper::Splitter - Amanda::Xfer::Source::Holding "
+ . "acts as a source and supplies cache_inform",
+ disable_leom => 1);
##
# test the cache_inform method
- sub test_taper_dest_cache_inform {
+ sub test_taper_dest_splitter_cache_inform {
my %params = @_;
my $xfer;
my $device;
# create a list of holding chuunks, some slab-aligned, some part-aligned,
# some not
my @holding_chunks;
- if (!$params{'omit_chunks'}) {
- my $offset = 0;
- my $do_chunk = sub {
- my ($break) = @_;
- die unless $break > $offset;
- push @holding_chunks, [ $cache_file, $offset, $break - $offset ];
- $offset = $break;
- };
- $do_chunk->(277);
- $do_chunk->($part_size);
- $do_chunk->($part_size+128*1024);
- $do_chunk->($part_size*3);
- $do_chunk->($part_size*3+1024);
- $do_chunk->($part_size*3+1024*2);
- $do_chunk->($part_size*3+1024*3);
- $do_chunk->($part_size*4);
- $do_chunk->($part_size*4 + 77);
- $do_chunk->($file_size - 1);
- $do_chunk->($file_size);
- }
+ my $offset = 0;
+ my $do_chunk = sub {
+ my ($break) = @_;
+ die unless $break > $offset;
+ push @holding_chunks, [ $cache_file, $offset, $break - $offset ];
+ $offset = $break;
+ };
+ $do_chunk->(277);
+ $do_chunk->($part_size);
+ $do_chunk->($part_size+128*1024);
+ $do_chunk->($part_size*3);
+ $do_chunk->($part_size*3+1024);
+ $do_chunk->($part_size*3+1024*2);
+ $do_chunk->($part_size*3+1024*3);
+ $do_chunk->($part_size*4);
+ $do_chunk->($part_size*4 + 77);
+ $do_chunk->($file_size - 1);
+ $do_chunk->($file_size);
# set up vtapes
my $testconf = Installcheck::Run::setup();
$device = Amanda::Device->new("file:" . Installcheck::Run::load_vtape($vtape_num++));
die("Could not open VFS device: " . $device->error())
unless ($device->status() == $Amanda::Device::DEVICE_STATUS_SUCCESS);
- $device->start($Amanda::Device::ACCESS_WRITE, "TESTCONF01", "20080102030405");
$device->property_set("MAX_VOLUME_USAGE", 1024*1024*2.5);
+ $device->property_set("LEOM", 0);
+ $device->start($Amanda::Device::ACCESS_WRITE, "TESTCONF01", "20080102030405");
my $dest = Amanda::Xfer::Dest::Taper::Splitter->new($device, 128*1024,
- 1024*1024, 0, undef);
+ 1024*1024, 1);
$xfer = Amanda::Xfer->new([
Amanda::Xfer::Source::Fd->new(fileno($fh)),
$dest,
die("Could not open VFS device: " . $device->error())
unless ($device->status() == $Amanda::Device::DEVICE_STATUS_SUCCESS);
$dest->use_device($device);
- $device->start($Amanda::Device::ACCESS_WRITE, "TESTCONF01", "20080102030405");
+ $device->property_set("LEOM", 0);
$device->property_set("MAX_VOLUME_USAGE", 1024*1024*2.5);
+ $device->start($Amanda::Device::ACCESS_WRITE, "TESTCONF01", "20080102030405");
}
# feed enough chunks to cache_inform
return @messages;
}
- is_deeply([ test_taper_dest_cache_inform() ],
+ is_deeply([ test_taper_dest_splitter_cache_inform() ],
[ "PART-OK", "PART-OK", "PART-FAILED",
"PART-OK", "PART-OK", "PART-OK",
"DONE" ],
- "cache_inform: element produces the correct series of messages");
-
- is_deeply([ test_taper_dest_cache_inform(omit_chunks => 1) ],
- [ "PART-OK", "PART-OK", "PART-FAILED",
- "ERROR: Failed part was not cached; cannot retry", "CANCELLED",
- "DONE" ],
- "cache_inform: element produces the correct series of messages when a chunk is missing");
+ "cache_inform: splitter element produces the correct series of messages");
rmtree($holding_base);
}
# and create the xfer
my $src = Amanda::Xfer::Source::Random->new(32768*34-7, $RANDOM_SEED);
- my $dest = Amanda::Xfer::Dest::Taper::DirectTCP->new($dev, 32768*16);
+ # note we ask for slightly less than 15 blocks; the dest should round up
+ my $dest = Amanda::Xfer::Dest::Taper::DirectTCP->new($dev, 32768*16-99);
$xfer = Amanda::Xfer->new([ $src, $dest ]);
my $start_new_part; # forward declaration
pass("Three xfers interlinked via DirectTCP complete successfully");
}
+# try cancelling a DirectTCP xfer while it's waiting in accept()
+{
+ my $xfer_src = Amanda::Xfer::Source::DirectTCPListen->new();
+ my $xfer_dst = Amanda::Xfer::Dest::Null->new(0);
+ my $xfer = Amanda::Xfer->new([ $xfer_src, $xfer_dst ]);
+
+ # start up the transfer, which starts a thread which will accept
+ # soon after that.
+ $xfer->start(sub {
+ my ($src, $msg, $xfer) = @_;
+ if ($msg->{'type'} == $XMSG_DONE) {
+ Amanda::MainLoop::quit();
+ }
+ });
+
+ sleep(1);
+
+ # Now, ideally we'd wait until the accept() is running, maybe testing it
+ # with a SYN or something like that. This is not terribly critical,
+ # because the element glue does not check for cancellation before it begins
+ # accepting.
+ $xfer->cancel();
+
+ Amanda::MainLoop::run();
+ pass("A DirectTCP accept operation can be cancelled");
+}
+
# test element comparison
{
my $a = Amanda::Xfer::Filter::Xor->new(0);