1 # Copyright (c) 2009, 2010 Zmanda Inc. All Rights Reserved.
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.
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
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
16 # Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300
17 # Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
19 use Test::More tests => 29;
25 use lib "@amperldir@";
26 use Installcheck::Config;
27 use Amanda::Config qw( :init );
29 use Amanda::Device qw( :constants );
33 use Amanda::Taper::Scribe qw( get_splitting_args_from_config );
36 # and disable Debug's die() and warn() overrides
37 Amanda::Debug::disable_die_override();
39 # put the debug messages somewhere
40 Amanda::Debug::dbopen("installcheck");
41 Installcheck::log_test_output();
43 # use some very small vtapes
44 my $volume_length = 512*1024;
47 $testconf = Installcheck::Config->new();
48 $testconf->add_tapetype("TEST-TAPE", [
49 "length" => ($volume_length / 1024) . " k",
53 my $cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF');
54 if ($cfg_result != $CFGERR_OK) {
55 my ($level, @errors) = Amanda::Config::config_errors();
56 die(join "\n", @errors);
59 my $taperoot = "$Installcheck::TMP/Amanda_Taper_Scribe";
69 for my $slot (1 .. $nslots) {
70 mkdir("$taperoot/slot$slot")
71 or die("Could not mkdir: $!");
75 # an accumulator for the sequence of events that transpire during a run
88 Math::BigInt->new($_[0]);
91 # and similarly an Amanda::Changer::Error
93 Amanda::Changer::Error->new(@_);
97 ## Mock classes for the scribe
100 package Mock::Taperscan;
101 use Amanda::Device qw( :constants );
102 use Amanda::MainLoop;
107 my @slots = @{ $params{'slots'} || [] };
108 my $chg = Amanda::Changer->new("chg-disk:$taperoot");
109 die $chg if $chg->isa("Amanda::Changer::Error");
111 # wedge in an extra device property to disable LEOM support, if requested
112 if ($params{'disable_leom'}) {
113 $chg->{'config'}->{'device_properties'}->{'leom'}->{'values'} = [ 0 ];
115 $chg->{'config'}->{'device_properties'}->{'leom'}->{'values'} = [ 1 ];
121 next_or_current => "current",
125 sub make_new_tape_label {
132 my $result_cb = $params{'result_cb'};
136 my @slotarg = (@{$self->{'slots'}})?
137 (slot => shift @{$self->{'slots'}})
138 : (relative_slot => $self->{'next_or_current'});
139 $self->{'next_or_current'} = 'next';
141 my $res_cb = make_cb('res_cb' => sub {
142 my ($err, $res) = @_;
144 my $slot = $res? $res->{'this_slot'} : "none";
145 main::event("scan-finished", main::undef_or_str($err), "slot: $slot");
150 $result_cb->(undef, $res, 'FAKELABEL', $ACCESS_WRITE);
154 # delay this load call a little bit -- just enough so that the
155 # request_volume_permission event reliably occurs first
156 Amanda::MainLoop::call_after(50, sub {
157 $self->{'chg'}->load(@slotarg, set_current => 1, res_cb => $res_cb);
161 package Mock::Feedback;
162 use base qw( Amanda::Taper::Scribe::Feedback );
165 use Installcheck::Config;
171 rq_answers => [ @rq_answers ],
175 sub request_volume_permission {
178 my $answer = shift @{$self->{'rq_answers'}};
179 main::event("request_volume_permission", "answer:", $answer);
180 $main::scribe->start_scan();
181 $params{'perm_cb'}->(%{$answer});
184 sub scribe_notif_new_tape {
188 main::event("scribe_notif_new_tape",
189 main::undef_or_str($params{'error'}), $params{'volume_label'});
192 sub scribe_notif_part_done {
196 # this omits $duration, as it's not constant
197 main::event("scribe_notif_part_done",
198 $params{'partnum'}, $params{'fileno'},
199 $params{'successful'}, $params{'size'});
202 sub scribe_notif_tape_done {
206 main::event("scribe_notif_tape_done",
207 $params{'volume_label'}, $params{'num_files'},
220 # utility fn to stringify changer errors (earlier perls' Test::More's
221 # fail to do this automatically)
222 sub undef_or_str { (defined $_[0])? "".$_[0] : undef; }
225 my ($nruns, $taperscan, $feedback) = @_;
229 reset_taperoot($nruns);
230 $main::scribe = Amanda::Taper::Scribe->new(
231 taperscan => $taperscan,
232 feedback => $feedback);
233 $devh = $main::scribe->{'devhandling'};
235 my ($start, $get_volume, $got_volume, $quit);
237 $start = make_cb(start => sub {
241 # give start() time to get the scan going before
242 # calling get_volume -- this wouldn't ordinarily be
243 # necessary, but we want to make sure that start() is
244 # really kicking off the scan.
249 $get_volume = make_cb(get_volume => sub {
250 if (++$runcount > $nruns) {
256 $devh->get_volume(volume_cb => $got_volume);
259 $got_volume = make_cb(got_volume => sub {
260 my ($scan_error, $config_denial_message, $error_denial_message,
261 $reservation, $volume_label, $access_mode) = @_;
264 undef_or_str($scan_error),
265 $config_denial_message, $error_denial_message,
266 $reservation? ("slot: ".$reservation->{'this_slot'}) : undef);
268 if ($scan_error or $config_denial_message or $error_denial_message) {
273 $reservation->release(finished_cb => sub {
275 event("release", $error);
284 $quit = make_cb(quit => sub {
286 Amanda::MainLoop::quit();
290 Amanda::MainLoop::run();
294 run_devh(3, Mock::Taperscan->new(), Mock::Feedback->new({allow => 1}, {allow => 1}, {allow => 1}));
295 is_deeply([ @events ], [
297 [ 'scan' ], # scan starts *before* get_volume
300 [ 'request_volume_permission', 'answer:', { allow => 1 }, ],
301 [ 'scan-finished', undef, "slot: 1" ],
302 [ 'got_volume', undef, undef, undef, "slot: 1" ],
303 [ 'release', undef ],
306 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
307 [ 'scan' ], # scan starts *after* request_volume_permission
308 [ 'scan-finished', undef, "slot: 2" ],
309 [ 'got_volume', undef, undef, undef, "slot: 2" ],
310 [ 'release', undef ],
313 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
315 [ 'scan-finished', undef, "slot: 3" ],
316 [ 'got_volume', undef, undef, undef, "slot: 3" ],
317 [ 'release', undef ],
320 ], "correct event sequence for basic run of DevHandling")
321 or diag(Dumper([@events]));
323 run_devh(1, Mock::Taperscan->new(), Mock::Feedback->new({cause => 'config', message => 'no-can-do'}));
324 is_deeply([ @events ], [
329 [ 'request_volume_permission', 'answer:', { cause => 'config', message => 'no-can-do' } ],
330 [ 'scan-finished', undef, "slot: 1" ],
331 [ 'got_volume', undef, 'no-can-do', undef, undef ],
334 ], "correct event sequence for a run without permission")
335 or diag(Dumper([@events]));
337 run_devh(1, Mock::Taperscan->new(slots => ["bogus"]), Mock::Feedback->new({allow => 1}));
338 is_deeply([ @events ], [
343 [ 'request_volume_permission', 'answer:', { allow => 1} ],
344 [ 'scan-finished', "Slot bogus not found", "slot: none" ],
345 [ 'got_volume', 'Slot bogus not found', undef, undef, undef ],
348 ], "correct event sequence for a run with a changer error")
349 or diag(Dumper([@events]));
351 run_devh(1, Mock::Taperscan->new(slots => ["bogus"]),
352 Mock::Feedback->new({cause => 'config', message => "not this time"}));
353 is_deeply([ @events ], [
358 [ 'request_volume_permission', 'answer:', {cause => 'config', message =>'not this time'} ],
359 [ 'scan-finished', "Slot bogus not found", "slot: none" ],
360 [ 'got_volume', 'Slot bogus not found', 'not this time', undef, undef ],
363 ], "correct event sequence for a run with no permission AND a changer config denial")
364 or diag(Dumper([@events]));
366 run_devh(1, Mock::Taperscan->new(slots => ["bogus"]), Mock::Feedback->new({cause => 'error', message => "frobnicator exploded!"}));
367 is_deeply([ @events ], [
372 [ 'request_volume_permission', 'answer:', {cause => 'error', message => "frobnicator exploded!"} ],
373 [ 'scan-finished', "Slot bogus not found", "slot: none" ],
374 [ 'got_volume', 'Slot bogus not found', undef, "frobnicator exploded!", undef ],
377 ], "correct event sequence for a run with no permission AND a changer error")
378 or diag(Dumper([@events]));
384 sub run_scribe_xfer_async {
385 my ($data_length, $scribe, %params) = @_;
388 my $finished_cb = $params{'finished_cb'};
389 my $steps = define_steps
390 cb_ref => \$finished_cb;
392 step start_scribe => sub {
393 if ($params{'start_scribe'}) {
394 $scribe->start(%{ $params{'start_scribe'} },
395 finished_cb => $steps->{'get_xdt'});
397 $steps->{'get_xdt'}->();
401 step get_xdt => sub {
406 my $xdt = $scribe->get_xfer_dest(
407 max_memory => 1024 * 64,
408 part_size => (defined $params{'part_size'})? $params{'part_size'} : (1024 * 128),
409 part_cache_type => $params{'part_cache_type'} || 'memory',
410 disk_cache_dirname => undef);
414 my $hdr = Amanda::Header->new();
415 $hdr->{type} = $Amanda::Header::F_DUMPFILE;
416 $hdr->{datestamp} = "20010203040506";
417 $hdr->{dumplevel} = 0;
418 $hdr->{compressed} = 1;
419 $hdr->{name} = "localhost";
420 $hdr->{disk} = "/home";
421 $hdr->{program} = "INSTALLCHECK";
423 $xfer = Amanda::Xfer->new([
424 Amanda::Xfer::Source::Random->new($data_length, 0x5EED5),
429 $scribe->handle_xmsg(@_);
435 dump_cb => $steps->{'dump_cb'});
438 step dump_cb => sub {
441 main::event("dump_cb",
443 [ map { "$_" } @{$params{'device_errors'}} ],
444 $params{'config_denial_message'},
451 sub run_scribe_xfer {
452 my ($data_length, $scribe, %params) = @_;
453 $params{'finished_cb'} = \&Amanda::MainLoop::quit;
454 run_scribe_xfer_async($data_length, $scribe, %params);
455 Amanda::MainLoop::run();
461 my $finished_cb = make_cb(finished_cb => sub {
463 die "$error" if $error;
465 Amanda::MainLoop::quit();
468 $scribe->quit(finished_cb => $finished_cb);
470 Amanda::MainLoop::run();
475 # write less than a tape full, without LEOM
478 $main::scribe = Amanda::Taper::Scribe->new(
479 taperscan => Mock::Taperscan->new(disable_leom => 1),
480 feedback => Mock::Feedback->new({allow => 1}));
483 run_scribe_xfer(1024*200, $main::scribe,
484 part_size => 96*1024,
485 start_scribe => { write_timestamp => "20010203040506" });
487 is_deeply([ @events ], [
489 [ 'scan-finished', undef, 'slot: 1' ],
490 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
491 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
492 [ 'scribe_notif_part_done', bi(1), bi(1), 1, bi(98304) ],
493 [ 'scribe_notif_part_done', bi(2), bi(2), 1, bi(98304) ],
494 [ 'scribe_notif_part_done', bi(3), bi(3), 1, bi(8192) ],
495 [ 'dump_cb', 'DONE', [], undef, bi(204800) ],
496 ], "correct event sequence for a multipart scribe of less than a whole volume, without LEOM")
497 or diag(Dumper([@events]));
499 # pick up where we left off, writing just a tiny bit more, and then quit
501 run_scribe_xfer(1024*30, $main::scribe);
503 quit_scribe($main::scribe);
505 is_deeply([ @events ], [
506 [ 'scribe_notif_part_done', bi(1), bi(4), 1, bi(30720) ],
507 [ 'dump_cb', 'DONE', [], undef, bi(30720) ],
508 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(4), bi(235520) ],
509 ], "correct event sequence for a subsequent single-part scribe, still on the same volume")
510 or diag(Dumper([@events]));
512 # write less than a tape full, *with* LEOM (should look the same as above)
515 $main::scribe = Amanda::Taper::Scribe->new(
516 taperscan => Mock::Taperscan->new(),
517 feedback => Mock::Feedback->new({ allow => 1 }));
520 run_scribe_xfer(1024*200, $main::scribe,
521 part_size => 96*1024,
522 start_scribe => { write_timestamp => "20010203040506" });
524 quit_scribe($main::scribe);
526 is_deeply([ @events ], [
528 [ 'scan-finished', undef, 'slot: 1' ],
529 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
530 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
531 [ 'scribe_notif_part_done', bi(1), bi(1), 1, bi(98304) ],
532 [ 'scribe_notif_part_done', bi(2), bi(2), 1, bi(98304) ],
533 [ 'scribe_notif_part_done', bi(3), bi(3), 1, bi(8192) ],
534 [ 'dump_cb', 'DONE', [], undef, bi(204800) ],
535 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(3), bi(204800) ],
536 ], "correct event sequence for a multipart scribe of less than a whole volume, with LEOM")
537 or diag(Dumper([@events]));
539 # start over again and try a multivolume write
541 # NOTE: the part size and volume size are such that the VFS driver produces
542 # ENOSPC while writing the fourth file header, rather than while writing
543 # data. This is a much less common error path, so it's good to test it.
546 $main::scribe = Amanda::Taper::Scribe->new(
547 taperscan => Mock::Taperscan->new(disable_leom => 1),
548 feedback => Mock::Feedback->new({ allow => 1 }, { allow => 1 }));
551 run_scribe_xfer($volume_length + $volume_length / 4, $main::scribe,
552 start_scribe => { write_timestamp => "20010203040506" });
554 quit_scribe($main::scribe);
556 is_deeply([ @events ], [
558 [ 'scan-finished', undef, 'slot: 1' ],
559 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
560 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
562 [ 'scribe_notif_part_done', bi(1), bi(1), 1, bi(131072) ],
563 [ 'scribe_notif_part_done', bi(2), bi(2), 1, bi(131072) ],
564 [ 'scribe_notif_part_done', bi(3), bi(3), 1, bi(131072) ],
565 [ 'scribe_notif_part_done', bi(4), bi(0), 0, bi(0) ],
567 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(3), bi(393216) ],
568 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
570 [ 'scan-finished', undef, 'slot: 2' ],
571 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
573 [ 'scribe_notif_part_done', bi(4), bi(1), 1, bi(131072) ],
574 [ 'scribe_notif_part_done', bi(5), bi(2), 1, bi(131072) ],
575 # empty part is written but not notified, although it is counted
576 # in scribe_notif_tape_done
578 [ 'dump_cb', 'DONE', [], undef, bi(655360) ],
579 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(3), bi(262144) ],
580 ], "correct event sequence for a multipart scribe of more than a whole volume, without LEOM")
581 or print (Dumper([@events]));
583 # same test, but with LEOM support
586 $main::scribe = Amanda::Taper::Scribe->new(
587 taperscan => Mock::Taperscan->new(),
588 feedback => Mock::Feedback->new({ allow => 1 },{ allow => 1 }));
591 run_scribe_xfer(1024*520, $main::scribe,
592 start_scribe => { write_timestamp => "20010203040506" });
594 quit_scribe($main::scribe);
596 is_deeply([ @events ], [
598 [ 'scan-finished', undef, 'slot: 1' ],
599 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
600 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
602 [ 'scribe_notif_part_done', bi(1), bi(1), 1, bi(131072) ],
603 [ 'scribe_notif_part_done', bi(2), bi(2), 1, bi(131072) ],
604 [ 'scribe_notif_part_done', bi(3), bi(3), 1, bi(32768) ], # LEOM comes earlier than PEOM did
606 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(3), bi(294912) ],
607 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
609 [ 'scan-finished', undef, 'slot: 2' ],
610 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
612 [ 'scribe_notif_part_done', bi(4), bi(1), 1, bi(131072) ],
613 [ 'scribe_notif_part_done', bi(5), bi(2), 1, bi(106496) ],
615 [ 'dump_cb', 'DONE', [], undef, bi(532480) ],
616 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(2), bi(237568) ],
617 ], "correct event sequence for a multipart scribe of more than a whole volume, with LEOM")
618 or print (Dumper([@events]));
620 # now a multivolume write where the second volume gives a changer error
623 $main::scribe = Amanda::Taper::Scribe->new(
624 taperscan => Mock::Taperscan->new(slots => ["1", "bogus"], disable_leom => 1),
625 feedback => Mock::Feedback->new({ allow => 1 },{ allow => 1 }));
628 run_scribe_xfer($volume_length + $volume_length / 4, $main::scribe,
629 start_scribe => { write_timestamp => "20010203040507" });
631 quit_scribe($main::scribe);
633 $experr = 'Slot bogus not found';
634 is_deeply([ @events ], [
636 [ 'scan-finished', undef, 'slot: 1' ],
637 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
638 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
640 [ 'scribe_notif_part_done', bi(1), bi(1), 1, bi(131072) ],
641 [ 'scribe_notif_part_done', bi(2), bi(2), 1, bi(131072) ],
642 [ 'scribe_notif_part_done', bi(3), bi(3), 1, bi(131072) ],
643 [ 'scribe_notif_part_done', bi(4), bi(0), 0, bi(0) ],
645 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(3), bi(393216) ],
646 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
648 [ 'scan-finished', $experr, 'slot: none' ],
649 [ 'scribe_notif_new_tape', $experr, undef ],
651 [ 'dump_cb', 'PARTIAL', [$experr], undef, bi(393216) ],
652 # (no scribe_notif_tape_done)
653 ], "correct event sequence for a multivolume scribe with no second vol, without LEOM")
654 or print (Dumper([@events]));
657 $main::scribe = Amanda::Taper::Scribe->new(
658 taperscan => Mock::Taperscan->new(slots => ["1", "bogus"]),
659 feedback => Mock::Feedback->new({ allow => 1 }, { allow => 1 }));
662 run_scribe_xfer($volume_length + $volume_length / 4, $main::scribe,
663 start_scribe => { write_timestamp => "20010203040507" });
665 quit_scribe($main::scribe);
667 $experr = 'Slot bogus not found';
668 is_deeply([ @events ], [
670 [ 'scan-finished', undef, 'slot: 1' ],
671 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
672 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
674 [ 'scribe_notif_part_done', bi(1), bi(1), 1, bi(131072) ],
675 [ 'scribe_notif_part_done', bi(2), bi(2), 1, bi(131072) ],
676 [ 'scribe_notif_part_done', bi(3), bi(3), 1, bi(32768) ], # LEOM comes long before PEOM
678 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(3), bi(294912) ],
679 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
681 [ 'scan-finished', $experr, 'slot: none' ],
682 [ 'scribe_notif_new_tape', $experr, undef ],
684 [ 'dump_cb', 'PARTIAL', [$experr], undef, bi(294912) ],
685 # (no scribe_notif_tape_done)
686 ], "correct event sequence for a multivolume scribe with no second vol, with LEOM")
687 or print (Dumper([@events]));
689 # now a multivolume write where the second volume does not have permission
692 $main::scribe = Amanda::Taper::Scribe->new(
693 taperscan => Mock::Taperscan->new(),
694 feedback => Mock::Feedback->new({ allow => 1 }, { cause => 'config', message => "sorry!" }));
697 run_scribe_xfer($volume_length + $volume_length / 4, $main::scribe,
698 start_scribe => { write_timestamp => "20010203040507" });
700 quit_scribe($main::scribe);
702 is_deeply([ @events ], [
704 [ 'scan-finished', undef, 'slot: 1' ],
705 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
706 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
708 [ 'scribe_notif_part_done', bi(1), bi(1), 1, bi(131072) ],
709 [ 'scribe_notif_part_done', bi(2), bi(2), 1, bi(131072) ],
710 [ 'scribe_notif_part_done', bi(3), bi(3), 1, bi(32768) ],
712 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(3), bi(294912) ],
713 [ 'request_volume_permission', 'answer:', { cause => 'config', message => "sorry!" } ],
715 [ 'scan-finished', undef, 'slot: 2' ],
717 [ 'dump_cb', 'PARTIAL', [], "sorry!", bi(294912) ],
718 ], "correct event sequence for a multivolume scribe with next vol denied")
719 or print (Dumper([@events]));
721 # a non-splitting xfer on a single volume
724 $main::scribe = Amanda::Taper::Scribe->new(
725 taperscan => Mock::Taperscan->new(disable_leom => 1),
726 feedback => Mock::Feedback->new({ allow => 1 }));
729 run_scribe_xfer(1024*300, $main::scribe, part_size => 0, part_cache_type => 'none',
730 start_scribe => { write_timestamp => "20010203040506" });
732 quit_scribe($main::scribe);
734 is_deeply([ @events ], [
736 [ 'scan-finished', undef, 'slot: 1' ],
737 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
738 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
739 [ 'scribe_notif_part_done', bi(1), bi(1), 1, bi(307200) ],
740 [ 'dump_cb', 'DONE', [], undef, bi(307200) ],
741 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(1), bi(307200) ],
742 ], "correct event sequence for a non-splitting scribe of less than a whole volume, without LEOM")
743 or diag(Dumper([@events]));
746 $main::scribe = Amanda::Taper::Scribe->new(
747 taperscan => Mock::Taperscan->new(),
748 feedback => Mock::Feedback->new({ allow => 1 }));
749 $Amanda::Config::debug_taper = 9;
751 run_scribe_xfer(1024*300, $main::scribe, part_size => 0, part_cache_type => 'none',
752 start_scribe => { write_timestamp => "20010203040506" });
754 quit_scribe($main::scribe);
756 is_deeply([ @events ], [
758 [ 'scan-finished', undef, 'slot: 1' ],
759 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
760 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
761 [ 'scribe_notif_part_done', bi(1), bi(1), 1, bi(307200) ],
762 [ 'dump_cb', 'DONE', [], undef, bi(307200) ],
763 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(1), bi(307200) ],
764 ], "correct event sequence for a non-splitting scribe of less than a whole volume, with LEOM")
765 or diag(Dumper([@events]));
767 # DirectTCP support is tested through the taper installcheck
769 # test get_splitting_args_from_config thoroughly
770 my $maxint64 = Math::BigInt->new("9223372036854775808");
773 { get_splitting_args_from_config(
776 "default is no params");
779 { get_splitting_args_from_config(
780 dle_tape_splitsize => 0,
781 dle_split_diskbuffer => $Installcheck::TMP,
782 dle_fallback_splitsize => 100,
784 { part_size => 0, part_cache_type => 'none' },
785 "tape_splitsize = 0 indicates no splitting");
788 { get_splitting_args_from_config(
789 dle_allow_split => 0,
791 part_cache_dir => "/tmp",
794 "default if dle_allow_split is false, no splitting");
797 { get_splitting_args_from_config(
798 dle_tape_splitsize => 200,
799 dle_fallback_splitsize => 150,
801 { part_cache_type => 'memory', part_size => 200, part_cache_max_size => 150 },
802 "when cache_inform is available, tape_splitsize is used, not fallback");
805 { get_splitting_args_from_config(
806 dle_tape_splitsize => 200,
808 { part_size => 200, part_cache_type => 'memory', part_cache_max_size => 1024*1024*10, },
809 "no split_diskbuffer and no fallback_splitsize, fall back to default (10M)");
812 { get_splitting_args_from_config(
813 dle_tape_splitsize => 200,
814 dle_split_diskbuffer => "$Installcheck::TMP/does!not!exist!",
815 dle_fallback_splitsize => 150,
817 { part_size => 200, part_cache_type => 'memory', part_cache_max_size => 150 },
818 "invalid split_diskbuffer => fall back (silently)");
821 { get_splitting_args_from_config(
822 dle_tape_splitsize => 200,
823 dle_split_diskbuffer => "$Installcheck::TMP/does!not!exist!",
825 { part_size => 200, part_cache_type => 'memory', part_cache_max_size => 1024*1024*10 },
826 ".. even to the default fallback (10M)");
829 { get_splitting_args_from_config(
830 dle_tape_splitsize => $maxint64,
831 dle_split_diskbuffer => "$Installcheck::TMP",
832 dle_fallback_splitsize => 250,
834 { part_size => $maxint64, part_cache_type => 'memory', part_cache_max_size => 250,
835 warning => "falling back to memory buffer for splitting: " .
836 "insufficient space in disk cache directory" },
837 "not enough space in split_diskbuffer => fall back (with warning)");
840 { get_splitting_args_from_config(
841 can_cache_inform => 0,
842 dle_tape_splitsize => 200,
843 dle_split_diskbuffer => "$Installcheck::TMP",
844 dle_fallback_splitsize => 150,
846 { part_size => 200, part_cache_type => 'disk', part_cache_dir => "$Installcheck::TMP" },
847 "if split_diskbuffer exists and splitsize is nonzero, use it");
850 { get_splitting_args_from_config(
851 dle_tape_splitsize => 0,
852 dle_split_diskbuffer => "$Installcheck::TMP",
853 dle_fallback_splitsize => 250,
855 { part_size => 0, part_cache_type => 'none' },
856 ".. but if splitsize is zero, no splitting");
859 { get_splitting_args_from_config(
860 dle_split_diskbuffer => "$Installcheck::TMP",
861 dle_fallback_splitsize => 250,
863 { part_size => 0, part_cache_type => 'none' },
864 ".. and if splitsize is missing, no splitting");
867 { get_splitting_args_from_config(
869 part_cache_type => 'none',
871 { part_size => 300, part_cache_type => 'none' },
872 "part_* parameters handled correctly when missing");
875 { get_splitting_args_from_config(
877 part_cache_type => 'disk',
878 part_cache_dir => $Installcheck::TMP,
879 part_cache_max_size => 250,
881 { part_size => 300, part_cache_type => 'disk',
882 part_cache_dir => $Installcheck::TMP, part_cache_max_size => 250, },
883 "part_* parameters handled correctly when specified");
886 { get_splitting_args_from_config(
888 part_cache_type => 'disk',
889 part_cache_dir => "$Installcheck::TMP/does!not!exist!",
890 part_cache_max_size => 250,
892 { part_size => 300, part_cache_type => 'none',
893 part_cache_max_size => 250,
894 warning => "part-cache-dir '$Installcheck::TMP/does!not!exist! does not exist; "
895 . "using part cache type 'none'"},
896 "part_* parameters handled correctly when specified");