aboutsummaryrefslogtreecommitdiffstats
path: root/actionmailer/test
diff options
context:
space:
mode:
authorJeremy Daer <jeremydaer@gmail.com>2016-05-13 17:43:48 -0700
committerJeremy Daer <jeremydaer@gmail.com>2016-05-15 18:44:16 -0700
commite35b98e6f5c54330245645f2ed40d56c74538902 (patch)
tree272bba30020bde27d177d2cf6227dfa8bb7a525f /actionmailer/test
parent6810847f495cd282c2659be738ac8271ecdec12f (diff)
downloadrails-e35b98e6f5c54330245645f2ed40d56c74538902.tar.gz
rails-e35b98e6f5c54330245645f2ed40d56c74538902.tar.bz2
rails-e35b98e6f5c54330245645f2ed40d56c74538902.zip
Action Mailer: Declarative exception handling with `rescue_from`.
Follows the same pattern as controllers and jobs. Exceptions raised in delivery jobs (enqueued by `#deliver_later`) are also delegated to the mailer's rescue_from handlers, so you can handle the DeserializationError raised by delivery jobs: ```ruby class MyMailer < ApplicationMailer rescue_from ActiveJob::DeserializationError do … end ``` ActiveSupport::Rescuable polish: * Add the `rescue_with_handler` class method so exceptions may be handled at the class level without requiring an instance. * Rationalize `exception.cause` handling. If no handler matches the exception, fall back to the handler that matches its cause. * Handle exceptions raised elsewhere. Pass `object: …` to execute the `rescue_from` handler (e.g. a method call or a block to instance_exec) against a different object. Defaults to `self`.
Diffstat (limited to 'actionmailer/test')
-rw-r--r--actionmailer/test/mailers/delayed_mailer.rb20
-rw-r--r--actionmailer/test/message_delivery_test.rb51
2 files changed, 70 insertions, 1 deletions
diff --git a/actionmailer/test/mailers/delayed_mailer.rb b/actionmailer/test/mailers/delayed_mailer.rb
index 62d4baa434..e6211ef028 100644
--- a/actionmailer/test/mailers/delayed_mailer.rb
+++ b/actionmailer/test/mailers/delayed_mailer.rb
@@ -1,6 +1,26 @@
+require 'active_job/arguments'
+
+class DelayedMailerError < StandardError; end
+
class DelayedMailer < ActionMailer::Base
+ cattr_accessor :last_error
+ cattr_accessor :last_rescue_from_instance
+
+ rescue_from DelayedMailerError do |error|
+ @@last_error = error
+ @@last_rescue_from_instance = self
+ end
+
+ rescue_from ActiveJob::DeserializationError do |error|
+ @@last_error = error
+ @@last_rescue_from_instance = self
+ end
def test_message(*)
mail(from: 'test-sender@test.com', to: 'test-receiver@test.com', subject: 'Test Subject', body: 'Test Body')
end
+
+ def test_raise(klass_name)
+ raise klass_name.constantize, 'boom'
+ end
end
diff --git a/actionmailer/test/message_delivery_test.rb b/actionmailer/test/message_delivery_test.rb
index f06d69369f..aaed94d519 100644
--- a/actionmailer/test/message_delivery_test.rb
+++ b/actionmailer/test/message_delivery_test.rb
@@ -12,16 +12,23 @@ class MessageDeliveryTest < ActiveSupport::TestCase
ActionMailer::Base.deliver_later_queue_name = :test_queue
ActionMailer::Base.delivery_method = :test
ActiveJob::Base.logger = Logger.new(nil)
- @mail = DelayedMailer.test_message(1, 2, 3)
ActionMailer::Base.deliveries.clear
ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true
ActiveJob::Base.queue_adapter.perform_enqueued_jobs = true
+
+ DelayedMailer.last_error = nil
+ DelayedMailer.last_rescue_from_instance = nil
+
+ @mail = DelayedMailer.test_message(1, 2, 3)
end
teardown do
ActiveJob::Base.logger = @previous_logger
ActionMailer::Base.delivery_method = @previous_delivery_method
ActionMailer::Base.deliver_later_queue_name = @previous_deliver_later_queue_name
+
+ DelayedMailer.last_error = nil
+ DelayedMailer.last_rescue_from_instance = nil
end
test 'should have a message' do
@@ -101,4 +108,46 @@ class MessageDeliveryTest < ActiveSupport::TestCase
@mail.deliver_later
end
end
+
+ test 'job delegates error handling to mailer' do
+ # Superclass not rescued by mailer's rescue_from RuntimeError
+ message = DelayedMailer.test_raise('StandardError')
+ assert_raise(StandardError) { message.deliver_later }
+ assert_nil DelayedMailer.last_error
+ assert_nil DelayedMailer.last_rescue_from_instance
+
+ # Rescued by mailer's rescue_from RuntimeError
+ message = DelayedMailer.test_raise('DelayedMailerError')
+ assert_nothing_raised { message.deliver_later }
+ assert_equal 'boom', DelayedMailer.last_error.message
+ assert_kind_of DelayedMailer, DelayedMailer.last_rescue_from_instance
+ end
+
+ class DeserializationErrorFixture
+ include GlobalID::Identification
+
+ def self.find(id)
+ raise 'boom, missing find'
+ end
+
+ attr_reader :id
+ def initialize(id = 1)
+ @id = id
+ end
+
+ def to_global_id(options = {})
+ super app: 'foo'
+ end
+ end
+
+ test 'job delegates deserialization errors to mailer class' do
+ # Inject an argument that can't be deserialized.
+ message = DelayedMailer.test_message(DeserializationErrorFixture.new)
+
+ # DeserializationError is raised, rescued, and delegated to the handler
+ # on the mailer class.
+ assert_nothing_raised { message.deliver_later }
+ assert_equal DelayedMailer, DelayedMailer.last_rescue_from_instance
+ assert_equal 'Error while trying to deserialize arguments: boom, missing find', DelayedMailer.last_error.message
+ end
end