1 # Copyright (c) 2009-2012 Zmanda Inc. All Rights Reserved.
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.
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
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
17 # Contact information: Zmanda Inc, 465 S. Mathilda Ave., Suite 300
18 # Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
20 use Test::More tests => 29;
26 use lib "@amperldir@";
27 use Installcheck::Config;
28 use Amanda::Config qw( :init );
30 use Amanda::Device qw( :constants );
34 use Amanda::Taper::Scribe qw( get_splitting_args_from_config );
37 # and disable Debug's die() and warn() overrides
38 Amanda::Debug::disable_die_override();
40 # put the debug messages somewhere
41 Amanda::Debug::dbopen("installcheck");
42 Installcheck::log_test_output();
44 # use some very small vtapes
45 my $volume_length = 512*1024;
48 $testconf = Installcheck::Config->new();
49 $testconf->add_tapetype("TEST-TAPE", [
50 "length" => ($volume_length / 1024) . " k",
54 my $cfg_result = config_init($CONFIG_INIT_EXPLICIT_NAME, 'TESTCONF');
55 if ($cfg_result != $CFGERR_OK) {
56 my ($level, @errors) = Amanda::Config::config_errors();
57 die(join "\n", @errors);
60 my $taperoot = "$Installcheck::TMP/Amanda_Taper_Scribe";
70 for my $slot (1 .. $nslots) {
71 mkdir("$taperoot/slot$slot")
72 or die("Could not mkdir: $!");
76 # an accumulator for the sequence of events that transpire during a run
89 Math::BigInt->new($_[0]);
92 # and similarly an Amanda::Changer::Error
94 Amanda::Changer::Error->new(@_);
98 ## Mock classes for the scribe
101 package Mock::Taperscan;
102 use Amanda::Device qw( :constants );
103 use Amanda::MainLoop;
108 my @slots = @{ $params{'slots'} || [] };
109 my $chg = $params{'changer'};
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",
129 sub make_new_tape_label {
136 my $result_cb = $params{'result_cb'};
140 my @slotarg = (@{$self->{'slots'}})?
141 (slot => shift @{$self->{'slots'}})
142 : (relative_slot => $self->{'next_or_current'});
143 $self->{'next_or_current'} = 'next';
145 my $res_cb = make_cb('res_cb' => sub {
146 my ($err, $res) = @_;
148 my $slot = $res? $res->{'this_slot'} : "none";
149 main::event("scan-finished", main::undef_or_str($err), "slot: $slot");
154 $result_cb->(undef, $res, 'FAKELABEL', $ACCESS_WRITE);
158 # delay this load call a little bit -- just enough so that the
159 # request_volume_permission event reliably occurs first
160 Amanda::MainLoop::call_after(50, sub {
161 $self->{'chg'}->load(@slotarg, set_current => 1, res_cb => $res_cb);
165 package Mock::Feedback;
166 use base qw( Amanda::Taper::Scribe::Feedback );
169 use Installcheck::Config;
175 rq_answers => [ @rq_answers ],
179 sub request_volume_permission {
182 my $answer = shift @{$self->{'rq_answers'}};
183 main::event("request_volume_permission", "answer:", $answer);
184 $main::scribe->start_scan();
185 $params{'perm_cb'}->(%{$answer});
188 sub scribe_notif_new_tape {
192 main::event("scribe_notif_new_tape",
193 main::undef_or_str($params{'error'}), $params{'volume_label'});
196 sub scribe_notif_part_done {
200 # this omits $duration, as it's not constant
201 main::event("scribe_notif_part_done",
202 $params{'partnum'}, $params{'fileno'},
203 $params{'successful'}, $params{'size'});
206 sub scribe_notif_tape_done {
210 main::event("scribe_notif_tape_done",
211 $params{'volume_label'}, $params{'num_files'},
213 $params{'finished_cb'}->();
225 # utility fn to stringify changer errors (earlier perls' Test::More's
226 # fail to do this automatically)
227 sub undef_or_str { (defined $_[0])? "".$_[0] : undef; }
230 my ($nruns, $taperscan, $feedback) = @_;
234 reset_taperoot($nruns);
235 $main::scribe = Amanda::Taper::Scribe->new(
236 taperscan => $taperscan,
237 feedback => $feedback);
238 $devh = $main::scribe->{'devhandling'};
240 my ($start, $get_volume, $got_volume, $quit);
242 $start = make_cb(start => sub {
246 # give start() time to get the scan going before
247 # calling get_volume -- this wouldn't ordinarily be
248 # necessary, but we want to make sure that start() is
249 # really kicking off the scan.
254 $get_volume = make_cb(get_volume => sub {
255 if (++$runcount > $nruns) {
261 $devh->get_volume(volume_cb => $got_volume);
264 $got_volume = make_cb(got_volume => sub {
265 my ($scan_error, $config_denial_message, $error_denial_message,
266 $reservation, $volume_label, $access_mode) = @_;
269 undef_or_str($scan_error),
270 $config_denial_message, $error_denial_message,
271 $reservation? ("slot: ".$reservation->{'this_slot'}) : undef);
273 if ($scan_error or $config_denial_message or $error_denial_message) {
278 $reservation->release(finished_cb => sub {
280 event("release", $error);
289 $quit = make_cb(quit => sub {
291 Amanda::MainLoop::quit();
295 Amanda::MainLoop::run();
299 my $chg = Amanda::Changer->new("chg-disk:$taperoot");
300 run_devh(3, Mock::Taperscan->new(changer => $chg), Mock::Feedback->new({allow => 1}, {allow => 1}, {allow => 1}));
301 is_deeply([ @events ], [
303 [ 'scan' ], # scan starts *before* get_volume
306 [ 'request_volume_permission', 'answer:', { allow => 1 }, ],
307 [ 'scan-finished', undef, "slot: 1" ],
308 [ 'got_volume', undef, undef, undef, "slot: 1" ],
309 [ 'release', undef ],
312 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
313 [ 'scan' ], # scan starts *after* request_volume_permission
314 [ 'scan-finished', undef, "slot: 2" ],
315 [ 'got_volume', undef, undef, undef, "slot: 2" ],
316 [ 'release', undef ],
319 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
321 [ 'scan-finished', undef, "slot: 3" ],
322 [ 'got_volume', undef, undef, undef, "slot: 3" ],
323 [ 'release', undef ],
326 ], "correct event sequence for basic run of DevHandling")
327 or diag(Dumper([@events]));
329 run_devh(1, Mock::Taperscan->new(changer => $chg), Mock::Feedback->new({cause => 'config', message => 'no-can-do'}));
330 is_deeply([ @events ], [
335 [ 'request_volume_permission', 'answer:', { cause => 'config', message => 'no-can-do' } ],
336 [ 'scan-finished', undef, "slot: 1" ],
337 [ 'got_volume', undef, 'no-can-do', undef, undef ],
340 ], "correct event sequence for a run without permission")
341 or diag(Dumper([@events]));
343 run_devh(1, Mock::Taperscan->new(slots => ["bogus"], changer => $chg), Mock::Feedback->new({allow => 1}));
344 is_deeply([ @events ], [
349 [ 'request_volume_permission', 'answer:', { allow => 1} ],
350 [ 'scan-finished', "Slot bogus not found", "slot: none" ],
351 [ 'got_volume', 'Slot bogus not found', undef, undef, undef ],
354 ], "correct event sequence for a run with a changer error")
355 or diag(Dumper([@events]));
357 run_devh(1, Mock::Taperscan->new(slots => ["bogus"], changer => $chg),
358 Mock::Feedback->new({cause => 'config', message => "not this time"}));
359 is_deeply([ @events ], [
364 [ 'request_volume_permission', 'answer:', {cause => 'config', message =>'not this time'} ],
365 [ 'scan-finished', "Slot bogus not found", "slot: none" ],
366 [ 'got_volume', 'Slot bogus not found', 'not this time', undef, undef ],
369 ], "correct event sequence for a run with no permission AND a changer config denial")
370 or diag(Dumper([@events]));
372 run_devh(1, Mock::Taperscan->new(slots => ["bogus"], changer => $chg), Mock::Feedback->new({cause => 'error', message => "frobnicator exploded!"}));
373 is_deeply([ @events ], [
378 [ 'request_volume_permission', 'answer:', {cause => 'error', message => "frobnicator exploded!"} ],
379 [ 'scan-finished', "Slot bogus not found", "slot: none" ],
380 [ 'got_volume', 'Slot bogus not found', undef, "frobnicator exploded!", undef ],
383 ], "correct event sequence for a run with no permission AND a changer error")
384 or diag(Dumper([@events]));
390 sub run_scribe_xfer_async {
391 my ($data_length, $scribe, %params) = @_;
394 my $finished_cb = $params{'finished_cb'};
395 my $steps = define_steps
396 cb_ref => \$finished_cb;
398 step start_scribe => sub {
399 if ($params{'start_scribe'}) {
400 $scribe->start(%{ $params{'start_scribe'} },
401 finished_cb => $steps->{'get_xdt'});
403 $steps->{'get_xdt'}->();
407 step get_xdt => sub {
412 my $xdt = $scribe->get_xfer_dest(
414 max_memory => 1024 * 64,
415 part_size => (defined $params{'part_size'})? $params{'part_size'} : (1024 * 128),
416 part_cache_type => $params{'part_cache_type'} || 'memory',
417 disk_cache_dirname => undef);
421 my $hdr = Amanda::Header->new();
422 $hdr->{type} = $Amanda::Header::F_DUMPFILE;
423 $hdr->{datestamp} = "20010203040506";
424 $hdr->{dumplevel} = 0;
425 $hdr->{compressed} = 1;
426 $hdr->{name} = "localhost";
427 $hdr->{disk} = "/home";
428 $hdr->{program} = "INSTALLCHECK";
430 $xfer = Amanda::Xfer->new([
431 Amanda::Xfer::Source::Random->new($data_length, 0x5EED5),
436 $scribe->handle_xmsg(@_);
442 dump_cb => $steps->{'dump_cb'});
445 step dump_cb => sub {
448 main::event("dump_cb",
450 [ map { "$_" } @{$params{'device_errors'}} ],
451 $params{'config_denial_message'},
458 sub run_scribe_xfer {
459 my ($data_length, $scribe, %params) = @_;
460 $params{'finished_cb'} = \&Amanda::MainLoop::quit;
461 run_scribe_xfer_async($data_length, $scribe, %params);
462 Amanda::MainLoop::run();
468 my $finished_cb = make_cb(finished_cb => sub {
470 die "$error" if $error;
472 Amanda::MainLoop::quit();
475 $scribe->quit(finished_cb => $finished_cb);
477 Amanda::MainLoop::run();
482 # write less than a tape full, without LEOM
485 $main::scribe = Amanda::Taper::Scribe->new(
486 taperscan => Mock::Taperscan->new(disable_leom => 1, changer => $chg),
487 feedback => Mock::Feedback->new({allow => 1}));
490 run_scribe_xfer(1024*200, $main::scribe,
491 part_size => 96*1024,
492 start_scribe => { write_timestamp => "20010203040506" });
494 is_deeply([ @events ], [
496 [ 'scan-finished', undef, 'slot: 1' ],
497 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
498 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
499 [ 'scribe_notif_part_done', bi(1), bi(1), 1, bi(98304) ],
500 [ 'scribe_notif_part_done', bi(2), bi(2), 1, bi(98304) ],
501 [ 'scribe_notif_part_done', bi(3), bi(3), 1, bi(8192) ],
502 [ 'dump_cb', 'DONE', [], undef, bi(204800) ],
503 ], "correct event sequence for a multipart scribe of less than a whole volume, without LEOM")
504 or diag(Dumper([@events]));
506 # pick up where we left off, writing just a tiny bit more, and then quit
508 run_scribe_xfer(1024*30, $main::scribe);
510 quit_scribe($main::scribe);
512 is_deeply([ @events ], [
513 [ 'scribe_notif_part_done', bi(1), bi(4), 1, bi(30720) ],
514 [ 'dump_cb', 'DONE', [], undef, bi(30720) ],
515 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(4), bi(235520) ],
516 ], "correct event sequence for a subsequent single-part scribe, still on the same volume")
517 or diag(Dumper([@events]));
519 # write less than a tape full, *with* LEOM (should look the same as above)
522 $main::scribe = Amanda::Taper::Scribe->new(
523 taperscan => Mock::Taperscan->new(changer => $chg),
524 feedback => Mock::Feedback->new({ allow => 1 }));
527 run_scribe_xfer(1024*200, $main::scribe,
528 part_size => 96*1024,
529 start_scribe => { write_timestamp => "20010203040506" });
531 quit_scribe($main::scribe);
533 is_deeply([ @events ], [
535 [ 'scan-finished', undef, 'slot: 1' ],
536 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
537 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
538 [ 'scribe_notif_part_done', bi(1), bi(1), 1, bi(98304) ],
539 [ 'scribe_notif_part_done', bi(2), bi(2), 1, bi(98304) ],
540 [ 'scribe_notif_part_done', bi(3), bi(3), 1, bi(8192) ],
541 [ 'dump_cb', 'DONE', [], undef, bi(204800) ],
542 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(3), bi(204800) ],
543 ], "correct event sequence for a multipart scribe of less than a whole volume, with LEOM")
544 or diag(Dumper([@events]));
546 # start over again and try a multivolume write
548 # NOTE: the part size and volume size are such that the VFS driver produces
549 # ENOSPC while writing the fourth file header, rather than while writing
550 # data. This is a much less common error path, so it's good to test it.
553 $main::scribe = Amanda::Taper::Scribe->new(
554 taperscan => Mock::Taperscan->new(disable_leom => 1, changer => $chg),
555 feedback => Mock::Feedback->new({ allow => 1 }, { allow => 1 }));
558 run_scribe_xfer($volume_length + $volume_length / 4, $main::scribe,
559 start_scribe => { write_timestamp => "20010203040506" });
561 quit_scribe($main::scribe);
563 is_deeply([ @events ], [
565 [ 'scan-finished', undef, 'slot: 1' ],
566 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
567 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
569 [ 'scribe_notif_part_done', bi(1), bi(1), 1, bi(131072) ],
570 [ 'scribe_notif_part_done', bi(2), bi(2), 1, bi(131072) ],
571 [ 'scribe_notif_part_done', bi(3), bi(3), 1, bi(131072) ],
572 [ 'scribe_notif_part_done', bi(4), bi(0), 0, bi(0) ],
574 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(3), bi(393216) ],
575 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
577 [ 'scan-finished', undef, 'slot: 2' ],
578 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
580 [ 'scribe_notif_part_done', bi(4), bi(1), 1, bi(131072) ],
581 [ 'scribe_notif_part_done', bi(5), bi(2), 1, bi(131072) ],
582 # empty part is written but not notified, although it is counted
583 # in scribe_notif_tape_done
585 [ 'dump_cb', 'DONE', [], undef, bi(655360) ],
586 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(3), bi(262144) ],
587 ], "correct event sequence for a multipart scribe of more than a whole volume, without LEOM" . Data::Dumper::Dumper(@events))
588 or print (Dumper([@events]));
590 # same test, but with LEOM support
593 $main::scribe = Amanda::Taper::Scribe->new(
594 taperscan => Mock::Taperscan->new(changer => $chg),
595 feedback => Mock::Feedback->new({ allow => 1 },{ allow => 1 }));
598 run_scribe_xfer(1024*520, $main::scribe,
599 start_scribe => { write_timestamp => "20010203040506" });
601 quit_scribe($main::scribe);
603 is_deeply([ @events ], [
605 [ 'scan-finished', undef, 'slot: 1' ],
606 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
607 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
609 [ 'scribe_notif_part_done', bi(1), bi(1), 1, bi(131072) ],
610 [ 'scribe_notif_part_done', bi(2), bi(2), 1, bi(131072) ],
611 [ 'scribe_notif_part_done', bi(3), bi(3), 1, bi(32768) ], # LEOM comes earlier than PEOM did
613 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(3), bi(294912) ],
614 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
616 [ 'scan-finished', undef, 'slot: 2' ],
617 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
619 [ 'scribe_notif_part_done', bi(4), bi(1), 1, bi(131072) ],
620 [ 'scribe_notif_part_done', bi(5), bi(2), 1, bi(106496) ],
622 [ 'dump_cb', 'DONE', [], undef, bi(532480) ],
623 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(2), bi(237568) ],
624 ], "correct event sequence for a multipart scribe of more than a whole volume, with LEOM")
625 or print (Dumper([@events]));
627 # now a multivolume write where the second volume gives a changer error
630 $main::scribe = Amanda::Taper::Scribe->new(
631 taperscan => Mock::Taperscan->new(slots => ["1", "bogus"], disable_leom => 1, changer => $chg),
632 feedback => Mock::Feedback->new({ allow => 1 },{ allow => 1 }));
635 run_scribe_xfer($volume_length + $volume_length / 4, $main::scribe,
636 start_scribe => { write_timestamp => "20010203040507" });
638 quit_scribe($main::scribe);
640 $experr = 'Slot bogus not found';
641 is_deeply([ @events ], [
643 [ 'scan-finished', undef, 'slot: 1' ],
644 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
645 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
647 [ 'scribe_notif_part_done', bi(1), bi(1), 1, bi(131072) ],
648 [ 'scribe_notif_part_done', bi(2), bi(2), 1, bi(131072) ],
649 [ 'scribe_notif_part_done', bi(3), bi(3), 1, bi(131072) ],
650 [ 'scribe_notif_part_done', bi(4), bi(0), 0, bi(0) ],
652 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(3), bi(393216) ],
653 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
655 [ 'scan-finished', $experr, 'slot: none' ],
656 [ 'scribe_notif_new_tape', $experr, undef ],
658 [ 'dump_cb', 'PARTIAL', [$experr], undef, bi(393216) ],
659 # (no scribe_notif_tape_done)
660 ], "correct event sequence for a multivolume scribe with no second vol, without LEOM")
661 or print (Dumper([@events]));
664 $main::scribe = Amanda::Taper::Scribe->new(
665 taperscan => Mock::Taperscan->new(slots => ["1", "bogus"], changer => $chg),
666 feedback => Mock::Feedback->new({ allow => 1 }, { allow => 1 }));
669 run_scribe_xfer($volume_length + $volume_length / 4, $main::scribe,
670 start_scribe => { write_timestamp => "20010203040507" });
672 quit_scribe($main::scribe);
674 $experr = 'Slot bogus not found';
675 is_deeply([ @events ], [
677 [ 'scan-finished', undef, 'slot: 1' ],
678 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
679 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
681 [ 'scribe_notif_part_done', bi(1), bi(1), 1, bi(131072) ],
682 [ 'scribe_notif_part_done', bi(2), bi(2), 1, bi(131072) ],
683 [ 'scribe_notif_part_done', bi(3), bi(3), 1, bi(32768) ], # LEOM comes long before PEOM
685 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(3), bi(294912) ],
686 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
688 [ 'scan-finished', $experr, 'slot: none' ],
689 [ 'scribe_notif_new_tape', $experr, undef ],
691 [ 'dump_cb', 'PARTIAL', [$experr], undef, bi(294912) ],
692 # (no scribe_notif_tape_done)
693 ], "correct event sequence for a multivolume scribe with no second vol, with LEOM")
694 or print (Dumper([@events]));
696 # now a multivolume write where the second volume does not have permission
699 $main::scribe = Amanda::Taper::Scribe->new(
700 taperscan => Mock::Taperscan->new(changer => $chg),
701 feedback => Mock::Feedback->new({ allow => 1 }, { cause => 'config', message => "sorry!" }));
704 run_scribe_xfer($volume_length + $volume_length / 4, $main::scribe,
705 start_scribe => { write_timestamp => "20010203040507" });
707 quit_scribe($main::scribe);
709 is_deeply([ @events ], [
711 [ 'scan-finished', undef, 'slot: 1' ],
712 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
713 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
715 [ 'scribe_notif_part_done', bi(1), bi(1), 1, bi(131072) ],
716 [ 'scribe_notif_part_done', bi(2), bi(2), 1, bi(131072) ],
717 [ 'scribe_notif_part_done', bi(3), bi(3), 1, bi(32768) ],
719 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(3), bi(294912) ],
720 [ 'request_volume_permission', 'answer:', { cause => 'config', message => "sorry!" } ],
722 [ 'scan-finished', undef, 'slot: 2' ],
724 [ 'dump_cb', 'PARTIAL', [], "sorry!", bi(294912) ],
725 ], "correct event sequence for a multivolume scribe with next vol denied")
726 or print (Dumper([@events]));
728 # a non-splitting xfer on a single volume
731 $main::scribe = Amanda::Taper::Scribe->new(
732 taperscan => Mock::Taperscan->new(disable_leom => 1, changer => $chg),
733 feedback => Mock::Feedback->new({ allow => 1 }));
736 run_scribe_xfer(1024*300, $main::scribe, part_size => 0, part_cache_type => 'none',
737 start_scribe => { write_timestamp => "20010203040506" });
739 quit_scribe($main::scribe);
741 is_deeply([ @events ], [
743 [ 'scan-finished', undef, 'slot: 1' ],
744 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
745 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
746 [ 'scribe_notif_part_done', bi(1), bi(1), 1, bi(307200) ],
747 [ 'dump_cb', 'DONE', [], undef, bi(307200) ],
748 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(1), bi(307200) ],
749 ], "correct event sequence for a non-splitting scribe of less than a whole volume, without LEOM")
750 or diag(Dumper([@events]));
753 $main::scribe = Amanda::Taper::Scribe->new(
754 taperscan => Mock::Taperscan->new(changer => $chg),
755 feedback => Mock::Feedback->new({ allow => 1 }));
756 $Amanda::Config::debug_taper = 9;
758 run_scribe_xfer(1024*300, $main::scribe, part_size => 0, part_cache_type => 'none',
759 start_scribe => { write_timestamp => "20010203040506" });
761 quit_scribe($main::scribe);
763 is_deeply([ @events ], [
765 [ 'scan-finished', undef, 'slot: 1' ],
766 [ 'request_volume_permission', 'answer:', { allow => 1 } ],
767 [ 'scribe_notif_new_tape', undef, 'FAKELABEL' ],
768 [ 'scribe_notif_part_done', bi(1), bi(1), 1, bi(307200) ],
769 [ 'dump_cb', 'DONE', [], undef, bi(307200) ],
770 [ 'scribe_notif_tape_done', 'FAKELABEL', bi(1), bi(307200) ],
771 ], "correct event sequence for a non-splitting scribe of less than a whole volume, with LEOM")
772 or diag(Dumper([@events]));
774 # DirectTCP support is tested through the taper installcheck
776 # test get_splitting_args_from_config thoroughly
777 my $maxint64 = Math::BigInt->new("9223372036854775808");
780 { get_splitting_args_from_config(
782 { allow_split => 0 },
783 "default is only allow_split set to 0");
786 { get_splitting_args_from_config(
787 dle_tape_splitsize => 0,
788 dle_split_diskbuffer => $Installcheck::TMP,
789 dle_fallback_splitsize => 100,
791 { allow_split => 0, part_size => 0, part_cache_type => 'none' },
792 "tape_splitsize = 0 indicates no splitting");
795 { get_splitting_args_from_config(
796 dle_allow_split => 0,
798 part_cache_dir => "/tmp",
800 { allow_split => 0 },
801 "default if dle_allow_split is false, no splitting");
804 { get_splitting_args_from_config(
805 dle_tape_splitsize => 200,
806 dle_fallback_splitsize => 150,
808 { allow_split => 1,part_cache_type => 'memory', part_size => 200, part_cache_max_size => 150 },
809 "when cache_inform is available, tape_splitsize is used, not fallback");
812 { get_splitting_args_from_config(
813 dle_tape_splitsize => 200,
815 { allow_split => 1, part_size => 200, part_cache_type => 'memory', part_cache_max_size => 1024*1024*10, },
816 "no split_diskbuffer and no fallback_splitsize, fall back to default (10M)");
819 { get_splitting_args_from_config(
820 dle_tape_splitsize => 200,
821 dle_split_diskbuffer => "$Installcheck::TMP/does!not!exist!",
822 dle_fallback_splitsize => 150,
824 { allow_split => 1, part_size => 200, part_cache_type => 'memory', part_cache_max_size => 150 },
825 "invalid split_diskbuffer => fall back (silently)");
828 { get_splitting_args_from_config(
829 dle_tape_splitsize => 200,
830 dle_split_diskbuffer => "$Installcheck::TMP/does!not!exist!",
832 { allow_split => 1, part_size => 200, part_cache_type => 'memory', part_cache_max_size => 1024*1024*10 },
833 ".. even to the default fallback (10M)");
836 { get_splitting_args_from_config(
837 dle_tape_splitsize => $maxint64,
838 dle_split_diskbuffer => "$Installcheck::TMP",
839 dle_fallback_splitsize => 250,
841 { allow_split => 1, part_size => $maxint64, part_cache_type => 'memory', part_cache_max_size => 250,
842 warning => "falling back to memory buffer for splitting: " .
843 "insufficient space in disk cache directory" },
844 "not enough space in split_diskbuffer => fall back (with warning)");
847 { get_splitting_args_from_config(
848 can_cache_inform => 0,
849 dle_tape_splitsize => 200,
850 dle_split_diskbuffer => "$Installcheck::TMP",
851 dle_fallback_splitsize => 150,
853 { allow_split => 1, part_size => 200, part_cache_type => 'disk', part_cache_dir => "$Installcheck::TMP" },
854 "if split_diskbuffer exists and splitsize is nonzero, use it");
857 { get_splitting_args_from_config(
858 dle_tape_splitsize => 0,
859 dle_split_diskbuffer => "$Installcheck::TMP",
860 dle_fallback_splitsize => 250,
862 { allow_split => 0, part_size => 0, part_cache_type => 'none' },
863 ".. but if splitsize is zero, no splitting");
866 { get_splitting_args_from_config(
867 dle_split_diskbuffer => "$Installcheck::TMP",
868 dle_fallback_splitsize => 250,
870 { allow_split => 0, part_size => 0, part_cache_type => 'none' },
871 ".. and if splitsize is missing, no splitting");
874 { get_splitting_args_from_config(
876 part_cache_type => 'none',
878 { allow_split => 1, part_size => 300, part_cache_type => 'none' },
879 "part_* parameters handled correctly when missing");
882 { get_splitting_args_from_config(
884 part_cache_type => 'disk',
885 part_cache_dir => $Installcheck::TMP,
886 part_cache_max_size => 250,
888 { allow_split => 1, part_size => 300, part_cache_type => 'disk',
889 part_cache_dir => $Installcheck::TMP, part_cache_max_size => 250, },
890 "part_* parameters handled correctly when specified");
893 { get_splitting_args_from_config(
895 part_cache_type => 'disk',
896 part_cache_dir => "$Installcheck::TMP/does!not!exist!",
897 part_cache_max_size => 250,
899 { allow_split => 1, part_size => 300, part_cache_type => 'none',
900 part_cache_max_size => 250,
901 warning => "part-cache-dir '$Installcheck::TMP/does!not!exist! does not exist; "
902 . "using part cache type 'none'"},
903 "part_* parameters handled correctly when specified");