activejob 5.2.7.1 → 6.1.4.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +109 -58
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +18 -13
  5. data/lib/active_job/arguments.rb +80 -30
  6. data/lib/active_job/base.rb +6 -1
  7. data/lib/active_job/callbacks.rb +46 -3
  8. data/lib/active_job/configured_job.rb +2 -0
  9. data/lib/active_job/core.rb +40 -21
  10. data/lib/active_job/enqueuing.rb +20 -7
  11. data/lib/active_job/exceptions.rb +60 -28
  12. data/lib/active_job/execution.rb +11 -2
  13. data/lib/active_job/gem_version.rb +4 -4
  14. data/lib/active_job/instrumentation.rb +40 -0
  15. data/lib/active_job/log_subscriber.rb +140 -0
  16. data/lib/active_job/logging.rb +3 -101
  17. data/lib/active_job/queue_adapter.rb +5 -0
  18. data/lib/active_job/queue_adapters/async_adapter.rb +1 -1
  19. data/lib/active_job/queue_adapters/backburner_adapter.rb +2 -2
  20. data/lib/active_job/queue_adapters/inline_adapter.rb +1 -1
  21. data/lib/active_job/queue_adapters/que_adapter.rb +2 -2
  22. data/lib/active_job/queue_adapters/sidekiq_adapter.rb +2 -2
  23. data/lib/active_job/queue_adapters/sucker_punch_adapter.rb +1 -1
  24. data/lib/active_job/queue_adapters/test_adapter.rb +32 -14
  25. data/lib/active_job/queue_adapters.rb +13 -11
  26. data/lib/active_job/queue_name.rb +23 -3
  27. data/lib/active_job/railtie.rb +20 -1
  28. data/lib/active_job/serializers/date_serializer.rb +20 -0
  29. data/lib/active_job/serializers/date_time_serializer.rb +16 -0
  30. data/lib/active_job/serializers/duration_serializer.rb +23 -0
  31. data/lib/active_job/serializers/module_serializer.rb +20 -0
  32. data/lib/active_job/serializers/object_serializer.rb +53 -0
  33. data/lib/active_job/serializers/symbol_serializer.rb +20 -0
  34. data/lib/active_job/serializers/time_object_serializer.rb +13 -0
  35. data/lib/active_job/serializers/time_serializer.rb +16 -0
  36. data/lib/active_job/serializers/time_with_zone_serializer.rb +16 -0
  37. data/lib/active_job/serializers.rb +66 -0
  38. data/lib/active_job/test_helper.rb +317 -68
  39. data/lib/active_job/timezones.rb +13 -0
  40. data/lib/active_job/translation.rb +1 -1
  41. data/lib/active_job.rb +2 -1
  42. data/lib/rails/generators/job/job_generator.rb +4 -0
  43. metadata +26 -11
  44. data/lib/active_job/queue_adapters/qu_adapter.rb +0 -46
@@ -1,7 +1,7 @@
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"
4
+ require "active_support/testing/assertions"
5
5
 
6
6
  module ActiveJob
7
7
  # Provides helper methods for testing Active Job
@@ -10,6 +10,8 @@ module ActiveJob
10
10
  :performed_jobs, :performed_jobs=,
11
11
  to: :queue_adapter
12
12
 
13
+ include ActiveSupport::Testing::Assertions
14
+
13
15
  module TestQueueAdapter
14
16
  extend ActiveSupport::Concern
15
17
 
@@ -52,7 +54,7 @@ module ActiveJob
52
54
  queue_adapter_changed_jobs.each { |klass| klass.disable_test_adapter }
53
55
  end
54
56
 
55
- # Specifies the queue adapter to use with all active job test helpers.
57
+ # Specifies the queue adapter to use with all Active Job test helpers.
56
58
  #
57
59
  # Returns an instance of the queue adapter and defaults to
58
60
  # <tt>ActiveJob::QueueAdapters::TestAdapter</tt>.
@@ -75,7 +77,7 @@ module ActiveJob
75
77
  # assert_enqueued_jobs 2
