Add is_exception check to the result of exception_action (inspired by GHPR#15)
Peter Rabbitson [Mon, 10 Aug 2015 15:29:05 +0000 (17:29 +0200)]
This builds upon work in 841efcb3 and 9bea2000, tying loose ends before next
commits

Read under -w

lib/DBIx/Class/Schema.pm
t/storage/txn.t

index 7b5ae64..36041bd 100644 (file)
@@ -8,7 +8,7 @@ use base 'DBIx::Class';
 use DBIx::Class::Carp;
 use Try::Tiny;
 use Scalar::Util qw/weaken blessed/;
-use DBIx::Class::_Util qw(refcount quote_sub);
+use DBIx::Class::_Util qw(refcount quote_sub is_exception);
 use Devel::GlobalDestruction;
 use namespace::clean;
 
@@ -1055,26 +1055,37 @@ default behavior will provide a detailed stack trace.
 =cut
 
 sub throw_exception {
-  my $self = shift;
+  my ($self, @args) = @_;
 
   if (my $act = $self->exception_action) {
-    if ($act->(@_)) {
-      DBIx::Class::Exception->throw(
+    try {
+      # if it throws - good, we'll go down to the catch
+      # if it doesn't - do different things depending on RV truthiness
+      if( $act->(@args) ) {
+        $args[0] = (
           "Invocation of the exception_action handler installed on $self did *not*"
         .' result in an exception. DBIx::Class is unable to function without a reliable'
         .' exception mechanism, ensure that exception_action does not hide exceptions'
-        ." (original error: $_[0])"
-      );
-    }
+        ." (original error: $args[0])"
+        );
+      }
+      else {
+        carp_unique (
+          "The exception_action handler installed on $self returned false instead"
+        .' of throwing an exception. This behavior has been deprecated, adjust your'
+        .' handler to always rethrow the supplied error.'
+        );
+      }
+    } catch {
+      # We call this to get the necessary warnings emitted and disregard the RV
+      # as it's definitely an exception if we got as far as catch{}
+      is_exception($_);
 
-    carp_unique (
-      "The exception_action handler installed on $self returned false instead"
-    .' of throwing an exception. This behavior has been deprecated, adjust your'
-    .' handler to always rethrow the supplied error.'
-    );
+      die $_;
+    };
   }
 
-  DBIx::Class::Exception->throw($_[0], $self->stacktrace);
+  DBIx::Class::Exception->throw( $args[0], $self->stacktrace );
 }
 
 =head2 deploy
index f8a729f..ea9845f 100644 (file)
@@ -453,6 +453,17 @@ warnings_are {
   } qr/\QTransaction aborted: $broken_exception. Rollback failed: lost connection to storage at @{[__FILE__]} line $ln\E\n/;  # FIXME wtf - ...\E$/m doesn't work here
 
   is @w, 1, 'One matching warning only';
+
+  # try the same broken exception object, but have exception_action inject it
+  $s->exception_action(sub { die $broken_exception });
+  eval {
+    $s->txn_do( sub {
+      die "some string masked away";
+    });
+  };
+  isa_ok $@, 'DBICTest::BrokenOverload', 'Deficient exception properly propagated';
+
+  is @w, 2, 'The warning was emitted a second time';
 }
 
 done_testing;