aboutsummaryrefslogtreecommitdiffstats
path: root/activejob
diff options
context:
space:
mode:
Diffstat (limited to 'activejob')
-rw-r--r--activejob/CHANGELOG.md81
-rw-r--r--activejob/MIT-LICENSE2
-rw-r--r--activejob/README.md9
-rw-r--r--activejob/Rakefile8
-rw-r--r--activejob/activejob.gemspec2
-rw-r--r--activejob/lib/active_job.rb2
-rw-r--r--activejob/lib/active_job/arguments.rb55
-rw-r--r--activejob/lib/active_job/base.rb47
-rw-r--r--activejob/lib/active_job/callbacks.rb6
-rw-r--r--activejob/lib/active_job/core.rb41
-rw-r--r--activejob/lib/active_job/enqueuing.rb6
-rw-r--r--activejob/lib/active_job/execution.rb1
-rw-r--r--activejob/lib/active_job/gem_version.rb6
-rw-r--r--activejob/lib/active_job/logging.rb11
-rw-r--r--activejob/lib/active_job/queue_adapter.rb14
-rw-r--r--activejob/lib/active_job/queue_adapters.rb9
-rw-r--r--activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb4
-rw-r--r--activejob/lib/active_job/queue_adapters/inline_adapter.rb2
-rw-r--r--activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb10
-rw-r--r--activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb4
-rw-r--r--activejob/lib/active_job/queue_adapters/test_adapter.rb42
-rw-r--r--activejob/lib/active_job/queue_name.rb17
-rw-r--r--activejob/lib/active_job/test_helper.rb153
-rw-r--r--activejob/test/adapters/test.rb3
-rw-r--r--activejob/test/cases/adapter_test.rb3
-rw-r--r--activejob/test/cases/argument_serialization_test.rb39
-rw-r--r--activejob/test/cases/logging_test.rb11
-rw-r--r--activejob/test/cases/queue_naming_test.rb57
-rw-r--r--activejob/test/cases/rescue_test.rb2
-rw-r--r--activejob/test/cases/test_helper_test.rb212
-rw-r--r--activejob/test/helper.rb12
-rw-r--r--activejob/test/integration/queuing_test.rb9
-rw-r--r--activejob/test/jobs/callback_job.rb29
-rw-r--r--activejob/test/jobs/kwargs_job.rb7
-rw-r--r--activejob/test/support/delayed_job/delayed/backend/test.rb4
-rw-r--r--activejob/test/support/integration/adapters/backburner.rb2
-rw-r--r--activejob/test/support/integration/adapters/qu.rb2
-rw-r--r--activejob/test/support/integration/adapters/resque.rb4
-rw-r--r--activejob/test/support/integration/adapters/sidekiq.rb5
-rw-r--r--activejob/test/support/integration/adapters/sneakers.rb2
-rw-r--r--activejob/test/support/integration/helper.rb2
41 files changed, 760 insertions, 177 deletions
diff --git a/activejob/CHANGELOG.md b/activejob/CHANGELOG.md
index b04883413e..d4e19274fa 100644
--- a/activejob/CHANGELOG.md
+++ b/activejob/CHANGELOG.md
@@ -1 +1,80 @@
-* Started project. \ No newline at end of file
+* Add an `:only` option to `perform_enqueued_jobs` to filter jobs based on
+ type.
+
+ This allows specific jobs to be tested, while preventing others from
+ being performed unnecessarily.
+
+ Example:
+
+ def test_hello_job
+ assert_performed_jobs 1, only: HelloJob do
+ HelloJob.perform_later('jeremy')
+ LoggingJob.perform_later
+ end
+ end
+
+ An array may also be specified, to support testing multiple jobs.
+
+ Example:
+
+ def test_hello_and_logging_jobs
+ 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
+
+ Fixes #18802.
+
+ *Michael Ryan*
+
+* Allow keyword arguments to be used with Active Job.
+
+ Fixes #18741.
+
+ *Sean Griffin*
+
+* Add `:only` option to `assert_enqueued_jobs`, to check the number of times
+ a specific kind of job is enqueued.
+
+ Example:
+
+ def test_logging_job
+ assert_enqueued_jobs 1, only: LoggingJob do
+ LoggingJob.perform_later
+ HelloJob.perform_later('jeremy')
+ end
+ end
+
+ *George Claghorn*
+
+* `ActiveJob::Base.deserialize` delegates to the job class.
+
+ Since `ActiveJob::Base#deserialize` can be overridden by subclasses (like
+ `ActiveJob::Base#serialize`) this allows jobs to attach arbitrary metadata
+ when they get serialized and read it back when they get performed.
+
+ Example:
+
+ class DeliverWebhookJob < ActiveJob::Base
+ def serialize
+ super.merge('attempt_number' => (@attempt_number || 0) + 1)
+ end
+
+ def deserialize(job_data)
+ super
+ @attempt_number = job_data['attempt_number']
+ end
+
+ rescue_from(TimeoutError) do |exception|
+ raise exception if @attempt_number > 5
+ retry_job(wait: 10)
+ end
+ end
+
+ *Isaac Seymour*
+
+Please check [4-2-stable](https://github.com/rails/rails/blob/4-2-stable/activejob/CHANGELOG.md) for previous changes.
diff --git a/activejob/MIT-LICENSE b/activejob/MIT-LICENSE
index 8b1e97b776..0cef8cdda0 100644
--- a/activejob/MIT-LICENSE
+++ b/activejob/MIT-LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2014 David Heinemeier Hansson
+Copyright (c) 2014-2015 David Heinemeier Hansson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/activejob/README.md b/activejob/README.md
index b5d27272b1..8c83d3669a 100644
--- a/activejob/README.md
+++ b/activejob/README.md
@@ -5,7 +5,7 @@ of queueing backends. These jobs can be everything from regularly scheduled
clean-ups, to billing charges, to mailings. Anything that can be chopped up into
small units of work and run in parallel, really.
-It also serves as the backend for ActionMailer's #deliver_later functionality
+It also serves as the backend for Action Mailer's #deliver_later functionality
that makes it easy to turn any mailing into a job for running later. That's
one of the most common jobs in a modern web application: Sending emails outside
of the request-response cycle, so the user doesn't have to wait on it.
@@ -26,7 +26,8 @@ Set the queue adapter for Active Job:
ActiveJob::Base.queue_adapter = :inline # default queue adapter
```
Note: To learn how to use your preferred queueing backend see its adapter
-documentation at ActiveJob::QueueAdapters.
+documentation at
+[ActiveJob::QueueAdapters](http://api.rubyonrails.org/classes/ActiveJob/QueueAdapters.html).
Declare a job like so:
@@ -110,7 +111,7 @@ Source code can be downloaded as part of the Rails project on GitHub
## License
-ActiveJob is released under the MIT license:
+Active Job is released under the MIT license:
* http://www.opensource.org/licenses/MIT
@@ -128,5 +129,3 @@ Bug reports can be filed for the Ruby on Rails project here:
Feature requests should be discussed on the rails-core mailing list here:
* https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core
-
-
diff --git a/activejob/Rakefile b/activejob/Rakefile
index dadd0baf82..1922f256ec 100644
--- a/activejob/Rakefile
+++ b/activejob/Rakefile
@@ -1,7 +1,7 @@
require 'rake/testtask'
require 'rubygems/package_task'
-ACTIVEJOB_ADAPTERS = %w(inline delayed_job qu que queue_classic resque sidekiq sneakers sucker_punch backburner)
+ACTIVEJOB_ADAPTERS = %w(inline delayed_job qu que queue_classic resque sidekiq sneakers sucker_punch backburner test)
ACTIVEJOB_ADAPTERS -= %w(queue_classic) if defined?(JRUBY_VERSION)
task default: :test
@@ -20,7 +20,7 @@ namespace :test do
desc 'Run integration tests for all adapters'
task :integration do
- run_without_aborting ACTIVEJOB_ADAPTERS.map { |a| "test:integration:#{a}" }
+ run_without_aborting (ACTIVEJOB_ADAPTERS - ['test']).map { |a| "test:integration:#{a}" }
end
task 'env:integration' do
@@ -35,6 +35,8 @@ namespace :test do
t.libs << 'test'
t.test_files = FileList['test/cases/**/*_test.rb']
t.verbose = true
+ t.warning = true
+ t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION)
end
namespace :isolated do
@@ -52,6 +54,8 @@ namespace :test do
t.libs << 'test'
t.test_files = FileList['test/integration/**/*_test.rb']
t.verbose = true
+ t.warning = true
+ t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION)
end
end
end
diff --git a/activejob/activejob.gemspec b/activejob/activejob.gemspec
index a9be2a8f00..5404ece804 100644
--- a/activejob/activejob.gemspec
+++ b/activejob/activejob.gemspec
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
s.summary = 'Job framework with pluggable queues.'
s.description = 'Declare job classes that can be run by a variety of queueing backends.'
- s.required_ruby_version = '>= 1.9.3'
+ s.required_ruby_version = '>= 2.2.0'
s.license = 'MIT'
diff --git a/activejob/lib/active_job.rb b/activejob/lib/active_job.rb
index 1b582f5877..3d4f63b261 100644
--- a/activejob/lib/active_job.rb
+++ b/activejob/lib/active_job.rb
@@ -1,5 +1,5 @@
#--
-# Copyright (c) 2014 David Heinemeier Hansson
+# Copyright (c) 2014-2015 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
diff --git a/activejob/lib/active_job/arguments.rb b/activejob/lib/active_job/arguments.rb
index 86b85ebdba..622c37098e 100644
--- a/activejob/lib/active_job/arguments.rb
+++ b/activejob/lib/active_job/arguments.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/hash'
+
module ActiveJob
# Raised when an exception is raised during job arguments deserialization.
#
@@ -24,10 +26,16 @@ module ActiveJob
extend self
TYPE_WHITELIST = [ NilClass, Fixnum, Float, String, TrueClass, FalseClass, Bignum ]
+ # Serializes a set of arguments. Whitelisted types are returned
+ # as-is. Arrays/Hashes are serialized element by element.
+ # All other types are serialized using GlobalID.
def serialize(arguments)
arguments.map { |argument| serialize_argument(argument) }
end
+ # Deserializes a set of arguments. Whitelisted types are returned
+ # as-is. Arrays/Hashes are deserialized element by element.
+ # All other types are deserialized using GlobalID.
def deserialize(arguments)
arguments.map { |argument| deserialize_argument(argument) }
rescue => e
@@ -36,7 +44,9 @@ module ActiveJob
private
GLOBALID_KEY = '_aj_globalid'.freeze
- private_constant :GLOBALID_KEY
+ SYMBOL_KEYS_KEY = '_aj_symbol_keys'.freeze
+ WITH_INDIFFERENT_ACCESS_KEY = '_aj_hash_with_indifferent_access'.freeze
+ private_constant :GLOBALID_KEY, :SYMBOL_KEYS_KEY, :WITH_INDIFFERENT_ACCESS_KEY
def serialize_argument(argument)
case argument
@@ -46,10 +56,15 @@ module ActiveJob
{ GLOBALID_KEY => argument.to_global_id.to_s }
when Array
argument.map { |arg| serialize_argument(arg) }
+ when ActiveSupport::HashWithIndifferentAccess
+ result = serialize_hash(argument)
+ result[WITH_INDIFFERENT_ACCESS_KEY] = serialize_argument(true)
+ result
when Hash
- argument.each_with_object({}) do |(key, value), hash|
- hash[serialize_hash_key(key)] = serialize_argument(value)
- end
+ symbol_keys = argument.each_key.grep(Symbol).map(&:to_s)
+ result = serialize_hash(argument)
+ result[SYMBOL_KEYS_KEY] = symbol_keys
+ result
else
raise SerializationError.new("Unsupported argument type: #{argument.class.name}")
end
@@ -67,7 +82,7 @@ module ActiveJob
if serialized_global_id?(argument)
deserialize_global_id argument
else
- deserialize_hash argument
+ deserialize_hash(argument)
end
else
raise ArgumentError, "Can only deserialize primitive arguments: #{argument.inspect}"
@@ -82,13 +97,27 @@ module ActiveJob
GlobalID::Locator.locate hash[GLOBALID_KEY]
end
+ def serialize_hash(argument)
+ argument.each_with_object({}) do |(key, value), hash|
+ hash[serialize_hash_key(key)] = serialize_argument(value)
+ end
+ end
+
def deserialize_hash(serialized_hash)
- serialized_hash.each_with_object({}.with_indifferent_access) do |(key, value), hash|
- hash[key] = deserialize_argument(value)
+ result = serialized_hash.transform_values { |v| deserialize_argument(v) }
+ if result.delete(WITH_INDIFFERENT_ACCESS_KEY)
+ result = result.with_indifferent_access
+ elsif symbol_keys = result.delete(SYMBOL_KEYS_KEY)
+ result = transform_symbol_keys(result, symbol_keys)
end
+ result
end
- RESERVED_KEYS = [GLOBALID_KEY, GLOBALID_KEY.to_sym]
+ RESERVED_KEYS = [
+ GLOBALID_KEY, GLOBALID_KEY.to_sym,
+ SYMBOL_KEYS_KEY, SYMBOL_KEYS_KEY.to_sym,
+ WITH_INDIFFERENT_ACCESS_KEY, WITH_INDIFFERENT_ACCESS_KEY.to_sym,
+ ]
private_constant :RESERVED_KEYS
def serialize_hash_key(key)
@@ -101,5 +130,15 @@ module ActiveJob
raise SerializationError.new("Only string and symbol hash keys may be serialized as job arguments, but #{key.inspect} is a #{key.class}")
end
end
+
+ def transform_symbol_keys(hash, symbol_keys)
+ hash.transform_keys do |key|
+ if symbol_keys.include?(key)
+ key.to_sym
+ else
+ key
+ end
+ end
+ end
end
end
diff --git a/activejob/lib/active_job/base.rb b/activejob/lib/active_job/base.rb
index a3bec1f827..fd49b3fda5 100644
--- a/activejob/lib/active_job/base.rb
+++ b/activejob/lib/active_job/base.rb
@@ -6,7 +6,52 @@ require 'active_job/execution'
require 'active_job/callbacks'
require 'active_job/logging'
-module ActiveJob
+module ActiveJob #:nodoc:
+ # = Active Job
+ #
+ # Active Job objects can be configured to work with different backend
+ # queuing frameworks. To specify a queue adapter to use:
+ #
+ # ActiveJob::Base.queue_adapter = :inline
+ #
+ # A list of supported adapters can be found in QueueAdapters.
+ #
+ # Active Job objects can be defined by creating a class that inherits
+ # from the ActiveJob::Base class. The only necessary method to
+ # implement is the "perform" method.
+ #
+ # To define an Active Job object:
+ #
+ # class ProcessPhotoJob < ActiveJob::Base
+ # def perform(photo)
+ # photo.watermark!('Rails')
+ # photo.rotate!(90.degrees)
+ # photo.resize_to_fit!(300, 300)
+ # photo.upload!
+ # end
+ # end
+ #
+ # Records that are passed in are serialized/deserialized using Global
+ # ID. More information can be found in Arguments.
+ #
+ # To enqueue a job to be performed as soon the queueing system is free:
+ #
+ # ProcessPhotoJob.perform_later(photo)
+ #
+ # To enqueue a job to be processed at some point in the future:
+ #
+ # ProcessPhotoJob.set(wait_until: Date.tomorrow.noon).perform_later(photo)
+ #
+ # More information can be found in ActiveJob::Core::ClassMethods#set
+ #
+ # A job can also be processed immediately without sending to the queue:
+ #
+ # ProcessPhotoJob.perform_now(photo)
+ #
+ # == Exceptions
+ #
+ # * DeserializationError - Error class for deserialization errors.
+ # * SerializationError - Error class for serialization errors.
class Base
include Core
include QueueAdapter
diff --git a/activejob/lib/active_job/callbacks.rb b/activejob/lib/active_job/callbacks.rb
index 29e2a878b4..2b6149e84e 100644
--- a/activejob/lib/active_job/callbacks.rb
+++ b/activejob/lib/active_job/callbacks.rb
@@ -3,8 +3,8 @@ require 'active_support/callbacks'
module ActiveJob
# = Active Job Callbacks
#
- # Active Job provides hooks during the lifecycle of a job. Callbacks allow you
- # to trigger logic during the lifecycle of a job. Available callbacks are:
+ # Active Job provides hooks during the life cycle of a job. Callbacks allow you
+ # to trigger logic during the life cycle of a job. Available callbacks are:
#
# * <tt>before_enqueue</tt>
# * <tt>around_enqueue</tt>
@@ -22,6 +22,8 @@ module ActiveJob
define_callbacks :enqueue
end
+ # These methods will be included into any Active Job object, adding
+ # callbacks for +perform+ and +enqueue+ methods.
module ClassMethods
# Defines a callback that will get called right before the
# job's perform method is executed.
diff --git a/activejob/lib/active_job/core.rb b/activejob/lib/active_job/core.rb
index f55db5a588..ddd7d1361c 100644
--- a/activejob/lib/active_job/core.rb
+++ b/activejob/lib/active_job/core.rb
@@ -17,13 +17,13 @@ module ActiveJob
attr_writer :queue_name
end
+ # These methods will be included into any Active Job object, adding
+ # helpers for de/serialization and creation of job instances.
module ClassMethods
# Creates a new job instance from a hash created with +serialize+
def deserialize(job_data)
- job = job_data['job_class'].constantize.new
- job.job_id = job_data['job_id']
- job.queue_name = job_data['queue_name']
- job.serialized_arguments = job_data['arguments']
+ job = job_data['job_class'].constantize.new
+ job.deserialize(job_data)
job
end
@@ -48,8 +48,8 @@ module ActiveJob
end
end
- # Creates a new job instance. Takes as arguments the arguments that
- # will be passed to the perform method.
+ # Creates a new job instance. Takes the arguments that will be
+ # passed to the perform method.
def initialize(*arguments)
@arguments = arguments
@job_id = SecureRandom.uuid
@@ -67,6 +67,32 @@ module ActiveJob
}
end
+ # Attaches the stored job data to the current instance. Receives a hash
+ # returned from +serialize+
+ #
+ # ==== Examples
+ #
+ # class DeliverWebhookJob < ActiveJob::Base
+ # def serialize
+ # super.merge('attempt_number' => (@attempt_number || 0) + 1)
+ # end
+ #
+ # def deserialize(job_data)
+ # super
+ # @attempt_number = job_data['attempt_number']
+ # end
+ #
+ # rescue_from(TimeoutError) do |exception|
+ # raise exception if @attempt_number > 5
+ # retry_job(wait: 10)
+ # end
+ # end
+ def deserialize(job_data)
+ self.job_id = job_data['job_id']
+ self.queue_name = job_data['queue_name']
+ self.serialized_arguments = job_data['arguments']
+ end
+
private
def deserialize_arguments_if_needed
if defined?(@serialized_arguments) && @serialized_arguments.present?
@@ -84,6 +110,3 @@ module ActiveJob
end
end
end
-
-
-
diff --git a/activejob/lib/active_job/enqueuing.rb b/activejob/lib/active_job/enqueuing.rb
index 74bcc1fa5d..430c17e1bf 100644
--- a/activejob/lib/active_job/enqueuing.rb
+++ b/activejob/lib/active_job/enqueuing.rb
@@ -4,13 +4,14 @@ module ActiveJob
module Enqueuing
extend ActiveSupport::Concern
+ # Includes the +perform_later+ method for job initialization.
module ClassMethods
# Push a job onto the queue. The arguments must be legal JSON types
# (string, int, float, nil, true, false, hash or array) or
# GlobalID::Identification instances. Arbitrary Ruby objects
# are not supported.
#
- # Returns an instance of the job class queued with args available in
+ # Returns an instance of the job class queued with arguments available in
# Job#arguments.
def perform_later(*args)
job_or_instantiate(*args).enqueue
@@ -22,7 +23,7 @@ module ActiveJob
end
end
- # Reschedule the job to be re-executed. This is useful in combination
+ # Reschedules the job to be re-executed. This is useful in combination
# with the +rescue_from+ option. When you rescue an exception from your job
# you can ask Active Job to retry performing your job.
#
@@ -37,6 +38,7 @@ module ActiveJob
# rescue_from(ErrorLoadingSite) do
# retry_job queue: :low_priority
# end
+ #
# def perform(*args)
# # raise ErrorLoadingSite if cannot scrape
# end
diff --git a/activejob/lib/active_job/execution.rb b/activejob/lib/active_job/execution.rb
index 7ff857206d..79d232da4a 100644
--- a/activejob/lib/active_job/execution.rb
+++ b/activejob/lib/active_job/execution.rb
@@ -6,6 +6,7 @@ module ActiveJob
extend ActiveSupport::Concern
include ActiveSupport::Rescuable
+ # Includes methods for executing and performing jobs instantly.
module ClassMethods
# Performs the job immediately.
#
diff --git a/activejob/lib/active_job/gem_version.rb b/activejob/lib/active_job/gem_version.rb
index f80e6563b8..27a5de93f4 100644
--- a/activejob/lib/active_job/gem_version.rb
+++ b/activejob/lib/active_job/gem_version.rb
@@ -5,10 +5,10 @@ module ActiveJob
end
module VERSION
- MAJOR = 4
- MINOR = 2
+ MAJOR = 5
+ MINOR = 0
TINY = 0
- PRE = "beta2"
+ PRE = "alpha"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/activejob/lib/active_job/logging.rb b/activejob/lib/active_job/logging.rb
index bb96668cfb..cd29e6908e 100644
--- a/activejob/lib/active_job/logging.rb
+++ b/activejob/lib/active_job/logging.rb
@@ -3,7 +3,7 @@ require 'active_support/tagged_logging'
require 'active_support/logger'
module ActiveJob
- module Logging
+ module Logging #:nodoc:
extend ActiveSupport::Concern
included do
@@ -75,7 +75,7 @@ module ActiveJob
def perform(event)
info do
job = event.payload[:job]
- "Performed #{job.class.name} from #{queue_name(event)} in #{event.duration.round(2).to_s}ms"
+ "Performed #{job.class.name} from #{queue_name(event)} in #{event.duration.round(2)}ms"
end
end
@@ -85,7 +85,12 @@ module ActiveJob
end
def args_info(job)
- job.arguments.any? ? " with arguments: #{job.arguments.map(&:inspect).join(", ")}" : ""
+ if job.arguments.any?
+ ' with arguments: ' +
+ job.arguments.map { |arg| arg.try(:to_global_id).try(:to_s) || arg.inspect }.join(', ')
+ else
+ ''
+ end
end
def scheduled_at(event)
diff --git a/activejob/lib/active_job/queue_adapter.rb b/activejob/lib/active_job/queue_adapter.rb
index fb54aec75e..d610d30e01 100644
--- a/activejob/lib/active_job/queue_adapter.rb
+++ b/activejob/lib/active_job/queue_adapter.rb
@@ -2,12 +2,18 @@ require 'active_job/queue_adapters/inline_adapter'
require 'active_support/core_ext/string/inflections'
module ActiveJob
- module QueueAdapter
+ # The <tt>ActiveJob::QueueAdapter</tt> module is used to load the
+ # correct adapter. The default queue adapter is the :inline queue.
+ module QueueAdapter #:nodoc:
extend ActiveSupport::Concern
+ # Includes the setter method for changing the active queue adapter.
module ClassMethods
mattr_reader(:queue_adapter) { ActiveJob::QueueAdapters::InlineAdapter }
+ # Specify the backend queue provider. The default queue adapter
+ # is the :inline queue. See QueueAdapters for more
+ # information.
def queue_adapter=(name_or_adapter)
@@queue_adapter = \
case name_or_adapter
@@ -15,8 +21,8 @@ module ActiveJob
ActiveJob::QueueAdapters::TestAdapter.new
when Symbol, String
load_adapter(name_or_adapter)
- when Class
- name_or_adapter
+ else
+ name_or_adapter if name_or_adapter.respond_to?(:enqueue)
end
end
@@ -26,4 +32,4 @@ module ActiveJob
end
end
end
-end \ No newline at end of file
+end
diff --git a/activejob/lib/active_job/queue_adapters.rb b/activejob/lib/active_job/queue_adapters.rb
index e865c901ce..4b91c93dbe 100644
--- a/activejob/lib/active_job/queue_adapters.rb
+++ b/activejob/lib/active_job/queue_adapters.rb
@@ -7,20 +7,21 @@ module ActiveJob
# * {Delayed Job}[https://github.com/collectiveidea/delayed_job]
# * {Qu}[https://github.com/bkeepers/qu]
# * {Que}[https://github.com/chanks/que]
- # * {QueueClassic 2.x}[https://github.com/ryandotsmith/queue_classic/tree/v2.2.3]
+ # * {queue_classic}[https://github.com/QueueClassic/queue_classic]
# * {Resque 1.x}[https://github.com/resque/resque/tree/1-x-stable]
# * {Sidekiq}[http://sidekiq.org]
# * {Sneakers}[https://github.com/jondot/sneakers]
# * {Sucker Punch}[https://github.com/brandonhilkert/sucker_punch]
#
- # #### Backends Features
+ # === Backends Features
#
# | | Async | Queues | Delayed | Priorities | Timeout | Retries |
# |-------------------|-------|--------|-----------|------------|---------|---------|
# | Backburner | Yes | Yes | Yes | Yes | Job | Global |
# | Delayed Job | Yes | Yes | Yes | Job | Global | Global |
+ # | Qu | Yes | Yes | No | No | No | Global |
# | Que | Yes | Yes | Yes | Job | No | Job |
- # | Queue Classic | Yes | Yes | No* | No | No | No |
+ # | queue_classic | Yes | Yes | No* | No | No | No |
# | Resque | Yes | Yes | Yes (Gem) | Queue | Global | Yes |
# | Sidekiq | Yes | Yes | Yes | Queue | No | Job |
# | Sneakers | Yes | Yes | No | Queue | Queue | No |
@@ -29,7 +30,7 @@ module ActiveJob
# | Active Job | Yes | Yes | Yes | No | No | No |
#
# NOTE:
- # Queue Classic does not support Job scheduling. However you can implement this
+ # queue_classic does not support Job scheduling. However you can implement this
# yourself or you can use the queue_classic-later gem. See the documentation for
# ActiveJob::QueueAdapters::QueueClassicAdapter.
#
diff --git a/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb b/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb
index 4d27c4fff8..69d9e70de3 100644
--- a/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb
@@ -6,10 +6,10 @@ module ActiveJob
#
# Delayed::Job (or DJ) encapsulates the common pattern of asynchronously
# executing longer tasks in the background. Although DJ can have many
- # storage backends one of the most used is based on Active Record.
+ # storage backends, one of the most used is based on Active Record.
# Read more about Delayed Job {here}[https://github.com/collectiveidea/delayed_job].
#
- # To use Delayed Job set the queue_adapter config to +:delayed_job+.
+ # To use Delayed Job, set the queue_adapter config to +:delayed_job+.
#
# Rails.application.config.active_job.queue_adapter = :delayed_job
class DelayedJobAdapter
diff --git a/activejob/lib/active_job/queue_adapters/inline_adapter.rb b/activejob/lib/active_job/queue_adapters/inline_adapter.rb
index e498454909..e25d88e723 100644
--- a/activejob/lib/active_job/queue_adapters/inline_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/inline_adapter.rb
@@ -15,7 +15,7 @@ module ActiveJob
end
def enqueue_at(*) #:nodoc:
- raise NotImplementedError.new("Use a queueing backend to enqueue jobs in the future. Read more at https://github.com/rails/activejob")
+ raise NotImplementedError.new("Use a queueing backend to enqueue jobs in the future. Read more at http://guides.rubyonrails.org/active_job_basics.html")
end
end
end
diff --git a/activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb b/activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb
index f160932578..34c11a68b2 100644
--- a/activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb
@@ -2,7 +2,7 @@ require 'queue_classic'
module ActiveJob
module QueueAdapters
- # == Queue Classic adapter for Active Job
+ # == queue_classic adapter for Active Job
#
# queue_classic provides a simple interface to a PostgreSQL-backed message
# queue. queue_classic specializes in concurrent locking and minimizing
@@ -11,9 +11,9 @@ module ActiveJob
# production environment and that adding another dependency (e.g. redis,
# beanstalkd, 0mq) is undesirable.
#
- # Read more about Queue Classic {here}[https://github.com/ryandotsmith/queue_classic].
+ # Read more about queue_classic {here}[https://github.com/QueueClassic/queue_classic].
#
- # To use Queue Classic set the queue_adapter config to +:queue_classic+.
+ # To use queue_classic set the queue_adapter config to +:queue_classic+.
#
# Rails.application.config.active_job.queue_adapter = :queue_classic
class QueueClassicAdapter
@@ -25,8 +25,8 @@ module ActiveJob
def enqueue_at(job, timestamp) #:nodoc:
queue = build_queue(job.queue_name)
unless queue.respond_to?(:enqueue_at)
- raise NotImplementedError, 'To be able to schedule jobs with Queue Classic ' \
- 'the QC::Queue needs to respond to `enqueue_at(timestamp, method, *args)`. '
+ raise NotImplementedError, 'To be able to schedule jobs with queue_classic ' \
+ 'the QC::Queue needs to respond to `enqueue_at(timestamp, method, *args)`. ' \
'You can implement this yourself or you can use the queue_classic-later gem.'
end
queue.enqueue_at(timestamp, "#{JobWrapper.name}.perform", job.serialize)
diff --git a/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb b/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb
index 7d80a6fd7a..21005fc728 100644
--- a/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb
@@ -21,8 +21,7 @@ module ActiveJob
Sidekiq::Client.push \
'class' => JobWrapper,
'queue' => job.queue_name,
- 'args' => [ job.serialize ],
- 'retry' => true
+ 'args' => [ job.serialize ]
end
def enqueue_at(job, timestamp) #:nodoc:
@@ -30,7 +29,6 @@ module ActiveJob
'class' => JobWrapper,
'queue' => job.queue_name,
'args' => [ job.serialize ],
- 'retry' => true,
'at' => timestamp
end
end
diff --git a/activejob/lib/active_job/queue_adapters/test_adapter.rb b/activejob/lib/active_job/queue_adapters/test_adapter.rb
index e4fdf60008..c9e2bdca27 100644
--- a/activejob/lib/active_job/queue_adapters/test_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/test_adapter.rb
@@ -11,9 +11,14 @@ module ActiveJob
# Rails.application.config.active_job.queue_adapter = :test
class TestAdapter
delegate :name, to: :class
- attr_accessor(:perform_enqueued_jobs, :perform_enqueued_at_jobs)
+ attr_accessor(:perform_enqueued_jobs, :perform_enqueued_at_jobs, :filter)
attr_writer(:enqueued_jobs, :performed_jobs)
+ def initialize
+ self.perform_enqueued_jobs = false
+ self.perform_enqueued_at_jobs = false
+ end
+
# Provides a store of all the enqueued jobs with the TestAdapter so you can check them.
def enqueued_jobs
@enqueued_jobs ||= []
@@ -25,22 +30,33 @@ module ActiveJob
end
def enqueue(job) #:nodoc:
- if perform_enqueued_jobs
- performed_jobs << {job: job.class, args: job.arguments, queue: job.queue_name}
- job.perform_now
- else
- enqueued_jobs << {job: job.class, args: job.arguments, queue: job.queue_name}
- end
+ return if filtered?(job)
+
+ job_data = { job: job.class, args: job.serialize['arguments'], queue: job.queue_name }
+ enqueue_or_perform(perform_enqueued_jobs, job, job_data)
end
def enqueue_at(job, timestamp) #:nodoc:
- if perform_enqueued_at_jobs
- performed_jobs << {job: job.class, args: job.arguments, queue: job.queue_name, at: timestamp}
- job.perform_now
- else
- enqueued_jobs << {job: job.class, args: job.arguments, queue: job.queue_name, at: timestamp}
- end
+ return if filtered?(job)
+
+ job_data = { job: job.class, args: job.serialize['arguments'], queue: job.queue_name, at: timestamp }
+ enqueue_or_perform(perform_enqueued_at_jobs, job, job_data)
end
+
+ private
+
+ def enqueue_or_perform(perform, job, job_data)
+ if perform
+ performed_jobs << job_data
+ Base.execute job.serialize
+ else
+ enqueued_jobs << job_data
+ end
+ end
+
+ def filtered?(job)
+ filter && !Array(filter).include?(job.class)
+ end
end
end
end
diff --git a/activejob/lib/active_job/queue_name.rb b/activejob/lib/active_job/queue_name.rb
index 45acb71605..9ae0345120 100644
--- a/activejob/lib/active_job/queue_name.rb
+++ b/activejob/lib/active_job/queue_name.rb
@@ -2,10 +2,20 @@ module ActiveJob
module QueueName
extend ActiveSupport::Concern
+ # Includes the ability to override the default queue name and prefix.
module ClassMethods
mattr_accessor(:queue_name_prefix)
mattr_accessor(:default_queue_name) { "default" }
+ # Specifies the name of the queue to process the job on.
+ #
+ # class PublishToFeedJob < ActiveJob::Base
+ # queue_as :feeds
+ #
+ # def perform(post)
+ # post.to_feed!
+ # end
+ # end
def queue_as(part_name=nil, &block)
if block_given?
self.queue_name = block
@@ -15,15 +25,18 @@ module ActiveJob
end
def queue_name_from_part(part_name) #:nodoc:
- queue_name = part_name.to_s.presence || default_queue_name
+ queue_name = part_name || default_queue_name
name_parts = [queue_name_prefix.presence, queue_name]
- name_parts.compact.join('_')
+ name_parts.compact.join(queue_name_delimiter)
end
end
included do
class_attribute :queue_name, instance_accessor: false
+ class_attribute :queue_name_delimiter, instance_accessor: false
+
self.queue_name = default_queue_name
+ self.queue_name_delimiter = '_' # set default delimiter to '_'
end
# Returns the name of the queue the job will be run on
diff --git a/activejob/lib/active_job/test_helper.rb b/activejob/lib/active_job/test_helper.rb
index af62fae9b9..25bc99a4f8 100644
--- a/activejob/lib/active_job/test_helper.rb
+++ b/activejob/lib/active_job/test_helper.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/hash/keys'
+
module ActiveJob
# Provides helper methods for testing Active Job
module TestHelper
@@ -40,20 +42,28 @@ module ActiveJob
# HelloJob.perform_later('rafael')
# end
# end
- def assert_enqueued_jobs(number)
+ #
+ # The number of times a specific job is enqueued can be asserted.
+ #
+ # def test_logging_job
+ # assert_enqueued_jobs 2, only: LoggingJob do
+ # LoggingJob.perform_later
+ # HelloJob.perform_later('jeremy')
+ # end
+ # end
+ def assert_enqueued_jobs(number, only: nil)
if block_given?
- original_count = enqueued_jobs.size
+ original_count = enqueued_jobs_size(only: only)
yield
- new_count = enqueued_jobs.size
- assert_equal original_count + number, new_count,
- "#{number} jobs expected, but #{new_count - original_count} were enqueued"
+ new_count = enqueued_jobs_size(only: only)
+ assert_equal original_count + number, new_count, "#{number} jobs expected, but #{new_count - original_count} were enqueued"
else
- enqueued_jobs_size = enqueued_jobs.size
- assert_equal number, enqueued_jobs_size, "#{number} jobs expected, but #{enqueued_jobs_size} were enqueued"
+ actual_count = enqueued_jobs_size(only: only)
+ assert_equal number, actual_count, "#{number} jobs expected, but #{actual_count} were enqueued"
end
end
- # Assert that no job have been enqueued.
+ # Asserts that no jobs have been enqueued.
#
# def test_jobs
# assert_no_enqueued_jobs
@@ -69,21 +79,37 @@ module ActiveJob
# end
# end
#
+ # It can be asserted that no jobs of a specific kind are enqueued:
+ #
+ # def test_no_logging
+ # assert_no_enqueued_jobs only: LoggingJob do
+ # HelloJob.perform_later('jeremy')
+ # end
+ # end
+ #
# Note: This assertion is simply a shortcut for:
#
- # assert_enqueued_jobs 0
- def assert_no_enqueued_jobs(&block)
- assert_enqueued_jobs 0, &block
+ # assert_enqueued_jobs 0, &block
+ def assert_no_enqueued_jobs(only: nil, &block)
+ assert_enqueued_jobs 0, only: only, &block
end
# Asserts that the number of performed jobs matches the given number.
+ # If no block is passed, <tt>perform_enqueued_jobs</tt>
+ # must be called around the job call.
#
# def test_jobs
# assert_performed_jobs 0
- # HelloJob.perform_later('xavier')
+ #
+ # perform_enqueued_jobs do
+ # HelloJob.perform_later('xavier')
+ # end
# assert_performed_jobs 1
- # HelloJob.perform_later('yves')
- # assert_performed_jobs 2
+ #
+ # perform_enqueued_jobs do
+ # HelloJob.perform_later('yves')
+ # assert_performed_jobs 2
+ # end
# end
#
# If a block is passed, that block should cause the specified number of
@@ -99,10 +125,32 @@ module ActiveJob
# HelloJob.perform_later('sean')
# end
# end
- def assert_performed_jobs(number)
+ #
+ # The block form supports filtering. If the :only option is specified,
+ # then only the listed job(s) will be performed.
+ #
+ # def test_hello_job
+ # assert_performed_jobs 1, only: HelloJob do
+ # HelloJob.perform_later('jeremy')
+ # LoggingJob.perform_later
+ # end
+ # end
+ #
+ # An array may also be specified, to support testing multiple jobs.
+ #
+ # def test_hello_and_logging_jobs
+ # assert_nothing_raised do
+ # assert_performed_jobs 2, only: [HelloJob, LoggingJob] do
+ # HelloJob.perform_later('jeremy')
+ # LoggingJob.perform_later('stewie')
+ # RescueJob.perform_later('david')
+ # end
+ # end
+ # end
+ def assert_performed_jobs(number, only: nil)
if block_given?
original_count = performed_jobs.size
- yield
+ perform_enqueued_jobs(only: only) { yield }
new_count = performed_jobs.size
assert_equal original_count + number, new_count,
"#{number} jobs expected, but #{new_count - original_count} were performed"
@@ -116,8 +164,11 @@ module ActiveJob
#
# def test_jobs
# assert_no_performed_jobs
- # HelloJob.perform_later('matthew')
- # assert_performed_jobs 1
+ #
+ # perform_enqueued_jobs do
+ # HelloJob.perform_later('matthew')
+ # assert_performed_jobs 1
+ # end
# end
#
# If a block is passed, that block should not cause any job to be performed.
@@ -128,16 +179,38 @@ module ActiveJob
# end
# end
#
+ # The block form supports filtering. If the :only option is specified,
+ # then only the listed job(s) will be performed.
+ #
+ # def test_hello_job
+ # assert_performed_jobs 1, only: HelloJob do
+ # HelloJob.perform_later('jeremy')
+ # LoggingJob.perform_later
+ # end
+ # end
+ #
+ # An array may also be specified, to support testing multiple jobs.
+ #
+ # def test_hello_and_logging_jobs
+ # assert_nothing_raised do
+ # assert_performed_jobs 2, only: [HelloJob, LoggingJob] do
+ # HelloJob.perform_later('jeremy')
+ # LoggingJob.perform_later('stewie')
+ # RescueJob.perform_later('david')
+ # end
+ # end
+ # end
+ #
# Note: This assertion is simply a shortcut for:
#
- # assert_performed_jobs 0
- def assert_no_performed_jobs(&block)
- assert_performed_jobs 0, &block
+ # assert_performed_jobs 0, &block
+ def assert_no_performed_jobs(only: nil, &block)
+ assert_performed_jobs 0, only: only, &block
end
# Asserts that the job passed in the block has been enqueued with the given arguments.
#
- # def assert_enqueued_job
+ # def test_assert_enqueued_with
# assert_enqueued_with(job: MyJob, args: [1,2,3], queue: 'low') do
# MyJob.perform_later(1,2,3)
# end
@@ -146,9 +219,10 @@ module ActiveJob
original_enqueued_jobs = enqueued_jobs.dup
clear_enqueued_jobs
args.assert_valid_keys(:job, :args, :at, :queue)
+ serialized_args = serialize_args_for_assertion(args)
yield
matching_job = enqueued_jobs.any? do |job|
- args.all? { |key, value| value == job[key] }
+ serialized_args.all? { |key, value| value == job[key] }
end
assert matching_job, "No enqueued job found with #{args}"
ensure
@@ -166,15 +240,28 @@ module ActiveJob
original_performed_jobs = performed_jobs.dup
clear_performed_jobs
args.assert_valid_keys(:job, :args, :at, :queue)
- yield
+ serialized_args = serialize_args_for_assertion(args)
+ perform_enqueued_jobs { yield }
matching_job = performed_jobs.any? do |job|
- args.all? { |key, value| value == job[key] }
+ serialized_args.all? { |key, value| value == job[key] }
end
assert matching_job, "No performed job found with #{args}"
ensure
queue_adapter.performed_jobs = original_performed_jobs + performed_jobs
end
+ def perform_enqueued_jobs(only: nil)
+ @old_perform_enqueued_jobs = queue_adapter.perform_enqueued_jobs
+ @old_perform_enqueued_at_jobs = queue_adapter.perform_enqueued_at_jobs
+ queue_adapter.perform_enqueued_jobs = true
+ queue_adapter.perform_enqueued_at_jobs = true
+ queue_adapter.filter = only
+ yield
+ ensure
+ queue_adapter.perform_enqueued_jobs = @old_perform_enqueued_jobs
+ queue_adapter.perform_enqueued_at_jobs = @old_perform_enqueued_at_jobs
+ end
+
def queue_adapter
ActiveJob::Base.queue_adapter
end
@@ -191,6 +278,22 @@ module ActiveJob
def clear_performed_jobs
performed_jobs.clear
end
+
+ def enqueued_jobs_size(only: nil)
+ if only
+ enqueued_jobs.select { |job| job[:job] == only }.size
+ else
+ enqueued_jobs.size
+ end
+ end
+
+ def serialize_args_for_assertion(args)
+ serialized_args = args.dup
+ if job_args = serialized_args.delete(:args)
+ serialized_args[:args] = ActiveJob::Arguments.serialize(job_args)
+ end
+ serialized_args
+ end
end
end
end
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
index 4fc235ae40..6570c55a83 100644
--- a/activejob/test/cases/adapter_test.rb
+++ b/activejob/test/cases/adapter_test.rb
@@ -2,7 +2,6 @@ require 'helper'
class AdapterTest < ActiveSupport::TestCase
test "should load #{ENV['AJADAPTER']} adapter" do
- ActiveJob::Base.queue_adapter = ENV['AJADAPTER'].to_sym
- assert_equal ActiveJob::Base.queue_adapter, "active_job/queue_adapters/#{ENV['AJADAPTER']}_adapter".classify.constantize
+ assert_equal "active_job/queue_adapters/#{ENV['AJADAPTER']}_adapter".classify, ActiveJob::Base.queue_adapter.name
end
end
diff --git a/activejob/test/cases/argument_serialization_test.rb b/activejob/test/cases/argument_serialization_test.rb
index dbe36fc572..8b9b62190f 100644
--- a/activejob/test/cases/argument_serialization_test.rb
+++ b/activejob/test/cases/argument_serialization_test.rb
@@ -2,6 +2,7 @@ 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
@@ -31,16 +32,26 @@ class ArgumentSerializationTest < ActiveSupport::TestCase
end
test 'should convert records to Global IDs' do
- assert_arguments_roundtrip [@person], ['_aj_globalid' => @person.to_gid.to_s]
+ assert_arguments_roundtrip [@person]
end
test 'should dive deep into arrays and hashes' do
- assert_arguments_roundtrip [3, [@person]], [3, ['_aj_globalid' => @person.to_gid.to_s]]
- assert_arguments_roundtrip [{ 'a' => @person }], [{ 'a' => { '_aj_globalid' => @person.to_gid.to_s }}.with_indifferent_access]
+ assert_arguments_roundtrip [3, [@person]]
+ assert_arguments_roundtrip [{ 'a' => @person }]
end
- test 'should stringify symbol hash keys' do
- assert_equal [ 'a' => 1 ], ActiveJob::Arguments.serialize([ a: 1 ])
+ 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
@@ -71,14 +82,22 @@ class ArgumentSerializationTest < ActiveSupport::TestCase
end
end
+ test 'allows for keyword arguments' do
+ KwargsJob.perform_later(argument: 2)
+
+ assert_equal "Job with argument: 2", JobBuffer.last_value
+ end
+
private
def assert_arguments_unchanged(*args)
- assert_arguments_roundtrip args, args
+ assert_arguments_roundtrip args
+ end
+
+ def assert_arguments_roundtrip(args)
+ assert_equal args, perform_round_trip(args)
end
- def assert_arguments_roundtrip(args, expected_serialized_args)
- serialized = ActiveJob::Arguments.serialize(args)
- assert_equal expected_serialized_args, serialized
- assert_equal args, ActiveJob::Arguments.deserialize(serialized)
+ def perform_round_trip(args)
+ ActiveJob::Arguments.deserialize(ActiveJob::Arguments.serialize(args))
end
end
diff --git a/activejob/test/cases/logging_test.rb b/activejob/test/cases/logging_test.rb
index 9c56ee08b6..64aae00441 100644
--- a/activejob/test/cases/logging_test.rb
+++ b/activejob/test/cases/logging_test.rb
@@ -4,6 +4,7 @@ require 'active_support/core_ext/numeric/time'
require 'jobs/hello_job'
require 'jobs/logging_job'
require 'jobs/nested_job'
+require 'models/person'
class AdapterTest < ActiveSupport::TestCase
include ActiveSupport::LogSubscriber::TestHelper
@@ -33,7 +34,7 @@ class AdapterTest < ActiveSupport::TestCase
def teardown
super
ActiveJob::Logging::LogSubscriber.log_subscribers.pop
- ActiveJob::Base.logger = @old_logger
+ set_logger @old_logger
end
def set_logger(logger)
@@ -65,6 +66,14 @@ class AdapterTest < ActiveSupport::TestCase
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_enqueue_job_logging
HelloJob.perform_later "Cristian"
assert_match(/Enqueued HelloJob \(Job ID: .*?\) to .*?:.*Cristian/, @logger.messages)
diff --git a/activejob/test/cases/queue_naming_test.rb b/activejob/test/cases/queue_naming_test.rb
index 4052477543..898016a704 100644
--- a/activejob/test/cases/queue_naming_test.rb
+++ b/activejob/test/cases/queue_naming_test.rb
@@ -9,8 +9,9 @@ class QueueNamingTest < ActiveSupport::TestCase
end
test 'uses given queue name job' do
+ original_queue_name = HelloJob.queue_name
+
begin
- original_queue_name = HelloJob.queue_name
HelloJob.queue_as :greetings
assert_equal "greetings", HelloJob.new.queue_name
ensure
@@ -18,9 +19,32 @@ class QueueNamingTest < ActiveSupport::TestCase
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
- original_queue_name = HelloJob.queue_name
HelloJob.queue_as { :another }
assert_equal "another", HelloJob.new.queue_name
ensure
@@ -29,8 +53,9 @@ class QueueNamingTest < ActiveSupport::TestCase
end
test 'can use arguments to determine queue_name in queue_as block' do
+ original_queue_name = HelloJob.queue_name
+
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
@@ -39,11 +64,11 @@ class QueueNamingTest < ActiveSupport::TestCase
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
+ 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
@@ -53,9 +78,25 @@ class QueueNamingTest < ActiveSupport::TestCase
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/rescue_test.rb b/activejob/test/cases/rescue_test.rb
index 1b6c2e9fac..58c9ca8992 100644
--- a/activejob/test/cases/rescue_test.rb
+++ b/activejob/test/cases/rescue_test.rb
@@ -2,8 +2,6 @@ require 'helper'
require 'jobs/rescue_job'
require 'models/person'
-require 'active_support/core_ext/object/inclusion'
-
class RescueTest < ActiveSupport::TestCase
setup do
JobBuffer.clear
diff --git a/activejob/test/cases/test_helper_test.rb b/activejob/test/cases/test_helper_test.rb
index 71c505a65f..58de2f2588 100644
--- a/activejob/test/cases/test_helper_test.rb
+++ b/activejob/test/cases/test_helper_test.rb
@@ -4,10 +4,10 @@ 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
- setup { queue_adapter.perform_enqueued_at_jobs = true }
-
def test_assert_enqueued_jobs
assert_nothing_raised do
assert_enqueued_jobs 1 do
@@ -44,11 +44,16 @@ class EnqueuedJobsTest < ActiveJob::TestCase
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
- # Scheduled jobs are being performed in this context
- HelloJob.set(wait_until: Date.tomorrow.noon).perform_later('godfrey')
+ HelloJob.perform_now
end
end
end
@@ -84,9 +89,68 @@ class EnqueuedJobsTest < ActiveJob::TestCase
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_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_enqueued_job
assert_enqueued_with(job: LoggingJob, queue: 'default') do
- NestedJob.set(wait_until: Date.tomorrow.noon).perform_later
+ LoggingJob.set(wait_until: Date.tomorrow.noon).perform_later
end
end
@@ -113,11 +177,28 @@ class EnqueuedJobsTest < ActiveJob::TestCase
end
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
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
@@ -143,22 +224,31 @@ class PerformedJobsTest < ActiveJob::TestCase
def test_assert_performed_jobs_with_no_block
assert_nothing_raised do
- HelloJob.perform_later('rafael')
+ perform_enqueued_jobs do
+ HelloJob.perform_later('rafael')
+ end
assert_performed_jobs 1
end
assert_nothing_raised do
- HelloJob.perform_later('aaron')
- HelloJob.perform_later('matthew')
- assert_performed_jobs 3
+ 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
- # Scheduled jobs are being enqueued in this context
- HelloJob.set(wait_until: Date.tomorrow.noon).perform_later('godfrey')
+ # empty block won't perform jobs
end
end
end
@@ -194,6 +284,83 @@ class PerformedJobsTest < ActiveJob::TestCase
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
@@ -213,4 +380,23 @@ class PerformedJobsTest < ActiveJob::TestCase
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
end
diff --git a/activejob/test/helper.rb b/activejob/test/helper.rb
index ce22833b11..db5265d7b2 100644
--- a/activejob/test/helper.rb
+++ b/activejob/test/helper.rb
@@ -7,17 +7,6 @@ GlobalID.app = 'aj'
@adapter = ENV['AJADAPTER'] || 'inline'
-def sidekiq?
- @adapter == 'sidekiq'
-end
-
-def ruby_193?
- RUBY_VERSION == '1.9.3' && RUBY_ENGINE != 'java'
-end
-
-# Sidekiq doesn't work with MRI 1.9.3
-exit if sidekiq? && ruby_193?
-
if ENV['AJ_INTEGRATION_TESTS']
require 'support/integration/helper'
else
@@ -26,5 +15,4 @@ end
require 'active_support/testing/autorun'
-ActiveJob::Base.logger.level = Logger::DEBUG
ActiveSupport::TestCase.test_order = :random
diff --git a/activejob/test/integration/queuing_test.rb b/activejob/test/integration/queuing_test.rb
index 779dedb53f..38874b51a8 100644
--- a/activejob/test/integration/queuing_test.rb
+++ b/activejob/test/integration/queuing_test.rb
@@ -3,16 +3,17 @@ 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
+ 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-listenting queue' do
+ test 'should not run jobs queued on a non-listening queue' do
+ skip if adapter_is?(:inline) || adapter_is?(:sucker_punch)
+ old_queue = TestJob.queue_name
+
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)
diff --git a/activejob/test/jobs/callback_job.rb b/activejob/test/jobs/callback_job.rb
index 056dd073e8..891ed9464e 100644
--- a/activejob/test/jobs/callback_job.rb
+++ b/activejob/test/jobs/callback_job.rb
@@ -1,12 +1,21 @@
class CallbackJob < ActiveJob::Base
before_perform ->(job) { job.history << "CallbackJob ran before_perform" }
- after_perform ->(job) { job.history << "CallbackJob ran after_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" }
+ after_enqueue ->(job) { job.history << "CallbackJob ran after_enqueue" }
- around_perform :around_perform
- around_enqueue :around_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")
@@ -17,16 +26,4 @@ class CallbackJob < ActiveJob::Base
@history ||= []
end
- # FIXME: Not sure why these can't be declared inline like before/after
- def around_perform
- history << "CallbackJob ran around_perform_start"
- yield
- history << "CallbackJob ran around_perform_stop"
- end
-
- def around_enqueue
- history << "CallbackJob ran around_enqueue_start"
- yield
- history << "CallbackJob ran around_enqueue_stop"
- 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/support/delayed_job/delayed/backend/test.rb b/activejob/test/support/delayed_job/delayed/backend/test.rb
index b50ed36fc2..f80ec3a5a6 100644
--- a/activejob/test/support/delayed_job/delayed/backend/test.rb
+++ b/activejob/test/support/delayed_job/delayed/backend/test.rb
@@ -43,9 +43,7 @@ module Delayed
end
def self.create(attrs = {})
- new(attrs).tap do |o|
- o.save
- end
+ new(attrs).tap(&:save)
end
def self.create!(*args); create(*args); end
diff --git a/activejob/test/support/integration/adapters/backburner.rb b/activejob/test/support/integration/adapters/backburner.rb
index 0cda36a273..2e82562948 100644
--- a/activejob/test/support/integration/adapters/backburner.rb
+++ b/activejob/test/support/integration/adapters/backburner.rb
@@ -29,7 +29,7 @@ module BackburnerJobsManager
def can_run?
begin
Backburner::Worker.connection.send :connect!
- rescue => e
+ rescue
return false
end
true
diff --git a/activejob/test/support/integration/adapters/qu.rb b/activejob/test/support/integration/adapters/qu.rb
index e913f04a24..3a5b66a057 100644
--- a/activejob/test/support/integration/adapters/qu.rb
+++ b/activejob/test/support/integration/adapters/qu.rb
@@ -30,7 +30,7 @@ module QuJobsManager
def can_run?
begin
Qu.backend.connection.client.connect
- rescue => e
+ rescue
return false
end
true
diff --git a/activejob/test/support/integration/adapters/resque.rb b/activejob/test/support/integration/adapters/resque.rb
index 9de3e7c879..912f4bc387 100644
--- a/activejob/test/support/integration/adapters/resque.rb
+++ b/activejob/test/support/integration/adapters/resque.rb
@@ -1,7 +1,7 @@
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.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"
@@ -41,7 +41,7 @@ module ResqueJobsManager
def can_run?
begin
Resque.redis.client.connect
- rescue => e
+ rescue
return false
end
true
diff --git a/activejob/test/support/integration/adapters/sidekiq.rb b/activejob/test/support/integration/adapters/sidekiq.rb
index 0a0a549c9e..6ff18fb56a 100644
--- a/activejob/test/support/integration/adapters/sidekiq.rb
+++ b/activejob/test/support/integration/adapters/sidekiq.rb
@@ -48,8 +48,9 @@ module SidekiqJobsManager
def can_run?
begin
- Sidekiq.redis { |conn| conn.connect }
- rescue => e
+ Sidekiq.redis(&:info)
+ Sidekiq.logger = nil
+ rescue
return false
end
true
diff --git a/activejob/test/support/integration/adapters/sneakers.rb b/activejob/test/support/integration/adapters/sneakers.rb
index f21bb38a32..875803a2d8 100644
--- a/activejob/test/support/integration/adapters/sneakers.rb
+++ b/activejob/test/support/integration/adapters/sneakers.rb
@@ -68,7 +68,7 @@ module SneakersJobsManager
def can_run?
begin
bunny_publisher
- rescue => e
+ rescue
return false
end
true
diff --git a/activejob/test/support/integration/helper.rb b/activejob/test/support/integration/helper.rb
index 9bd45e09e8..39e41b6d29 100644
--- a/activejob/test/support/integration/helper.rb
+++ b/activejob/test/support/integration/helper.rb
@@ -20,7 +20,7 @@ require 'rails/test_help'
Rails.backtrace_cleaner.remove_silencers!
require_relative 'test_case_helpers'
-ActiveSupport::TestCase.send(:include, TestCaseHelpers)
+ActiveSupport::TestCase.include(TestCaseHelpers)
JobsManager.current_manager.start_workers