76
78
  # end
77
79
  #
78
- # If a block is passed, that block will cause the specified number of
80
+ # If a block is passed, asserts that the block will cause the specified number of
79
81
  # jobs to be enqueued.
80
82
  #
81
83
  # def test_jobs_again
@@ -89,7 +91,7 @@ module ActiveJob
89
91
  # end
90
92
  # end
91
93
  #
92
- # The number of times a specific job was enqueued can be asserted.
94
+ # Asserts the number of times a specific job was enqueued by passing +:only+ option.
93
95
  #
94
96
  # def test_logging_job
95
97
  # assert_enqueued_jobs 1, only: LoggingJob do
@@ -98,7 +100,7 @@ module ActiveJob
98
100
  # end
99
101
  # end
100
102
  #
101
- # The number of times a job except specific class was enqueued can be asserted.
103
+ # Asserts the number of times a job except specific class was enqueued by passing +:except+ option.
102
104
  #
103
105
  # def test_logging_job
104
106
  # assert_enqueued_jobs 1, except: HelloJob do
@@ -107,7 +109,10 @@ module ActiveJob
107
109
  # end
108
110
  # end
109
111
  #
110
- # The number of times a job is enqueued to a specific queue can also be asserted.
112
+ # +:only+ and +:except+ options accepts Class, Array of Class or Proc. When passed a Proc,
113
+ # a hash containing the job's class and it's argument are passed as argument.
114
+ #
115
+ # Asserts the number of times a job is enqueued to a specific queue by passing +:queue+ option.
111
116
  #
112
117
  # def test_logging_job
113
118
  # assert_enqueued_jobs 2, queue: 'default' do
@@ -115,16 +120,20 @@ module ActiveJob
115
120
  # HelloJob.perform_later('elfassy')
116
121
  # end
117
122
  # end
118
- def assert_enqueued_jobs(number, only: nil, except: nil, queue: nil)
123
+ def assert_enqueued_jobs(number, only: nil, except: nil, queue: nil, &block)
119
124
  if block_given?
120
- original_count = enqueued_jobs_size(only: only, except: except, queue: queue)
121
- yield
122
- new_count = enqueued_jobs_size(only: only, except: except, queue: queue)
123
- assert_equal number, new_count - original_count, "#{number} jobs expected, but #{new_count - original_count} were enqueued"
125
+ original_jobs = enqueued_jobs_with(only: only, except: except, queue: queue)
126
+
127
+ assert_nothing_raised(&block)
128
+
129
+ new_jobs = enqueued_jobs_with(only: only, except: except, queue: queue)
130
+
131
+ actual_count = (new_jobs - original_jobs).count
124
132
  else
125
- actual_count = enqueued_jobs_size(only: only, except: except, queue: queue)
126
- assert_equal number, actual_count, "#{number} jobs expected, but #{actual_count} were enqueued"
133
+ actual_count = enqueued_jobs_with(only: only, except: except, queue: queue).count
127
134
  end
135
+
136
+ assert_equal number, actual_count, "#{number} jobs expected, but #{actual_count} were enqueued"
128
137
  end
129
138
 
130
139
  # Asserts that no jobs have been enqueued.
@@ -135,7 +144,7 @@ module ActiveJob
135
144
  # assert_enqueued_jobs 1
136
145
  # end
137
146
  #
138
- # If a block is passed, that block should not cause any job to be enqueued.
147
+ # If a block is passed, asserts that the block will not cause any job to be enqueued.
139
148
  #
140
149
  # def test_jobs_again
141
150
  # assert_no_enqueued_jobs do
@@ -143,7 +152,7 @@ module ActiveJob
143
152
  # end
144
153
  # end
145
154
  #
146
- # It can be asserted that no jobs of a specific kind are enqueued:
155
+ # Asserts that no jobs of a specific kind are enqueued by passing +:only+ option.
147
156
  #
148
157
  # def test_no_logging
