diff options
author | ecoologic <erikecoologic@gmail.com> | 2014-10-07 23:17:56 +1000 |
---|---|---|
committer | ecoologic <erikecoologic@gmail.com> | 2014-10-07 23:17:56 +1000 |
commit | 117f09c5d1eb600908001bb7b5ee353756e56456 (patch) | |
tree | 717d45020cf652840f90c09579692e30bf31237b /activejob/test | |
parent | 8caf16a281260fedb0677c85047469e99c48da94 (diff) | |
parent | 75780373af9a3ddd4cc1bda3d4dbfe6121102b2e (diff) | |
download | rails-117f09c5d1eb600908001bb7b5ee353756e56456.tar.gz rails-117f09c5d1eb600908001bb7b5ee353756e56456.tar.bz2 rails-117f09c5d1eb600908001bb7b5ee353756e56456.zip |
Merge remote-tracking branch 'origin/master' into guides-template-inheritance
Diffstat (limited to 'activejob/test')
31 files changed, 927 insertions, 77 deletions
diff --git a/activejob/test/cases/callbacks_test.rb b/activejob/test/cases/callbacks_test.rb index 9a0657ee89..9af2380767 100644 --- a/activejob/test/cases/callbacks_test.rb +++ b/activejob/test/cases/callbacks_test.rb @@ -5,7 +5,8 @@ require 'active_support/core_ext/object/inclusion' class CallbacksTest < ActiveSupport::TestCase test 'perform callbacks' do - performed_callback_job = CallbackJob.new.tap { |j| j.execute("A-JOB-ID") } + performed_callback_job = CallbackJob.new("A-JOB-ID") + performed_callback_job.perform_now assert "CallbackJob ran before_perform".in? performed_callback_job.history assert "CallbackJob ran after_perform".in? performed_callback_job.history assert "CallbackJob ran around_perform_start".in? performed_callback_job.history @@ -13,7 +14,7 @@ class CallbacksTest < ActiveSupport::TestCase end test 'enqueue callbacks' do - enqueued_callback_job = CallbackJob.enqueue + enqueued_callback_job = CallbackJob.perform_later assert "CallbackJob ran before_enqueue".in? enqueued_callback_job.history assert "CallbackJob ran after_enqueue".in? enqueued_callback_job.history assert "CallbackJob ran around_enqueue_start".in? enqueued_callback_job.history diff --git a/activejob/test/cases/job_serialization_test.rb b/activejob/test/cases/job_serialization_test.rb index fc1b77744c..db22783030 100644 --- a/activejob/test/cases/job_serialization_test.rb +++ b/activejob/test/cases/job_serialization_test.rb @@ -9,7 +9,7 @@ class JobSerializationTest < ActiveSupport::TestCase end test 'serialize job with gid' do - GidJob.enqueue @person + GidJob.perform_later @person assert_equal "Person with ID: 5", JobBuffer.last_value end end diff --git a/activejob/test/cases/logging_test.rb b/activejob/test/cases/logging_test.rb index 888c183a0b..9c56ee08b6 100644 --- a/activejob/test/cases/logging_test.rb +++ b/activejob/test/cases/logging_test.rb @@ -42,34 +42,43 @@ class AdapterTest < ActiveSupport::TestCase def test_uses_active_job_as_tag - HelloJob.enqueue "Cristian" + HelloJob.perform_later "Cristian" assert_match(/\[ActiveJob\]/, @logger.messages) end + def test_uses_job_name_as_tag + LoggingJob.perform_later "Dummy" + assert_match(/\[LoggingJob\]/, @logger.messages) + end + + def test_uses_job_id_as_tag + LoggingJob.perform_later "Dummy" + assert_match(/\[LOGGING-JOB-ID\]/, @logger.messages) + end + + def test_logs_correct_queue_name + original_queue_name = LoggingJob.queue_name + LoggingJob.queue_as :php_jobs + LoggingJob.perform_later("Dummy") + assert_match(/to .*?\(php_jobs\).*/, @logger.messages) + ensure + LoggingJob.queue_name = original_queue_name + end + def test_enqueue_job_logging - HelloJob.enqueue "Cristian" + HelloJob.perform_later "Cristian" assert_match(/Enqueued HelloJob \(Job ID: .*?\) to .*?:.*Cristian/, @logger.messages) end def test_perform_job_logging - LoggingJob.enqueue "Dummy" + LoggingJob.perform_later "Dummy" assert_match(/Performing LoggingJob from .*? with arguments:.*Dummy/, @logger.messages) assert_match(/Dummy, here is it: Dummy/, @logger.messages) assert_match(/Performed LoggingJob from .*? in .*ms/, @logger.messages) end - def test_perform_uses_job_name_job_logging - LoggingJob.enqueue "Dummy" - assert_match(/\[LoggingJob\]/, @logger.messages) - end - - def test_perform_uses_job_id_job_logging - LoggingJob.enqueue "Dummy" - assert_match(/\[LOGGING-JOB-ID\]/, @logger.messages) - end - def test_perform_nested_jobs_logging - NestedJob.enqueue + NestedJob.perform_later assert_match(/\[LoggingJob\] \[.*?\]/, @logger.messages) assert_match(/\[ActiveJob\] Enqueued NestedJob \(Job ID: .*\) to/, @logger.messages) assert_match(/\[ActiveJob\] \[NestedJob\] \[NESTED-JOB-ID\] Performing NestedJob from/, @logger.messages) @@ -81,14 +90,14 @@ class AdapterTest < ActiveSupport::TestCase end def test_enqueue_at_job_logging - HelloJob.enqueue_at 1, "Cristian" + HelloJob.set(wait_until: 24.hours.from_now).perform_later "Cristian" assert_match(/Enqueued HelloJob \(Job ID: .*\) to .*? at.*Cristian/, @logger.messages) rescue NotImplementedError skip end def test_enqueue_in_job_logging - HelloJob.enqueue_in 2, "Cristian" + HelloJob.set(wait: 2.seconds).perform_later "Cristian" assert_match(/Enqueued HelloJob \(Job ID: .*\) to .*? at.*Cristian/, @logger.messages) rescue NotImplementedError skip diff --git a/activejob/test/cases/parameters_test.rb b/activejob/test/cases/parameters_test.rb index 78853c51e1..92f835af5d 100644 --- a/activejob/test/cases/parameters_test.rb +++ b/activejob/test/cases/parameters_test.rb @@ -26,8 +26,8 @@ class ParameterSerializationTest < ActiveSupport::TestCase end test 'should dive deep into arrays or hashes' do - assert_equal [ { "a" => Person.find(5).gid.to_s }.with_indifferent_access ], ActiveJob::Arguments.serialize([ { a: Person.find(5) } ]) - assert_equal [ [ Person.find(5).gid.to_s ] ], ActiveJob::Arguments.serialize([ [ Person.find(5) ] ]) + assert_equal [ { "a" => Person.find(5).to_gid.to_s }.with_indifferent_access ], ActiveJob::Arguments.serialize([ { a: Person.find(5) } ]) + assert_equal [ [ Person.find(5).to_gid.to_s ] ], ActiveJob::Arguments.serialize([ [ Person.find(5) ] ]) end test 'should dive deep into arrays or hashes and raise exception on complex objects' do @@ -45,11 +45,11 @@ class ParameterSerializationTest < ActiveSupport::TestCase end test 'should serialize records with global id' do - assert_equal [ Person.find(5).gid.to_s ], ActiveJob::Arguments.serialize([ Person.find(5) ]) + assert_equal [ Person.find(5).to_gid.to_s ], ActiveJob::Arguments.serialize([ Person.find(5) ]) end test 'should serialize values and records together' do - assert_equal [ 3, Person.find(5).gid.to_s ], ActiveJob::Arguments.serialize([ 3, Person.find(5) ]) + assert_equal [ 3, Person.find(5).to_gid.to_s ], ActiveJob::Arguments.serialize([ 3, Person.find(5) ]) end end @@ -59,19 +59,19 @@ class ParameterDeserializationTest < ActiveSupport::TestCase end test 'should deserialize records with global id' do - assert_equal [ Person.find(5) ], ActiveJob::Arguments.deserialize([ Person.find(5).gid ]) + assert_equal [ Person.find(5) ], ActiveJob::Arguments.deserialize([ Person.find(5).to_gid ]) end test 'should serialize values and records together' do - assert_equal [ 3, Person.find(5) ], ActiveJob::Arguments.deserialize([ 3, Person.find(5).gid ]) + assert_equal [ 3, Person.find(5) ], ActiveJob::Arguments.deserialize([ 3, Person.find(5).to_gid ]) end test 'should dive deep when deserialising arrays' do - assert_equal [ [ 3, Person.find(5) ] ], ActiveJob::Arguments.deserialize([ [ 3, Person.find(5).gid ] ]) + assert_equal [ [ 3, Person.find(5) ] ], ActiveJob::Arguments.deserialize([ [ 3, Person.find(5).to_gid ] ]) end test 'should dive deep when deserialising hashes' do - assert_equal [ { "5" => Person.find(5) } ], ActiveJob::Arguments.deserialize([ { "5" => Person.find(5).gid } ]) + assert_equal [ { "5" => Person.find(5) } ], ActiveJob::Arguments.deserialize([ { "5" => Person.find(5).to_gid } ]) end end diff --git a/activejob/test/cases/queue_naming_test.rb b/activejob/test/cases/queue_naming_test.rb index fdfd1afceb..4052477543 100644 --- a/activejob/test/cases/queue_naming_test.rb +++ b/activejob/test/cases/queue_naming_test.rb @@ -8,20 +8,38 @@ class QueueNamingTest < ActiveSupport::TestCase assert_equal "default", HelloJob.queue_name end - test 'name appended in job' do + test 'uses given queue name job' do begin + original_queue_name = HelloJob.queue_name HelloJob.queue_as :greetings - LoggingJob.queue_as :bookkeeping + assert_equal "greetings", HelloJob.new.queue_name + ensure + HelloJob.queue_name = original_queue_name + end + end - assert_equal "default", NestedJob.queue_name - assert_equal "greetings", HelloJob.queue_name - assert_equal "bookkeeping", LoggingJob.queue_name + test 'evals block given to queue_as to determine queue' do + begin + original_queue_name = HelloJob.queue_name + HelloJob.queue_as { :another } + assert_equal "another", HelloJob.new.queue_name ensure - HelloJob.queue_name = LoggingJob.queue_name = ActiveJob::Base.default_queue_name + HelloJob.queue_name = original_queue_name end end - test 'should prefix the queue name' do + test 'can use arguments to determine queue_name in queue_as block' do + begin + original_queue_name = HelloJob.queue_name + HelloJob.queue_as { self.arguments.first=='1' ? :one : :two } + assert_equal "one", HelloJob.new('1').queue_name + assert_equal "two", HelloJob.new('3').queue_name + ensure + HelloJob.queue_name = original_queue_name + end + end + + test 'queu_name_prefix prepended to the queue name' do begin original_queue_name_prefix = ActiveJob::Base.queue_name_prefix original_queue_name = HelloJob.queue_name @@ -35,4 +53,9 @@ class QueueNamingTest < ActiveSupport::TestCase end end + test 'uses queue passed to #set' do + job = HelloJob.set(queue: :some_queue).perform_later + assert_equal "some_queue", job.queue_name + end + end diff --git a/activejob/test/cases/queuing_test.rb b/activejob/test/cases/queuing_test.rb index f020316d7e..0eeabbf693 100644 --- a/activejob/test/cases/queuing_test.rb +++ b/activejob/test/cases/queuing_test.rb @@ -9,18 +9,18 @@ class QueuingTest < ActiveSupport::TestCase end test 'run queued job' do - HelloJob.enqueue + HelloJob.perform_later assert_equal "David says hello", JobBuffer.last_value end test 'run queued job with arguments' do - HelloJob.enqueue "Jamie" + HelloJob.perform_later "Jamie" assert_equal "Jamie says hello", JobBuffer.last_value end test 'run queued job later' do begin - result = HelloJob.enqueue_at 1.second.ago, "Jamie" + result = HelloJob.set(wait_until: 1.second.ago).perform_later "Jamie" assert result rescue NotImplementedError skip @@ -28,15 +28,15 @@ class QueuingTest < ActiveSupport::TestCase end test 'job returned by enqueue has the arguments available' do - job = HelloJob.enqueue "Jamie" + job = HelloJob.perform_later "Jamie" assert_equal [ "Jamie" ], job.arguments end - test 'job returned by enqueue_at has the timestamp available' do + test 'job returned by perform_at has the timestamp available' do begin - job = HelloJob.enqueue_at Time.utc(2014, 1, 1) - assert_equal Time.utc(2014, 1, 1), job.enqueued_at + job = HelloJob.set(wait_until: Time.utc(2014, 1, 1)).perform_later + assert_equal Time.utc(2014, 1, 1).to_f, job.scheduled_at rescue NotImplementedError skip end diff --git a/activejob/test/cases/rescue_test.rb b/activejob/test/cases/rescue_test.rb index d9ea3c91d7..1b6c2e9fac 100644 --- a/activejob/test/cases/rescue_test.rb +++ b/activejob/test/cases/rescue_test.rb @@ -10,22 +10,27 @@ class RescueTest < ActiveSupport::TestCase end test 'rescue perform exception with retry' do - job = RescueJob.new - job.execute(SecureRandom.uuid, "david") + job = RescueJob.new("david") + job.perform_now assert_equal [ "rescued from ArgumentError", "performed beautifully" ], JobBuffer.values end test 'let through unhandled perform exception' do - job = RescueJob.new + job = RescueJob.new("other") assert_raises(RescueJob::OtherError) do - job.execute(SecureRandom.uuid, "other") + job.perform_now end end test 'rescue from deserialization errors' do - RescueJob.enqueue Person.new(404) + RescueJob.perform_later Person.new(404) assert_includes JobBuffer.values, 'rescued from DeserializationError' assert_includes JobBuffer.values, 'DeserializationError original exception was Person::RecordNotFound' assert_not_includes JobBuffer.values, 'performed beautifully' end + + test "should not wrap DeserializationError in DeserializationError" do + RescueJob.perform_later [Person.new(404)] + assert_includes JobBuffer.values, 'DeserializationError original exception was Person::RecordNotFound' + end end diff --git a/activejob/test/cases/test_case_test.rb b/activejob/test/cases/test_case_test.rb new file mode 100644 index 0000000000..1d0fdbd22d --- /dev/null +++ b/activejob/test/cases/test_case_test.rb @@ -0,0 +1,14 @@ +require 'helper' +require 'jobs/hello_job' +require 'jobs/logging_job' +require 'jobs/nested_job' + +class ActiveJobTestCaseTest < ActiveJob::TestCase + def test_include_helper + assert_includes self.class.ancestors, ActiveJob::TestHelper + end + + def test_set_test_adapter + assert_instance_of ActiveJob::QueueAdapters::TestAdapter, self.queue_adapter + end +end diff --git a/activejob/test/cases/test_helper_test.rb b/activejob/test/cases/test_helper_test.rb new file mode 100644 index 0000000000..eab540bb6c --- /dev/null +++ b/activejob/test/cases/test_helper_test.rb @@ -0,0 +1,214 @@ +require 'helper' +require 'active_support/core_ext/time' +require 'active_support/core_ext/date' +require 'jobs/hello_job' +require 'jobs/logging_job' +require 'jobs/nested_job' + +class EnqueuedJobsTest < ActiveJob::TestCase + setup { queue_adapter.perform_enqueued_at_jobs = true } + + def test_assert_enqueued_jobs + assert_nothing_raised do + assert_enqueued_jobs 1 do + HelloJob.perform_later('david') + end + end + end + + def test_repeated_enqueued_jobs_calls + assert_nothing_raised do + assert_enqueued_jobs 1 do + HelloJob.perform_later('abdelkader') + end + end + + assert_nothing_raised do + assert_enqueued_jobs 2 do + HelloJob.perform_later('sean') + HelloJob.perform_later('yves') + end + end + end + + def test_assert_enqueued_jobs_with_no_block + assert_nothing_raised do + HelloJob.perform_later('rafael') + assert_enqueued_jobs 1 + end + + assert_nothing_raised do + HelloJob.perform_later('aaron') + HelloJob.perform_later('matthew') + assert_enqueued_jobs 3 + end + end + + def test_assert_no_enqueued_jobs + assert_nothing_raised do + assert_no_enqueued_jobs do + # Scheduled jobs are being performed in this context + HelloJob.set(wait_until: Date.tomorrow.noon).perform_later('godfrey') + end + end + end + + def test_assert_enqueued_jobs_too_few_sent + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_enqueued_jobs 2 do + HelloJob.perform_later('xavier') + end + end + + assert_match(/2 .* but 1/, error.message) + end + + def test_assert_enqueued_jobs_too_many_sent + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_enqueued_jobs 1 do + HelloJob.perform_later('cristian') + HelloJob.perform_later('guillermo') + end + end + + assert_match(/1 .* but 2/, error.message) + end + + def test_assert_no_enqueued_jobs_failure + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_no_enqueued_jobs do + HelloJob.perform_later('jeremy') + end + end + + assert_match(/0 .* but 1/, error.message) + end + + def test_assert_enqueued_job + assert_enqueued_with(job: LoggingJob, queue: 'default') do + NestedJob.set(wait_until: Date.tomorrow.noon).perform_later + end + end + + def test_assert_enqueued_job_failure + assert_raise ActiveSupport::TestCase::Assertion do + assert_enqueued_with(job: LoggingJob, queue: 'default') do + NestedJob.perform_later + end + end + + assert_raise ActiveSupport::TestCase::Assertion do + assert_enqueued_with(job: NestedJob, queue: 'low') do + NestedJob.perform_later + end + end + end + + def test_assert_enqueued_job_args + assert_raise ArgumentError do + assert_enqueued_with(class: LoggingJob) do + NestedJob.set(wait_until: Date.tomorrow.noon).perform_later + end + end + end +end + +class PerformedJobsTest < ActiveJob::TestCase + setup { queue_adapter.perform_enqueued_jobs = true } + + def test_assert_performed_jobs + assert_nothing_raised do + assert_performed_jobs 1 do + HelloJob.perform_later('david') + end + end + end + + def test_repeated_performed_jobs_calls + assert_nothing_raised do + assert_performed_jobs 1 do + HelloJob.perform_later('abdelkader') + end + end + + assert_nothing_raised do + assert_performed_jobs 2 do + HelloJob.perform_later('sean') + HelloJob.perform_later('yves') + end + end + end + + def test_assert_performed_jobs_with_no_block + assert_nothing_raised do + HelloJob.perform_later('rafael') + assert_performed_jobs 1 + end + + assert_nothing_raised do + HelloJob.perform_later('aaron') + HelloJob.perform_later('matthew') + assert_performed_jobs 3 + end + end + + def test_assert_no_performed_jobs + assert_nothing_raised do + assert_no_performed_jobs do + # Scheduled jobs are being enqueued in this context + HelloJob.set(wait_until: Date.tomorrow.noon).perform_later('godfrey') + end + end + end + + def test_assert_performed_jobs_too_few_sent + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_performed_jobs 2 do + HelloJob.perform_later('xavier') + end + end + + assert_match(/2 .* but 1/, error.message) + end + + def test_assert_performed_jobs_too_many_sent + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_performed_jobs 1 do + HelloJob.perform_later('cristian') + HelloJob.perform_later('guillermo') + end + end + + assert_match(/1 .* but 2/, error.message) + end + + def test_assert_no_performed_jobs_failure + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_no_performed_jobs do + HelloJob.perform_later('jeremy') + end + end + + assert_match(/0 .* but 1/, error.message) + end + + def test_assert_performed_job + assert_performed_with(job: NestedJob, queue: 'default') do + NestedJob.perform_later + end + end + + def test_assert_performed_job_failure + assert_raise ActiveSupport::TestCase::Assertion do + assert_performed_with(job: LoggingJob, at: Date.tomorrow.noon, queue: 'default') do + NestedJob.set(wait_until: Date.tomorrow.noon).perform_later + end + end + + assert_raise ActiveSupport::TestCase::Assertion do + assert_performed_with(job: NestedJob, at: Date.tomorrow.noon, queue: 'low') do + NestedJob.set(queue: 'low', wait_until: Date.tomorrow.noon).perform_later + end + end + end +end diff --git a/activejob/test/helper.rb b/activejob/test/helper.rb index ca67700273..ce22833b11 100644 --- a/activejob/test/helper.rb +++ b/activejob/test/helper.rb @@ -1,6 +1,7 @@ require File.expand_path('../../../load_paths', __FILE__) require 'active_job' +require 'support/job_buffer' GlobalID.app = 'aj' @@ -10,41 +11,20 @@ def sidekiq? @adapter == 'sidekiq' end -def rubinius? - RUBY_ENGINE == 'rbx' -end - def ruby_193? RUBY_VERSION == '1.9.3' && RUBY_ENGINE != 'java' end -#Sidekiq don't work with MRI 1.9.3 -#Travis uses rbx 2.6 which don't support unicode characters in methods. -#Remove the check when Travis change to rbx 2.7+ -exit if sidekiq? && (ruby_193? || rubinius?) +# Sidekiq doesn't work with MRI 1.9.3 +exit if sidekiq? && ruby_193? -require "adapters/#{@adapter}" +if ENV['AJ_INTEGRATION_TESTS'] + require 'support/integration/helper' +else + require "adapters/#{@adapter}" +end require 'active_support/testing/autorun' ActiveJob::Base.logger.level = Logger::DEBUG - -module JobBuffer - class << self - def clear - @buffer = [] - end - - def add(value) - @buffer << value - end - - def values - @buffer - end - - def last_value - @buffer.last - end - end -end +ActiveSupport::TestCase.test_order = :random diff --git a/activejob/test/integration/queuing_test.rb b/activejob/test/integration/queuing_test.rb new file mode 100644 index 0000000000..779dedb53f --- /dev/null +++ b/activejob/test/integration/queuing_test.rb @@ -0,0 +1,46 @@ +require 'helper' +require 'jobs/logging_job' +require 'active_support/core_ext/numeric/time' + +class QueuingTest < ActiveSupport::TestCase + test 'should run jobs enqueued on a listenting queue' do + TestJob.perform_later @id + wait_for_jobs_to_finish_for(5.seconds) + assert job_executed + end + + test 'should not run jobs queued on a non-listenting queue' do + begin + skip if adapter_is?(:inline) || adapter_is?(:sucker_punch) + old_queue = TestJob.queue_name + TestJob.queue_as :some_other_queue + TestJob.perform_later @id + wait_for_jobs_to_finish_for(2.seconds) + assert_not job_executed + ensure + TestJob.queue_name = old_queue + end + end + + test 'should not run job enqueued in the future' do + begin + TestJob.set(wait: 10.minutes).perform_later @id + wait_for_jobs_to_finish_for(5.seconds) + assert_not job_executed + rescue NotImplementedError + skip + end + end + + test 'should run job enqueued in the future at the specified time' do + begin + TestJob.set(wait: 3.seconds).perform_later @id + wait_for_jobs_to_finish_for(2.seconds) + assert_not job_executed + wait_for_jobs_to_finish_for(10.seconds) + assert job_executed + rescue NotImplementedError + skip + end + end +end diff --git a/activejob/test/jobs/gid_job.rb b/activejob/test/jobs/gid_job.rb index 35c2366ec4..e485bfa2dd 100644 --- a/activejob/test/jobs/gid_job.rb +++ b/activejob/test/jobs/gid_job.rb @@ -1,3 +1,5 @@ +require_relative '../support/job_buffer' + class GidJob < ActiveJob::Base def perform(person) JobBuffer.add("Person with ID: #{person.id}") diff --git a/activejob/test/jobs/hello_job.rb b/activejob/test/jobs/hello_job.rb index 4c6256af0d..022fa58e4a 100644 --- a/activejob/test/jobs/hello_job.rb +++ b/activejob/test/jobs/hello_job.rb @@ -1,3 +1,5 @@ +require_relative '../support/job_buffer' + class HelloJob < ActiveJob::Base def perform(greeter = "David") JobBuffer.add("#{greeter} says hello") diff --git a/activejob/test/jobs/nested_job.rb b/activejob/test/jobs/nested_job.rb index fd66f68991..8c4ec549a6 100644 --- a/activejob/test/jobs/nested_job.rb +++ b/activejob/test/jobs/nested_job.rb @@ -1,6 +1,6 @@ class NestedJob < ActiveJob::Base def perform - LoggingJob.enqueue "NestedJob" + LoggingJob.perform_later "NestedJob" end def job_id diff --git a/activejob/test/jobs/rescue_job.rb b/activejob/test/jobs/rescue_job.rb index e9cb37d1c4..f1b9c9349e 100644 --- a/activejob/test/jobs/rescue_job.rb +++ b/activejob/test/jobs/rescue_job.rb @@ -1,10 +1,12 @@ +require_relative '../support/job_buffer' + class RescueJob < ActiveJob::Base class OtherError < StandardError; end rescue_from(ArgumentError) do JobBuffer.add('rescued from ArgumentError') arguments[0] = "DIFFERENT!" - retry_now + retry_job end rescue_from(ActiveJob::DeserializationError) do |e| diff --git a/activejob/test/support/integration/adapters/backburner.rb b/activejob/test/support/integration/adapters/backburner.rb new file mode 100644 index 0000000000..0cda36a273 --- /dev/null +++ b/activejob/test/support/integration/adapters/backburner.rb @@ -0,0 +1,38 @@ +module BackburnerJobsManager + def setup + ActiveJob::Base.queue_adapter = :backburner + Backburner.configure do |config| + config.logger = Rails.logger + end + unless can_run? + puts "Cannot run integration tests for backburner. To be able to run integration tests for backburner you need to install and start beanstalkd.\n" + exit + end + end + + def clear_jobs + tube.clear + end + + def start_workers + @thread = Thread.new { Backburner.work "integration-tests" } # backburner dasherizes the queue name + end + + def stop_workers + @thread.kill + end + + def tube + @tube ||= Beaneater::Tube.new(Backburner::Worker.connection, "backburner.worker.queue.integration-tests") # backburner dasherizes the queue name + end + + def can_run? + begin + Backburner::Worker.connection.send :connect! + rescue => e + return false + end + true + end +end + diff --git a/activejob/test/support/integration/adapters/delayed_job.rb b/activejob/test/support/integration/adapters/delayed_job.rb new file mode 100644 index 0000000000..dbd0d1a4db --- /dev/null +++ b/activejob/test/support/integration/adapters/delayed_job.rb @@ -0,0 +1,20 @@ +require 'delayed_job' +require 'delayed_job_active_record' + +module DelayedJobJobsManager + def setup + ActiveJob::Base.queue_adapter = :delayed_job + end + def clear_jobs + Delayed::Job.delete_all + end + + def start_workers + @worker = Delayed::Worker.new(quiet: false, sleep_delay: 0.5, queues: %w(integration_tests)) + @thread = Thread.new { @worker.start } + end + + def stop_workers + @worker.stop + end +end diff --git a/activejob/test/support/integration/adapters/inline.rb b/activejob/test/support/integration/adapters/inline.rb new file mode 100644 index 0000000000..83c38f706f --- /dev/null +++ b/activejob/test/support/integration/adapters/inline.rb @@ -0,0 +1,15 @@ +module InlineJobsManager + def setup + ActiveJob::Base.queue_adapter = :inline + end + + def clear_jobs + end + + def start_workers + end + + def stop_workers + end +end + diff --git a/activejob/test/support/integration/adapters/qu.rb b/activejob/test/support/integration/adapters/qu.rb new file mode 100644 index 0000000000..e913f04a24 --- /dev/null +++ b/activejob/test/support/integration/adapters/qu.rb @@ -0,0 +1,38 @@ +module QuJobsManager + def setup + require 'qu-rails' + require 'qu-redis' + ActiveJob::Base.queue_adapter = :qu + ENV['REDISTOGO_URL'] = "tcp://127.0.0.1:6379/12" + backend = Qu::Backend::Redis.new + backend.namespace = "active_jobs_int_test" + Qu.backend = backend + Qu.logger = Rails.logger + Qu.interval = 0.5 + unless can_run? + puts "Cannot run integration tests for qu. To be able to run integration tests for qu you need to install and start redis.\n" + exit + end + end + + def clear_jobs + Qu.clear "integration_tests" + end + + def start_workers + @thread = Thread.new { Qu::Worker.new("integration_tests").start } + end + + def stop_workers + @thread.kill + end + + def can_run? + begin + Qu.backend.connection.client.connect + rescue => e + return false + end + true + end +end diff --git a/activejob/test/support/integration/adapters/que.rb b/activejob/test/support/integration/adapters/que.rb new file mode 100644 index 0000000000..a5b9b3ec0a --- /dev/null +++ b/activejob/test/support/integration/adapters/que.rb @@ -0,0 +1,37 @@ +module QueJobsManager + def setup + require 'sequel' + ActiveJob::Base.queue_adapter = :que + que_url = ENV['QUE_DATABASE_URL'] || 'postgres://localhost/active_jobs_que_int_test' + uri = URI.parse(que_url) + user = uri.user||ENV['USER'] + pass = uri.password + db = uri.path[1..-1] + %x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -c 'drop database "#{db}"' -U #{user} -t template1} + %x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -c 'create database "#{db}"' -U #{user} -t template1} + Que.connection = Sequel.connect(que_url) + Que.migrate! + Que.mode = :off + Que.worker_count = 1 + rescue Sequel::DatabaseConnectionError + puts "Cannot run integration tests for que. To be able to run integration tests for que you need to install and start postgresql.\n" + exit + end + + def clear_jobs + Que.clear! + end + + def start_workers + @thread = Thread.new do + loop do + Que::Job.work("integration_tests") + sleep 0.5 + end + end + end + + def stop_workers + @thread.kill + end +end diff --git a/activejob/test/support/integration/adapters/queue_classic.rb b/activejob/test/support/integration/adapters/queue_classic.rb new file mode 100644 index 0000000000..81d1935132 --- /dev/null +++ b/activejob/test/support/integration/adapters/queue_classic.rb @@ -0,0 +1,45 @@ +module QueueClassicJobsManager + def setup + ENV['QC_DATABASE_URL'] ||= 'postgres://localhost/active_jobs_qc_int_test' + ENV['QC_LISTEN_TIME'] = "0.5" + uri = URI.parse(ENV['QC_DATABASE_URL']) + user = uri.user||ENV['USER'] + pass = uri.password + db = uri.path[1..-1] + %x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -c 'drop database "#{db}"' -U #{user} -t template1} + %x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -c 'create database "#{db}"' -U #{user} -t template1} + ActiveJob::Base.queue_adapter = :queue_classic + QC::Setup.create + rescue PG::ConnectionBad + puts "Cannot run integration tests for queue_classic. To be able to run integration tests for queue_classic you need to install and start postgresql.\n" + exit + end + + def clear_jobs + QC::Queue.new("integration_tests").delete_all + retried = false + rescue => e + puts "Got exception while trying to clear jobs: #{e.inspect}" + if retried + puts "Already retried. Raising exception" + raise e + else + puts "Retrying" + retried = true + QC::Conn.connection = QC::Conn.connect + retry + end + end + + def start_workers + @pid = fork do + QC::Conn.connection = QC::Conn.connect + worker = QC::Worker.new(q_name: 'integration_tests') + worker.start + end + end + + def stop_workers + Process.kill 'HUP', @pid + end +end diff --git a/activejob/test/support/integration/adapters/resque.rb b/activejob/test/support/integration/adapters/resque.rb new file mode 100644 index 0000000000..03ffd3fd62 --- /dev/null +++ b/activejob/test/support/integration/adapters/resque.rb @@ -0,0 +1,47 @@ +module ResqueJobsManager + def setup + ActiveJob::Base.queue_adapter = :resque + Resque.redis = Redis::Namespace.new 'active_jobs_int_test', redis: Redis.connect(url: "tcp://127.0.0.1:6379/12", :thread_safe => true) + Resque.logger = Rails.logger + unless can_run? + puts "Cannot run integration tests for resque. To be able to run integration tests for resque you need to install and start redis.\n" + exit + end + end + + def clear_jobs + Resque.queues.each { |queue_name| Resque.redis.del "queue:#{queue_name}" } + Resque.redis.keys("delayed:*").each { |key| Resque.redis.del "#{key}" } + Resque.redis.del "delayed_queue_schedule" + end + + def start_workers + @resque_thread = Thread.new do + Resque::Worker.new("integration_tests").work(0.5) + end + @scheduler_thread = Thread.new do + Resque::Scheduler.configure do |c| + c.poll_sleep_amount = 0.5 + c.dynamic = true + c.verbose = true + c.logfile = nil + end + Resque::Scheduler.master_lock.release! + Resque::Scheduler.run + end + end + + def stop_workers + @resque_thread.kill + @scheduler_thread.kill + end + + def can_run? + begin + Resque.redis.client.connect + rescue => e + return false + end + true + end +end diff --git a/activejob/test/support/integration/adapters/sidekiq.rb b/activejob/test/support/integration/adapters/sidekiq.rb new file mode 100644 index 0000000000..b3c3dcff22 --- /dev/null +++ b/activejob/test/support/integration/adapters/sidekiq.rb @@ -0,0 +1,58 @@ +require 'sidekiq/cli' +require 'sidekiq/api' + +module SidekiqJobsManager + + def setup + ActiveJob::Base.queue_adapter = :sidekiq + unless can_run? + puts "Cannot run integration tests for sidekiq. To be able to run integration tests for sidekiq you need to install and start redis.\n" + exit + end + end + + def clear_jobs + Sidekiq::ScheduledSet.new.clear + Sidekiq::Queue.new("integration_tests").clear + end + + def start_workers + fork do + sidekiq = Sidekiq::CLI.instance + logfile = Rails.root.join("log/sidekiq.log").to_s + pidfile = Rails.root.join("tmp/sidekiq.pid").to_s + sidekiq.parse([ "--require", Rails.root.to_s, + "--queue", "integration_tests", + "--logfile", logfile, + "--pidfile", pidfile, + "--environment", "test", + "--concurrency", "1", + "--timeout", "1", + "--daemon", + "--verbose" + ]) + require 'celluloid' + require 'sidekiq/scheduled' + Sidekiq.poll_interval = 0.5 + Sidekiq::Scheduled.const_set :INITIAL_WAIT, 1 + sidekiq.run + end + sleep 1 + end + + def stop_workers + pidfile = Rails.root.join("tmp/sidekiq.pid").to_s + Process.kill 'TERM', File.open(pidfile).read.to_i + FileUtils.rm_f pidfile + rescue + end + + def can_run? + begin + Sidekiq.redis { |conn| conn.connect } + rescue => e + return false + end + true + end +end diff --git a/activejob/test/support/integration/adapters/sneakers.rb b/activejob/test/support/integration/adapters/sneakers.rb new file mode 100644 index 0000000000..f21bb38a32 --- /dev/null +++ b/activejob/test/support/integration/adapters/sneakers.rb @@ -0,0 +1,90 @@ +require 'sneakers/runner' +require 'sneakers/publisher' +require 'timeout' + +module Sneakers + class Publisher + def safe_ensure_connected + @mutex.synchronize do + ensure_connection! unless connected? + end + end + end +end + + +module SneakersJobsManager + def setup + ActiveJob::Base.queue_adapter = :sneakers + Sneakers.configure :heartbeat => 2, + :amqp => 'amqp://guest:guest@localhost:5672', + :vhost => '/', + :exchange => 'active_jobs_sneakers_int_test', + :exchange_type => :direct, + :daemonize => true, + :threads => 1, + :workers => 1, + :pid_path => Rails.root.join("tmp/sneakers.pid").to_s, + :log => Rails.root.join("log/sneakers.log").to_s + unless can_run? + puts "Cannot run integration tests for sneakers. To be able to run integration tests for sneakers you need to install and start rabbitmq.\n" + exit + end + end + + def clear_jobs + bunny_queue.purge + end + + def start_workers + @pid = fork do + queues = %w(integration_tests) + workers = queues.map do |q| + worker_klass = "ActiveJobWorker"+Digest::MD5.hexdigest(q) + Sneakers.const_set(worker_klass, Class.new(ActiveJob::QueueAdapters::SneakersAdapter::JobWrapper) do + from_queue q + end) + end + Sneakers::Runner.new(workers).run + end + begin + Timeout.timeout(10) do + while bunny_queue.status[:consumer_count] == 0 + sleep 0.5 + end + end + rescue Timeout::Error + stop_workers + raise "Failed to start sneakers worker" + end + end + + def stop_workers + Process.kill 'TERM', @pid + Process.kill 'TERM', File.open(Rails.root.join("tmp/sneakers.pid").to_s).read.to_i + rescue + end + + def can_run? + begin + bunny_publisher + rescue => e + return false + end + true + end + + protected + def bunny_publisher + @bunny_publisher ||= begin + p = ActiveJob::QueueAdapters::SneakersAdapter::JobWrapper.send(:publisher) + p.safe_ensure_connected + p + end + end + + def bunny_queue + @queue ||= bunny_publisher.exchange.channel.queue "integration_tests", durable: true + end + +end diff --git a/activejob/test/support/integration/adapters/sucker_punch.rb b/activejob/test/support/integration/adapters/sucker_punch.rb new file mode 100644 index 0000000000..691ba35c90 --- /dev/null +++ b/activejob/test/support/integration/adapters/sucker_punch.rb @@ -0,0 +1,5 @@ +module SuckerPunchJobsManager + def setup + ActiveJob::Base.queue_adapter = :sucker_punch + end +end diff --git a/activejob/test/support/integration/dummy_app_template.rb b/activejob/test/support/integration/dummy_app_template.rb new file mode 100644 index 0000000000..28aae0f884 --- /dev/null +++ b/activejob/test/support/integration/dummy_app_template.rb @@ -0,0 +1,21 @@ +if ENV['AJADAPTER'] == 'delayed_job' + generate "delayed_job:active_record" + rake("db:migrate") +end + +initializer 'activejob.rb', <<-CODE +require "#{File.expand_path("../jobs_manager.rb", __FILE__)}" +JobsManager.current_manager.setup +CODE + +file 'app/jobs/test_job.rb', <<-CODE +class TestJob < ActiveJob::Base + queue_as :integration_tests + + def perform(x) + File.open(Rails.root.join("tmp/\#{x}"), "w+") do |f| + f.write x + end + end +end +CODE diff --git a/activejob/test/support/integration/helper.rb b/activejob/test/support/integration/helper.rb new file mode 100644 index 0000000000..ccd5036b36 --- /dev/null +++ b/activejob/test/support/integration/helper.rb @@ -0,0 +1,32 @@ +puts "\n\n" +puts "*** Running integration tests for #{ENV['AJADAPTER']} ***" +puts "\n\n" + +ENV["RAILS_ENV"] = "test" +ActiveJob::Base.queue_name_prefix = nil + +require 'rails/generators/rails/app/app_generator' + +dummy_app_path = Dir.mktmpdir + "/dummy" +dummy_app_template = File.expand_path("../dummy_app_template.rb", __FILE__) +args = Rails::Generators::ARGVScrubber.new(["new", dummy_app_path, "--skip-gemfile", "--skip-bundle", + "--skip-git", "--skip-spring", "-d", "sqlite3", "--skip-javascript", "--force", "--quite", + "--template", dummy_app_template]).prepare! +Rails::Generators::AppGenerator.start args + +require "#{dummy_app_path}/config/environment.rb" + +ActiveRecord::Migrator.migrations_paths = [ Rails.root.join('db/migrate').to_s ] +require 'rails/test_help' + +Rails.backtrace_cleaner.remove_silencers! + +require_relative 'test_case_helpers' +ActiveSupport::TestCase.send(:include, TestCaseHelpers) + +JobsManager.current_manager.start_workers + +Minitest.after_run do + JobsManager.current_manager.stop_workers + JobsManager.current_manager.clear_jobs +end diff --git a/activejob/test/support/integration/jobs_manager.rb b/activejob/test/support/integration/jobs_manager.rb new file mode 100644 index 0000000000..4df34aaeb1 --- /dev/null +++ b/activejob/test/support/integration/jobs_manager.rb @@ -0,0 +1,27 @@ +class JobsManager + @@managers = {} + attr :adapter_name + + def self.current_manager + @@managers[ENV['AJADAPTER']] ||= new(ENV['AJADAPTER']) + end + + def initialize(adapter_name) + @adapter_name = adapter_name + require_relative "adapters/#{adapter_name}" + extend "#{adapter_name.camelize}JobsManager".constantize + end + + def setup + ActiveJob::Base.queue_adapter = nil + end + + def clear_jobs + end + + def start_workers + end + + def stop_workers + end +end diff --git a/activejob/test/support/integration/test_case_helpers.rb b/activejob/test/support/integration/test_case_helpers.rb new file mode 100644 index 0000000000..ee2f6aebea --- /dev/null +++ b/activejob/test/support/integration/test_case_helpers.rb @@ -0,0 +1,48 @@ +require 'active_support/concern' +require 'support/integration/jobs_manager' + +module TestCaseHelpers + extend ActiveSupport::Concern + + included do + self.use_transactional_fixtures = false + + setup do + clear_jobs + @id = "AJ-#{SecureRandom.uuid}" + end + + teardown do + clear_jobs + end + end + + protected + + def jobs_manager + JobsManager.current_manager + end + + def clear_jobs + jobs_manager.clear_jobs + end + + def adapter_is?(adapter) + ActiveJob::Base.queue_adapter.name.split("::").last.gsub(/Adapter$/, '').underscore==adapter.to_s + end + + def wait_for_jobs_to_finish_for(seconds=60) + begin + Timeout.timeout(seconds) do + while !job_executed do + sleep 0.25 + end + end + rescue Timeout::Error + end + end + + def job_executed + Dummy::Application.root.join("tmp/#{@id}").exist? + end +end diff --git a/activejob/test/support/job_buffer.rb b/activejob/test/support/job_buffer.rb new file mode 100644 index 0000000000..620cb5288d --- /dev/null +++ b/activejob/test/support/job_buffer.rb @@ -0,0 +1,19 @@ +module JobBuffer + class << self + def clear + values.clear + end + + def add(value) + values << value + end + + def values + @values ||= [] + end + + def last_value + values.last + end + end +end diff --git a/activejob/test/support/queue_classic/inline.rb b/activejob/test/support/queue_classic/inline.rb index 5e9c295e01..5743d5bbb5 100644 --- a/activejob/test/support/queue_classic/inline.rb +++ b/activejob/test/support/queue_classic/inline.rb @@ -7,5 +7,17 @@ module QC receiver = eval(receiver_str) receiver.send(message, *args) end + + def enqueue_in(seconds, method, *args) + receiver_str, _, message = method.rpartition('.') + receiver = eval(receiver_str) + receiver.send(message, *args) + end + + def enqueue_at(not_before, method, *args) + receiver_str, _, message = method.rpartition('.') + receiver = eval(receiver_str) + receiver.send(message, *args) + end end end |