activejob 5.2.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +145 -14
- data/MIT-LICENSE +1 -1
- data/README.md +17 -10
- data/lib/active_job/arguments.rb +54 -33
- data/lib/active_job/base.rb +3 -1
- data/lib/active_job/callbacks.rb +4 -1
- data/lib/active_job/core.rb +54 -25
- data/lib/active_job/enqueuing.rb +26 -5
- data/lib/active_job/exceptions.rb +44 -21
- data/lib/active_job/execution.rb +4 -4
- data/lib/active_job/gem_version.rb +2 -2
- data/lib/active_job/logging.rb +40 -9
- data/lib/active_job/queue_adapter.rb +2 -0
- data/lib/active_job/queue_adapters/async_adapter.rb +1 -1
- data/lib/active_job/queue_adapters/backburner_adapter.rb +2 -2
- data/lib/active_job/queue_adapters/inline_adapter.rb +1 -1
- data/lib/active_job/queue_adapters/test_adapter.rb +22 -8
- data/lib/active_job/queue_adapters.rb +8 -10
- data/lib/active_job/queue_name.rb +21 -1
- data/lib/active_job/railtie.rb +16 -1
- data/lib/active_job/serializers/date_serializer.rb +21 -0
- data/lib/active_job/serializers/date_time_serializer.rb +21 -0
- data/lib/active_job/serializers/duration_serializer.rb +24 -0
- data/lib/active_job/serializers/object_serializer.rb +54 -0
- data/lib/active_job/serializers/symbol_serializer.rb +21 -0
- data/lib/active_job/serializers/time_serializer.rb +21 -0
- data/lib/active_job/serializers/time_with_zone_serializer.rb +21 -0
- data/lib/active_job/serializers.rb +63 -0
- data/lib/active_job/test_helper.rb +290 -61
- data/lib/active_job/timezones.rb +13 -0
- data/lib/active_job/translation.rb +1 -1
- data/lib/active_job.rb +2 -1
- data/lib/rails/generators/job/job_generator.rb +4 -0
- metadata +19 -12
- data/lib/active_job/queue_adapters/qu_adapter.rb +0 -46
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
|
5
|
+
module ActiveJob
|
6
|
+
# The <tt>ActiveJob::Serializers</tt> module is used to store a list of known serializers
|
7
|
+
# and to add new ones. It also has helpers to serialize/deserialize objects.
|
8
|
+
module Serializers # :nodoc:
|
9
|
+
extend ActiveSupport::Autoload
|
10
|
+
|
11
|
+
autoload :ObjectSerializer
|
12
|
+
autoload :SymbolSerializer
|
13
|
+
autoload :DurationSerializer
|
14
|
+
autoload :DateTimeSerializer
|
15
|
+
autoload :DateSerializer
|
16
|
+
autoload :TimeWithZoneSerializer
|
17
|
+
autoload :TimeSerializer
|
18
|
+
|
19
|
+
mattr_accessor :_additional_serializers
|
20
|
+
self._additional_serializers = Set.new
|
21
|
+
|
22
|
+
class << self
|
23
|
+
# Returns serialized representative of the passed object.
|
24
|
+
# Will look up through all known serializers.
|
25
|
+
# Raises <tt>ActiveJob::SerializationError</tt> if it can't find a proper serializer.
|
26
|
+
def serialize(argument)
|
27
|
+
serializer = serializers.detect { |s| s.serialize?(argument) }
|
28
|
+
raise SerializationError.new("Unsupported argument type: #{argument.class.name}") unless serializer
|
29
|
+
serializer.serialize(argument)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns deserialized object.
|
33
|
+
# Will look up through all known serializers.
|
34
|
+
# If no serializer found will raise <tt>ArgumentError</tt>.
|
35
|
+
def deserialize(argument)
|
36
|
+
serializer_name = argument[Arguments::OBJECT_SERIALIZER_KEY]
|
37
|
+
raise ArgumentError, "Serializer name is not present in the argument: #{argument.inspect}" unless serializer_name
|
38
|
+
|
39
|
+
serializer = serializer_name.safe_constantize
|
40
|
+
raise ArgumentError, "Serializer #{serializer_name} is not known" unless serializer
|
41
|
+
|
42
|
+
serializer.deserialize(argument)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns list of known serializers.
|
46
|
+
def serializers
|
47
|
+
self._additional_serializers
|
48
|
+
end
|
49
|
+
|
50
|
+
# Adds new serializers to a list of known serializers.
|
51
|
+
def add_serializers(*new_serializers)
|
52
|
+
self._additional_serializers += new_serializers.flatten
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
add_serializers SymbolSerializer,
|
57
|
+
DurationSerializer,
|
58
|
+
DateTimeSerializer,
|
59
|
+
DateSerializer,
|
60
|
+
TimeWithZoneSerializer,
|
61
|
+
TimeSerializer
|
62
|
+
end
|
63
|
+
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/class/subclasses"
|
4
|
-
require "active_support/core_ext/hash/keys"
|
5
4
|
|
6
5
|
module ActiveJob
|
7
6
|
# Provides helper methods for testing Active Job
|
@@ -52,7 +51,7 @@ module ActiveJob
|
|
52
51
|
queue_adapter_changed_jobs.each { |klass| klass.disable_test_adapter }
|
53
52
|
end
|
54
53
|
|
55
|
-
# Specifies the queue adapter to use with all
|
54
|
+
# Specifies the queue adapter to use with all Active Job test helpers.
|
56
55
|
#
|
57
56
|
# Returns an instance of the queue adapter and defaults to
|
58
57
|
# <tt>ActiveJob::QueueAdapters::TestAdapter</tt>.
|
@@ -75,7 +74,7 @@ module ActiveJob
|
|
75
74
|
# assert_enqueued_jobs 2
|
76
75
|
# end
|
77
76
|
#
|
78
|
-
# If a block is passed, that block will cause the specified number of
|
77
|
+
# If a block is passed, asserts that the block will cause the specified number of
|
79
78
|
# jobs to be enqueued.
|
80
79
|
#
|
81
80
|
# def test_jobs_again
|
@@ -89,7 +88,7 @@ module ActiveJob
|
|
89
88
|
# end
|
90
89
|
# end
|
91
90
|
#
|
92
|
-
#
|
91
|
+
# Asserts the number of times a specific job was enqueued by passing +:only+ option.
|
93
92
|
#
|
94
93
|
# def test_logging_job
|
95
94
|
# assert_enqueued_jobs 1, only: LoggingJob do
|
@@ -98,7 +97,7 @@ module ActiveJob
|
|
98
97
|
# end
|
99
98
|
# end
|
100
99
|
#
|
101
|
-
#
|
100
|
+
# Asserts the number of times a job except specific class was enqueued by passing +:except+ option.
|
102
101
|
#
|
103
102
|
# def test_logging_job
|
104
103
|
# assert_enqueued_jobs 1, except: HelloJob do
|
@@ -107,7 +106,10 @@ module ActiveJob
|
|
107
106
|
# end
|
108
107
|
# end
|
109
108
|
#
|
110
|
-
#
|
109
|
+
# +:only+ and +:except+ options accepts Class, Array of Class or Proc. When passed a Proc,
|
110
|
+
# a hash containing the job's class and it's argument are passed as argument.
|
111
|
+
#
|
112
|
+
# Asserts the number of times a job is enqueued to a specific queue by passing +:queue+ option.
|
111
113
|
#
|
112
114
|
# def test_logging_job
|
113
115
|
# assert_enqueued_jobs 2, queue: 'default' do
|
@@ -117,14 +119,18 @@ module ActiveJob
|
|
117
119
|
# end
|
118
120
|
def assert_enqueued_jobs(number, only: nil, except: nil, queue: nil)
|
119
121
|
if block_given?
|
120
|
-
original_count =
|
122
|
+
original_count = enqueued_jobs_with(only: only, except: except, queue: queue)
|
123
|
+
|
121
124
|
yield
|
122
|
-
|
123
|
-
|
125
|
+
|
126
|
+
new_count = enqueued_jobs_with(only: only, except: except, queue: queue)
|
127
|
+
|
128
|
+
actual_count = new_count - original_count
|
124
129
|
else
|
125
|
-
actual_count =
|
126
|
-
assert_equal number, actual_count, "#{number} jobs expected, but #{actual_count} were enqueued"
|
130
|
+
actual_count = enqueued_jobs_with(only: only, except: except, queue: queue)
|
127
131
|
end
|
132
|
+
|
133
|
+
assert_equal number, actual_count, "#{number} jobs expected, but #{actual_count} were enqueued"
|
128
134
|
end
|
129
135
|
|
130
136
|
# Asserts that no jobs have been enqueued.
|
@@ -135,7 +141,7 @@ module ActiveJob
|
|
135
141
|
# assert_enqueued_jobs 1
|
136
142
|
# end
|
137
143
|
#
|
138
|
-
# If a block is passed, that block
|
144
|
+
# If a block is passed, asserts that the block will not cause any job to be enqueued.
|
139
145
|
#
|
140
146
|
# def test_jobs_again
|
141
147
|
# assert_no_enqueued_jobs do
|
@@ -143,7 +149,7 @@ module ActiveJob
|
|
143
149
|
# end
|
144
150
|
# end
|
145
151
|
#
|
146
|
-
#
|
152
|
+
# Asserts that no jobs of a specific kind are enqueued by passing +:only+ option.
|
147
153
|
#
|
148
154
|
# def test_no_logging
|
149
155
|
# assert_no_enqueued_jobs only: LoggingJob do
|
@@ -151,7 +157,7 @@ module ActiveJob
|
|
151
157
|
# end
|
152
158
|
# end
|
153
159
|
#
|
154
|
-
#
|
160
|
+
# Asserts that no jobs except specific class are enqueued by passing +:except+ option.
|
155
161
|
#
|
156
162
|
# def test_no_logging
|
157
163
|
# assert_no_enqueued_jobs except: HelloJob do
|
@@ -159,16 +165,27 @@ module ActiveJob
|
|
159
165
|
# end
|
160
166
|
# end
|
161
167
|
#
|
168
|
+
# +:only+ and +:except+ options accepts Class, Array of Class or Proc. When passed a Proc,
|
169
|
+
# a hash containing the job's class and it's argument are passed as argument.
|
170
|
+
#
|
171
|
+
# Asserts that no jobs are enqueued to a specific queue by passing +:queue+ option
|
172
|
+
#
|
173
|
+
# def test_no_logging
|
174
|
+
# assert_no_enqueued_jobs queue: 'default' do
|
175
|
+
# LoggingJob.set(queue: :some_queue).perform_later
|
176
|
+
# end
|
177
|
+
# end
|
178
|
+
#
|
162
179
|
# Note: This assertion is simply a shortcut for:
|
163
180
|
#
|
164
181
|
# assert_enqueued_jobs 0, &block
|
165
|
-
def assert_no_enqueued_jobs(only: nil, except: nil, &block)
|
166
|
-
assert_enqueued_jobs 0, only: only, except: except, &block
|
182
|
+
def assert_no_enqueued_jobs(only: nil, except: nil, queue: nil, &block)
|
183
|
+
assert_enqueued_jobs 0, only: only, except: except, queue: queue, &block
|
167
184
|
end
|
168
185
|
|
169
186
|
# Asserts that the number of performed jobs matches the given number.
|
170
187
|
# If no block is passed, <tt>perform_enqueued_jobs</tt>
|
171
|
-
# must be called around the job call.
|
188
|
+
# must be called around or after the job call.
|
172
189
|
#
|
173
190
|
# def test_jobs
|
174
191
|
# assert_performed_jobs 0
|
@@ -178,13 +195,14 @@ module ActiveJob
|
|
178
195
|
# end
|
179
196
|
# assert_performed_jobs 1
|
180
197
|
#
|
181
|
-
#
|
182
|
-
#
|
183
|
-
#
|
184
|
-
#
|
198
|
+
# HelloJob.perform_later('yves')
|
199
|
+
#
|
200
|
+
# perform_enqueued_jobs
|
201
|
+
#
|
202
|
+
# assert_performed_jobs 2
|
185
203
|
# end
|
186
204
|
#
|
187
|
-
# If a block is passed, that block
|
205
|
+
# If a block is passed, asserts that the block will cause the specified number of
|
188
206
|
# jobs to be performed.
|
189
207
|
#
|
190
208
|
# def test_jobs_again
|
@@ -198,7 +216,7 @@ module ActiveJob
|
|
198
216
|
# end
|
199
217
|
# end
|
200
218
|
#
|
201
|
-
#
|
219
|
+
# This method also supports filtering. If the +:only+ option is specified,
|
202
220
|
# then only the listed job(s) will be performed.
|
203
221
|
#
|
204
222
|
# def test_hello_job
|
@@ -208,7 +226,7 @@ module ActiveJob
|
|
208
226
|
# end
|
209
227
|
# end
|
210
228
|
#
|
211
|
-
# Also if the
|
229
|
+
# Also if the +:except+ option is specified,
|
212
230
|
# then the job(s) except specific class will be performed.
|
213
231
|
#
|
214
232
|
# def test_hello_job
|
@@ -229,17 +247,42 @@ module ActiveJob
|
|
229
247
|
# end
|
230
248
|
# end
|
231
249
|
# end
|
232
|
-
|
250
|
+
#
|
251
|
+
# A proc may also be specified. When passed a Proc, the job's instance will be passed as argument.
|
252
|
+
#
|
253
|
+
# def test_hello_and_logging_jobs
|
254
|
+
# assert_nothing_raised do
|
255
|
+
# assert_performed_jobs(1, only: ->(job) { job.is_a?(HelloJob) }) do
|
256
|
+
# HelloJob.perform_later('jeremy')
|
257
|
+
# LoggingJob.perform_later('stewie')
|
258
|
+
# RescueJob.perform_later('david')
|
259
|
+
# end
|
260
|
+
# end
|
261
|
+
# end
|
262
|
+
#
|
263
|
+
# If the +:queue+ option is specified,
|
264
|
+
# then only the job(s) enqueued to a specific queue will be performed.
|
265
|
+
#
|
266
|
+
# def test_assert_performed_jobs_with_queue_option
|
267
|
+
# assert_performed_jobs 1, queue: :some_queue do
|
268
|
+
# HelloJob.set(queue: :some_queue).perform_later("jeremy")
|
269
|
+
# HelloJob.set(queue: :other_queue).perform_later("bogdan")
|
270
|
+
# end
|
271
|
+
# end
|
272
|
+
def assert_performed_jobs(number, only: nil, except: nil, queue: nil, &block)
|
233
273
|
if block_given?
|
234
274
|
original_count = performed_jobs.size
|
235
|
-
|
275
|
+
|
276
|
+
perform_enqueued_jobs(only: only, except: except, queue: queue, &block)
|
277
|
+
|
236
278
|
new_count = performed_jobs.size
|
237
|
-
|
238
|
-
|
279
|
+
|
280
|
+
performed_jobs_size = new_count - original_count
|
239
281
|
else
|
240
|
-
performed_jobs_size =
|
241
|
-
assert_equal number, performed_jobs_size, "#{number} jobs expected, but #{performed_jobs_size} were performed"
|
282
|
+
performed_jobs_size = performed_jobs_with(only: only, except: except, queue: queue)
|
242
283
|
end
|
284
|
+
|
285
|
+
assert_equal number, performed_jobs_size, "#{number} jobs expected, but #{performed_jobs_size} were performed"
|
243
286
|
end
|
244
287
|
|
245
288
|
# Asserts that no jobs have been performed.
|
@@ -253,7 +296,7 @@ module ActiveJob
|
|
253
296
|
# end
|
254
297
|
# end
|
255
298
|
#
|
256
|
-
# If a block is passed, that block
|
299
|
+
# If a block is passed, asserts that the block will not cause any job to be performed.
|
257
300
|
#
|
258
301
|
# def test_jobs_again
|
259
302
|
# assert_no_performed_jobs do
|
@@ -261,7 +304,7 @@ module ActiveJob
|
|
261
304
|
# end
|
262
305
|
# end
|
263
306
|
#
|
264
|
-
# The block form supports filtering. If the
|
307
|
+
# The block form supports filtering. If the +:only+ option is specified,
|
265
308
|
# then only the listed job(s) will not be performed.
|
266
309
|
#
|
267
310
|
# def test_no_logging
|
@@ -270,7 +313,7 @@ module ActiveJob
|
|
270
313
|
# end
|
271
314
|
# end
|
272
315
|
#
|
273
|
-
# Also if the
|
316
|
+
# Also if the +:except+ option is specified,
|
274
317
|
# then the job(s) except specific class will not be performed.
|
275
318
|
#
|
276
319
|
# def test_no_logging
|
@@ -279,14 +322,53 @@ module ActiveJob
|
|
279
322
|
# end
|
280
323
|
# end
|
281
324
|
#
|
325
|
+
# +:only+ and +:except+ options accepts Class, Array of Class or Proc. When passed a Proc,
|
326
|
+
# an instance of the job will be passed as argument.
|
327
|
+
#
|
328
|
+
# If the +:queue+ option is specified,
|
329
|
+
# then only the job(s) enqueued to a specific queue will not be performed.
|
330
|
+
#
|
331
|
+
# def test_assert_no_performed_jobs_with_queue_option
|
332
|
+
# assert_no_performed_jobs queue: :some_queue do
|
333
|
+
# HelloJob.set(queue: :other_queue).perform_later("jeremy")
|
334
|
+
# end
|
335
|
+
# end
|
336
|
+
#
|
282
337
|
# Note: This assertion is simply a shortcut for:
|
283
338
|
#
|
284
339
|
# assert_performed_jobs 0, &block
|
285
|
-
def assert_no_performed_jobs(only: nil, except: nil, &block)
|
286
|
-
assert_performed_jobs 0, only: only, except: except, &block
|
340
|
+
def assert_no_performed_jobs(only: nil, except: nil, queue: nil, &block)
|
341
|
+
assert_performed_jobs 0, only: only, except: except, queue: queue, &block
|
287
342
|
end
|
288
343
|
|
289
|
-
# Asserts that the job
|
344
|
+
# Asserts that the job has been enqueued with the given arguments.
|
345
|
+
#
|
346
|
+
# def test_assert_enqueued_with
|
347
|
+
# MyJob.perform_later(1,2,3)
|
348
|
+
# assert_enqueued_with(job: MyJob, args: [1,2,3], queue: 'low')
|
349
|
+
#
|
350
|
+
# MyJob.set(wait_until: Date.tomorrow.noon).perform_later
|
351
|
+
# assert_enqueued_with(job: MyJob, at: Date.tomorrow.noon)
|
352
|
+
# end
|
353
|
+
#
|
354
|
+
#
|
355
|
+
# The +args+ argument also accepts a proc which will get passed the actual
|
356
|
+
# job's arguments. Your proc needs to return a boolean value determining if
|
357
|
+
# the job's arguments matches your expectation. This is useful to check only
|
358
|
+
# for a subset of arguments.
|
359
|
+
#
|
360
|
+
# def test_assert_enqueued_with
|
361
|
+
# expected_args = ->(job_args) do
|
362
|
+
# assert job_args.first.key?(:foo)
|
363
|
+
# end
|
364
|
+
#
|
365
|
+
# MyJob.perform_later(foo: 'bar', other_arg: 'No need to check in the test')
|
366
|
+
# assert_enqueued_with(job: MyJob, args: expected_args, queue: 'low')
|
367
|
+
# end
|
368
|
+
#
|
369
|
+
#
|
370
|
+
# If a block is passed, asserts that the block will cause the job to be
|
371
|
+
# enqueued with the given arguments.
|
290
372
|
#
|
291
373
|
# def test_assert_enqueued_with
|
292
374
|
# assert_enqueued_with(job: MyJob, args: [1,2,3], queue: 'low') do
|
@@ -298,19 +380,70 @@ module ActiveJob
|
|
298
380
|
# end
|
299
381
|
# end
|
300
382
|
def assert_enqueued_with(job: nil, args: nil, at: nil, queue: nil)
|
301
|
-
original_enqueued_jobs_count = enqueued_jobs.count
|
302
383
|
expected = { job: job, args: args, at: at, queue: queue }.compact
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
384
|
+
expected_args = prepare_args_for_assertion(expected)
|
385
|
+
|
386
|
+
if block_given?
|
387
|
+
original_enqueued_jobs_count = enqueued_jobs.count
|
388
|
+
|
389
|
+
yield
|
390
|
+
|
391
|
+
jobs = enqueued_jobs.drop(original_enqueued_jobs_count)
|
392
|
+
else
|
393
|
+
jobs = enqueued_jobs
|
394
|
+
end
|
395
|
+
|
396
|
+
matching_job = jobs.find do |enqueued_job|
|
397
|
+
deserialized_job = deserialize_args_for_assertion(enqueued_job)
|
398
|
+
|
399
|
+
expected_args.all? do |key, value|
|
400
|
+
if value.respond_to?(:call)
|
401
|
+
value.call(deserialized_job[key])
|
402
|
+
else
|
403
|
+
value == deserialized_job[key]
|
404
|
+
end
|
405
|
+
end
|
308
406
|
end
|
407
|
+
|
309
408
|
assert matching_job, "No enqueued job found with #{expected}"
|
310
409
|
instantiate_job(matching_job)
|
311
410
|
end
|
312
411
|
|
313
|
-
# Asserts that the job
|
412
|
+
# Asserts that the job has been performed with the given arguments.
|
413
|
+
#
|
414
|
+
# def test_assert_performed_with
|
415
|
+
# MyJob.perform_later(1,2,3)
|
416
|
+
#
|
417
|
+
# perform_enqueued_jobs
|
418
|
+
#
|
419
|
+
# assert_performed_with(job: MyJob, args: [1,2,3], queue: 'high')
|
420
|
+
#
|
421
|
+
# MyJob.set(wait_until: Date.tomorrow.noon).perform_later
|
422
|
+
#
|
423
|
+
# perform_enqueued_jobs
|
424
|
+
#
|
425
|
+
# assert_performed_with(job: MyJob, at: Date.tomorrow.noon)
|
426
|
+
# end
|
427
|
+
#
|
428
|
+
# The +args+ argument also accepts a proc which will get passed the actual
|
429
|
+
# job's arguments. Your proc needs to return a boolean value determining if
|
430
|
+
# the job's arguments matches your expectation. This is useful to check only
|
431
|
+
# for a subset of arguments.
|
432
|
+
#
|
433
|
+
# def test_assert_performed_with
|
434
|
+
# expected_args = ->(job_args) do
|
435
|
+
# assert job_args.first.key?(:foo)
|
436
|
+
# end
|
437
|
+
# MyJob.perform_later(foo: 'bar', other_arg: 'No need to check in the test')
|
438
|
+
#
|
439
|
+
# perform_enqueued_jobs
|
440
|
+
#
|
441
|
+
# assert_performed_with(job: MyJob, args: expected_args, queue: 'high')
|
442
|
+
# end
|
443
|
+
#
|
444
|
+
# If a block is passed, that block performs all of the jobs that were
|
445
|
+
# enqueued throughout the duration of the block and asserts that
|
446
|
+
# the job has been performed with the given arguments in the block.
|
314
447
|
#
|
315
448
|
# def test_assert_performed_with
|
316
449
|
# assert_performed_with(job: MyJob, args: [1,2,3], queue: 'high') do
|
@@ -321,20 +454,39 @@ module ActiveJob
|
|
321
454
|
# MyJob.set(wait_until: Date.tomorrow.noon).perform_later
|
322
455
|
# end
|
323
456
|
# end
|
324
|
-
def assert_performed_with(job: nil, args: nil, at: nil, queue: nil)
|
325
|
-
original_performed_jobs_count = performed_jobs.count
|
457
|
+
def assert_performed_with(job: nil, args: nil, at: nil, queue: nil, &block)
|
326
458
|
expected = { job: job, args: args, at: at, queue: queue }.compact
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
459
|
+
expected_args = prepare_args_for_assertion(expected)
|
460
|
+
|
461
|
+
if block_given?
|
462
|
+
original_performed_jobs_count = performed_jobs.count
|
463
|
+
|
464
|
+
perform_enqueued_jobs(&block)
|
465
|
+
|
466
|
+
jobs = performed_jobs.drop(original_performed_jobs_count)
|
467
|
+
else
|
468
|
+
jobs = performed_jobs
|
469
|
+
end
|
470
|
+
|
471
|
+
matching_job = jobs.find do |enqueued_job|
|
472
|
+
deserialized_job = deserialize_args_for_assertion(enqueued_job)
|
473
|
+
|
474
|
+
expected_args.all? do |key, value|
|
475
|
+
if value.respond_to?(:call)
|
476
|
+
value.call(deserialized_job[key])
|
477
|
+
else
|
478
|
+
value == deserialized_job[key]
|
479
|
+
end
|
480
|
+
end
|
332
481
|
end
|
482
|
+
|
333
483
|
assert matching_job, "No performed job found with #{expected}"
|
334
484
|
instantiate_job(matching_job)
|
335
485
|
end
|
336
486
|
|
337
|
-
# Performs all enqueued jobs
|
487
|
+
# Performs all enqueued jobs. If a block is given, performs all of the jobs
|
488
|
+
# that were enqueued throughout the duration of the block. If a block is
|
489
|
+
# not given, performs all of the enqueued jobs up to this point in the test.
|
338
490
|
#
|
339
491
|
# def test_perform_enqueued_jobs
|
340
492
|
# perform_enqueued_jobs do
|
@@ -343,6 +495,14 @@ module ActiveJob
|
|
343
495
|
# assert_performed_jobs 1
|
344
496
|
# end
|
345
497
|
#
|
498
|
+
# def test_perform_enqueued_jobs_without_block
|
499
|
+
# MyJob.perform_later(1, 2, 3)
|
500
|
+
#
|
501
|
+
# perform_enqueued_jobs
|
502
|
+
#
|
503
|
+
# assert_performed_jobs 1
|
504
|
+
# end
|
505
|
+
#
|
346
506
|
# This method also supports filtering. If the +:only+ option is specified,
|
347
507
|
# then only the listed job(s) will be performed.
|
348
508
|
#
|
@@ -365,24 +525,45 @@ module ActiveJob
|
|
365
525
|
# assert_performed_jobs 1
|
366
526
|
# end
|
367
527
|
#
|
368
|
-
|
528
|
+
# +:only+ and +:except+ options accepts Class, Array of Class or Proc. When passed a Proc,
|
529
|
+
# an instance of the job will be passed as argument.
|
530
|
+
#
|
531
|
+
# If the +:queue+ option is specified,
|
532
|
+
# then only the job(s) enqueued to a specific queue will be performed.
|
533
|
+
#
|
534
|
+
# def test_perform_enqueued_jobs_with_queue
|
535
|
+
# perform_enqueued_jobs queue: :some_queue do
|
536
|
+
# MyJob.set(queue: :some_queue).perform_later(1, 2, 3) # will be performed
|
537
|
+
# HelloJob.set(queue: :other_queue).perform_later(1, 2, 3) # will not be performed
|
538
|
+
# end
|
539
|
+
# assert_performed_jobs 1
|
540
|
+
# end
|
541
|
+
#
|
542
|
+
def perform_enqueued_jobs(only: nil, except: nil, queue: nil)
|
543
|
+
return flush_enqueued_jobs(only: only, except: except, queue: queue) unless block_given?
|
544
|
+
|
369
545
|
validate_option(only: only, except: except)
|
546
|
+
|
370
547
|
old_perform_enqueued_jobs = queue_adapter.perform_enqueued_jobs
|
371
548
|
old_perform_enqueued_at_jobs = queue_adapter.perform_enqueued_at_jobs
|
372
549
|
old_filter = queue_adapter.filter
|
373
550
|
old_reject = queue_adapter.reject
|
551
|
+
old_queue = queue_adapter.queue
|
374
552
|
|
375
553
|
begin
|
376
554
|
queue_adapter.perform_enqueued_jobs = true
|
377
555
|
queue_adapter.perform_enqueued_at_jobs = true
|
378
556
|
queue_adapter.filter = only
|
379
557
|
queue_adapter.reject = except
|
558
|
+
queue_adapter.queue = queue
|
559
|
+
|
380
560
|
yield
|
381
561
|
ensure
|
382
562
|
queue_adapter.perform_enqueued_jobs = old_perform_enqueued_jobs
|
383
563
|
queue_adapter.perform_enqueued_at_jobs = old_perform_enqueued_at_jobs
|
384
564
|
queue_adapter.filter = old_filter
|
385
565
|
queue_adapter.reject = old_reject
|
566
|
+
queue_adapter.queue = old_queue
|
386
567
|
end
|
387
568
|
end
|
388
569
|
|
@@ -404,31 +585,79 @@ module ActiveJob
|
|
404
585
|
performed_jobs.clear
|
405
586
|
end
|
406
587
|
|
407
|
-
def
|
588
|
+
def jobs_with(jobs, only: nil, except: nil, queue: nil)
|
408
589
|
validate_option(only: only, except: except)
|
409
|
-
|
590
|
+
|
591
|
+
jobs.count do |job|
|
410
592
|
job_class = job.fetch(:job)
|
593
|
+
|
411
594
|
if only
|
412
|
-
next false unless
|
595
|
+
next false unless filter_as_proc(only).call(job)
|
413
596
|
elsif except
|
414
|
-
next false if
|
597
|
+
next false if filter_as_proc(except).call(job)
|
415
598
|
end
|
599
|
+
|
416
600
|
if queue
|
417
601
|
next false unless queue.to_s == job.fetch(:queue, job_class.queue_name)
|
418
602
|
end
|
603
|
+
|
604
|
+
yield job if block_given?
|
605
|
+
|
419
606
|
true
|
420
607
|
end
|
421
608
|
end
|
422
609
|
|
423
|
-
def
|
424
|
-
|
425
|
-
|
426
|
-
|
610
|
+
def filter_as_proc(filter)
|
611
|
+
return filter if filter.is_a?(Proc)
|
612
|
+
|
613
|
+
->(job) { Array(filter).include?(job.fetch(:job)) }
|
614
|
+
end
|
615
|
+
|
616
|
+
def enqueued_jobs_with(only: nil, except: nil, queue: nil, &block)
|
617
|
+
jobs_with(enqueued_jobs, only: only, except: except, queue: queue, &block)
|
618
|
+
end
|
619
|
+
|
620
|
+
def performed_jobs_with(only: nil, except: nil, queue: nil, &block)
|
621
|
+
jobs_with(performed_jobs, only: only, except: except, queue: queue, &block)
|
622
|
+
end
|
623
|
+
|
624
|
+
def flush_enqueued_jobs(only: nil, except: nil, queue: nil)
|
625
|
+
enqueued_jobs_with(only: only, except: except, queue: queue) do |payload|
|
626
|
+
instantiate_job(payload).perform_now
|
627
|
+
queue_adapter.performed_jobs << payload
|
628
|
+
end
|
629
|
+
end
|
630
|
+
|
631
|
+
def prepare_args_for_assertion(args)
|
632
|
+
args.dup.tap do |arguments|
|
633
|
+
arguments[:at] = round_time_arguments(arguments[:at]) if arguments[:at]
|
634
|
+
arguments[:args] = round_time_arguments(arguments[:args]) if arguments[:args]
|
635
|
+
end
|
636
|
+
end
|
637
|
+
|
638
|
+
def round_time_arguments(argument)
|
639
|
+
case argument
|
640
|
+
when Time, ActiveSupport::TimeWithZone, DateTime
|
641
|
+
argument.change(usec: 0)
|
642
|
+
when Hash
|
643
|
+
argument.transform_values { |value| round_time_arguments(value) }
|
644
|
+
when Array
|
645
|
+
argument.map { |element| round_time_arguments(element) }
|
646
|
+
else
|
647
|
+
argument
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
def deserialize_args_for_assertion(job)
|
652
|
+
job.dup.tap do |new_job|
|
653
|
+
new_job[:at] = round_time_arguments(Time.at(new_job[:at])) if new_job[:at]
|
654
|
+
new_job[:args] = ActiveJob::Arguments.deserialize(new_job[:args]) if new_job[:args]
|
427
655
|
end
|
428
656
|
end
|
429
657
|
|
430
658
|
def instantiate_job(payload)
|
431
|
-
|
659
|
+
args = ActiveJob::Arguments.deserialize(payload[:args])
|
660
|
+
job = payload[:job].new(*args)
|
432
661
|
job.scheduled_at = Time.at(payload[:at]) if payload.key?(:at)
|
433
662
|
job.queue_name = payload[:queue]
|
434
663
|
job
|
data/lib/active_job.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright (c) 2014-
|
4
|
+
# Copyright (c) 2014-2019 David Heinemeier Hansson
|
5
5
|
#
|
6
6
|
# Permission is hereby granted, free of charge, to any person obtaining
|
7
7
|
# a copy of this software and associated documentation files (the
|
@@ -33,6 +33,7 @@ module ActiveJob
|
|
33
33
|
|
34
34
|
autoload :Base
|
35
35
|
autoload :QueueAdapters
|
36
|
+
autoload :Serializers
|
36
37
|
autoload :ConfiguredJob
|
37
38
|
autoload :TestCase
|
38
39
|
autoload :TestHelper
|