149
158
  # assert_no_enqueued_jobs only: LoggingJob do
@@ -151,7 +160,7 @@ module ActiveJob
151
160
  # end
152
161
  # end
153
162
  #
154
- # It can be asserted that no jobs except specific class are enqueued:
163
+ # Asserts that no jobs except specific class are enqueued by passing +:except+ option.
155
164
  #
156
165
  # def test_no_logging
157
166
  # assert_no_enqueued_jobs except: HelloJob do
@@ -159,16 +168,27 @@ module ActiveJob
159
168
  # end
160
169
  # end
161
170
  #
171
+ # +:only+ and +:except+ options accepts Class, Array of Class or Proc. When passed a Proc,
172
+ # a hash containing the job's class and it's argument are passed as argument.
173
+ #
174
+ # Asserts that no jobs are enqueued to a specific queue by passing +:queue+ option
175
+ #
176
+ # def test_no_logging
177
+ # assert_no_enqueued_jobs queue: 'default' do
178
+ # LoggingJob.set(queue: :some_queue).perform_later
179
+ # end
180
+ # end
181
+ #
162
182
  # Note: This assertion is simply a shortcut for:
163
183
  #
164
184
  # 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
185
+ def assert_no_enqueued_jobs(only: nil, except: nil, queue: nil, &block)
186
+ assert_enqueued_jobs 0, only: only, except: except, queue: queue, &block
167
187
  end
168
188
 
169
189
  # Asserts that the number of performed jobs matches the given number.
170
190
  # If no block is passed, <tt>perform_enqueued_jobs</tt>
171
- # must be called around the job call.
191
+ # must be called around or after the job call.
172
192
  #
173
193
  # def test_jobs
174
194
  # assert_performed_jobs 0
@@ -178,13 +198,14 @@ module ActiveJob
178
198
  # end
179
199
  # assert_performed_jobs 1
180
200
  #
181
- # perform_enqueued_jobs do
182
- # HelloJob.perform_later('yves')
183
- # assert_performed_jobs 2
184
- # end
201
+ # HelloJob.perform_later('yves')
202
+ #
203
+ # perform_enqueued_jobs
204
+ #
205
+ # assert_performed_jobs 2
185
206
  # end
186
207
  #
187
- # If a block is passed, that block should cause the specified number of
208
+ # If a block is passed, asserts that the block will cause the specified number of
188
209
  # jobs to be performed.
189
210
  #
190
211
  # def test_jobs_again
@@ -198,7 +219,7 @@ module ActiveJob
198
219
  # end
199
220
  # end
200
221
  #
201
- # The block form supports filtering. If the :only option is specified,
222
+ # This method also supports filtering. If the +:only+ option is specified,
202
223
  # then only the listed job(s) will be performed.
203
224
  #
204
225
  # def test_hello_job
@@ -208,7 +229,7 @@ module ActiveJob
208
229
  # end
209
230
  # end
210
231
  #
211
- # Also if the :except option is specified,
232
+ # Also if the +:except+ option is specified,
212
233
  # then the job(s) except specific class will be performed.
213
234
  #
214
235
  # def test_hello_job
@@ -229,17 +250,42 @@ module ActiveJob
229
250
  # end
230
251
  # end
231
252
  # end
232
- def assert_performed_jobs(number, only: nil, except: nil)
253
+ #
254
+ # A proc may also be specified. When passed a Proc, the job's instance will be passed as argument.
255
+ #
256
+ # def test_hello_and_logging_jobs
257
+ # assert_nothing_raised do
258
+ # assert_performed_jobs(1, only: ->(job) { job.is_a?(HelloJob) }) do
259
+ # HelloJob.perform_later('jeremy')
260
+ # LoggingJob.perform_later('stewie')
261
+ # RescueJob.perform_later('david')
262
+ # end
263
+ # end
264
+ # end
265
+ #
266
+ # If the +:queue+ option is specified,
267
+ # then only the job(s) enqueued to a specific queue will be performed.
268
+ #
269
+ # def test_assert_performed_jobs_with_queue_option
270
+ # assert_performed_jobs 1, queue: :some_queue do
271
+ # HelloJob.set(queue: :some_queue).perform_later("jeremy")
272
+ # HelloJob.set(queue: :other_queue).perform_later("bogdan")
273
+ # end
274
+ # end
275
+ def assert_performed_jobs(number, only: nil, except: nil, queue: nil, &block)
233
276
  if block_given?
