mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
8cbc19d86b
Fix: https://github.com/rails/rails/issues/43472 The reporter is held by the executor, but the `Rails` module provides a nicer `Rails.error` shortcut. For ease of use, two block based specialized methods are exposed. `handle`, which swallow errors and forward them to the subscribers: ```ruby Rails.error.handle do 1 + '1' # raises TypeError end 1 + 1 # This will be executed ``` `record`, which forward the errors to the subscribes but let it continue rewinding the call stack: ```ruby Rails.error.record do 1 + '1' # raises TypeError end 1 + 1 # This won't be executed. ``` For cases where the blocked based API isn't suitable, the lower level `report` method can be used: ```ruby Rails.error.report(error, handled: true / false) ```
131 lines
3.9 KiB
Ruby
131 lines
3.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require_relative "abstract_unit"
|
|
require "active_support/execution_context/test_helper"
|
|
|
|
class ErrorReporterTest < ActiveSupport::TestCase
|
|
# ExecutionContext is automatically reset in Rails app via executor hooks set in railtie
|
|
# But not in Active Support's own test suite.
|
|
include ActiveSupport::ExecutionContext::TestHelper
|
|
|
|
class ErrorSubscriber
|
|
attr_reader :events
|
|
|
|
def initialize
|
|
@events = []
|
|
end
|
|
|
|
def report(error, handled:, severity:, context:)
|
|
@events << [error, handled, severity, context]
|
|
end
|
|
end
|
|
|
|
setup do
|
|
@reporter = ActiveSupport::ErrorReporter.new
|
|
@subscriber = ErrorSubscriber.new
|
|
@reporter.subscribe(@subscriber)
|
|
@error = ArgumentError.new("Oops")
|
|
end
|
|
|
|
test "receives the execution context" do
|
|
@reporter.set_context(section: "admin")
|
|
error = ArgumentError.new("Oops")
|
|
@reporter.report(error, handled: true)
|
|
assert_equal [[error, true, :warning, { section: "admin" }]], @subscriber.events
|
|
end
|
|
|
|
test "passed context has priority over the execution context" do
|
|
@reporter.set_context(section: "admin")
|
|
error = ArgumentError.new("Oops")
|
|
@reporter.report(error, handled: true, context: { section: "public" })
|
|
assert_equal [[error, true, :warning, { section: "public" }]], @subscriber.events
|
|
end
|
|
|
|
test "#handle swallow and report any unhandled error" do
|
|
error = ArgumentError.new("Oops")
|
|
@reporter.handle do
|
|
raise error
|
|
end
|
|
assert_equal [[error, true, :warning, {}]], @subscriber.events
|
|
end
|
|
|
|
test "#handle can be scoped to an exception class" do
|
|
assert_raises ArgumentError do
|
|
@reporter.handle(NameError) do
|
|
raise ArgumentError
|
|
end
|
|
end
|
|
assert_equal [], @subscriber.events
|
|
end
|
|
|
|
test "#record report any unhandled error and re-raise them" do
|
|
error = ArgumentError.new("Oops")
|
|
assert_raises ArgumentError do
|
|
@reporter.record do
|
|
raise error
|
|
end
|
|
end
|
|
assert_equal [[error, false, :error, {}]], @subscriber.events
|
|
end
|
|
|
|
test "#record can be scoped to an exception class" do
|
|
assert_raises ArgumentError do
|
|
@reporter.record(NameError) do
|
|
raise ArgumentError
|
|
end
|
|
end
|
|
assert_equal [], @subscriber.events
|
|
end
|
|
|
|
test "can have multiple subscribers" do
|
|
second_subscriber = ErrorSubscriber.new
|
|
@reporter.subscribe(second_subscriber)
|
|
|
|
error = ArgumentError.new("Oops")
|
|
@reporter.report(error, handled: true)
|
|
|
|
assert_equal 1, @subscriber.events.size
|
|
assert_equal 1, second_subscriber.events.size
|
|
end
|
|
|
|
test "handled errors default to :warning severity" do
|
|
@reporter.report(@error, handled: true)
|
|
assert_equal :warning, @subscriber.events.dig(0, 2)
|
|
end
|
|
|
|
test "unhandled errors default to :error severity" do
|
|
@reporter.report(@error, handled: false)
|
|
assert_equal :error, @subscriber.events.dig(0, 2)
|
|
end
|
|
|
|
class FailingErrorSubscriber
|
|
Error = Class.new(StandardError)
|
|
|
|
def initialize(error)
|
|
@error = error
|
|
end
|
|
|
|
def report(_error, handled:, severity:, context:)
|
|
raise @error
|
|
end
|
|
end
|
|
|
|
test "subscriber errors are re-raised if no logger is set" do
|
|
subscriber_error = FailingErrorSubscriber::Error.new("Big Oopsie")
|
|
@reporter.subscribe(FailingErrorSubscriber.new(subscriber_error))
|
|
assert_raises FailingErrorSubscriber::Error do
|
|
@reporter.report(@error, handled: true)
|
|
end
|
|
end
|
|
|
|
test "subscriber errors are logged if a logger is set" do
|
|
subscriber_error = FailingErrorSubscriber::Error.new("Big Oopsie")
|
|
@reporter.subscribe(FailingErrorSubscriber.new(subscriber_error))
|
|
log = StringIO.new
|
|
@reporter.logger = ActiveSupport::Logger.new(log)
|
|
@reporter.report(@error, handled: true)
|
|
|
|
expected = "Error subscriber raised an error: Big Oopsie (ErrorReporterTest::FailingErrorSubscriber::Error)"
|
|
assert_equal expected, log.string.lines.first.chomp
|
|
end
|
|
end
|