Created
October 8, 2015 09:03
-
-
Save arturictus/bbdf020b2deca2e29c94 to your computer and use it in GitHub Desktop.
Revisions
-
arturictus created this gist
Oct 8, 2015 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,356 @@ def specific_enqueued_jobs(job) enqueued_jobs.select{ |j| j if j[:job] == job } end require 'active_support/core_ext/class/subclasses' require 'active_support/core_ext/hash/keys' module ActiveJob # Provides helper methods for testing Active Job module RSpecHelper extend ActiveSupport::Concern included do def before_setup # :nodoc: test_adapter = ActiveJob::QueueAdapters::TestAdapter.new @old_queue_adapters = (ActiveJob::Base.subclasses << ActiveJob::Base).select do |klass| # only override explicitly set adapters, a quirk of `class_attribute` klass.singleton_class.public_instance_methods(false).include?(:_queue_adapter) end.map do |klass| [klass, klass.queue_adapter].tap do klass.queue_adapter = test_adapter end end clear_enqueued_jobs clear_performed_jobs super end def after_teardown # :nodoc: super @old_queue_adapters.each do |(klass, adapter)| klass.queue_adapter = adapter end end # Asserts that the number of enqueued jobs matches the given number. # # def test_jobs # expect_enqueued_jobs 0 # HelloJob.perform_later('david') # expect_enqueued_jobs 1 # HelloJob.perform_later('abdelkader') # expect_enqueued_jobs 2 # end # # If a block is passed, that block should cause the specified number of # jobs to be enqueued. # # def test_jobs_again # expect_enqueued_jobs 1 do # HelloJob.perform_later('cristian') # end # # expect_enqueued_jobs 2 do # HelloJob.perform_later('aaron') # HelloJob.perform_later('rafael') # end # end # # The number of times a specific job is enqueued can be asserted. # # def test_logging_job # expect_enqueued_jobs 2, only: LoggingJob do # LoggingJob.perform_later # HelloJob.perform_later('jeremy') # end # end require 'rspec/expectations' RSpec::Matchers.define :have_enqueued_jobs do |expected| match do |actual| actual == expected end failure_message do |actual| "#{expected} jobs expected, but #{actual} were enqueued" end end def expect_enqueued_jobs(number, only: nil) if block_given? original_count = enqueued_jobs_size(only: only) yield new_count = enqueued_jobs_size(only: only) expect(number).to have_enqueued_jobs(new_count - original_count) else actual_count = enqueued_jobs_size(only: only) expect(number).to have_enqueued_jobs(actual_count) end end # Asserts that no jobs have been enqueued. # # def test_jobs # expect_no_enqueued_jobs # HelloJob.perform_later('jeremy') # expect_enqueued_jobs 1 # end # # If a block is passed, that block should not cause any job to be enqueued. # # def test_jobs_again # expect_no_enqueued_jobs do # # No job should be enqueued from this block # end # end # # It can be asserted that no jobs of a specific kind are enqueued: # # def test_no_logging # expect_no_enqueued_jobs only: LoggingJob do # HelloJob.perform_later('jeremy') # end # end # # Note: This assertion is simply a shortcut for: # # expect_enqueued_jobs 0, &block def expect_no_enqueued_jobs(only: nil, &block) expect_enqueued_jobs 0, only: only, &block end # Asserts that the number of performed jobs matches the given number. # If no block is passed, <tt>perform_enqueued_jobs</tt> # must be called around the job call. # # def test_jobs # expect_performed_jobs 0 # # perform_enqueued_jobs do # HelloJob.perform_later('xavier') # end # expect_performed_jobs 1 # # perform_enqueued_jobs do # HelloJob.perform_later('yves') # expect_performed_jobs 2 # end # end # # If a block is passed, that block should cause the specified number of # jobs to be performed. # # def test_jobs_again # expect_performed_jobs 1 do # HelloJob.perform_later('robin') # end # # expect_performed_jobs 2 do # HelloJob.perform_later('carlos') # HelloJob.perform_later('sean') # end # end # # The block form supports filtering. If the :only option is specified, # then only the listed job(s) will be performed. # # def test_hello_job # expect_performed_jobs 1, only: HelloJob do # HelloJob.perform_later('jeremy') # LoggingJob.perform_later # end # end # # An array may also be specified, to support testing multiple jobs. # # def test_hello_and_logging_jobs # assert_nothing_raised do # expect_performed_jobs 2, only: [HelloJob, LoggingJob] do # HelloJob.perform_later('jeremy') # LoggingJob.perform_later('stewie') # RescueJob.perform_later('david') # end # end # end RSpec::Matchers.define :have_performed_jobs do |expected| match do |actual| actual == expected end failure_message do |actual| "#{expected} jobs expected, but #{actual} were performed" end end def expect_performed_jobs(number, only: nil) if block_given? original_count = performed_jobs.size perform_enqueued_jobs(only: only) { yield } new_count = performed_jobs.size expect(number).to have_performed_jobs(new_count - original_count) else performed_jobs_size = performed_jobs.size expect(number).to have_performed_jobs(performed_jobs_size) end end # Asserts that no jobs have been performed. # # def test_jobs # expect_no_performed_jobs # # perform_enqueued_jobs do # HelloJob.perform_later('matthew') # expect_performed_jobs 1 # end # end # # If a block is passed, that block should not cause any job to be performed. # # def test_jobs_again # expect_no_performed_jobs do # # No job should be performed from this block # end # end # # The block form supports filtering. If the :only option is specified, # then only the listed job(s) will be performed. # # def test_hello_job # expect_performed_jobs 1, only: HelloJob do # HelloJob.perform_later('jeremy') # LoggingJob.perform_later # end # end # # An array may also be specified, to support testing multiple jobs. # # def test_hello_and_logging_jobs # assert_nothing_raised do # expect_performed_jobs 2, only: [HelloJob, LoggingJob] do # HelloJob.perform_later('jeremy') # LoggingJob.perform_later('stewie') # RescueJob.perform_later('david') # end # end # end # # Note: This assertion is simply a shortcut for: # # expect_performed_jobs 0, &block def expect_no_performed_jobs(only: nil, &block) expect_performed_jobs 0, only: only, &block end # Asserts that the job passed in the block has been enqueued with the given arguments. # # def test_assert_enqueued_with # assert_enqueued_with(job: MyJob, args: [1,2,3], queue: 'low') 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 RSpec::Matchers.define :have_enqueued_job do |expected| match do |actual| actual == expected end failure_message do |actual| "#{expected} jobs expected, but #{actual} were performed" end end def assert_enqueued_with(args = {}) original_enqueued_jobs_count = enqueued_jobs.count args.assert_valid_keys(:job, :args, :at, :queue) serialized_args = serialize_args_for_assertion(args) yield in_block_jobs = enqueued_jobs.drop(original_enqueued_jobs_count) matching_job = in_block_jobs.find do |job| serialized_args.all? { |key, value| value == job[key] } end assert matching_job, "No enqueued job found with #{args}" instantiate_job(matching_job) end # Asserts that the job passed in the block has been performed with the given arguments. # # def test_assert_performed_with # assert_performed_with(job: MyJob, args: [1,2,3], queue: 'high') 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(args = {}) original_performed_jobs_count = performed_jobs.count args.assert_valid_keys(:job, :args, :at, :queue) serialized_args = serialize_args_for_assertion(args) perform_enqueued_jobs { yield } in_block_jobs = performed_jobs.drop(original_performed_jobs_count) matching_job = in_block_jobs.find do |job| serialized_args.all? { |key, value| value == job[key] } end assert matching_job, "No performed job found with #{args}" instantiate_job(matching_job) end def perform_enqueued_jobs(only: nil) 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 begin queue_adapter.perform_enqueued_jobs = true queue_adapter.perform_enqueued_at_jobs = true queue_adapter.filter = only yield 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 end end def queue_adapter ActiveJob::Base.queue_adapter end delegate :enqueued_jobs, :enqueued_jobs=, :performed_jobs, :performed_jobs=, to: :queue_adapter private def clear_enqueued_jobs # :nodoc: enqueued_jobs.clear end def clear_performed_jobs # :nodoc: performed_jobs.clear end def enqueued_jobs_size(only: nil) # :nodoc: if only enqueued_jobs.count { |job| Array(only).include?(job.fetch(:job)) } else enqueued_jobs.count end end def serialize_args_for_assertion(args) # :nodoc: args.dup.tap do |serialized_args| serialized_args[:args] = ActiveJob::Arguments.serialize(serialized_args[:args]) if serialized_args[:args] serialized_args[:at] = serialized_args[:at].to_f if serialized_args[:at] end end def instantiate_job(payload) # :nodoc: job = payload[:job].new(*payload[:args]) job.scheduled_at = Time.at(payload[:at]) if payload.key?(:at) job.queue_name = payload[:queue] job end end end end