lib/active_job/test_helper.rb in activejob-6.0.6.1 vs lib/active_job/test_helper.rb in activejob-6.1.0.rc1

- old
+ new

@@ -115,21 +115,21 @@ # assert_enqueued_jobs 2, queue: 'default' do # LoggingJob.perform_later # HelloJob.perform_later('elfassy') # end # end - def assert_enqueued_jobs(number, only: nil, except: nil, queue: nil) + def assert_enqueued_jobs(number, only: nil, except: nil, queue: nil, &block) if block_given? - original_count = enqueued_jobs_with(only: only, except: except, queue: queue) + original_jobs = enqueued_jobs_with(only: only, except: except, queue: queue) - yield + assert_nothing_raised(&block) - new_count = enqueued_jobs_with(only: only, except: except, queue: queue) + new_jobs = enqueued_jobs_with(only: only, except: except, queue: queue) - actual_count = new_count - original_count + actual_count = (new_jobs - original_jobs).count else - actual_count = enqueued_jobs_with(only: only, except: except, queue: queue) + actual_count = enqueued_jobs_with(only: only, except: except, queue: queue).count end assert_equal number, actual_count, "#{number} jobs expected, but #{actual_count} were enqueued" end @@ -277,11 +277,11 @@ new_count = performed_jobs.size performed_jobs_size = new_count - original_count else - performed_jobs_size = performed_jobs_with(only: only, except: except, queue: queue) + performed_jobs_size = performed_jobs_with(only: only, except: except, queue: queue).count end assert_equal number, performed_jobs_size, "#{number} jobs expected, but #{performed_jobs_size} were performed" end @@ -343,146 +343,145 @@ # Asserts that the job has been enqueued with the given arguments. # # def test_assert_enqueued_with # MyJob.perform_later(1,2,3) - # assert_enqueued_with(job: MyJob, args: [1,2,3], queue: 'low') + # assert_enqueued_with(job: MyJob, args: [1,2,3]) # - # MyJob.set(wait_until: Date.tomorrow.noon).perform_later - # assert_enqueued_with(job: MyJob, at: Date.tomorrow.noon) + # MyJob.set(wait_until: Date.tomorrow.noon, queue: "my_queue").perform_later + # assert_enqueued_with(at: Date.tomorrow.noon, queue: "my_queue") # end # - # The +at+ and +args+ arguments also accept a proc. + # The given arguments may also be specified as matcher procs that return a + # boolean value indicating whether a job's attribute meets certain criteria. # - # To the +at+ proc, it will get passed the actual job's at argument. + # For example, a proc can be used to match a range of times: # # def test_assert_enqueued_with - # expected_time = ->(at) do - # (Date.yesterday..Date.tomorrow).cover?(at) - # end + # at_matcher = ->(job_at) { (Date.yesterday..Date.tomorrow).cover?(job_at) } # - # MyJob.set(at: Date.today.noon).perform_later - # assert_enqueued_with(job: MyJob, at: expected_time) + # MyJob.set(wait_until: Date.today.noon).perform_later + # + # assert_enqueued_with(job: MyJob, at: at_matcher) # end # - # To the +args+ proc, it will get passed the actual job's arguments - # Your proc needs to return a boolean value determining if - # the job's arguments matches your expectation. This is useful to check only - # for a subset of arguments. + # A proc can also be used to match a subset of a job's args: # # def test_assert_enqueued_with - # expected_args = ->(job_args) do - # assert job_args.first.key?(:foo) - # end + # args_matcher = ->(job_args) { job_args[0].key?(:foo) } # - # MyJob.perform_later(foo: 'bar', other_arg: 'No need to check in the test') - # assert_enqueued_with(job: MyJob, args: expected_args, queue: 'low') + # MyJob.perform_later(foo: "bar", other_arg: "No need to check in the test") + # + # assert_enqueued_with(job: MyJob, args: args_matcher) # end # # If a block is passed, asserts that the block will cause the job to be # enqueued with the given arguments. # # def test_assert_enqueued_with - # assert_enqueued_with(job: MyJob, args: [1,2,3], queue: 'low') do + # assert_enqueued_with(job: MyJob, args: [1,2,3]) do # MyJob.perform_later(1,2,3) # end # # assert_enqueued_with(job: MyJob, at: Date.tomorrow.noon) do # MyJob.set(wait_until: Date.tomorrow.noon).perform_later # end # end - def assert_enqueued_with(job: nil, args: nil, at: nil, queue: nil) + def assert_enqueued_with(job: nil, args: nil, at: nil, queue: nil, &block) expected = { job: job, args: args, at: at, queue: queue }.compact expected_args = prepare_args_for_assertion(expected) + potential_matches = [] if block_given? - original_enqueued_jobs_count = enqueued_jobs.count + original_enqueued_jobs = enqueued_jobs.dup - yield + assert_nothing_raised(&block) - jobs = enqueued_jobs.drop(original_enqueued_jobs_count) + jobs = enqueued_jobs - original_enqueued_jobs else jobs = enqueued_jobs end matching_job = jobs.find do |enqueued_job| deserialized_job = deserialize_args_for_assertion(enqueued_job) + potential_matches << deserialized_job expected_args.all? do |key, value| if value.respond_to?(:call) value.call(deserialized_job[key]) else value == deserialized_job[key] end end end - assert matching_job, "No enqueued job found with #{expected}" + message = +"No enqueued job found with #{expected}" + message << "\n\nPotential matches: #{potential_matches.join("\n")}" if potential_matches.present? + assert matching_job, message instantiate_job(matching_job) end # Asserts that the job has been performed with the given arguments. # # def test_assert_performed_with # MyJob.perform_later(1,2,3) # # perform_enqueued_jobs # - # assert_performed_with(job: MyJob, args: [1,2,3], queue: 'high') + # assert_performed_with(job: MyJob, args: [1,2,3]) # - # MyJob.set(wait_until: Date.tomorrow.noon).perform_later + # MyJob.set(wait_until: Date.tomorrow.noon, queue: "my_queue").perform_later # # perform_enqueued_jobs # - # assert_performed_with(job: MyJob, at: Date.tomorrow.noon) + # assert_performed_with(at: Date.tomorrow.noon, queue: "my_queue") # end # - # The +at+ and +args+ arguments also accept a proc. + # The given arguments may also be specified as matcher procs that return a + # boolean value indicating whether a job's attribute meets certain criteria. # - # To the +at+ proc, it will get passed the actual job's at argument. + # For example, a proc can be used to match a range of times: # - # def test_assert_enqueued_with - # expected_time = ->(at) do - # (Date.yesterday..Date.tomorrow).cover?(at) - # end + # def test_assert_performed_with + # at_matcher = ->(job_at) { (Date.yesterday..Date.tomorrow).cover?(job_at) } # - # MyJob.set(at: Date.today.noon).perform_later - # assert_enqueued_with(job: MyJob, at: expected_time) + # MyJob.set(wait_until: Date.today.noon).perform_later + # + # perform_enqueued_jobs + # + # assert_performed_with(job: MyJob, at: at_matcher) # end # - # To the +args+ proc, it will get passed the actual job's arguments - # Your proc needs to return a boolean value determining if - # the job's arguments matches your expectation. This is useful to check only - # for a subset of arguments. + # A proc can also be used to match a subset of a job's args: # # def test_assert_performed_with - # expected_args = ->(job_args) do - # assert job_args.first.key?(:foo) - # end - # MyJob.perform_later(foo: 'bar', other_arg: 'No need to check in the test') + # args_matcher = ->(job_args) { job_args[0].key?(:foo) } # + # MyJob.perform_later(foo: "bar", other_arg: "No need to check in the test") + # # perform_enqueued_jobs # - # assert_performed_with(job: MyJob, args: expected_args, queue: 'high') + # assert_performed_with(job: MyJob, args: args_matcher) # end # # If a block is passed, that block performs all of the jobs that were # enqueued throughout the duration of the block and asserts that # the job has been performed with the given arguments in the block. # # def test_assert_performed_with - # assert_performed_with(job: MyJob, args: [1,2,3], queue: 'high') do + # assert_performed_with(job: MyJob, args: [1,2,3]) do # MyJob.perform_later(1,2,3) # end # # assert_performed_with(job: MyJob, at: Date.tomorrow.noon) do # MyJob.set(wait_until: Date.tomorrow.noon).perform_later # end # end def assert_performed_with(job: nil, args: nil, at: nil, queue: nil, &block) expected = { job: job, args: args, at: at, queue: queue }.compact expected_args = prepare_args_for_assertion(expected) + potential_matches = [] if block_given? original_performed_jobs_count = performed_jobs.count perform_enqueued_jobs(&block) @@ -492,21 +491,25 @@ jobs = performed_jobs end matching_job = jobs.find do |enqueued_job| deserialized_job = deserialize_args_for_assertion(enqueued_job) + potential_matches << deserialized_job expected_args.all? do |key, value| if value.respond_to?(:call) value.call(deserialized_job[key]) else value == deserialized_job[key] end end end - assert matching_job, "No performed job found with #{expected}" + message = +"No performed job found with #{expected}" + message << "\n\nPotential matches: #{potential_matches.join("\n")}" if potential_matches.present? + assert matching_job, message + instantiate_job(matching_job) end # Performs all enqueued jobs. If a block is given, performs all of the jobs # that were enqueued throughout the duration of the block. If a block is @@ -561,35 +564,40 @@ # HelloJob.set(queue: :other_queue).perform_later(1, 2, 3) # will not be performed # end # assert_performed_jobs 1 # end # - def perform_enqueued_jobs(only: nil, except: nil, queue: nil) - return flush_enqueued_jobs(only: only, except: except, queue: queue) unless block_given? + # If the +:at+ option is specified, then only run jobs enqueued to run + # immediately or before the given time + 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? validate_option(only: only, except: except) old_perform_enqueued_jobs = queue_adapter.perform_enqueued_jobs old_perform_enqueued_at_jobs = queue_adapter.perform_enqueued_at_jobs old_filter = queue_adapter.filter old_reject = queue_adapter.reject old_queue = queue_adapter.queue + old_at = queue_adapter.at begin queue_adapter.perform_enqueued_jobs = true queue_adapter.perform_enqueued_at_jobs = true queue_adapter.filter = only queue_adapter.reject = except queue_adapter.queue = queue + queue_adapter.at = at - yield + assert_nothing_raised(&block) ensure queue_adapter.perform_enqueued_jobs = old_perform_enqueued_jobs queue_adapter.perform_enqueued_at_jobs = old_perform_enqueued_at_jobs queue_adapter.filter = old_filter queue_adapter.reject = old_reject queue_adapter.queue = old_queue + queue_adapter.at = old_at end end # Accesses the queue_adapter set by ActiveJob::Base. # @@ -607,14 +615,14 @@ def clear_performed_jobs performed_jobs.clear end - def jobs_with(jobs, only: nil, except: nil, queue: nil) + def jobs_with(jobs, only: nil, except: nil, queue: nil, at: nil) validate_option(only: only, except: except) - jobs.count do |job| + jobs.dup.select do |job| job_class = job.fetch(:job) if only next false unless filter_as_proc(only).call(job) elsif except @@ -623,10 +631,14 @@ if queue next false unless queue.to_s == job.fetch(:queue, job_class.queue_name) end + if at && job[:at] + next false if job[:at] > at.to_f + end + yield job if block_given? true end end @@ -635,44 +647,31 @@ return filter if filter.is_a?(Proc) ->(job) { Array(filter).include?(job.fetch(:job)) } end - def enqueued_jobs_with(only: nil, except: nil, queue: nil, &block) - jobs_with(enqueued_jobs, only: only, except: except, queue: queue, &block) + def enqueued_jobs_with(only: nil, except: nil, queue: nil, at: nil, &block) + jobs_with(enqueued_jobs, only: only, except: except, queue: queue, at: at, &block) end def performed_jobs_with(only: nil, except: nil, queue: nil, &block) jobs_with(performed_jobs, only: only, except: except, queue: queue, &block) end - def flush_enqueued_jobs(only: nil, except: nil, queue: nil) - enqueued_jobs_with(only: only, except: except, queue: queue) do |payload| - instantiate_job(payload).perform_now + def flush_enqueued_jobs(only: nil, except: nil, queue: nil, at: nil) + enqueued_jobs_with(only: only, except: except, queue: queue, at: at) do |payload| + queue_adapter.enqueued_jobs.delete(payload) queue_adapter.performed_jobs << payload - end + instantiate_job(payload).perform_now + end.count end def prepare_args_for_assertion(args) args.dup.tap do |arguments| - if arguments[:at] && !arguments[:at].respond_to?(:call) + if arguments[:at].acts_like?(:time) at_range = arguments[:at] - 1..arguments[:at] + 1 arguments[:at] = ->(at) { at_range.cover?(at) } end - arguments[:args] = round_time_arguments(arguments[:args]) if arguments[:args] - end - end - - def round_time_arguments(argument) - case argument - when Time, ActiveSupport::TimeWithZone, DateTime - argument.change(usec: 0) - when Hash - argument.transform_values { |value| round_time_arguments(value) } - when Array - argument.map { |element| round_time_arguments(element) } - else - argument end end def deserialize_args_for_assertion(job) job.dup.tap do |new_job|