Skip to content

Commit

Permalink
Active Job: Correctly use the desired test adapter in tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ghiculescu committed Sep 25, 2023
1 parent d8391b2 commit ba72b27
Show file tree
Hide file tree
Showing 13 changed files with 472 additions and 21 deletions.
13 changes: 13 additions & 0 deletions activejob/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
* All tests now respect the `active_job.queue_adapter` config

Previously if you had set `config.active_job.queue_adapter` in your `config/application.rb`
or `config/environments/test.rb` file, the adapter you selected was previously not used consistently
across all tests. In some tests your adapter would be used, but other tests would use the `TestAdapter`.

In Rails 7.1, all tests will respect the `queue_adapter` config if provided. If no config is provided,
the `TestAdapter` will continue to be used.

See [#48585](https://github.com/rails/rails/pull/48585) for more details.

*Alex Ghiculescu*

* Clarify the backoff strategy for the recommended `:wait` option when retrying jobs

`wait: :exponentially_longer` is waiting polynomially longer, so it is now recommended to use `wait: :polynomially_longer` to keep the same behavior.
Expand Down
20 changes: 14 additions & 6 deletions activejob/lib/active_job/queue_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ def adapter_name(adapter) # :nodoc:
# = Active Job Queue adapter
#
# The +ActiveJob::QueueAdapter+ module is used to load the
# correct adapter. The default queue adapter is the +:async+ queue.
# correct adapter. The default queue adapter is +:async+,
# which loads the ActiveJob::QueueAdapters::AsyncAdapter.
module QueueAdapter # :nodoc:
extend ActiveSupport::Concern

Expand All @@ -24,22 +25,20 @@ module QueueAdapter # :nodoc:
class_attribute :_queue_adapter, instance_accessor: false, instance_predicate: false

delegate :queue_adapter, to: :class

self.queue_adapter = :async
end

# Includes the setter method for changing the active queue adapter.
module ClassMethods
# Returns the backend queue provider. The default queue adapter
# is the +:async+ queue. See QueueAdapters for more information.
# is +:async+. See QueueAdapters for more information.
def queue_adapter
_queue_adapter
with_default_if_no_adapter_set { _queue_adapter }
end

# Returns string denoting the name of the configured queue adapter.
# By default returns <tt>"async"</tt>.
def queue_adapter_name
_queue_adapter_name
with_default_if_no_adapter_set { _queue_adapter_name }
end

# Specify the backend queue provider. The default queue adapter
Expand All @@ -61,6 +60,15 @@ def queue_adapter=(name_or_adapter)
end

private
def with_default_if_no_adapter_set
value = yield
if value.nil?
self.queue_adapter = :async
value = yield
end
value
end

def assign_adapter(adapter_name, queue_adapter)
self._queue_adapter_name = adapter_name
self._queue_adapter = queue_adapter
Expand Down
2 changes: 1 addition & 1 deletion activejob/lib/active_job/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class Railtie < Rails::Railtie # :nodoc:

initializer "active_job.set_configs" do |app|
options = app.config.active_job
options.queue_adapter ||= :async
options.queue_adapter ||= (Rails.env.test? ? :test : :async)

config.after_initialize do
options.each do |k, v|
Expand Down
46 changes: 38 additions & 8 deletions activejob/lib/active_job/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ def enable_test_adapter(test_adapter)
ActiveJob::Base.include(TestQueueAdapter)

def before_setup # :nodoc:
test_adapter = queue_adapter_for_test

queue_adapter_changed_jobs.each do |klass|
klass.enable_test_adapter(test_adapter)
if (test_adapter = test_adapter_should_be(klass))
klass.enable_test_adapter(test_adapter)
end
end

clear_enqueued_jobs
Expand All @@ -56,15 +56,14 @@ def after_teardown # :nodoc:

# Specifies the queue adapter to use with all Active Job test helpers.
#
# Returns an instance of the queue adapter and defaults to
# ActiveJob::QueueAdapters::TestAdapter.
# The default adapter in tests is ActiveJob::QueueAdapters::TestAdapter.
# Implement this method in a test class to override this.
#
# Note: The adapter provided by this method must provide some additional
# methods from those expected of a standard ActiveJob::QueueAdapter
# in order to be used with the active job test helpers. Refer to
# in order to be used with the Active Job test helpers. Refer to
# ActiveJob::QueueAdapters::TestAdapter.
def queue_adapter_for_test
ActiveJob::QueueAdapters::TestAdapter.new
end

# Asserts that the number of enqueued jobs matches the given number.
Expand Down Expand Up @@ -121,6 +120,8 @@ def queue_adapter_for_test
# end
# end
def assert_enqueued_jobs(number, only: nil, except: nil, queue: nil, &block)
require_active_job_test_adapter!("assert_enqueued_jobs")

if block_given?
original_jobs = enqueued_jobs_with(only: only, except: except, queue: queue)

Expand Down Expand Up @@ -183,6 +184,8 @@ def assert_enqueued_jobs(number, only: nil, except: nil, queue: nil, &block)
#
# assert_enqueued_jobs 0, &block
def assert_no_enqueued_jobs(only: nil, except: nil, queue: nil, &block)
require_active_job_test_adapter!("assert_no_enqueued_jobs")

assert_enqueued_jobs 0, only: only, except: except, queue: queue, &block
end

Expand Down Expand Up @@ -273,6 +276,8 @@ def assert_no_enqueued_jobs(only: nil, except: nil, queue: nil, &block)
# end
# end
def assert_performed_jobs(number, only: nil, except: nil, queue: nil, &block)
require_active_job_test_adapter!("assert_performed_jobs")

if block_given?
original_count = performed_jobs.size

Expand Down Expand Up @@ -341,6 +346,8 @@ def assert_performed_jobs(number, only: nil, except: nil, queue: nil, &block)
#
# assert_performed_jobs 0, &block
def assert_no_performed_jobs(only: nil, except: nil, queue: nil, &block)
require_active_job_test_adapter!("assert_no_performed_jobs")

assert_performed_jobs 0, only: only, except: except, queue: queue, &block
end

Expand Down Expand Up @@ -397,6 +404,8 @@ def assert_no_performed_jobs(only: nil, except: nil, queue: nil, &block)
# end
# end
def assert_enqueued_with(job: nil, args: nil, at: nil, queue: nil, priority: nil, &block)
require_active_job_test_adapter!("assert_enqueued_with")

expected = { job: job, args: args, at: at, queue: queue, priority: priority }.compact
expected_args = prepare_args_for_assertion(expected)
potential_matches = []
Expand Down Expand Up @@ -499,6 +508,8 @@ def assert_enqueued_with(job: nil, args: nil, at: nil, queue: nil, priority: nil
# end
# end
def assert_performed_with(job: nil, args: nil, at: nil, queue: nil, priority: nil, &block)
require_active_job_test_adapter!("assert_performed_with")

expected = { job: job, args: args, at: at, queue: queue, priority: priority }.compact
expected_args = prepare_args_for_assertion(expected)
potential_matches = []
Expand Down Expand Up @@ -606,7 +617,10 @@ def assert_performed_with(job: nil, args: nil, at: nil, queue: nil, priority: ni
# If an adapter other than the test adapter is in use, this method just yields.
# See queue_adapter_for_test for more information.
def perform_enqueued_jobs(only: nil, except: nil, queue: nil, at: nil, &block)
return flush_enqueued_jobs(only: only, except: except, queue: queue, at: at) unless block_given?
unless block_given?
require_active_job_test_adapter!("perform_enqueued_jobs (without a block)")
return flush_enqueued_jobs(only: only, except: except, queue: queue, at: at)
end

return _assert_nothing_raised_or_warn("perform_enqueued_jobs", &block) unless using_test_adapter?

Expand Down Expand Up @@ -648,6 +662,22 @@ def queue_adapter
end

private
def test_adapter_should_be(klass)
if (override_in_test_class = queue_adapter_for_test)
return override_in_test_class
end

if klass._queue_adapter.nil?
ActiveJob::QueueAdapters::TestAdapter.new
end
end

def require_active_job_test_adapter!(method)
unless using_test_adapter?
raise ArgumentError.new("#{method} requires the Active Job test adapter, you're using #{queue_adapter.class.name}.")
end
end

def using_test_adapter?
queue_adapter.is_a?(ActiveJob::QueueAdapters::TestAdapter)
end
Expand Down
3 changes: 3 additions & 0 deletions activejob/test/cases/delayed_job_adapter_test.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# frozen_string_literal: true

require "helper"
require "active_job/queue_adapters/delayed_job_adapter"
require "jobs/hello_job"
require "jobs/disable_log_job"

class DelayedJobAdapterTest < ActiveSupport::TestCase
test "does not log arguments when log_arguments is set to false on a job" do
Expand Down
4 changes: 4 additions & 0 deletions activejob/test/cases/instrumentation_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,17 @@ class InstrumentationTest < ActiveSupport::TestCase
end

test "retry emits an enqueue retry event" do
skip if adapter_is?(:inline, :sneakers)

events = subscribed("enqueue_retry.active_job") do
perform_enqueued_jobs { RetryJob.perform_later("DefaultsError", 2) }
end
assert_equal 1, events.size
end

test "retry exhaustion emits a retry_stopped event" do
skip if adapter_is?(:inline, :sneakers)

events = subscribed("retry_stopped.active_job") do
perform_enqueued_jobs { RetryJob.perform_later("CustomCatchError", 6) }
end
Expand Down
6 changes: 6 additions & 0 deletions activejob/test/cases/logging_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ def test_job_no_error_logging_on_rescuable_job
end

def test_enqueue_retry_logging
skip if adapter_is?(:inline, :sneakers)

perform_enqueued_jobs do
RetryJob.perform_later "DefaultsError", 2
assert_match(/Retrying RetryJob \(Job ID: .*?\) after \d+ attempts in 3 seconds, due to a DefaultsError.*\./, @logger.messages)
Expand All @@ -292,13 +294,17 @@ def test_enqueue_retry_logging_on_retry_job
end

def test_retry_stopped_logging
skip if adapter_is?(:inline, :sneakers)

perform_enqueued_jobs do
RetryJob.perform_later "CustomCatchError", 6
end
assert_match(/Stopped retrying RetryJob \(Job ID: .*?\) due to a CustomCatchError.*, which reoccurred on \d+ attempts\./, @logger.messages)
end

def test_retry_stopped_logging_without_block
skip if adapter_is?(:inline, :sneakers)

perform_enqueued_jobs do
RetryJob.perform_later "DefaultsError", 6
rescue DefaultsError
Expand Down
13 changes: 13 additions & 0 deletions activejob/test/cases/queue_adapter_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,19 @@ class QueueAdapterTest < ActiveJob::TestCase
assert_equal base_queue_adapter, child_job_three.queue_adapter, "child_job_three's queue adapter should remain unchanged"
end

test "should default to :async adapter if no adapters are set at all" do
ActiveJob::Base.disable_test_adapter
_queue_adapter_was = ActiveJob::Base._queue_adapter
_queue_adapter_name_was = ActiveJob::Base._queue_adapter_name
ActiveJob::Base._queue_adapter = ActiveJob::Base._queue_adapter_name = nil

assert_equal "async", ActiveJob::Base.queue_adapter_name
assert_kind_of ActiveJob::QueueAdapters::AsyncAdapter, ActiveJob::Base.queue_adapter
ensure
ActiveJob::Base._queue_adapter = _queue_adapter_was
ActiveJob::Base._queue_adapter_name = _queue_adapter_name_was
end

test "should extract a reasonable name from a class instance" do
child_job = Class.new(ActiveJob::Base)
child_job.queue_adapter = ActiveJob::QueueAdapters::StubOneAdapter.new
Expand Down
31 changes: 29 additions & 2 deletions activejob/test/cases/test_case_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,37 @@ def test_include_helper
end

def test_set_test_adapter
assert_kind_of ActiveJob::QueueAdapters::TestAdapter, queue_adapter
# The queue adapter the job uses depends on the Active Job config.
# See https://github.com/rails/rails/pull/48585 for logic.
expected = case ActiveJob::Base.queue_adapter_name.to_sym
when :test
ActiveJob::QueueAdapters::TestAdapter
when :inline
ActiveJob::QueueAdapters::InlineAdapter
when :async
ActiveJob::QueueAdapters::AsyncAdapter
when :backburner
ActiveJob::QueueAdapters::BackburnerAdapter
when :delayed_job
ActiveJob::QueueAdapters::DelayedJobAdapter
when :queue_classic
ActiveJob::QueueAdapters::QueueClassicAdapter
when :resque
ActiveJob::QueueAdapters::ResqueAdapter
when :sidekiq
ActiveJob::QueueAdapters::SidekiqAdapter
when :sneakers
ActiveJob::QueueAdapters::SneakersAdapter
when :sucker_punch
ActiveJob::QueueAdapters::SuckerPunchAdapter
else
raise NotImplementedError.new
end

assert_kind_of expected, queue_adapter
end

def test_does_not_perform_enqueued_jobs_by_default
assert_nil queue_adapter.perform_enqueued_jobs
assert_nil ActiveJob::QueueAdapters::TestAdapter.new.perform_enqueued_jobs
end
end
Loading

0 comments on commit ba72b27

Please sign in to comment.