234
277
  original_count = performed_jobs.size
235
- perform_enqueued_jobs(only: only, except: except) { yield }
278
+
279
+ perform_enqueued_jobs(only: only, except: except, queue: queue, &block)
280
+
236
281
  new_count = performed_jobs.size
237
- assert_equal number, new_count - original_count,
238
- "#{number} jobs expected, but #{new_count - original_count} were performed"
282
+
283
+ performed_jobs_size = new_count - original_count
239
284
  else
240
- performed_jobs_size = performed_jobs.size
241
- assert_equal number, performed_jobs_size, "#{number} jobs expected, but #{performed_jobs_size} were performed"
285
+ performed_jobs_size = performed_jobs_with(only: only, except: except, queue: queue).count
242
286
  end
287
+
288
+ assert_equal number, performed_jobs_size, "#{number} jobs expected, but #{performed_jobs_size} were performed"
243
289
  end
244
290
 
245
291
  # Asserts that no jobs have been performed.
@@ -253,7 +299,7 @@ module ActiveJob
253
299
  # end
254
300
  # end
255
301
  #
256
- # If a block is passed, that block should not cause any job to be performed.
302
+ # If a block is passed, asserts that the block will not cause any job to be performed.
257
303
  #
258
304
  # def test_jobs_again
259
305
  # assert_no_performed_jobs do
@@ -261,7 +307,7 @@ module ActiveJob
261
307
  # end
262
308
  # end
263
309
  #
264
- # The block form supports filtering. If the :only option is specified,
310
+ # The block form supports filtering. If the +:only+ option is specified,
265
311
  # then only the listed job(s) will not be performed.
266
312
  #
267
313
  # def test_no_logging
@@ -270,7 +316,7 @@ module ActiveJob
270
316
  # end
271
317
  # end
272
318
  #
273
- # Also if the :except option is specified,
319
+ # Also if the +:except+ option is specified,
274
320
  # then the job(s) except specific class will not be performed.
275
321
  #
276
322
  # def test_no_logging
@@ -279,17 +325,63 @@ module ActiveJob
279
325
  # end
280
326
  # end
281
327
  #
328
+ # +:only+ and +:except+ options accepts Class, Array of Class or Proc. When passed a Proc,
329
+ # an instance of the job will be passed as argument.
330
+ #
331
+ # If the +:queue+ option is specified,
332
+ # then only the job(s) enqueued to a specific queue will not be performed.
333
+ #
334
+ # def test_assert_no_performed_jobs_with_queue_option
335
+ # assert_no_performed_jobs queue: :some_queue do
336
+ # HelloJob.set(queue: :other_queue).perform_later("jeremy")
337
+ # end
338
+ # end
339
+ #
282
340
  # Note: This assertion is simply a shortcut for:
283
341
  #
284
342
  # 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
343
+ def assert_no_performed_jobs(only: nil, except: nil, queue: nil, &block)
344
+ assert_performed_jobs 0, only: only, except: except, queue: queue, &block
287
345
  end
288
346
 
