rails: Rails 6 inconsistently overrides ActiveJob queue_adapter setting with TestAdapter
Summary
Like many folks, I set this in my config/environments/test.rb
file:
config.active_job.queue_adapter = :inline
The reason I do this is to have easy-to-test, deterministic behavior of any potentially async delayed jobs triggered by the application. Under Rails 5, all of my tests (children of ActiveSupport::TestCase
and ActionDispatch::SystemTestCase
alike) would respect this queue adapter. However, under Rails 6, any built-in Rails test case that includes ActiveJob::TestHelper
will also override this setting for all descendants of ActiveJob::Base
(relevant source).
The net effect of this is that my perform_later
and deliver_later
calls to jobs aren’t being fired synchronously (or, in fact, at all) during my system tests, which is leading to test failures upon upgrading to Rails 6.
Steps to reproduce
Here are two tests that demonstrates the problem:
require "test_helper"
class JobTest < ActiveSupport::TestCase
class SomeJob < ActiveJob::Base
cattr_accessor :job_ran
def perform
@@job_ran = true
end
end
def test_some_job
assert_equal :inline, Rails.application.config.active_job.queue_adapter
assert_equal ActiveJob::QueueAdapters::InlineAdapter, SomeJob.queue_adapter.class
SomeJob.perform_later
assert_equal true, SomeJob.job_ran
end
end
class JobSystemTest < ActionDispatch::SystemTestCase
class OtherJob < ActiveJob::Base
cattr_accessor :job_ran
def perform
@@job_ran = true
end
end
def test_other_job
assert_equal :inline, Rails.application.config.active_job.queue_adapter
assert_equal ActiveJob::QueueAdapters::InlineAdapter, OtherJob.queue_adapter.class
OtherJob.perform_later
assert_equal true, OtherJob.job_ran
end
end
Expected behavior
I would expect the behavior to have remained as it did under Rails 5, where the active_job.queue_adapter
setting would be respected for all of Rails’ test types.
Actual behavior
The first test, which descends from ActiveSupport::TestCase
will pass and behave as it did under Rails 5. However, the second test, descending from from ActionDispatch::SystemTestCase
will now fail under Rails 6, because OtherJob
’s queue_adapter
will have been reset by ActiveJob::TestHelper
to be an instance of TestAdapter
JobSystemTest#test_other_job [/Users/justin/code/testdouble/present/test/lib/job_test.rb:33]:
--- expected
+++ actual
@@ -1 +1 @@
-ActiveJob::QueueAdapters::InlineAdapter
+ActiveJob::QueueAdapters::TestAdapter
System configuration
Rails version: 6.0.0 as well as 6-0-stable, as of today.
Ruby version: ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-darwin18]
About this issue
- Original URL
- State: open
- Created 5 years ago
- Reactions: 47
- Comments: 43 (24 by maintainers)
Commits related to this issue
- Bundle update rspec-rails We need to this to support testing Sidekiq jobs inline, see https://github.com/rails/rails/issues/37270 and https://github.com/rspec/rspec-rails/pull/2242 for more informati... — committed to alphagov/content-data-api by thomasleese 4 years ago
- Bundle update rspec-rails We need to this to support testing Sidekiq jobs inline, see https://github.com/rails/rails/issues/37270 and https://github.com/rspec/rspec-rails/pull/2242 for more informati... — committed to alphagov/content-data-api by thomasleese 4 years ago
- Let the user choose active job queue in system test This reverts commit 3e4c770f529237dbaa5877ff80aa0d0b4594b0d1. Do not remove ::ActionDispatch::IntegrationTest::Behavior because this lead to unwan... — committed to rspec/rspec-rails by benoittgt 4 years ago
- Bundle update rspec-rails We need to this to support testing Sidekiq jobs inline, see https://github.com/rails/rails/issues/37270 and https://github.com/rspec/rspec-rails/pull/2242 for more informati... — committed to alphagov/content-data-api by thomasleese 4 years ago
- Bundle update rspec-rails We need to this to support testing Sidekiq jobs inline, see https://github.com/rails/rails/issues/37270 and https://github.com/rspec/rspec-rails/pull/2242 for more informati... — committed to alphagov/content-data-api by thomasleese 4 years ago
- Bundle update rspec-rails We need to this to support testing Sidekiq jobs inline, see https://github.com/rails/rails/issues/37270 and https://github.com/rspec/rspec-rails/pull/2242 for more informati... — committed to alphagov/content-data-api by thomasleese 4 years ago
- Lock rails to 6.0.0; 6.0.1 causes the system tests to fail due to "Net::ReadTimeout with #<TCPSocket:(closed)>" https://github.com/rails/rails/issues/37270 — committed to Sam-Killgallon/board-games by Sam-Killgallon 4 years ago
- Lock rails to 6.0.0; 6.0.1 causes the system tests to fail due to "Net::ReadTimeout with #<TCPSocket:(closed)>" https://github.com/rails/rails/issues/37270 — committed to Sam-Killgallon/board-games by Sam-Killgallon 4 years ago
- Lock rails to 6.0.0; 6.0.1 causes the system tests to fail due to "Net::ReadTimeout with #<TCPSocket:(closed)>" https://github.com/rails/rails/issues/37270 — committed to Sam-Killgallon/board-games by Sam-Killgallon 4 years ago
I had a similar problem with RSpec and request tests, I could workaround that with a little adaption of the code from @coorasse’s response above.
This issue showed up for us because we use the
:sidekiq
adapter even in our test environment. We were testing Sidekiq queue length in two of our tests, one which was a request spec, and the other just a model spec. The model spec had the correct adapter, but the request spec did not. Just providing more context for anyone else who comes across this issue! Adding(ActiveJob::Base.descendants << ActiveJob::Base).each(&:disable_test_adapter)
toconfig.before(:suite)
in ourspec_helper.rb
fixed it.We have the same issue with Rails
6.0.2.1
. Workaround: adding insetup
:(thanks @searls ❤️ )
This helped me:
@gmcgibbon Could we get this issue reopened?
I’d like to leave this here, since it could help somebody else. In our standard configuration we use rspec and we run system tests with an
inline
adapter, and other tests withtest
adapter. We had this RSpec configuration:this needs to be changed to:
Hi everyone! I’d love some feedback on this: https://github.com/rails/rails/pull/48585
By the way, for anyone looking to just disable this, one might write a setup hook like this one, invoking the
disable_test_adapter
method also added by the ActiveJob::TestHelper:The only thing that worked for me was something like:
cause the line suggested in this thread
broke other tests, that uses the test adapter and were executed after my test with the real queue adapter. I don’t really understand why it works that way, but for me it does.
OK, with my rspec setup, in an rspec/rails
:system
test, what’s happening is first the rspecbefore
block runs.THEN this Rails ActiveJob test_helper before_setup block runs: https://github.com/rails/rails/blob/master/activejob/lib/active_job/test_helper.rb#L36-L46
That before_setup calls
enable_test_adapter
with an argument being the methodqueue_adapter_for_test
. Butqueue_adapter_for_test
is hard-coded to ActiveJob::QueueAdapters::TestAdapter.new https://github.com/rails/rails/blob/master/activejob/lib/active_job/test_helper.rb#L63-L65I am not sure if this is a bad interaction between rspec-rails and rails that needs to be fixed on rspec side… but I also don’t understand how this architecture allows you to change the test ActiveJob adapter at all, it seems to have a
before_setup
that is hard-coded to insist on the Test adapter (ie :test).I don’t understand what the intent/purpose of that code in activejob/lib/active_job/test_helper.rb is, it’s very confusing.
The comments go on to say:
There is nothing talking about “additional methods” in the TestAdapter source/comments though that I can find.
I’m pretty bewildered. This is all very old code that predates Rails 6, so I’m not sure why things are breaking just in Rails 6, especially because this code doesn’t make any sense to me in the first place.
My workaround was to wrap the code inside a
This way, any jobs that are enqueued inside the block, will be run automatically.
It is mysterious and frustrating!
It definitely matters what kind of test it was. So interstingly, there was a previous bug in Rails related to this that only applied to system tests, that was fixed in: https://github.com/rails/rails/pull/36283
However, that PR makes system tests “Inherit from ActiveSupport::TestCase instead of ActionDispatch::IntegrationTest” to fix the problem – which implies the problem might still be there in IntegrationTests, or perhaps Integration tests are intentionally not designed to allow queue_adapter setting?
@rept, you say you are using rspec requests tests… but guess what, rspec says: “Request specs provide a thin wrapper around Rails’ integration test”,
There are two things to tease apart here:
So, while a pain, if I were you and had time/energy and wanted to try to help get somewhere here, I’d try making a fresh empty Rails app that has nothing in it, and seeing if I can reproduce the problem without usingRspec, using a Rails integration test specifically – not rspec. (or if you’re having the problem in another test type, in that one).
Then report that with the reproduction (if you can do it as a self-contained test-case, even better) – either here, or make a new issue with more specific scope and concise problem report.
Sorry, I know a bug like this is annoying.
Rails still force
TestAdapter
to be used. None of the solutions above didn’t help, I can’t change the adapter nor before tests starts nor even just beforeperform_later
call. Only spreadingperform_enqueued_jobs
in tests helped me.TL; DR: Upgrading from Rails 5 to 6 caused this bug. However, I cannot confirm that
6-0-stable
ormaster
fixed the problem.Background
When I enqueue a job via Ajax, I’m using the
provider_job_id
to set up a websocket listener to provide visual feedback on how this particular job is doing.For some reasone, the
provider_job_id
is not properly kept between requests when I use theTestAdapter
(not sure why, I think it’s simply not persisting it). So I’ve been using Sidekiq even in tests:But I have Sidekiq run the jobs inline in feature tests (that way, the
provider_job_id
is reliably kept):So, my capybara tests started failing as of Rails 6:
I could not even move the patch to the RSpec
config.around
block, it works only right here, in the test.I started noticing in my test logs that, in Rails 6, the job is only enqueued but not run. (And when I wrapped the test in
perform_enqueued_jobs do
, the job ran, but theprovider_job_id
was not matching from when the job was enqueued compared to when the websocket channel is set up.)Thank you @searls for the detailed bug report, can you confirm whether
6-0-stable
fixed this for you?@gmcgibbon Did you try the “Steps to reproduce” from the issue description on
6-0-master
? I’ll try that.I’m truly sorry I wasn’t there when the Rails 6 release candidates were battle tested 😢 Let me know if I can be of further assistance.
@benoittgt Happy to
We added a patch on RSpec to do that on system spec but maybe we could handle it for integration spec too.
See https://github.com/rspec/rspec-rails/pull/2242 and https://relishapp.com/rspec/rspec-rails/v/4-0/docs/system-specs/system-spec#the-activejob-queue-adapter-can-be-changed
Could you open an issue?
Thanks @beauraF. That’s precisely what #36283 was trying to sidestep for system test cases. I’m thinking we might have to change the behaviour of
ActiveJob::TestHelper
because it looks like its inclusion in integration tests is intentional. It seems we likely have to delay enabling the test adapter on jobs until just before we assert.Backported in ea77dbffdc81d6e40bbde155961ab57f1450d1e4, 1a09b6ebfb75a26dbb4143bf220733aefa854dd8, and 109aad7ca93f0bcb2319df19b45f05b6794b3b92. Let me know if you’re still having issues against
6-0-stable
and we can reopen. Thanks!