Subject: | fatal programming errors lost in __compose_pass_or_stop and __compose_pass_or_skip |
Fatal programming errors are caught nicely when running a simple brick
directly or composing bricks with __and and __or, but error messages are
lost when composing bricks with __compose_pass_or_skip and
__compose_pass_or_stop. The program_error entry in the results hash
shows up, but the message hash entry is empty. See the attached test for
examples.
The change to__compose_pass_or_skip is simple, change Brick::Composers
line 258:
die if( ref $eval_error );
to:
die if( $eval_error );
__compose_pass_or_stop is a little more confusing. The problem is that
if the brick dies with a message, that message ends up in $result and
since this (line 334):
next if $result;
comes before this (line 340):
die if( ref $at and $at ); # die for program errors
We never get a chance to die. I moved line 340 up above line 334 and
changed it to:
die if( $at ); # die for program errors
which seems to have take care of the problem without breaking anything.
Even so, the logic in __compose_pass_or_stop needs review. I think it
can actually be simplified into:
my $sub = $bucket->add_to_bucket( {
code => sub {
my $last_result;
foreach my $sub ( @subs )
{
no warnings 'uninitialized';
$last_result = eval { $sub->( @_ ) };
my $at = $@;
die $at if $at; # throw an exception
next if $last_ result; # continue if success
return; # error but no fatal error
};
return $last_result;
},
});
Subject: | fatals.t |
#!/usr/local/bin/perl
use strict;
use warnings;
use ACS::SetLibs qw( eptf );
use Test::More tests => 19;
use_ok( 'Brick' );
use_ok( 'Brick::Profile' );
my $brick = Brick->new();
isa_ok( $brick, 'Brick' );
for ( qw( composed_posk
composed_post
composed_and
composed_or ) ) {
my $profile
= Brick::Profile->new( $brick, [ [ test => $_ => {} ] ] );
isa_ok( $profile, 'Brick::Profile' );
my $result = $brick->apply( $profile, {} );
isa_ok( $result, 'Brick::Result' );
ok( defined $result->[0]->[3]->{program_error}, 'program error caught' );
like( $result->[0]->[3]->{message},
qr/\Acheck for this/, "got correct error message with $_" );
}
sub Brick::Bucket::test_brick{
my ( $bucket, $setup ) = @_;
return $bucket->add_to_bucket( {
code => sub {
die 'check for this';
return 1;
},
} );
}
sub Brick::Bucket::composed_posk{
my ( $bucket, $setup ) = @_;
return $bucket->__compose_pass_or_skip(
$bucket->test_brick,
);
}
sub Brick::Bucket::composed_post{
my ( $bucket, $setup ) = @_;
return $bucket->__compose_pass_or_stop(
$bucket->test_brick,
);
}
sub Brick::Bucket::composed_and{
my ( $bucket, $setup ) = @_;
return $bucket->__and(
$bucket->test_brick,
);
}
sub Brick::Bucket::composed_or{
my ( $bucket, $setup ) = @_;
return $bucket->__or(
$bucket->test_brick,
);
}