Skip to content

Commit

Permalink
Fixup have_enqueued_job matcher on job retries
Browse files Browse the repository at this point in the history
Previously we were checking only job counts, so if one job was
performed and one job was added - matcher failed. Check by unique
id (`#hash`) instead.
We cannot use `job['job_id']` here, because job retains `job_id` on retry.
  • Loading branch information
ojab committed Feb 15, 2022
1 parent 620a869 commit f6b2620
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 6 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Expand Up @@ -5,6 +5,7 @@ on:
- 'main'
- '*-maintenance'
- '*-dev'
- '*'
pull_request:
branches:
- '*'
Expand Down
20 changes: 17 additions & 3 deletions lib/rspec/rails/matchers/active_job.rb
Expand Up @@ -230,11 +230,25 @@ def initialize(job)
def matches?(proc)
raise ArgumentError, "have_enqueued_job and enqueue_job only support block expectations" unless Proc === proc

original_enqueued_jobs_count = queue_adapter.enqueued_jobs.count
original_enqueued_jobs_hashes = queue_adapter.enqueued_jobs.map(&:hash)
proc.call
in_block_jobs = queue_adapter.enqueued_jobs.drop(original_enqueued_jobs_count)

check(in_block_jobs)
in_block_jobs = queue_adapter.enqueued_jobs.each_with_object({}) do |job, memo|
memo[job.hash] ||= {job: job, count: 0}
memo[job.hash][:count] += 1
end

original_enqueued_jobs_hashes.each do |job_hash|
in_block_jobs[job_hash][:count] -= 1 if in_block_jobs.key?(job_hash)
end

in_block_jobs = in_block_jobs.flat_map do |hash, job_and_count|
count, job = job_and_count.values_at(:count, :job)

Array.new(count, job) if count.positive?
end

check(in_block_jobs.compact)
end

def does_not_match?(proc)
Expand Down
6 changes: 3 additions & 3 deletions rspec-rails.gemspec
Expand Up @@ -46,12 +46,12 @@ Gem::Specification.new do |s|
# get released.
%w[core expectations mocks support].each do |name|
if ENV['RSPEC_CI']
s.add_runtime_dependency "rspec-#{name}", ENV.fetch('RSPEC_VERSION', '3.11.0.pre')
s.add_runtime_dependency "rspec-#{name}", ENV.fetch('RSPEC_VERSION', '3.12.0.pre')
elsif RSpec::Rails::Version::STRING =~ /pre/ # prerelease builds
expected_rspec_version = "3.11.0.pre"
expected_rspec_version = "3.12.0.pre"
s.add_runtime_dependency "rspec-#{name}", "= #{expected_rspec_version}"
else
expected_rspec_version = "3.10.0"
expected_rspec_version = "3.11.0"
s.add_runtime_dependency "rspec-#{name}", "~> #{expected_rspec_version.split(".")[0..1].join(".")}"
end
end
Expand Down
25 changes: 25 additions & 0 deletions spec/rspec/rails/matchers/active_job_spec.rb
Expand Up @@ -98,6 +98,31 @@ def self.name; "LoggingJob"; end
expect { }.not_to have_enqueued_job
end

context "when job is retried" do
include ActiveJob::TestHelper

let(:retried_job) do
Class.new(ActiveJob::Base) do
retry_on StandardError, wait: 5, queue: :retry

def self.name; "RetriedJob"; end
def perform; raise StandardError; end
end
end

before do
stub_const("RetriedJob", retried_job)
queue_adapter.perform_enqueued_jobs = true
end

it "passes with reenqueued job" do
time = Time.current.change(usec: 0)
travel_to time do
expect { retried_job.perform_later }.to have_enqueued_job(retried_job).on_queue(:retry).at(time + 5)
end
end
end

it "fails when job is not enqueued" do
expect {
expect { }.to have_enqueued_job
Expand Down

0 comments on commit f6b2620

Please sign in to comment.