289
- # Asserts that the job passed in the block has been enqueued with the given arguments.
347
+ # Asserts that the job has been enqueued with the given arguments.
348
+ #
349
+ # def test_assert_enqueued_with
350
+ # MyJob.perform_later(1,2,3)
351
+ # assert_enqueued_with(job: MyJob, args: [1,2,3])
352
+ #
353
+ # MyJob.set(wait_until: Date.tomorrow.noon, queue: "my_queue").perform_later
354
+ # assert_enqueued_with(at: Date.tomorrow.noon, queue: "my_queue")
355
+ # end
356
+ #
357
+ # The given arguments may also be specified as matcher procs that return a
358
+ # boolean value indicating whether a job's attribute meets certain criteria.
359
+ #
360
+ # For example, a proc can be used to match a range of times:
361
+ #
362
+ # def test_assert_enqueued_with
363
+ # at_matcher = ->(job_at) { (Date.yesterday..Date.tomorrow).cover?(job_at) }
364
+ #
365
+ # MyJob.set(wait_until: Date.today.noon).perform_later
366
+ #
367
+ # assert_enqueued_with(job: MyJob, at: at_matcher)
368
+ # end
369
+ #
370
+ # A proc can also be used to match a subset of a job's args:
290
371
  #
291
372
  # def test_assert_enqueued_with
292
- # assert_enqueued_with(job: MyJob, args: [1,2,3], queue: 'low') do
373
+ # args_matcher = ->(job_args) { job_args[0].key?(:foo) }
374
+ #
375
+ # MyJob.perform_later(foo: "bar", other_arg: "No need to check in the test")
376
+ #
377
+ # assert_enqueued_with(job: MyJob, args: args_matcher)
378
+ # end
379
+ #
380
+ # If a block is passed, asserts that the block will cause the job to be
381
+ # enqueued with the given arguments.
382
+ #
383
+ # def test_assert_enqueued_with
384
+ # assert_enqueued_with(job: MyJob, args: [1,2,3]) do
293
385
  # MyJob.perform_later(1,2,3)
294
386
  # end
295
387
  #
@@ -297,24 +389,89 @@ module ActiveJob
297
389
  # MyJob.set(wait_until: Date.tomorrow.noon).perform_later
298
390
  # end
299
391
  # end
300
- def assert_enqueued_with(job: nil, args: nil, at: nil, queue: nil)
301
- original_enqueued_jobs_count = enqueued_jobs.count
392
+ def assert_enqueued_with(job: nil, args: nil, at: nil, queue: nil, &block)
302
393
  expected = { job: job, args: args, at: at, queue: queue }.compact
303
394
  expected_args = prepare_args_for_assertion(expected)
304
- yield
305
- in_block_jobs = enqueued_jobs.drop(original_enqueued_jobs_count)
306
- matching_job = in_block_jobs.find do |in_block_job|
307
- deserialized_job = deserialize_args_for_assertion(in_block_job)
308
- expected_args.all? { |key, value| value == deserialized_job[key] }
395
+ potential_matches = []
396
+
397
+ if block_given?
398
+ original_enqueued_jobs = enqueued_jobs.dup
399
+
400
+ assert_nothing_raised(&block)
401
+
402
+ jobs = enqueued_jobs - original_enqueued_jobs
403
+ else
404
+ jobs = enqueued_jobs
405
+ end
406
+
407
+ matching_job = jobs.find do |enqueued_job|
408
+ deserialized_job = deserialize_args_for_assertion(enqueued_job)
409
+ potential_matches << deserialized_job
410
+
411
+ expected_args.all? do |key, value|
412
+ if value.respond_to?(:call)
413
+ value.call(deserialized_job[key])
414
+ else
415
+ value == deserialized_job[key]
416
+ end
417
+ end
309
418
  end
310
- assert matching_job, "No enqueued job found with #{expected}"
419
+
420
+ message = +"No enqueued job found with #{expected}"
421
+ message << "\n\nPotential matches: #{potential_matches.join("\n")}" if potential_matches.present?
422
+ assert matching_job, message
311
423
  instantiate_job(matching_job)
312
424
  end
313
425
 
314
- # Asserts that the job passed in the block has been performed with the given arguments.
426
+ # Asserts that the job has been performed with the given arguments.
427
+ #
428
+ # def test_assert_performed_with
429
+ # MyJob.perform_later(1,2,3)
430
+ #
431
+ # perform_enqueued_jobs
432
+ #
433
+ # assert_performed_with(job: MyJob, args: [1,2,3])
434
+ #
435
+ # MyJob.set(wait_until: Date.tomorrow.noon, queue: "my_queue").perform_later
436
+ #
437
+ # perform_enqueued_jobs
438
+ #
439
+ # assert_performed_with(at: Date.tomorrow.noon, queue: "my_queue")
440
+ # end
441
+ #
442
+ # The given arguments may also be specified as matcher procs that return a
443
+ # boolean value indicating whether a job's attribute meets certain criteria.
444
+ #
445
+ # For example, a proc can be used to match a range of times:
315
446
  #
316
447
  # def test_assert_performed_with
317
- # assert_performed_with(job: MyJob, args: [1,2,3], queue: 'high') do
448
+ # at_matcher = ->(job_at) { (Date.yesterday..Date.tomorrow).cover?(job_at) }
449
+ #
450
+ # MyJob.set(wait_until: Date.today.noon).perform_later
451
+ #
452
+ # perform_enqueued_jobs
453
+ #
454
+ # assert_performed_with(job: MyJob, at: at_matcher)
455
+ # end
456
+ #
457
+ # A proc can also be used to match a subset of a job's args:
458
+ #
459
+ # def test_assert_performed_with
460
+ # args_matcher = ->(job_args) { job_args[0].key?(:foo) }
461
+ #
462
+ # MyJob.perform_later(foo: "bar", other_arg: "No need to check in the test")
463
+ #
464
+ # perform_enqueued_jobs
465
+ #
466
+ # assert_performed_with(job: MyJob, args: args_matcher)
467
+ # end
468
+ #
469
+ # If a block is passed, that block performs all of the jobs that were
470
+ # enqueued throughout the duration of the block and asserts that
471
+ # the job has been performed with the given arguments in the block.
472
+ #
473
+ # def test_assert_performed_with
474
+ # assert_performed_with(job: MyJob, args: [1,2,3]) do
318
475
  # MyJob.perform_later(1,2,3)
319
476
  # end
320
477
  #
@@ -322,21 +479,44 @@ module ActiveJob
322
479
  # MyJob.set(wait_until: Date.tomorrow.noon).perform_later
323
480
  # end
324
481
  # end
325
- def assert_performed_with(job: nil, args: nil, at: nil, queue: nil)
326
- original_performed_jobs_count = performed_jobs.count
482
+ def assert_performed_with(job: nil, args: nil, at: nil, queue: nil, &block)
327
483
  expected = { job: job, args: args, at: at, queue: queue }.compact
328
484
  expected_args = prepare_args_for_assertion(expected)
329
- perform_enqueued_jobs { yield }
330
- in_block_jobs = performed_jobs.drop(original_performed_jobs_count)
331
- matching_job = in_block_jobs.find do |in_block_job|
332
- deserialized_job = deserialize_args_for_assertion(in_block_job)
333
- expected_args.all? { |key, value| value == deserialized_job[key] }
485
+ potential_matches = []
486
+
487
+ if block_given?
488
+ original_performed_jobs_count = performed_jobs.count
489
+
490
+ perform_enqueued_jobs(&block)
491
+
492
+ jobs = performed_jobs.drop(original_performed_jobs_count)
493
+ else
494
+ jobs = performed_jobs
334
495
  end
335
- assert matching_job, "No performed job found with #{expected}"
496
+
497
+ matching_job = jobs.find do |enqueued_job|
498
+ deserialized_job = deserialize_args_for_assertion(enqueued_job)
499
+ potential_matches << deserialized_job
500
+
501
+ expected_args.all? do |key, value|
502
+ if value.respond_to?(:call)
503
+ value.call(deserialized_job[key])
504
+ else
505
+ value == deserialized_job[key]
506
+ end
507
+ end
508
+ end
509
+
510
+ message = +"No performed job found with #{expected}"
511
+ message << "\n\nPotential matches: #{potential_matches.join("\n")}" if potential_matches.present?
512
+ assert matching_job, message
513
+
336
514
  instantiate_job(matching_job)
337
515
  end
338
516
 
339
- # Performs all enqueued jobs in the duration of the block.
517
+ # Performs all enqueued jobs. If a block is given, performs all of the jobs
518
+ # that were enqueued throughout the duration of the block. If a block is
519
+ # not given, performs all of the enqueued jobs up to this point in the test.
340
520
  #
341
521
  # def test_perform_enqueued_jobs
342
522
  # perform_enqueued_jobs do
@@ -345,6 +525,14 @@ module ActiveJob
345
525
  # assert_performed_jobs 1
346
526
  # end
347
527
  #
528
+ # def test_perform_enqueued_jobs_without_block
529
+ # MyJob.perform_later(1, 2, 3)
530
+ #
531
+ # perform_enqueued_jobs
532
+ #
533
+ # assert_performed_jobs 1
534
+ # end
535
+ #
348
536
  # This method also supports filtering. If the +:only+ option is specified,
349
537
  # then only the listed job(s) will be performed.
350
538
  #
@@ -367,24 +555,50 @@ module ActiveJob
367
555
  # assert_performed_jobs 1
368
556
  # end
369
557
  #
370
- def perform_enqueued_jobs(only: nil, except: nil)
558
+ # +:only+ and +:except+ options accepts Class, Array of Class or Proc. When passed a Proc,
559
+ # an instance of the job will be passed as argument.
560
+ #
561
+ # If the +:queue+ option is specified,
562
+ # then only the job(s) enqueued to a specific queue will be performed.
563
+ #
564
+ # def test_perform_enqueued_jobs_with_queue
565
+ # perform_enqueued_jobs queue: :some_queue do
566
+ # MyJob.set(queue: :some_queue).perform_later(1, 2, 3) # will be performed
567
+ # HelloJob.set(queue: :other_queue).perform_later(1, 2, 3) # will not be performed
568
+ # end
569
+ # assert_performed_jobs 1
570
+ # end
571
+ #
572
+ # If the +:at+ option is specified, then only run jobs enqueued to run
573
+ # immediately or before the given time
574
+ def perform_enqueued_jobs(only: nil, except: nil, queue: nil, at: nil, &block)
575
+ return flush_enqueued_jobs(only: only, except: except, queue: queue, at: at) unless block_given?
576
+
371
577
  validate_option(only: only, except: except)
578
+
372
579
  old_perform_enqueued_jobs = queue_adapter.perform_enqueued_jobs
373
580
  old_perform_enqueued_at_jobs = queue_adapter.perform_enqueued_at_jobs
374
581
  old_filter = queue_adapter.filter
375
582
  old_reject = queue_adapter.reject
583
+ old_queue = queue_adapter.queue
584
+ old_at = queue_adapter.at
376
585
 
377
586
  begin
378
587
  queue_adapter.perform_enqueued_jobs = true
379
588
  queue_adapter.perform_enqueued_at_jobs = true
380
589
  queue_adapter.filter = only
381
590
  queue_adapter.reject = except
382
- yield
591
+ queue_adapter.queue = queue
592
+ queue_adapter.at = at
593
+
594
+ assert_nothing_raised(&block)
383
595
  ensure
384
596
  queue_adapter.perform_enqueued_jobs = old_perform_enqueued_jobs
385
597
  queue_adapter.perform_enqueued_at_jobs = old_perform_enqueued_at_jobs
386
598
  queue_adapter.filter = old_filter
387
599
  queue_adapter.reject = old_reject
600
+ queue_adapter.queue = old_queue
601
+ queue_adapter.at = old_at
388
602
  end
389
603
  end
390
604
 
@@ -406,39 +620,74 @@ module ActiveJob
406
620
  performed_jobs.clear
407
621
  end
408
622
 
409
- def enqueued_jobs_size(only: nil, except: nil, queue: nil)
623
+ def jobs_with(jobs, only: nil, except: nil, queue: nil, at: nil)
410
624
  validate_option(only: only, except: except)
411
- enqueued_jobs.count do |job|
625
+
626
+ jobs.dup.select do |job|
412
627
  job_class = job.fetch(:job)
628
+
413
629
  if only
414
- next false unless Array(only).include?(job_class)
630
+ next false unless filter_as_proc(only).call(job)
415
631
  elsif except
416
- next false if Array(except).include?(job_class)
632
+ next false if filter_as_proc(except).call(job)
417
633
  end
634
+
418
635
  if queue
419
636
  next false unless queue.to_s == job.fetch(:queue, job_class.queue_name)
420
637
  end
638
+
639
+ if at && job[:at]
640
+ next false if job[:at] > at.to_f
641
+ end
642
+
643
+ yield job if block_given?
644
+
421
645
  true
422
646
  end
423
647
  end
424
648
 
649
+ def filter_as_proc(filter)
650
+ return filter if filter.is_a?(Proc)
651
+
652
+ ->(job) { Array(filter).include?(job.fetch(:job)) }
653
+ end
654
+
655
+ def enqueued_jobs_with(only: nil, except: nil, queue: nil, at: nil, &block)
656
+ jobs_with(enqueued_jobs, only: only, except: except, queue: queue, at: at, &block)
657
+ end
658
+
659
+ def performed_jobs_with(only: nil, except: nil, queue: nil, &block)
660
+ jobs_with(performed_jobs, only: only, except: except, queue: queue, &block)
661
+ end
662
+
663
+ def flush_enqueued_jobs(only: nil, except: nil, queue: nil, at: nil)
664
+ enqueued_jobs_with(only: only, except: except, queue: queue, at: at) do |payload|
665
+ queue_adapter.enqueued_jobs.delete(payload)
666
+ queue_adapter.performed_jobs << payload
667
+ instantiate_job(payload).perform_now
668
+ end.count
669
+ end
670
+
425
671
  def prepare_args_for_assertion(args)
426
672
  args.dup.tap do |arguments|
427
- arguments[:at] = arguments[:at].to_f if arguments[:at]
673
+ if arguments[:at].acts_like?(:time)
674
+ at_range = arguments[:at] - 1..arguments[:at] + 1
675
+ arguments[:at] = ->(at) { at_range.cover?(at) }
676
+ end
428
677
  end
429
678
  end
430
679
 
431
680
  def deserialize_args_for_assertion(job)
432
681
  job.dup.tap do |new_job|
682
+ new_job[:at] = Time.at(new_job[:at]) if new_job[:at]
433
683
  new_job[:args] = ActiveJob::Arguments.deserialize(new_job[:args]) if new_job[:args]
434
684
  end
435
685
  end
436
686
 
437
687
  def instantiate_job(payload)
438
- args = ActiveJob::Arguments.deserialize(payload[:args])
439
- job = payload[:job].new(*args)
688
+ job = payload[:job].deserialize(payload)
440
689
  job.scheduled_at = Time.at(payload[:at]) if payload.key?(:at)
441
- job.queue_name = payload[:queue]
690
+ job.send(:deserialize_arguments_if_needed)
442
691
  job
443
692
  end
444
693
 
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveJob
4
+ module Timezones #:nodoc:
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ around_perform do |job, block|
9
+ Time.use_zone(job.timezone, &block)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -5,7 +5,7 @@ module ActiveJob
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- around_perform do |job, block, _|
8
+ around_perform do |job, block|
9
9
  I18n.with_locale(job.locale, &block)
10
10
  end
11
11
  end
data/lib/active_job.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # Copyright (c) 2014-2018 David Heinemeier Hansson
4
+ # Copyright (c) 2014-2020 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
@@ -28,6 +28,10 @@ module Rails # :nodoc:
28
28
  end
29
29
 
30
30
  private
31
+ def file_name
32
+ @_file_name ||= super.sub(/_job\z/i, "")
33
+ end
34
+
31
35
  def application_job_file_name
32
36
  @application_job_file_name ||= if mountable_engine?
33
37
  "app/jobs/#{namespaced_path}/application_job.rb"