sidekiq 8.1.0 → 8.1.2

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.
@@ -0,0 +1,331 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+ require "sidekiq"
5
+
6
+ module Sidekiq
7
+ class Testing
8
+ class TestModeAlreadySetError < RuntimeError; end
9
+ class << self
10
+ attr_accessor :__global_test_mode
11
+
12
+ # Calling without a block sets the global test mode, affecting
13
+ # all threads. Calling with a block only affects the current Thread.
14
+ def __set_test_mode(mode)
15
+ if block_given?
16
+ # Reentrant testing modes will lead to a rat's nest of code which is
17
+ # hard to reason about. You can set the testing mode once globally and
18
+ # you can override that global setting once per-thread.
19
+ raise TestModeAlreadySetError, "Nesting test modes is not supported" if __local_test_mode
20
+
21
+ self.__local_test_mode = mode
22
+ begin
23
+ yield
24
+ ensure
25
+ self.__local_test_mode = nil
26
+ end
27
+ else
28
+ self.__global_test_mode = mode
29
+ end
30
+ end
31
+
32
+ def __test_mode
33
+ __local_test_mode || __global_test_mode
34
+ end
35
+
36
+ def __local_test_mode
37
+ Thread.current[:__sidekiq_test_mode]
38
+ end
39
+
40
+ def __local_test_mode=(value)
41
+ Thread.current[:__sidekiq_test_mode] = value
42
+ end
43
+
44
+ def disable!(&block)
45
+ __set_test_mode(:disable, &block)
46
+ end
47
+
48
+ def fake!(&block)
49
+ __set_test_mode(:fake, &block)
50
+ end
51
+
52
+ def inline!(&block)
53
+ __set_test_mode(:inline, &block)
54
+ end
55
+
56
+ def enabled?
57
+ __test_mode != :disable
58
+ end
59
+
60
+ def disabled?
61
+ __test_mode == :disable
62
+ end
63
+
64
+ def fake?
65
+ __test_mode == :fake
66
+ end
67
+
68
+ def inline?
69
+ __test_mode == :inline
70
+ end
71
+
72
+ def server_middleware
73
+ @server_chain ||= Middleware::Chain.new(Sidekiq.default_configuration)
74
+ yield @server_chain if block_given?
75
+ @server_chain
76
+ end
77
+ end
78
+ end
79
+
80
+ class EmptyQueueError < RuntimeError; end
81
+
82
+ module TestingClient
83
+ private def atomic_push(conn, payloads)
84
+ if Sidekiq::Testing.fake?
85
+ payloads.each do |job|
86
+ job = Sidekiq.load_json(Sidekiq.dump_json(job))
87
+ job["enqueued_at"] = ::Process.clock_gettime(::Process::CLOCK_REALTIME, :millisecond) unless job["at"]
88
+ Queues.push(job["queue"], job["class"], job)
89
+ end
90
+ true
91
+ elsif Sidekiq::Testing.inline?
92
+ payloads.each do |job|
93
+ klass = Object.const_get(job["class"])
94
+ job["id"] ||= SecureRandom.hex(12)
95
+ job_hash = Sidekiq.load_json(Sidekiq.dump_json(job))
96
+ klass.process_job(job_hash)
97
+ end
98
+ true
99
+ else
100
+ super
101
+ end
102
+ end
103
+ end
104
+
105
+ Sidekiq::Client.prepend TestingClient
106
+
107
+ module Queues
108
+ ##
109
+ # The Queues class is only for testing the fake queue implementation.
110
+ # There are 2 data structures involved in tandem. This is due to the
111
+ # Rspec syntax of change(HardJob.jobs, :size). It keeps a reference
112
+ # to the array. Because the array was derived from a filter of the total
113
+ # jobs enqueued, it appeared as though the array didn't change.
114
+ #
115
+ # To solve this, we'll keep 2 hashes containing the jobs. One with keys based
116
+ # on the queue, and another with keys of the job type, so the array for
117
+ # HardJob.jobs is a straight reference to a real array.
118
+ #
119
+ # Queue-based hash:
120
+ #
121
+ # {
122
+ # "default"=>[
123
+ # {
124
+ # "class"=>"TestTesting::HardJob",
125
+ # "args"=>[1, 2],
126
+ # "retry"=>true,
127
+ # "queue"=>"default",
128
+ # "jid"=>"abc5b065c5c4b27fc1102833",
129
+ # "created_at"=>1447445554.419934
130
+ # }
131
+ # ]
132
+ # }
133
+ #
134
+ # Job-based hash:
135
+ #
136
+ # {
137
+ # "TestTesting::HardJob"=>[
138
+ # {
139
+ # "class"=>"TestTesting::HardJob",
140
+ # "args"=>[1, 2],
141
+ # "retry"=>true,
142
+ # "queue"=>"default",
143
+ # "jid"=>"abc5b065c5c4b27fc1102833",
144
+ # "created_at"=>1447445554.419934
145
+ # }
146
+ # ]
147
+ # }
148
+ #
149
+ # Example:
150
+ #
151
+ # require 'sidekiq/testing'
152
+ #
153
+ # assert_equal 0, Sidekiq::Queues["default"].size
154
+ # HardJob.perform_async(:something)
155
+ # assert_equal 1, Sidekiq::Queues["default"].size
156
+ # assert_equal :something, Sidekiq::Queues["default"].first['args'][0]
157
+ #
158
+ # You can also clear all jobs:
159
+ #
160
+ # assert_equal 0, Sidekiq::Queues["default"].size
161
+ # HardJob.perform_async(:something)
162
+ # Sidekiq::Queues.clear_all
163
+ # assert_equal 0, Sidekiq::Queues["default"].size
164
+ #
165
+ # This can be useful to make sure jobs don't linger between tests:
166
+ #
167
+ # RSpec.configure do |config|
168
+ # config.before(:each) do
169
+ # Sidekiq::Queues.clear_all
170
+ # end
171
+ # end
172
+ #
173
+ class << self
174
+ def [](queue)
175
+ jobs_by_queue[queue]
176
+ end
177
+
178
+ def push(queue, klass, job)
179
+ jobs_by_queue[queue] << job
180
+ jobs_by_class[klass] << job
181
+ end
182
+
183
+ def jobs_by_queue
184
+ @jobs_by_queue ||= Hash.new { |hash, key| hash[key] = [] }
185
+ end
186
+
187
+ def jobs_by_class
188
+ @jobs_by_class ||= Hash.new { |hash, key| hash[key] = [] }
189
+ end
190
+ alias_method :jobs_by_worker, :jobs_by_class
191
+
192
+ def delete_for(jid, queue, klass)
193
+ jobs_by_queue[queue.to_s].delete_if { |job| job["jid"] == jid }
194
+ jobs_by_class[klass].delete_if { |job| job["jid"] == jid }
195
+ end
196
+
197
+ def clear_for(queue, klass)
198
+ jobs_by_queue[queue.to_s].clear
199
+ jobs_by_class[klass].clear
200
+ end
201
+
202
+ def clear_all
203
+ jobs_by_queue.clear
204
+ jobs_by_class.clear
205
+ end
206
+ end
207
+ end
208
+
209
+ module Job
210
+ ##
211
+ # The Sidekiq testing infrastructure overrides perform_async
212
+ # so that it does not actually touch the network. Instead it
213
+ # stores the asynchronous jobs in a per-class array so that
214
+ # their presence/absence can be asserted by your tests.
215
+ #
216
+ # This is similar to ActionMailer's :test delivery_method and its
217
+ # ActionMailer::Base.deliveries array.
218
+ #
219
+ # Example:
220
+ #
221
+ # require 'sidekiq/testing'
222
+ #
223
+ # assert_equal 0, HardJob.jobs.size
224
+ # HardJob.perform_async(:something)
225
+ # assert_equal 1, HardJob.jobs.size
226
+ # assert_equal :something, HardJob.jobs[0]['args'][0]
227
+ #
228
+ # You can also clear and drain all job types:
229
+ #
230
+ # Sidekiq::Job.clear_all # or .drain_all
231
+ #
232
+ # This can be useful to make sure jobs don't linger between tests:
233
+ #
234
+ # RSpec.configure do |config|
235
+ # config.before(:each) do
236
+ # Sidekiq::Job.clear_all
237
+ # end
238
+ # end
239
+ #
240
+ # or for acceptance testing, i.e. with cucumber:
241
+ #
242
+ # AfterStep do
243
+ # Sidekiq::Job.drain_all
244
+ # end
245
+ #
246
+ # When I sign up as "foo@example.com"
247
+ # Then I should receive a welcome email to "foo@example.com"
248
+ #
249
+ module ClassMethods
250
+ # Queue for this worker
251
+ def queue
252
+ get_sidekiq_options["queue"]
253
+ end
254
+
255
+ # Jobs queued for this worker
256
+ def jobs
257
+ Queues.jobs_by_class[to_s]
258
+ end
259
+
260
+ # Clear all jobs for this worker
261
+ def clear
262
+ Queues.clear_for(queue, to_s)
263
+ end
264
+
265
+ # Drain and run all jobs for this worker
266
+ def drain
267
+ while jobs.any?
268
+ next_job = jobs.first
269
+ Queues.delete_for(next_job["jid"], next_job["queue"], to_s)
270
+ process_job(next_job)
271
+ end
272
+ end
273
+
274
+ # Pop out a single job and perform it
275
+ def perform_one
276
+ raise(EmptyQueueError, "perform_one called with empty job queue") if jobs.empty?
277
+ next_job = jobs.first
278
+ Queues.delete_for(next_job["jid"], next_job["queue"], to_s)
279
+ process_job(next_job)
280
+ end
281
+
282
+ def process_job(job)
283
+ instance = new
284
+ instance.jid = job["jid"]
285
+ instance.bid = job["bid"] if instance.respond_to?(:bid=)
286
+ Sidekiq::Testing.server_middleware.invoke(instance, job, job["queue"]) do
287
+ execute_job(instance, job["args"])
288
+ end
289
+ end
290
+
291
+ def execute_job(worker, args)
292
+ worker.perform(*args)
293
+ end
294
+ end
295
+
296
+ class << self
297
+ def jobs # :nodoc:
298
+ Queues.jobs_by_queue.values.flatten
299
+ end
300
+
301
+ # Clear all queued jobs
302
+ def clear_all
303
+ Queues.clear_all
304
+ end
305
+
306
+ # Drain (execute) all queued jobs
307
+ def drain_all
308
+ while jobs.any?
309
+ job_classes = jobs.map { |job| job["class"] }.uniq
310
+
311
+ job_classes.each do |job_class|
312
+ Object.const_get(job_class).drain
313
+ end
314
+ end
315
+ end
316
+ end
317
+ end
318
+
319
+ module TestingExtensions
320
+ def jobs_for(klass)
321
+ jobs.select do |job|
322
+ marshalled = job["args"][0]
323
+ marshalled.index(klass.to_s) && YAML.safe_load(marshalled)[0] == klass
324
+ end
325
+ end
326
+ end
327
+ end
328
+
329
+ if defined?(::Rails) && Rails.respond_to?(:env) && !Rails.env.test? && !$TESTING # rubocop:disable Style/GlobalVars
330
+ warn("⛔️ WARNING: Sidekiq testing API enabled, but this is not the test environment. Your jobs will not go to Redis.", uplevel: 1)
331
+ end
@@ -1,30 +1,2 @@
1
- # frozen_string_literal: true
2
-
3
- require "sidekiq/testing"
4
-
5
- ##
6
- # The Sidekiq inline infrastructure overrides perform_async so that it
7
- # actually calls perform instead. This allows jobs to be run inline in a
8
- # testing environment.
9
- #
10
- # This is similar to `Resque.inline = true` functionality.
11
- #
12
- # Example:
13
- #
14
- # require 'sidekiq/testing/inline'
15
- #
16
- # $external_variable = 0
17
- #
18
- # class ExternalJob
19
- # include Sidekiq::Job
20
- #
21
- # def perform
22
- # $external_variable = 1
23
- # end
24
- # end
25
- #
26
- # assert_equal 0, $external_variable
27
- # ExternalJob.perform_async
28
- # assert_equal 1, $external_variable
29
- #
30
- Sidekiq::Testing.inline!
1
+ Sidekiq.testing!(:inline)
2
+ warn('⛔️ `require "sidekiq/testing/inline"` is deprecated and will be removed in Sidekiq 9.0. See https://sidekiq.org/wiki/Testing#new-api')
@@ -1,334 +1,2 @@
1
- # frozen_string_literal: true
2
-
3
- require "securerandom"
4
- require "sidekiq"
5
-
6
- module Sidekiq
7
- class Testing
8
- class TestModeAlreadySetError < RuntimeError; end
9
- class << self
10
- attr_accessor :__global_test_mode
11
-
12
- # Calling without a block sets the global test mode, affecting
13
- # all threads. Calling with a block only affects the current Thread.
14
- def __set_test_mode(mode)
15
- if block_given?
16
- # Reentrant testing modes will lead to a rat's nest of code which is
17
- # hard to reason about. You can set the testing mode once globally and
18
- # you can override that global setting once per-thread.
19
- raise TestModeAlreadySetError, "Nesting test modes is not supported" if __local_test_mode
20
-
21
- self.__local_test_mode = mode
22
- begin
23
- yield
24
- ensure
25
- self.__local_test_mode = nil
26
- end
27
- else
28
- self.__global_test_mode = mode
29
- end
30
- end
31
-
32
- def __test_mode
33
- __local_test_mode || __global_test_mode
34
- end
35
-
36
- def __local_test_mode
37
- Thread.current[:__sidekiq_test_mode]
38
- end
39
-
40
- def __local_test_mode=(value)
41
- Thread.current[:__sidekiq_test_mode] = value
42
- end
43
-
44
- def disable!(&block)
45
- __set_test_mode(:disable, &block)
46
- end
47
-
48
- def fake!(&block)
49
- __set_test_mode(:fake, &block)
50
- end
51
-
52
- def inline!(&block)
53
- __set_test_mode(:inline, &block)
54
- end
55
-
56
- def enabled?
57
- __test_mode != :disable
58
- end
59
-
60
- def disabled?
61
- __test_mode == :disable
62
- end
63
-
64
- def fake?
65
- __test_mode == :fake
66
- end
67
-
68
- def inline?
69
- __test_mode == :inline
70
- end
71
-
72
- def server_middleware
73
- @server_chain ||= Middleware::Chain.new(Sidekiq.default_configuration)
74
- yield @server_chain if block_given?
75
- @server_chain
76
- end
77
- end
78
- end
79
-
80
- # Default to fake testing to keep old behavior
81
- Sidekiq::Testing.fake!
82
-
83
- class EmptyQueueError < RuntimeError; end
84
-
85
- module TestingClient
86
- private def atomic_push(conn, payloads)
87
- if Sidekiq::Testing.fake?
88
- payloads.each do |job|
89
- job = Sidekiq.load_json(Sidekiq.dump_json(job))
90
- job["enqueued_at"] = ::Process.clock_gettime(::Process::CLOCK_REALTIME, :millisecond) unless job["at"]
91
- Queues.push(job["queue"], job["class"], job)
92
- end
93
- true
94
- elsif Sidekiq::Testing.inline?
95
- payloads.each do |job|
96
- klass = Object.const_get(job["class"])
97
- job["id"] ||= SecureRandom.hex(12)
98
- job_hash = Sidekiq.load_json(Sidekiq.dump_json(job))
99
- klass.process_job(job_hash)
100
- end
101
- true
102
- else
103
- super
104
- end
105
- end
106
- end
107
-
108
- Sidekiq::Client.prepend TestingClient
109
-
110
- module Queues
111
- ##
112
- # The Queues class is only for testing the fake queue implementation.
113
- # There are 2 data structures involved in tandem. This is due to the
114
- # Rspec syntax of change(HardJob.jobs, :size). It keeps a reference
115
- # to the array. Because the array was derived from a filter of the total
116
- # jobs enqueued, it appeared as though the array didn't change.
117
- #
118
- # To solve this, we'll keep 2 hashes containing the jobs. One with keys based
119
- # on the queue, and another with keys of the job type, so the array for
120
- # HardJob.jobs is a straight reference to a real array.
121
- #
122
- # Queue-based hash:
123
- #
124
- # {
125
- # "default"=>[
126
- # {
127
- # "class"=>"TestTesting::HardJob",
128
- # "args"=>[1, 2],
129
- # "retry"=>true,
130
- # "queue"=>"default",
131
- # "jid"=>"abc5b065c5c4b27fc1102833",
132
- # "created_at"=>1447445554.419934
133
- # }
134
- # ]
135
- # }
136
- #
137
- # Job-based hash:
138
- #
139
- # {
140
- # "TestTesting::HardJob"=>[
141
- # {
142
- # "class"=>"TestTesting::HardJob",
143
- # "args"=>[1, 2],
144
- # "retry"=>true,
145
- # "queue"=>"default",
146
- # "jid"=>"abc5b065c5c4b27fc1102833",
147
- # "created_at"=>1447445554.419934
148
- # }
149
- # ]
150
- # }
151
- #
152
- # Example:
153
- #
154
- # require 'sidekiq/testing'
155
- #
156
- # assert_equal 0, Sidekiq::Queues["default"].size
157
- # HardJob.perform_async(:something)
158
- # assert_equal 1, Sidekiq::Queues["default"].size
159
- # assert_equal :something, Sidekiq::Queues["default"].first['args'][0]
160
- #
161
- # You can also clear all jobs:
162
- #
163
- # assert_equal 0, Sidekiq::Queues["default"].size
164
- # HardJob.perform_async(:something)
165
- # Sidekiq::Queues.clear_all
166
- # assert_equal 0, Sidekiq::Queues["default"].size
167
- #
168
- # This can be useful to make sure jobs don't linger between tests:
169
- #
170
- # RSpec.configure do |config|
171
- # config.before(:each) do
172
- # Sidekiq::Queues.clear_all
173
- # end
174
- # end
175
- #
176
- class << self
177
- def [](queue)
178
- jobs_by_queue[queue]
179
- end
180
-
181
- def push(queue, klass, job)
182
- jobs_by_queue[queue] << job
183
- jobs_by_class[klass] << job
184
- end
185
-
186
- def jobs_by_queue
187
- @jobs_by_queue ||= Hash.new { |hash, key| hash[key] = [] }
188
- end
189
-
190
- def jobs_by_class
191
- @jobs_by_class ||= Hash.new { |hash, key| hash[key] = [] }
192
- end
193
- alias_method :jobs_by_worker, :jobs_by_class
194
-
195
- def delete_for(jid, queue, klass)
196
- jobs_by_queue[queue.to_s].delete_if { |job| job["jid"] == jid }
197
- jobs_by_class[klass].delete_if { |job| job["jid"] == jid }
198
- end
199
-
200
- def clear_for(queue, klass)
201
- jobs_by_queue[queue.to_s].clear
202
- jobs_by_class[klass].clear
203
- end
204
-
205
- def clear_all
206
- jobs_by_queue.clear
207
- jobs_by_class.clear
208
- end
209
- end
210
- end
211
-
212
- module Job
213
- ##
214
- # The Sidekiq testing infrastructure overrides perform_async
215
- # so that it does not actually touch the network. Instead it
216
- # stores the asynchronous jobs in a per-class array so that
217
- # their presence/absence can be asserted by your tests.
218
- #
219
- # This is similar to ActionMailer's :test delivery_method and its
220
- # ActionMailer::Base.deliveries array.
221
- #
222
- # Example:
223
- #
224
- # require 'sidekiq/testing'
225
- #
226
- # assert_equal 0, HardJob.jobs.size
227
- # HardJob.perform_async(:something)
228
- # assert_equal 1, HardJob.jobs.size
229
- # assert_equal :something, HardJob.jobs[0]['args'][0]
230
- #
231
- # You can also clear and drain all job types:
232
- #
233
- # Sidekiq::Job.clear_all # or .drain_all
234
- #
235
- # This can be useful to make sure jobs don't linger between tests:
236
- #
237
- # RSpec.configure do |config|
238
- # config.before(:each) do
239
- # Sidekiq::Job.clear_all
240
- # end
241
- # end
242
- #
243
- # or for acceptance testing, i.e. with cucumber:
244
- #
245
- # AfterStep do
246
- # Sidekiq::Job.drain_all
247
- # end
248
- #
249
- # When I sign up as "foo@example.com"
250
- # Then I should receive a welcome email to "foo@example.com"
251
- #
252
- module ClassMethods
253
- # Queue for this worker
254
- def queue
255
- get_sidekiq_options["queue"]
256
- end
257
-
258
- # Jobs queued for this worker
259
- def jobs
260
- Queues.jobs_by_class[to_s]
261
- end
262
-
263
- # Clear all jobs for this worker
264
- def clear
265
- Queues.clear_for(queue, to_s)
266
- end
267
-
268
- # Drain and run all jobs for this worker
269
- def drain
270
- while jobs.any?
271
- next_job = jobs.first
272
- Queues.delete_for(next_job["jid"], next_job["queue"], to_s)
273
- process_job(next_job)
274
- end
275
- end
276
-
277
- # Pop out a single job and perform it
278
- def perform_one
279
- raise(EmptyQueueError, "perform_one called with empty job queue") if jobs.empty?
280
- next_job = jobs.first
281
- Queues.delete_for(next_job["jid"], next_job["queue"], to_s)
282
- process_job(next_job)
283
- end
284
-
285
- def process_job(job)
286
- instance = new
287
- instance.jid = job["jid"]
288
- instance.bid = job["bid"] if instance.respond_to?(:bid=)
289
- Sidekiq::Testing.server_middleware.invoke(instance, job, job["queue"]) do
290
- execute_job(instance, job["args"])
291
- end
292
- end
293
-
294
- def execute_job(worker, args)
295
- worker.perform(*args)
296
- end
297
- end
298
-
299
- class << self
300
- def jobs # :nodoc:
301
- Queues.jobs_by_queue.values.flatten
302
- end
303
-
304
- # Clear all queued jobs
305
- def clear_all
306
- Queues.clear_all
307
- end
308
-
309
- # Drain (execute) all queued jobs
310
- def drain_all
311
- while jobs.any?
312
- job_classes = jobs.map { |job| job["class"] }.uniq
313
-
314
- job_classes.each do |job_class|
315
- Object.const_get(job_class).drain
316
- end
317
- end
318
- end
319
- end
320
- end
321
-
322
- module TestingExtensions
323
- def jobs_for(klass)
324
- jobs.select do |job|
325
- marshalled = job["args"][0]
326
- marshalled.index(klass.to_s) && YAML.safe_load(marshalled)[0] == klass
327
- end
328
- end
329
- end
330
- end
331
-
332
- if defined?(::Rails) && Rails.respond_to?(:env) && !Rails.env.test? && !$TESTING # rubocop:disable Style/GlobalVars
333
- warn("⛔️ WARNING: Sidekiq testing API enabled, but this is not the test environment. Your jobs will not go to Redis.", uplevel: 1)
334
- end
1
+ Sidekiq.testing!(:fake)
2
+ warn('⛔️ `require "sidekiq/testing"` is deprecated and will be removed in Sidekiq 9.0. See https://sidekiq.org/wiki/Testing#new-api')