mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #29034 from peterjm/handle_loops_in_exception_handling
Handle loops in the cause chain in Rescuable#rescue_with_handler
This commit is contained in:
commit
f96c14096c
2 changed files with 41 additions and 3 deletions
|
@ -84,12 +84,18 @@ module ActiveSupport
|
|||
# end
|
||||
#
|
||||
# Returns the exception if it was handled and +nil+ if it was not.
|
||||
def rescue_with_handler(exception, object: self)
|
||||
def rescue_with_handler(exception, object: self, visited_exceptions: [])
|
||||
visited_exceptions << exception
|
||||
|
||||
if handler = handler_for_rescue(exception, object: object)
|
||||
handler.call exception
|
||||
exception
|
||||
elsif exception
|
||||
rescue_with_handler(exception.cause, object: object)
|
||||
if visited_exceptions.include?(exception.cause)
|
||||
nil
|
||||
else
|
||||
rescue_with_handler(exception.cause, object: object, visited_exceptions: visited_exceptions)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -43,7 +43,9 @@ class Stargate
|
|||
def dispatch(method)
|
||||
send(method)
|
||||
rescue Exception => e
|
||||
rescue_with_handler(e)
|
||||
unless rescue_with_handler(e)
|
||||
@result = "unhandled"
|
||||
end
|
||||
end
|
||||
|
||||
def attack
|
||||
|
@ -58,6 +60,26 @@ class Stargate
|
|||
raise MadRonon.new("dex")
|
||||
end
|
||||
|
||||
def crash
|
||||
raise "unhandled RuntimeError"
|
||||
end
|
||||
|
||||
def looped_crash
|
||||
ex1 = StandardError.new("error 1")
|
||||
ex2 = StandardError.new("error 2")
|
||||
begin
|
||||
begin
|
||||
raise ex1
|
||||
rescue
|
||||
# sets the cause on ex2 to be ex1
|
||||
raise ex2
|
||||
end
|
||||
rescue
|
||||
# sets the cause on ex1 to be ex2
|
||||
raise ex1
|
||||
end
|
||||
end
|
||||
|
||||
def fall_back_to_cause
|
||||
# This exception is the cause and has a handler.
|
||||
ronanize
|
||||
|
@ -139,4 +161,14 @@ class RescuableTest < ActiveSupport::TestCase
|
|||
@stargate.dispatch :fall_back_to_cause
|
||||
assert_equal "dex", @stargate.result
|
||||
end
|
||||
|
||||
def test_unhandled_exceptions
|
||||
@stargate.dispatch(:crash)
|
||||
assert_equal "unhandled", @stargate.result
|
||||
end
|
||||
|
||||
def test_rescue_handles_loops_in_exception_cause_chain
|
||||
@stargate.dispatch :looped_crash
|
||||
assert_equal "unhandled", @stargate.result
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue