diff options
Diffstat (limited to 'activejob/test')
60 files changed, 2229 insertions, 0 deletions
diff --git a/activejob/test/adapters/async.rb b/activejob/test/adapters/async.rb new file mode 100644 index 0000000000..df58027599 --- /dev/null +++ b/activejob/test/adapters/async.rb @@ -0,0 +1,5 @@ +require 'concurrent' +require 'active_job/async_job' + +ActiveJob::Base.queue_adapter = :async +ActiveJob::AsyncJob.perform_immediately! diff --git a/activejob/test/adapters/backburner.rb b/activejob/test/adapters/backburner.rb new file mode 100644 index 0000000000..65d05f850b --- /dev/null +++ b/activejob/test/adapters/backburner.rb @@ -0,0 +1,3 @@ +require 'support/backburner/inline' + +ActiveJob::Base.queue_adapter = :backburner
\ No newline at end of file diff --git a/activejob/test/adapters/delayed_job.rb b/activejob/test/adapters/delayed_job.rb new file mode 100644 index 0000000000..afd9c9deb7 --- /dev/null +++ b/activejob/test/adapters/delayed_job.rb @@ -0,0 +1,7 @@ +ActiveJob::Base.queue_adapter = :delayed_job + +$LOAD_PATH << File.dirname(__FILE__) + "/../support/delayed_job" + +Delayed::Worker.delay_jobs = false +Delayed::Worker.backend = :test + diff --git a/activejob/test/adapters/inline.rb b/activejob/test/adapters/inline.rb new file mode 100644 index 0000000000..e0092552c4 --- /dev/null +++ b/activejob/test/adapters/inline.rb @@ -0,0 +1 @@ +ActiveJob::Base.queue_adapter = :inline
\ No newline at end of file diff --git a/activejob/test/adapters/qu.rb b/activejob/test/adapters/qu.rb new file mode 100644 index 0000000000..7728c843b4 --- /dev/null +++ b/activejob/test/adapters/qu.rb @@ -0,0 +1,3 @@ +require 'qu-immediate' + +ActiveJob::Base.queue_adapter = :qu diff --git a/activejob/test/adapters/que.rb b/activejob/test/adapters/que.rb new file mode 100644 index 0000000000..e6abc57457 --- /dev/null +++ b/activejob/test/adapters/que.rb @@ -0,0 +1,4 @@ +require 'support/que/inline' + +ActiveJob::Base.queue_adapter = :que +Que.mode = :sync diff --git a/activejob/test/adapters/queue_classic.rb b/activejob/test/adapters/queue_classic.rb new file mode 100644 index 0000000000..ad5ced3cc2 --- /dev/null +++ b/activejob/test/adapters/queue_classic.rb @@ -0,0 +1,2 @@ +require 'support/queue_classic/inline' +ActiveJob::Base.queue_adapter = :queue_classic diff --git a/activejob/test/adapters/resque.rb b/activejob/test/adapters/resque.rb new file mode 100644 index 0000000000..af7080358d --- /dev/null +++ b/activejob/test/adapters/resque.rb @@ -0,0 +1,2 @@ +ActiveJob::Base.queue_adapter = :resque +Resque.inline = true diff --git a/activejob/test/adapters/sidekiq.rb b/activejob/test/adapters/sidekiq.rb new file mode 100644 index 0000000000..cd9d2034de --- /dev/null +++ b/activejob/test/adapters/sidekiq.rb @@ -0,0 +1,2 @@ +require 'sidekiq/testing/inline' +ActiveJob::Base.queue_adapter = :sidekiq diff --git a/activejob/test/adapters/sneakers.rb b/activejob/test/adapters/sneakers.rb new file mode 100644 index 0000000000..204166a700 --- /dev/null +++ b/activejob/test/adapters/sneakers.rb @@ -0,0 +1,2 @@ +require 'support/sneakers/inline' +ActiveJob::Base.queue_adapter = :sneakers diff --git a/activejob/test/adapters/sucker_punch.rb b/activejob/test/adapters/sucker_punch.rb new file mode 100644 index 0000000000..d2d1712946 --- /dev/null +++ b/activejob/test/adapters/sucker_punch.rb @@ -0,0 +1,2 @@ +require 'sucker_punch/testing/inline' +ActiveJob::Base.queue_adapter = :sucker_punch diff --git a/activejob/test/adapters/test.rb b/activejob/test/adapters/test.rb new file mode 100644 index 0000000000..7180b38a57 --- /dev/null +++ b/activejob/test/adapters/test.rb @@ -0,0 +1,3 @@ +ActiveJob::Base.queue_adapter = :test +ActiveJob::Base.queue_adapter.perform_enqueued_jobs = true +ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true diff --git a/activejob/test/cases/adapter_test.rb b/activejob/test/cases/adapter_test.rb new file mode 100644 index 0000000000..6d75ae9a7c --- /dev/null +++ b/activejob/test/cases/adapter_test.rb @@ -0,0 +1,7 @@ +require 'helper' + +class AdapterTest < ActiveSupport::TestCase + test "should load #{ENV['AJ_ADAPTER']} adapter" do + assert_equal "active_job/queue_adapters/#{ENV['AJ_ADAPTER']}_adapter".classify, ActiveJob::Base.queue_adapter.class.name + end +end diff --git a/activejob/test/cases/argument_serialization_test.rb b/activejob/test/cases/argument_serialization_test.rb new file mode 100644 index 0000000000..933972a52b --- /dev/null +++ b/activejob/test/cases/argument_serialization_test.rb @@ -0,0 +1,110 @@ +require 'helper' +require 'active_job/arguments' +require 'models/person' +require 'active_support/core_ext/hash/indifferent_access' +require 'jobs/kwargs_job' + +class ArgumentSerializationTest < ActiveSupport::TestCase + setup do + @person = Person.find('5') + end + + [ nil, 1, 1.0, 1_000_000_000_000_000_000_000, + 'a', true, false, + [ 1, 'a' ], + { 'a' => 1 } + ].each do |arg| + test "serializes #{arg.class} verbatim" do + assert_arguments_unchanged arg + end + end + + [ :a, Object.new, self, Person.find('5').to_gid ].each do |arg| + test "does not serialize #{arg.class}" do + assert_raises ActiveJob::SerializationError do + ActiveJob::Arguments.serialize [ arg ] + end + + assert_raises ActiveJob::DeserializationError do + ActiveJob::Arguments.deserialize [ arg ] + end + end + end + + test 'should convert records to Global IDs' do + assert_arguments_roundtrip [@person] + end + + test 'should dive deep into arrays and hashes' do + assert_arguments_roundtrip [3, [@person]] + assert_arguments_roundtrip [{ 'a' => @person }] + end + + test 'should maintain string and symbol keys' do + assert_arguments_roundtrip([a: 1, "b" => 2]) + end + + test 'should maintain hash with indifferent access' do + symbol_key = { a: 1 } + string_key = { 'a' => 1 } + indifferent_access = { a: 1 }.with_indifferent_access + + assert_not_instance_of ActiveSupport::HashWithIndifferentAccess, perform_round_trip([symbol_key]).first + assert_not_instance_of ActiveSupport::HashWithIndifferentAccess, perform_round_trip([string_key]).first + assert_instance_of ActiveSupport::HashWithIndifferentAccess, perform_round_trip([indifferent_access]).first + end + + test 'should disallow non-string/symbol hash keys' do + assert_raises ActiveJob::SerializationError do + ActiveJob::Arguments.serialize [ { 1 => 2 } ] + end + + assert_raises ActiveJob::SerializationError do + ActiveJob::Arguments.serialize [ { :a => [{ 2 => 3 }] } ] + end + + assert_raises ActiveJob::SerializationError do + ActiveJob::Arguments.serialize [ '_aj_globalid' => 1 ] + end + + assert_raises ActiveJob::SerializationError do + ActiveJob::Arguments.serialize [ :_aj_globalid => 1 ] + end + end + + test 'should not allow non-primitive objects' do + assert_raises ActiveJob::SerializationError do + ActiveJob::Arguments.serialize [Object.new] + end + + assert_raises ActiveJob::SerializationError do + ActiveJob::Arguments.serialize [1, [Object.new]] + end + end + + test 'allows for keyword arguments' do + KwargsJob.perform_later(argument: 2) + + assert_equal "Job with argument: 2", JobBuffer.last_value + end + + test 'raises a friendly SerializationError for records without ids' do + err = assert_raises ActiveJob::SerializationError do + ActiveJob::Arguments.serialize [Person.new(nil)] + end + assert_match 'Unable to serialize Person without an id.', err.message + end + + private + def assert_arguments_unchanged(*args) + assert_arguments_roundtrip args + end + + def assert_arguments_roundtrip(args) + assert_equal args, perform_round_trip(args) + end + + def perform_round_trip(args) + ActiveJob::Arguments.deserialize(ActiveJob::Arguments.serialize(args)) + end +end diff --git a/activejob/test/cases/async_job_test.rb b/activejob/test/cases/async_job_test.rb new file mode 100644 index 0000000000..2642cfc608 --- /dev/null +++ b/activejob/test/cases/async_job_test.rb @@ -0,0 +1,42 @@ +require 'helper' +require 'jobs/hello_job' +require 'jobs/queue_as_job' + +class AsyncJobTest < ActiveSupport::TestCase + def using_async_adapter? + ActiveJob::Base.queue_adapter.is_a? ActiveJob::QueueAdapters::AsyncAdapter + end + + setup do + ActiveJob::AsyncJob.perform_asynchronously! + end + + teardown do + ActiveJob::AsyncJob::QUEUES.clear + ActiveJob::AsyncJob.perform_immediately! + end + + test "#create_thread_pool returns a thread_pool" do + thread_pool = ActiveJob::AsyncJob.create_thread_pool + assert thread_pool.is_a? Concurrent::ExecutorService + assert_not thread_pool.is_a? Concurrent::ImmediateExecutor + end + + test "#create_thread_pool returns an ImmediateExecutor after #perform_immediately! is called" do + ActiveJob::AsyncJob.perform_immediately! + thread_pool = ActiveJob::AsyncJob.create_thread_pool + assert thread_pool.is_a? Concurrent::ImmediateExecutor + end + + test "enqueuing without specifying a queue uses the default queue" do + skip unless using_async_adapter? + HelloJob.perform_later + assert ActiveJob::AsyncJob::QUEUES.key? 'default' + end + + test "enqueuing to a queue that does not exist creates the queue" do + skip unless using_async_adapter? + QueueAsJob.perform_later + assert ActiveJob::AsyncJob::QUEUES.key? QueueAsJob::MY_QUEUE.to_s + end +end diff --git a/activejob/test/cases/callbacks_test.rb b/activejob/test/cases/callbacks_test.rb new file mode 100644 index 0000000000..9af2380767 --- /dev/null +++ b/activejob/test/cases/callbacks_test.rb @@ -0,0 +1,23 @@ +require 'helper' +require 'jobs/callback_job' + +require 'active_support/core_ext/object/inclusion' + +class CallbacksTest < ActiveSupport::TestCase + test 'perform callbacks' do + 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 + assert "CallbackJob ran around_perform_stop".in? performed_callback_job.history + end + + test 'enqueue callbacks' do + 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 + assert "CallbackJob ran around_enqueue_stop".in? enqueued_callback_job.history + end +end diff --git a/activejob/test/cases/job_serialization_test.rb b/activejob/test/cases/job_serialization_test.rb new file mode 100644 index 0000000000..229517774e --- /dev/null +++ b/activejob/test/cases/job_serialization_test.rb @@ -0,0 +1,32 @@ +require 'helper' +require 'jobs/gid_job' +require 'jobs/hello_job' +require 'models/person' + +class JobSerializationTest < ActiveSupport::TestCase + setup do + JobBuffer.clear + @person = Person.find(5) + end + + test 'serialize job with gid' do + GidJob.perform_later @person + assert_equal "Person with ID: 5", JobBuffer.last_value + end + + test 'serialize includes current locale' do + assert_equal :en, HelloJob.new.serialize['locale'] + end + + test 'deserialize sets locale' do + job = HelloJob.new + job.deserialize 'locale' => :es + assert_equal :es, job.locale + end + + test 'deserialize sets default locale' do + job = HelloJob.new + job.deserialize({}) + assert_equal :en, job.locale + end +end diff --git a/activejob/test/cases/logging_test.rb b/activejob/test/cases/logging_test.rb new file mode 100644 index 0000000000..820e9112de --- /dev/null +++ b/activejob/test/cases/logging_test.rb @@ -0,0 +1,122 @@ +require 'helper' +require "active_support/log_subscriber/test_helper" +require 'active_support/core_ext/numeric/time' +require 'jobs/hello_job' +require 'jobs/logging_job' +require 'jobs/nested_job' +require 'models/person' + +class LoggingTest < ActiveSupport::TestCase + include ActiveSupport::LogSubscriber::TestHelper + include ActiveSupport::Logger::Severity + + class TestLogger < ActiveSupport::Logger + def initialize + @file = StringIO.new + super(@file) + end + + def messages + @file.rewind + @file.read + end + end + + def setup + super + JobBuffer.clear + @old_logger = ActiveJob::Base.logger + @logger = ActiveSupport::TaggedLogging.new(TestLogger.new) + set_logger @logger + ActiveJob::Logging::LogSubscriber.attach_to :active_job + end + + def teardown + super + ActiveJob::Logging::LogSubscriber.log_subscribers.pop + set_logger @old_logger + end + + def set_logger(logger) + ActiveJob::Base.logger = logger + end + + + def test_uses_active_job_as_tag + 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_globalid_parameter_logging + person = Person.new(123) + LoggingJob.perform_later person + assert_match(%r{Enqueued.*gid://aj/Person/123}, @logger.messages) + assert_match(%r{Dummy, here is it: #<Person:.*>}, @logger.messages) + assert_match(%r{Performing.*gid://aj/Person/123}, @logger.messages) + end + + def test_globalid_nested_parameter_logging + person = Person.new(123) + LoggingJob.perform_later(person: person) + assert_match(%r{Enqueued.*gid://aj/Person/123}, @logger.messages) + assert_match(%r{Dummy, here is it: .*#<Person:.*>}, @logger.messages) + assert_match(%r{Performing.*gid://aj/Person/123}, @logger.messages) + end + + def test_enqueue_job_logging + HelloJob.perform_later "Cristian" + assert_match(/Enqueued HelloJob \(Job ID: .*?\) to .*?:.*Cristian/, @logger.messages) + end + + def test_perform_job_logging + 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_nested_jobs_logging + 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) + assert_match(/\[ActiveJob\] \[NestedJob\] \[NESTED-JOB-ID\] Enqueued LoggingJob \(Job ID: .*?\) to .* with arguments: "NestedJob"/, @logger.messages) + assert_match(/\[ActiveJob\].*\[LoggingJob\] \[LOGGING-JOB-ID\] Performing LoggingJob from .* with arguments: "NestedJob"/, @logger.messages) + assert_match(/\[ActiveJob\].*\[LoggingJob\] \[LOGGING-JOB-ID\] Dummy, here is it: NestedJob/, @logger.messages) + assert_match(/\[ActiveJob\].*\[LoggingJob\] \[LOGGING-JOB-ID\] Performed LoggingJob from .* in/, @logger.messages) + assert_match(/\[ActiveJob\] \[NestedJob\] \[NESTED-JOB-ID\] Performed NestedJob from .* in/, @logger.messages) + end + + def test_enqueue_at_job_logging + 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.set(wait: 2.seconds).perform_later "Cristian" + assert_match(/Enqueued HelloJob \(Job ID: .*\) to .*? at.*Cristian/, @logger.messages) + rescue NotImplementedError + skip + end +end diff --git a/activejob/test/cases/queue_adapter_test.rb b/activejob/test/cases/queue_adapter_test.rb new file mode 100644 index 0000000000..fb3fdc392f --- /dev/null +++ b/activejob/test/cases/queue_adapter_test.rb @@ -0,0 +1,56 @@ +require 'helper' + +module ActiveJob + module QueueAdapters + class StubOneAdapter + def enqueue(*); end + def enqueue_at(*); end + end + + class StubTwoAdapter + def enqueue(*); end + def enqueue_at(*); end + end + end +end + +class QueueAdapterTest < ActiveJob::TestCase + test 'should forbid nonsense arguments' do + assert_raises(ArgumentError) { ActiveJob::Base.queue_adapter = Mutex } + assert_raises(ArgumentError) { ActiveJob::Base.queue_adapter = Mutex.new } + end + + test 'should warn on passing an adapter class' do + klass = Class.new do + def self.name + 'fake' + end + + def enqueue(*); end + def enqueue_at(*); end + end + + assert_deprecated { ActiveJob::Base.queue_adapter = klass } + end + + test 'should allow overriding the queue_adapter at the child class level without affecting the parent or its sibling' do + base_queue_adapter = ActiveJob::Base.queue_adapter + + child_job_one = Class.new(ActiveJob::Base) + child_job_one.queue_adapter = :stub_one + + assert_not_equal ActiveJob::Base.queue_adapter, child_job_one.queue_adapter + assert_kind_of ActiveJob::QueueAdapters::StubOneAdapter, child_job_one.queue_adapter + + child_job_two = Class.new(ActiveJob::Base) + child_job_two.queue_adapter = :stub_two + + assert_kind_of ActiveJob::QueueAdapters::StubTwoAdapter, child_job_two.queue_adapter + assert_kind_of ActiveJob::QueueAdapters::StubOneAdapter, child_job_one.queue_adapter, "child_job_one's queue adapter should remain unchanged" + assert_equal base_queue_adapter, ActiveJob::Base.queue_adapter, "ActiveJob::Base's queue adapter should remain unchanged" + + child_job_three = Class.new(ActiveJob::Base) + + assert_not_nil child_job_three.queue_adapter + end +end diff --git a/activejob/test/cases/queue_naming_test.rb b/activejob/test/cases/queue_naming_test.rb new file mode 100644 index 0000000000..898016a704 --- /dev/null +++ b/activejob/test/cases/queue_naming_test.rb @@ -0,0 +1,102 @@ +require 'helper' +require 'jobs/hello_job' +require 'jobs/logging_job' +require 'jobs/nested_job' + +class QueueNamingTest < ActiveSupport::TestCase + test 'name derived from base' do + assert_equal "default", HelloJob.queue_name + end + + test 'uses given queue name job' do + original_queue_name = HelloJob.queue_name + + begin + HelloJob.queue_as :greetings + assert_equal "greetings", HelloJob.new.queue_name + ensure + HelloJob.queue_name = original_queue_name + end + end + + test 'allows a blank queue name' do + original_queue_name = HelloJob.queue_name + + begin + HelloJob.queue_as "" + assert_equal "", HelloJob.new.queue_name + ensure + HelloJob.queue_name = original_queue_name + end + end + + test 'does not use a nil queue name' do + original_queue_name = HelloJob.queue_name + + begin + HelloJob.queue_as nil + assert_equal "default", HelloJob.new.queue_name + ensure + HelloJob.queue_name = original_queue_name + end + end + + test 'evals block given to queue_as to determine queue' do + original_queue_name = HelloJob.queue_name + + begin + HelloJob.queue_as { :another } + assert_equal "another", HelloJob.new.queue_name + ensure + HelloJob.queue_name = original_queue_name + end + end + + test 'can use arguments to determine queue_name in queue_as block' do + original_queue_name = HelloJob.queue_name + + begin + 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 'queue_name_prefix prepended to the queue name with default delimiter' do + original_queue_name_prefix = ActiveJob::Base.queue_name_prefix + original_queue_name = HelloJob.queue_name + + begin + ActiveJob::Base.queue_name_prefix = 'aj' + HelloJob.queue_as :low + assert_equal 'aj_low', HelloJob.queue_name + ensure + ActiveJob::Base.queue_name_prefix = original_queue_name_prefix + HelloJob.queue_name = original_queue_name + end + end + + test 'queue_name_prefix prepended to the queue name with custom delimiter' do + original_queue_name_prefix = ActiveJob::Base.queue_name_prefix + original_queue_name_delimiter = ActiveJob::Base.queue_name_delimiter + original_queue_name = HelloJob.queue_name + + begin + ActiveJob::Base.queue_name_delimiter = '.' + ActiveJob::Base.queue_name_prefix = 'aj' + HelloJob.queue_as :low + assert_equal 'aj.low', HelloJob.queue_name + ensure + ActiveJob::Base.queue_name_prefix = original_queue_name_prefix + ActiveJob::Base.queue_name_delimiter = original_queue_name_delimiter + HelloJob.queue_name = original_queue_name + 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/queue_priority_test.rb b/activejob/test/cases/queue_priority_test.rb new file mode 100644 index 0000000000..ca17b51dad --- /dev/null +++ b/activejob/test/cases/queue_priority_test.rb @@ -0,0 +1,47 @@ +require 'helper' +require 'jobs/hello_job' + +class QueuePriorityTest < ActiveSupport::TestCase + test 'priority unset by default' do + assert_equal nil, HelloJob.priority + end + + test 'uses given priority' do + original_priority = HelloJob.priority + + begin + HelloJob.queue_with_priority 90 + assert_equal 90, HelloJob.new.priority + ensure + HelloJob.priority = original_priority + end + end + + test 'evals block given to priority to determine priority' do + original_priority = HelloJob.priority + + begin + HelloJob.queue_with_priority { 25 } + assert_equal 25, HelloJob.new.priority + ensure + HelloJob.priority = original_priority + end + end + + test 'can use arguments to determine priority in priority block' do + original_priority = HelloJob.priority + + begin + HelloJob.queue_with_priority { self.arguments.first=='1' ? 99 : 11 } + assert_equal 99, HelloJob.new('1').priority + assert_equal 11, HelloJob.new('3').priority + ensure + HelloJob.priority = original_priority + end + end + + test 'uses priority passed to #set' do + job = HelloJob.set(priority: 123).perform_later + assert_equal 123, job.priority + end +end diff --git a/activejob/test/cases/queuing_test.rb b/activejob/test/cases/queuing_test.rb new file mode 100644 index 0000000000..0eeabbf693 --- /dev/null +++ b/activejob/test/cases/queuing_test.rb @@ -0,0 +1,44 @@ +require 'helper' +require 'jobs/hello_job' +require 'active_support/core_ext/numeric/time' + + +class QueuingTest < ActiveSupport::TestCase + setup do + JobBuffer.clear + end + + test 'run queued job' do + HelloJob.perform_later + assert_equal "David says hello", JobBuffer.last_value + end + + test 'run queued job with arguments' do + HelloJob.perform_later "Jamie" + assert_equal "Jamie says hello", JobBuffer.last_value + end + + test 'run queued job later' do + begin + result = HelloJob.set(wait_until: 1.second.ago).perform_later "Jamie" + assert result + rescue NotImplementedError + skip + end + end + + test 'job returned by enqueue has the arguments available' do + job = HelloJob.perform_later "Jamie" + assert_equal [ "Jamie" ], job.arguments + end + + + test 'job returned by perform_at has the timestamp available' do + begin + 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 + end +end diff --git a/activejob/test/cases/rescue_test.rb b/activejob/test/cases/rescue_test.rb new file mode 100644 index 0000000000..58c9ca8992 --- /dev/null +++ b/activejob/test/cases/rescue_test.rb @@ -0,0 +1,34 @@ +require 'helper' +require 'jobs/rescue_job' +require 'models/person' + +class RescueTest < ActiveSupport::TestCase + setup do + JobBuffer.clear + end + + test 'rescue perform exception with retry' do + 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("other") + assert_raises(RescueJob::OtherError) do + job.perform_now + end + end + + test 'rescue from deserialization errors' do + 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..616454a4b6 --- /dev/null +++ b/activejob/test/cases/test_case_test.rb @@ -0,0 +1,23 @@ +require 'helper' +require 'jobs/hello_job' +require 'jobs/logging_job' +require 'jobs/nested_job' + +class ActiveJobTestCaseTest < ActiveJob::TestCase + # this tests that this job class doesn't get its adapter set. + # that's the correct behavior since we don't want to break + # the `class_attribute` inheritance + class TestClassAttributeInheritanceJob < ActiveJob::Base + def self.queue_adapter=(*) + raise 'Attempting to break `class_attribute` inheritance, bad!' + end + end + + def test_include_helper + assert_includes self.class.ancestors, ActiveJob::TestHelper + end + + def test_set_test_adapter + assert_kind_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..f7ee763e8a --- /dev/null +++ b/activejob/test/cases/test_helper_test.rb @@ -0,0 +1,511 @@ +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' +require 'jobs/rescue_job' +require 'models/person' + +class EnqueuedJobsTest < ActiveJob::TestCase + 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_message + HelloJob.perform_later('sean') + e = assert_raises Minitest::Assertion do + assert_enqueued_jobs 2 do + HelloJob.perform_later('sean') + end + end + assert_match "Expected: 2", e.message + assert_match "Actual: 1", e.message + 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_with_no_block + assert_nothing_raised do + assert_no_enqueued_jobs + end + end + + def test_assert_no_enqueued_jobs + assert_nothing_raised do + assert_no_enqueued_jobs do + HelloJob.perform_now + 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_jobs_with_only_option + assert_nothing_raised do + assert_enqueued_jobs 1, only: HelloJob do + HelloJob.perform_later('jeremy') + LoggingJob.perform_later + end + end + end + + def test_assert_enqueued_jobs_with_only_option_and_none_sent + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_enqueued_jobs 1, only: HelloJob do + LoggingJob.perform_later + end + end + + assert_match(/1 .* but 0/, error.message) + end + + def test_assert_enqueued_jobs_with_only_option_and_too_few_sent + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_enqueued_jobs 5, only: HelloJob do + HelloJob.perform_later('jeremy') + 4.times { LoggingJob.perform_later } + end + end + + assert_match(/5 .* but 1/, error.message) + end + + def test_assert_enqueued_jobs_with_only_option_and_too_many_sent + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_enqueued_jobs 1, only: HelloJob do + 2.times { HelloJob.perform_later('jeremy') } + end + end + + assert_match(/1 .* but 2/, error.message) + end + + def test_assert_enqueued_jobs_with_only_option_as_array + assert_nothing_raised do + assert_enqueued_jobs 2, only: [HelloJob, LoggingJob] do + HelloJob.perform_later('jeremy') + LoggingJob.perform_later('stewie') + RescueJob.perform_later('david') + end + end + end + + def test_assert_no_enqueued_jobs_with_only_option + assert_nothing_raised do + assert_no_enqueued_jobs only: HelloJob do + LoggingJob.perform_later + end + end + end + + def test_assert_no_enqueued_jobs_with_only_option_failure + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_no_enqueued_jobs only: HelloJob do + HelloJob.perform_later('jeremy') + LoggingJob.perform_later + end + end + + assert_match(/0 .* but 1/, error.message) + end + + def test_assert_no_enqueued_jobs_with_only_option_as_array + assert_nothing_raised do + assert_no_enqueued_jobs only: [HelloJob, RescueJob] do + LoggingJob.perform_later + end + end + end + + def test_assert_enqueued_job + assert_enqueued_with(job: LoggingJob, queue: 'default') do + LoggingJob.set(wait_until: Date.tomorrow.noon).perform_later + end + end + + def test_assert_enqueued_job_returns + job = assert_enqueued_with(job: LoggingJob) do + LoggingJob.set(wait_until: 5.minutes.from_now).perform_later(1, 2, 3) + end + + assert_instance_of LoggingJob, job + assert_in_delta 5.minutes.from_now, job.scheduled_at, 1 + assert_equal 'default', job.queue_name + assert_equal [1, 2, 3], job.arguments + 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 + + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_enqueued_with(job: NestedJob, queue: 'low') do + NestedJob.perform_later + end + end + + assert_equal 'No enqueued job found with {:job=>NestedJob, :queue=>"low"}', error.message + 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 + + def test_assert_enqueued_job_with_at_option + assert_enqueued_with(job: HelloJob, at: Date.tomorrow.noon) do + HelloJob.set(wait_until: Date.tomorrow.noon).perform_later + end + end + + def test_assert_enqueued_job_with_global_id_args + ricardo = Person.new(9) + assert_enqueued_with(job: HelloJob, args: [ricardo]) do + HelloJob.perform_later(ricardo) + end + end + + def test_assert_enqueued_job_failure_with_global_id_args + ricardo = Person.new(9) + wilma = Person.new(11) + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_enqueued_with(job: HelloJob, args: [wilma]) do + HelloJob.perform_later(ricardo) + end + end + + assert_equal "No enqueued job found with {:job=>HelloJob, :args=>[#{wilma.inspect}]}", error.message + end + + def test_assert_enqueued_job_does_not_change_jobs_count + HelloJob.perform_later + assert_enqueued_with(job: HelloJob) do + HelloJob.perform_later + end + + assert_equal 2, ActiveJob::Base.queue_adapter.enqueued_jobs.count + end +end + +class PerformedJobsTest < ActiveJob::TestCase + def test_performed_enqueue_jobs_with_only_option_doesnt_leak_outside_the_block + assert_equal nil, queue_adapter.filter + perform_enqueued_jobs only: HelloJob do + assert_equal HelloJob, queue_adapter.filter + end + assert_equal nil, queue_adapter.filter + end + + 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_message + HelloJob.perform_later('sean') + e = assert_raises Minitest::Assertion do + assert_performed_jobs 2 do + HelloJob.perform_later('sean') + end + end + assert_match "Expected: 2", e.message + assert_match "Actual: 1", e.message + end + + def test_assert_performed_jobs_with_no_block + assert_nothing_raised do + perform_enqueued_jobs do + HelloJob.perform_later('rafael') + end + assert_performed_jobs 1 + end + + assert_nothing_raised do + perform_enqueued_jobs do + HelloJob.perform_later('aaron') + HelloJob.perform_later('matthew') + assert_performed_jobs 3 + end + end + end + + def test_assert_no_performed_jobs_with_no_block + assert_nothing_raised do + assert_no_performed_jobs + end + end + + def test_assert_no_performed_jobs + assert_nothing_raised do + assert_no_performed_jobs do + # empty block won't perform jobs + 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_jobs_with_only_option + assert_nothing_raised do + assert_performed_jobs 1, only: HelloJob do + HelloJob.perform_later('jeremy') + LoggingJob.perform_later + end + end + end + + def test_assert_performed_jobs_with_only_option_as_array + assert_nothing_raised do + assert_performed_jobs 2, only: [HelloJob, LoggingJob] do + HelloJob.perform_later('jeremy') + LoggingJob.perform_later('stewie') + RescueJob.perform_later('david') + end + end + end + + def test_assert_performed_jobs_with_only_option_and_none_sent + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_performed_jobs 1, only: HelloJob do + LoggingJob.perform_later + end + end + + assert_match(/1 .* but 0/, error.message) + end + + def test_assert_performed_jobs_with_only_option_and_too_few_sent + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_performed_jobs 5, only: HelloJob do + HelloJob.perform_later('jeremy') + 4.times { LoggingJob.perform_later } + end + end + + assert_match(/5 .* but 1/, error.message) + end + + def test_assert_performed_jobs_with_only_option_and_too_many_sent + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_performed_jobs 1, only: HelloJob do + 2.times { HelloJob.perform_later('jeremy') } + end + end + + assert_match(/1 .* but 2/, error.message) + end + + def test_assert_no_performed_jobs_with_only_option + assert_nothing_raised do + assert_no_performed_jobs only: HelloJob do + LoggingJob.perform_later + end + end + end + + def test_assert_no_performed_jobs_with_only_option_as_array + assert_nothing_raised do + assert_no_performed_jobs only: [HelloJob, RescueJob] do + LoggingJob.perform_later + end + end + end + + def test_assert_no_performed_jobs_with_only_option_failure + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_no_performed_jobs only: HelloJob do + HelloJob.perform_later('jeremy') + LoggingJob.perform_later + 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_returns + job = assert_performed_with(job: NestedJob, queue: 'default') do + NestedJob.perform_later + end + + assert_instance_of NestedJob, job + assert_nil job.scheduled_at + assert_equal [], job.arguments + assert_equal 'default', job.queue_name + end + + def test_assert_performed_job_failure + assert_raise ActiveSupport::TestCase::Assertion do + assert_performed_with(job: LoggingJob) do + HelloJob.perform_later + end + end + + assert_raise ActiveSupport::TestCase::Assertion do + assert_performed_with(job: HelloJob, queue: 'low') do + HelloJob.set(queue: 'important').perform_later + end + end + end + + def test_assert_performed_job_with_at_option + assert_performed_with(job: HelloJob, at: Date.tomorrow.noon) do + HelloJob.set(wait_until: Date.tomorrow.noon).perform_later + end + + assert_raise ActiveSupport::TestCase::Assertion do + assert_performed_with(job: HelloJob, at: Date.today.noon) do + HelloJob.set(wait_until: Date.tomorrow.noon).perform_later + end + end + end + + def test_assert_performed_job_with_global_id_args + ricardo = Person.new(9) + assert_performed_with(job: HelloJob, args: [ricardo]) do + HelloJob.perform_later(ricardo) + end + end + + def test_assert_performed_job_failure_with_global_id_args + ricardo = Person.new(9) + wilma = Person.new(11) + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_performed_with(job: HelloJob, args: [wilma]) do + HelloJob.perform_later(ricardo) + end + end + + assert_equal "No performed job found with {:job=>HelloJob, :args=>[#{wilma.inspect}]}", error.message + end + + def test_assert_performed_job_does_not_change_jobs_count + assert_performed_with(job: HelloJob) do + HelloJob.perform_later + end + + assert_performed_with(job: HelloJob) do + HelloJob.perform_later + end + + assert_equal 2, ActiveJob::Base.queue_adapter.performed_jobs.count + end +end diff --git a/activejob/test/cases/translation_test.rb b/activejob/test/cases/translation_test.rb new file mode 100644 index 0000000000..d5e3aaf9e3 --- /dev/null +++ b/activejob/test/cases/translation_test.rb @@ -0,0 +1,20 @@ +require 'helper' +require 'jobs/translated_hello_job' + +class TranslationTest < ActiveSupport::TestCase + setup do + JobBuffer.clear + I18n.available_locales = [:en, :de] + @job = TranslatedHelloJob.new('Johannes') + end + + teardown do + I18n.available_locales = [:en] + end + + test 'it performs the job in the given locale' do + @job.locale = :de + @job.perform_now + assert_equal "Johannes says Guten Tag", JobBuffer.last_value + end +end diff --git a/activejob/test/helper.rb b/activejob/test/helper.rb new file mode 100644 index 0000000000..7e86415f48 --- /dev/null +++ b/activejob/test/helper.rb @@ -0,0 +1,18 @@ +require File.expand_path('../../../load_paths', __FILE__) + +require 'active_job' +require 'support/job_buffer' + +ActiveSupport.halt_callback_chains_on_return_false = false +GlobalID.app = 'aj' + +@adapter = ENV['AJ_ADAPTER'] || 'inline' + +if ENV['AJ_INTEGRATION_TESTS'] + require 'support/integration/helper' +else + ActiveJob::Base.logger = Logger.new(nil) + require "adapters/#{@adapter}" +end + +require 'active_support/testing/autorun' diff --git a/activejob/test/integration/queuing_test.rb b/activejob/test/integration/queuing_test.rb new file mode 100644 index 0000000000..e435ed4aa6 --- /dev/null +++ b/activejob/test/integration/queuing_test.rb @@ -0,0 +1,99 @@ +require 'helper' +require 'jobs/logging_job' +require 'jobs/hello_job' +require 'active_support/core_ext/numeric/time' + +class QueuingTest < ActiveSupport::TestCase + test 'should run jobs enqueued on a listening 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-listening queue' do + skip if adapter_is?(:inline, :async, :sucker_punch, :que) + old_queue = TestJob.queue_name + + begin + 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 supply a wrapped class name to Sidekiq' do + skip unless adapter_is?(:sidekiq) + Sidekiq::Testing.fake! do + ::HelloJob.perform_later + hash = ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper.jobs.first + assert_equal "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper", hash['class'] + assert_equal "HelloJob", hash['wrapped'] + 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: 5.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 + + test 'should supply a provider_job_id when available for immediate jobs' do + skip unless adapter_is?(:delayed_job, :sidekiq, :qu, :que, :queue_classic) + test_job = TestJob.perform_later @id + assert test_job.provider_job_id, 'Provider job id should be set by provider' + end + + test 'should supply a provider_job_id when available for delayed jobs' do + skip unless adapter_is?(:delayed_job, :sidekiq, :que, :queue_classic) + delayed_test_job = TestJob.set(wait: 1.minute).perform_later @id + assert delayed_test_job.provider_job_id, 'Provider job id should by set for delayed jobs by provider' + end + + test 'current locale is kept while running perform_later' do + skip if adapter_is?(:inline) + + begin + I18n.available_locales = [:en, :de] + I18n.locale = :de + + TestJob.perform_later @id + wait_for_jobs_to_finish_for(5.seconds) + assert job_executed + assert_equal 'de', job_output + ensure + I18n.available_locales = [:en] + I18n.locale = :en + end + end + + test 'should run job with higher priority first' do + skip unless adapter_is?(:delayed_job, :que) + + wait_until = Time.now + 3.seconds + TestJob.set(wait_until: wait_until, priority: 20).perform_later "#{@id}.1" + TestJob.set(wait_until: wait_until, priority: 10).perform_later "#{@id}.2" + wait_for_jobs_to_finish_for(10.seconds) + assert job_executed "#{@id}.1" + assert job_executed "#{@id}.2" + assert job_executed_at("#{@id}.2") < job_executed_at("#{@id}.1") + end +end diff --git a/activejob/test/jobs/callback_job.rb b/activejob/test/jobs/callback_job.rb new file mode 100644 index 0000000000..891ed9464e --- /dev/null +++ b/activejob/test/jobs/callback_job.rb @@ -0,0 +1,29 @@ +class CallbackJob < ActiveJob::Base + before_perform ->(job) { job.history << "CallbackJob ran before_perform" } + after_perform ->(job) { job.history << "CallbackJob ran after_perform" } + + before_enqueue ->(job) { job.history << "CallbackJob ran before_enqueue" } + after_enqueue ->(job) { job.history << "CallbackJob ran after_enqueue" } + + around_perform do |job, block| + job.history << "CallbackJob ran around_perform_start" + block.call + job.history << "CallbackJob ran around_perform_stop" + end + + around_enqueue do |job, block| + job.history << "CallbackJob ran around_enqueue_start" + block.call + job.history << "CallbackJob ran around_enqueue_stop" + end + + + def perform(person = "david") + # NOTHING! + end + + def history + @history ||= [] + end + +end diff --git a/activejob/test/jobs/gid_job.rb b/activejob/test/jobs/gid_job.rb new file mode 100644 index 0000000000..e485bfa2dd --- /dev/null +++ b/activejob/test/jobs/gid_job.rb @@ -0,0 +1,8 @@ +require_relative '../support/job_buffer' + +class GidJob < ActiveJob::Base + def perform(person) + JobBuffer.add("Person with ID: #{person.id}") + end +end + diff --git a/activejob/test/jobs/hello_job.rb b/activejob/test/jobs/hello_job.rb new file mode 100644 index 0000000000..022fa58e4a --- /dev/null +++ b/activejob/test/jobs/hello_job.rb @@ -0,0 +1,7 @@ +require_relative '../support/job_buffer' + +class HelloJob < ActiveJob::Base + def perform(greeter = "David") + JobBuffer.add("#{greeter} says hello") + end +end diff --git a/activejob/test/jobs/kwargs_job.rb b/activejob/test/jobs/kwargs_job.rb new file mode 100644 index 0000000000..2df17d15ae --- /dev/null +++ b/activejob/test/jobs/kwargs_job.rb @@ -0,0 +1,7 @@ +require_relative '../support/job_buffer' + +class KwargsJob < ActiveJob::Base + def perform(argument: 1) + JobBuffer.add("Job with argument: #{argument}") + end +end diff --git a/activejob/test/jobs/logging_job.rb b/activejob/test/jobs/logging_job.rb new file mode 100644 index 0000000000..d84ed8589b --- /dev/null +++ b/activejob/test/jobs/logging_job.rb @@ -0,0 +1,10 @@ +class LoggingJob < ActiveJob::Base + def perform(dummy) + logger.info "Dummy, here is it: #{dummy}" + end + + def job_id + "LOGGING-JOB-ID" + end +end + diff --git a/activejob/test/jobs/nested_job.rb b/activejob/test/jobs/nested_job.rb new file mode 100644 index 0000000000..8c4ec549a6 --- /dev/null +++ b/activejob/test/jobs/nested_job.rb @@ -0,0 +1,10 @@ +class NestedJob < ActiveJob::Base + def perform + LoggingJob.perform_later "NestedJob" + end + + def job_id + "NESTED-JOB-ID" + end +end + diff --git a/activejob/test/jobs/queue_as_job.rb b/activejob/test/jobs/queue_as_job.rb new file mode 100644 index 0000000000..897aef52e5 --- /dev/null +++ b/activejob/test/jobs/queue_as_job.rb @@ -0,0 +1,10 @@ +require_relative '../support/job_buffer' + +class QueueAsJob < ActiveJob::Base + MY_QUEUE = :low_priority + queue_as MY_QUEUE + + def perform(greeter = "David") + JobBuffer.add("#{greeter} says hello") + end +end diff --git a/activejob/test/jobs/rescue_job.rb b/activejob/test/jobs/rescue_job.rb new file mode 100644 index 0000000000..f1b9c9349e --- /dev/null +++ b/activejob/test/jobs/rescue_job.rb @@ -0,0 +1,27 @@ +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_job + end + + rescue_from(ActiveJob::DeserializationError) do |e| + JobBuffer.add('rescued from DeserializationError') + JobBuffer.add("DeserializationError original exception was #{e.original_exception.class.name}") + end + + def perform(person = "david") + case person + when "david" + raise ArgumentError, "Hair too good" + when "other" + raise OtherError + else + JobBuffer.add('performed beautifully') + end + end +end diff --git a/activejob/test/jobs/translated_hello_job.rb b/activejob/test/jobs/translated_hello_job.rb new file mode 100644 index 0000000000..9657cd3f54 --- /dev/null +++ b/activejob/test/jobs/translated_hello_job.rb @@ -0,0 +1,10 @@ +require_relative '../support/job_buffer' + +class TranslatedHelloJob < ActiveJob::Base + def perform(greeter = "David") + translations = { en: 'Hello', de: 'Guten Tag' } + hello = translations[I18n.locale] + + JobBuffer.add("#{greeter} says #{hello}") + end +end diff --git a/activejob/test/models/person.rb b/activejob/test/models/person.rb new file mode 100644 index 0000000000..76a8f40616 --- /dev/null +++ b/activejob/test/models/person.rb @@ -0,0 +1,20 @@ +class Person + class RecordNotFound < StandardError; end + + include GlobalID::Identification + + attr_reader :id + + def self.find(id) + raise RecordNotFound.new("Cannot find person with ID=404") if id.to_i==404 + new(id) + end + + def initialize(id) + @id = id + end + + def ==(other_person) + other_person.is_a?(Person) && id.to_s == other_person.id.to_s + end +end diff --git a/activejob/test/support/backburner/inline.rb b/activejob/test/support/backburner/inline.rb new file mode 100644 index 0000000000..f761b53e27 --- /dev/null +++ b/activejob/test/support/backburner/inline.rb @@ -0,0 +1,8 @@ +require 'backburner' + +Backburner::Worker.class_eval do + class << self; alias_method :original_enqueue, :enqueue; end + def self.enqueue(job_class, args=[], opts={}) + job_class.perform(*args) + end +end
\ No newline at end of file diff --git a/activejob/test/support/delayed_job/delayed/backend/test.rb b/activejob/test/support/delayed_job/delayed/backend/test.rb new file mode 100644 index 0000000000..f80ec3a5a6 --- /dev/null +++ b/activejob/test/support/delayed_job/delayed/backend/test.rb @@ -0,0 +1,111 @@ +#copied from https://github.com/collectiveidea/delayed_job/blob/master/spec/delayed/backend/test.rb +require 'ostruct' + +# An in-memory backend suitable only for testing. Tries to behave as if it were an ORM. +module Delayed + module Backend + module Test + class Job + attr_accessor :id + attr_accessor :priority + attr_accessor :attempts + attr_accessor :handler + attr_accessor :last_error + attr_accessor :run_at + attr_accessor :locked_at + attr_accessor :locked_by + attr_accessor :failed_at + attr_accessor :queue + + include Delayed::Backend::Base + + cattr_accessor :id + self.id = 0 + + def initialize(hash = {}) + self.attempts = 0 + self.priority = 0 + self.id = (self.class.id += 1) + hash.each{|k,v| send(:"#{k}=", v)} + end + + @jobs = [] + def self.all + @jobs + end + + def self.count + all.size + end + + def self.delete_all + all.clear + end + + def self.create(attrs = {}) + new(attrs).tap(&:save) + end + + def self.create!(*args); create(*args); end + + def self.clear_locks!(worker_name) + all.select{|j| j.locked_by == worker_name}.each {|j| j.locked_by = nil; j.locked_at = nil} + end + + # Find a few candidate jobs to run (in case some immediately get locked by others). + def self.find_available(worker_name, limit = 5, max_run_time = Worker.max_run_time) + jobs = all.select do |j| + j.run_at <= db_time_now && + (j.locked_at.nil? || j.locked_at < db_time_now - max_run_time || j.locked_by == worker_name) && + !j.failed? + end + + jobs = jobs.select{|j| Worker.queues.include?(j.queue)} if Worker.queues.any? + jobs = jobs.select{|j| j.priority >= Worker.min_priority} if Worker.min_priority + jobs = jobs.select{|j| j.priority <= Worker.max_priority} if Worker.max_priority + jobs.sort_by{|j| [j.priority, j.run_at]}[0..limit-1] + end + + # Lock this job for this worker. + # Returns true if we have the lock, false otherwise. + def lock_exclusively!(max_run_time, worker) + now = self.class.db_time_now + if locked_by != worker + # We don't own this job so we will update the locked_by name and the locked_at + self.locked_at = now + self.locked_by = worker + end + + return true + end + + def self.db_time_now + Time.current + end + + def update_attributes(attrs = {}) + attrs.each{|k,v| send(:"#{k}=", v)} + save + end + + def destroy + self.class.all.delete(self) + end + + def save + self.run_at ||= Time.current + + self.class.all << self unless self.class.all.include?(self) + true + end + + def save!; save; end + + def reload + reset + self + end + end + end + end +end diff --git a/activejob/test/support/delayed_job/delayed/serialization/test.rb b/activejob/test/support/delayed_job/delayed/serialization/test.rb new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/activejob/test/support/delayed_job/delayed/serialization/test.rb diff --git a/activejob/test/support/integration/adapters/async.rb b/activejob/test/support/integration/adapters/async.rb new file mode 100644 index 0000000000..42beb12b1f --- /dev/null +++ b/activejob/test/support/integration/adapters/async.rb @@ -0,0 +1,9 @@ +module AsyncJobsManager + def setup + ActiveJob::Base.queue_adapter = :async + end + + def clear_jobs + ActiveJob::AsyncJob::QUEUES.clear + end +end diff --git a/activejob/test/support/integration/adapters/backburner.rb b/activejob/test/support/integration/adapters/backburner.rb new file mode 100644 index 0000000000..2e82562948 --- /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 + 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..0b591964bc --- /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: true, 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..256ddb3cf3 --- /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'] = "redis://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 + 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..0cd8952a28 --- /dev/null +++ b/activejob/test/support/integration/adapters/que.rb @@ -0,0 +1,39 @@ +module QueJobsManager + def setup + require 'sequel' + ActiveJob::Base.queue_adapter = :que + Que.mode = :off + Que.worker_count = 1 + end + + def clear_jobs + Que.clear! + end + + def start_workers + que_url = ENV['QUE_DATABASE_URL'] || 'postgres:///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 if exists "#{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! + + @thread = Thread.new do + loop do + Que::Job.work + sleep 0.5 + end + end + + 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 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..29c04bf625 --- /dev/null +++ b/activejob/test/support/integration/adapters/queue_classic.rb @@ -0,0 +1,37 @@ +module QueueClassicJobsManager + def setup + ENV['QC_DATABASE_URL'] ||= 'postgres:///active_jobs_qc_int_test' + ENV['QC_RAILS_DATABASE'] = 'false' + ENV['QC_LISTEN_TIME'] = "0.5" + ActiveJob::Base.queue_adapter = :queue_classic + end + + def clear_jobs + QC::Queue.new("integration_tests").delete_all + end + + def start_workers + 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 if exists "#{db}"' -U #{user} -t template1} + %x{#{"PGPASSWORD=\"#{pass}\"" if pass} psql -c 'create database "#{db}"' -U #{user} -t template1} + QC::Setup.create + + QC.default_conn_adapter.disconnect + QC.default_conn_adapter = nil + @pid = fork do + worker = QC::Worker.new(q_name: 'integration_tests') + worker.start + end + + 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 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..912f4bc387 --- /dev/null +++ b/activejob/test/support/integration/adapters/resque.rb @@ -0,0 +1,49 @@ +module ResqueJobsManager + def setup + ActiveJob::Base.queue_adapter = :resque + Resque.redis = Redis::Namespace.new 'active_jobs_int_test', redis: Redis.connect(url: "redis://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 + w = Resque::Worker.new("integration_tests") + w.term_child = true + w.work(0.5) + end + @scheduler_thread = Thread.new do + Resque::Scheduler.configure do |c| + c.poll_sleep_amount = 0.5 + c.dynamic = true + c.quiet = 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 + 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..9aa07bcb52 --- /dev/null +++ b/activejob/test/support/integration/adapters/sidekiq.rb @@ -0,0 +1,98 @@ +require 'sidekiq/api' + +require 'sidekiq/testing' +Sidekiq::Testing.disable! + +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 + continue_read, continue_write = IO.pipe + death_read, death_write = IO.pipe + + @pid = fork do + continue_read.close + death_write.close + + # Celluloid & Sidekiq are not warning-clean :( + $VERBOSE = false + + $stdin.reopen('/dev/null') + $stdout.sync = true + $stderr.sync = true + + logfile = Rails.root.join("log/sidekiq.log").to_s + Sidekiq::Logging.initialize_logger(logfile) + + self_read, self_write = IO.pipe + trap "TERM" do + self_write.puts("TERM") + end + + Thread.new do + begin + death_read.read + rescue Exception + end + self_write.puts("TERM") + end + + require 'celluloid' + Celluloid.logger = nil + require 'sidekiq/launcher' + sidekiq = Sidekiq::Launcher.new({queues: ["integration_tests"], + environment: "test", + concurrency: 1, + timeout: 1, + }) + Sidekiq.average_scheduled_poll_interval = 0.5 + Sidekiq.options[:poll_interval_average] = 1 + begin + sidekiq.run + continue_write.puts "started" + while readable_io = IO.select([self_read]) + signal = readable_io.first[0].gets.strip + raise Interrupt if signal == "TERM" + end + rescue Interrupt + end + + sidekiq.stop + exit! + end + continue_write.close + death_read.close + @worker_lifeline = death_write + + raise "Failed to start worker" unless continue_read.gets == "started\n" + end + + def stop_workers + if @pid + Process.kill 'TERM', @pid + Process.wait @pid + end + end + + def can_run? + begin + Sidekiq.redis(&:info) + Sidekiq.logger = nil + rescue + 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..875803a2d8 --- /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 + 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..9c0d66b469 --- /dev/null +++ b/activejob/test/support/integration/adapters/sucker_punch.rb @@ -0,0 +1,6 @@ +module SuckerPunchJobsManager + def setup + ActiveJob::Base.queue_adapter = :sucker_punch + SuckerPunch.logger = nil + 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..0c062a025e --- /dev/null +++ b/activejob/test/support/integration/dummy_app_template.rb @@ -0,0 +1,26 @@ +if ENV['AJ_ADAPTER'] == 'delayed_job' + generate "delayed_job:active_record", "--quiet" +end + +rake("db:migrate") + +initializer 'activejob.rb', <<-CODE +require "#{File.expand_path("../jobs_manager.rb", __FILE__)}" +JobsManager.current_manager.setup +CODE + +initializer 'i18n.rb', <<-CODE +I18n.available_locales = [:en, :de] +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 I18n.locale + 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..4a1b0bfbcb --- /dev/null +++ b/activejob/test/support/integration/helper.rb @@ -0,0 +1,30 @@ +puts "\n\n*** rake aj:integration:#{ENV['AJ_ADAPTER']} ***\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", "--quiet", + "--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.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..78d48e8d9a --- /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['AJ_ADAPTER']] ||= new(ENV['AJ_ADAPTER']) + 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..8319d09520 --- /dev/null +++ b/activejob/test/support/integration/test_case_helpers.rb @@ -0,0 +1,56 @@ +require 'active_support/concern' +require 'support/integration/jobs_manager' + +module TestCaseHelpers + extend ActiveSupport::Concern + + included do + self.use_transactional_tests = 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_class_symbols) + adapter_class_symbols.map(&:to_s).include?(ActiveJob::Base.queue_adapter.class.name.split("::").last.gsub(/Adapter$/, '').underscore) + 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(id=@id) + Dummy::Application.root.join("tmp/#{id}").exist? + end + + def job_executed_at(id=@id) + File.new(Dummy::Application.root.join("tmp/#{id}")).ctime + end + + def job_output + File.read Dummy::Application.root.join("tmp/#{@id}") + 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/que/inline.rb b/activejob/test/support/que/inline.rb new file mode 100644 index 0000000000..0950e52d28 --- /dev/null +++ b/activejob/test/support/que/inline.rb @@ -0,0 +1,14 @@ +require 'que' + +Que::Job.class_eval do + class << self; alias_method :original_enqueue, :enqueue; end + def self.enqueue(*args) + if args.last.is_a?(Hash) + options = args.pop + options.delete(:run_at) + options.delete(:priority) + args << options unless options.empty? + end + self.run(*args) + end +end diff --git a/activejob/test/support/queue_classic/inline.rb b/activejob/test/support/queue_classic/inline.rb new file mode 100644 index 0000000000..5743d5bbb5 --- /dev/null +++ b/activejob/test/support/queue_classic/inline.rb @@ -0,0 +1,23 @@ +require 'queue_classic' + +module QC + class Queue + def enqueue(method, *args) + receiver_str, _, message = method.rpartition('.') + 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 diff --git a/activejob/test/support/sneakers/inline.rb b/activejob/test/support/sneakers/inline.rb new file mode 100644 index 0000000000..16d9b830fa --- /dev/null +++ b/activejob/test/support/sneakers/inline.rb @@ -0,0 +1,12 @@ +require 'sneakers' + +module Sneakers + module Worker + module ClassMethods + def enqueue(msg) + worker = self.new(nil, nil, {}) + worker.work(*msg) + end + end + end +end |