rekiq 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,400 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rekiq::Job do
4
+ describe '#new' do
5
+ context 'when no args' do
6
+ before { @job = Rekiq::Job.new }
7
+
8
+ it 'returns an instance of Job' do
9
+ expect(@job).not_to be_nil
10
+ end
11
+
12
+ it 'sets attribute shift as 0' do
13
+ expect(@job.shift).to eq(0)
14
+ end
15
+
16
+ it 'sets reschedule_post_work as nil' do
17
+ expect(@job.reschedule_post_work).to eq(nil)
18
+ end
19
+
20
+ it 'sets schedule_expired as nil' do
21
+ expect(@job.schedule_expired).to eq(nil)
22
+ end
23
+ end
24
+
25
+ context 'when shift passed as argument' do
26
+ let(:shift) { 5 * 60 }
27
+ before do
28
+ @job = Rekiq::Job.new('shift' => shift)
29
+ end
30
+
31
+ it 'sets shift to passed value' do
32
+ expect(@job.shift).to eq(shift)
33
+ end
34
+ end
35
+
36
+ context 'when reschedule_post_work and ' \
37
+ 'schedule_expired passed as true' do
38
+ let(:reschedule_post_work) { true }
39
+ let(:schedule_expired) { true }
40
+ before do
41
+ @job =
42
+ Rekiq::Job.new \
43
+ 'reschedule_post_work' => reschedule_post_work,
44
+ 'schedule_expired' => schedule_expired
45
+ end
46
+
47
+ it 'sets reschedule_post_work to true' do
48
+ expect(@job.reschedule_post_work).to eq(true)
49
+ end
50
+
51
+ it 'sets schedule_expired to true' do
52
+ expect(@job.schedule_expired).to eq(true)
53
+ end
54
+ end
55
+ end
56
+
57
+ describe '#from_short_key_hash' do
58
+ context 'hash returned from Job#to_short_key_hash' do
59
+ let(:job) { build(:job, :randomized_attributes) }
60
+ let(:hash) { job.to_short_key_hash }
61
+ before { @job = Rekiq::Job.from_short_key_hash(hash) }
62
+
63
+ it 'returns job instance' do
64
+ expect(@job.class).to eq(Rekiq::Job)
65
+ end
66
+
67
+ it 'returns job with shift value before serialization' do
68
+ expect(@job.shift).to eq(job.shift)
69
+ end
70
+
71
+ it 'returns job with reschedule_post_work value before serialization' do
72
+ expect(@job.reschedule_post_work).to eq(job.reschedule_post_work)
73
+ end
74
+
75
+ it 'returns job with schedule_expired value before serialization' do
76
+ expect(@job.schedule_expired).to eq(job.schedule_expired)
77
+ end
78
+
79
+ it 'returns job with expiration_margin value before serialization' do
80
+ expect(@job.expiration_margin).to eq(job.expiration_margin)
81
+ end
82
+
83
+ it 'returns job with schedule value before serialization' do
84
+ expect(@job.schedule.class).to eq(job.schedule.class)
85
+ end
86
+
87
+ it 'returns job with working schedule' do
88
+ time = Time.now
89
+ expect(@job.schedule.next_occurrence(time)).to(
90
+ eq(job.schedule.next_occurrence(time))
91
+ )
92
+ end
93
+ end
94
+ end
95
+
96
+ describe '.to_short_key_hash' do
97
+ context 'given job instance' do
98
+ let(:job) { build(:job, :randomized_attributes) }
99
+ before { @val = job.to_short_key_hash }
100
+
101
+ it 'returns an hash' do
102
+ expect(@val.class).to eq(Hash)
103
+ end
104
+
105
+ it 'returns hash with key sft with shift value' do
106
+ expect(@val['sft']).to eq(job.shift)
107
+ end
108
+
109
+ it 'returns hash with key rpw with reschedule_post_work value' do
110
+ expect(@val['rpw']).to eq(job.reschedule_post_work)
111
+ end
112
+
113
+ it 'returns hash with key sh with schedule_expired value' do
114
+ expect(@val['se']).to eq(job.schedule_expired)
115
+ end
116
+
117
+ it 'returns hash with key em with expiration_margin value' do
118
+ expect(@val['em']).to eq(job.expiration_margin)
119
+ end
120
+
121
+ it 'returns hash with sch key with schedule serialized with YAML::dump' do
122
+ expect(@val['sch']).to eq(YAML::dump(job.schedule))
123
+ end
124
+ end
125
+ end
126
+
127
+ describe '#next_work_time' do
128
+ context 'non recurring schedule in future' do
129
+ let(:exceed_by) { 10 * 60 }
130
+ let(:schedule_time) { Time.now + exceed_by }
131
+ let(:schedule) { IceCube::Schedule.new(schedule_time) }
132
+
133
+ context 'schedule expired as true' do
134
+ let(:schedule_expired) { true }
135
+
136
+ context 'calculating from current time' do
137
+ let(:job) do
138
+ build(:job, schedule: schedule, schedule_expired: schedule_expired)
139
+ end
140
+ before { @next_work_time = job.next_work_time }
141
+
142
+ it 'return schedule time' do
143
+ expect(@next_work_time).to eq(schedule_time)
144
+ end
145
+ end
146
+
147
+ context 'shift to time between current and schedule time' do
148
+ let(:shift) { - exceed_by / 2 }
149
+
150
+ context 'calculating from current time' do
151
+ let(:job) do
152
+ build(:job,
153
+ schedule: schedule,
154
+ schedule_expired: schedule_expired,
155
+ shift: shift)
156
+ end
157
+ before { @next_work_time = job.next_work_time }
158
+
159
+ it 'returns shifted schedule time' do
160
+ expect(@next_work_time).to eq(schedule_time + shift)
161
+ end
162
+ end
163
+ end
164
+
165
+ context 'shift to time after schedule time' do
166
+ let(:shift) { 60 }
167
+
168
+ context 'calculating from current time' do
169
+ let(:job) do
170
+ build(:job, schedule: schedule,
171
+ schedule_expired: schedule_expired,
172
+ shift: shift)
173
+ end
174
+ before { @next_work_time = job.next_work_time }
175
+
176
+ it 'returns shifted schedule time' do
177
+ expect(@next_work_time).to eq(schedule_time + shift)
178
+ end
179
+ end
180
+ end
181
+
182
+ context 'shift to time before current time' do
183
+ let(:shift) { - (schedule_time - Time.now + 60) }
184
+
185
+ context 'calculating from current time' do
186
+ let(:job) do
187
+ build(:job, schedule: schedule,
188
+ schedule_expired: schedule_expired,
189
+ shift: shift)
190
+ end
191
+ before { @next_work_time = job.next_work_time }
192
+
193
+ it 'returns shifted schedule time' do
194
+ expect(@next_work_time).to eq(schedule_time + shift)
195
+ end
196
+ end
197
+ end
198
+ end
199
+
200
+ context 'schedule expired as false' do
201
+ let(:schedule_expired) { false }
202
+ let(:expiration_margin) { 10 * 60 }
203
+
204
+ context 'calculating from current time' do
205
+ let(:job) do
206
+ build(:job, schedule: schedule,
207
+ schedule_expired: schedule_expired,
208
+ expiration_margin: expiration_margin)
209
+ end
210
+ before { @next_work_time = job.next_work_time }
211
+
212
+ it 'returns schedule time' do
213
+ expect(@next_work_time).to eq(schedule_time)
214
+ end
215
+ end
216
+
217
+ context 'shift to time between current and schedule time' do
218
+ let(:shift) { - exceed_by / 2 }
219
+
220
+ context 'calculating from current time' do
221
+ let(:job) do
222
+ build(:job, schedule: schedule,
223
+ schedule_expired: schedule_expired,
224
+ expiration_margin: expiration_margin,
225
+ shift: shift)
226
+ end
227
+ before { @next_work_time = job.next_work_time }
228
+
229
+ it 'returns shifted schedule time' do
230
+ expect(@next_work_time).to eq(schedule_time + shift)
231
+ end
232
+ end
233
+ end
234
+
235
+ context 'shift to time after schedule time' do
236
+ let(:shift) { 60 }
237
+
238
+ context 'calculating from current time' do
239
+ let(:job) do
240
+ build(:job, schedule: schedule,
241
+ schedule_expired: schedule_expired,
242
+ expiration_margin: expiration_margin,
243
+ shift: shift)
244
+ end
245
+ before { @next_work_time = job.next_work_time }
246
+
247
+ it 'returns shifted schedule time' do
248
+ expect(@next_work_time).to eq(schedule_time + shift)
249
+ end
250
+ end
251
+ end
252
+
253
+ context 'shift to time inside expired margin' do
254
+ let(:shift) { - (schedule_time - Time.now + expiration_margin / 2) }
255
+
256
+ context 'calculating from current time' do
257
+ let(:job) do
258
+ build(:job, schedule: schedule,
259
+ schedule_expired: schedule_expired,
260
+ expiration_margin: expiration_margin,
261
+ shift: shift)
262
+ end
263
+ before { @next_work_time = job.next_work_time }
264
+
265
+ it 'returns shifted schedule time' do
266
+ expect(@next_work_time).to eq(schedule_time + shift)
267
+ end
268
+ end
269
+ end
270
+
271
+ context 'shift to time before expired margin' do
272
+ let(:shift) { - (schedule_time - Time.now + expiration_margin * 2) }
273
+
274
+ context 'calculating from current time' do
275
+ let(:job) do
276
+ build(:job, schedule: schedule,
277
+ schedule_expired: schedule_expired,
278
+ expiration_margin: expiration_margin,
279
+ shift: shift)
280
+ end
281
+ before { @next_work_time = job.next_work_time }
282
+
283
+ it 'returns nil' do
284
+ expect(@next_work_time).to be_nil
285
+ end
286
+ end
287
+ end
288
+ end
289
+ end
290
+
291
+ context 'non recurring expired schedule' do
292
+ let(:expired_by) { 10 * 60 }
293
+ let(:schedule_time) { Time.now - expired_by }
294
+ let(:schedule) { IceCube::Schedule.new(schedule_time) }
295
+
296
+ context 'schedule expired as true' do
297
+ let(:schedule_expired) { true }
298
+
299
+ context 'calculating from current time' do
300
+ let(:job) do
301
+ build(:job, schedule: schedule,
302
+ schedule_expired: schedule_expired)
303
+ end
304
+ before { @next_work_time = job.next_work_time }
305
+
306
+ it 'returns nil' do
307
+ expect(@next_work_time).to be_nil
308
+ end
309
+ end
310
+
311
+ context 'calculating from before schedule time' do
312
+ let(:from) { schedule_time - 60 }
313
+ let(:job) do
314
+ build(:job, schedule: schedule,
315
+ schedule_expired: schedule_expired)
316
+ end
317
+ before { @next_work_time = job.next_work_time(from) }
318
+
319
+ it 'returns schedule time' do
320
+ expect(@next_work_time).to eq(schedule_time)
321
+ end
322
+ end
323
+
324
+ context 'shift to after current time' do
325
+ let(:shift) { expired_by * 2 }
326
+
327
+ context 'calculating from current time' do
328
+ let(:job) do
329
+ build(:job, schedule: schedule,
330
+ schedule_expired: schedule_expired,
331
+ shift: shift)
332
+ end
333
+ before { @next_work_time = job.next_work_time }
334
+
335
+ it 'returns shifted schedule time' do
336
+ expect(@next_work_time).to eq(schedule_time + shift)
337
+ end
338
+ end
339
+ end
340
+ end
341
+
342
+ context 'schedule expired as false' do
343
+ let(:schedule_expired) { false }
344
+
345
+ context 'expiration margin as 0' do
346
+ let(:expiration_margin) { 0 }
347
+
348
+ context 'calculating from current time' do
349
+ let(:job) do
350
+ build(:job, schedule: schedule,
351
+ schedule_expired: schedule_expired,
352
+ expiration_margin: expiration_margin)
353
+ end
354
+ before { @next_work_time = job.next_work_time }
355
+
356
+ it 'returns nil' do
357
+ expect(@next_work_time).to be_nil
358
+ end
359
+ end
360
+ end
361
+
362
+ context 'expiration margin above expiration time' do
363
+ let(:expiration_margin) { expired_by * 2 }
364
+
365
+ context 'calculating from before schedule time' do
366
+ let(:from) { schedule_time - expiration_margin - 60 }
367
+ let(:job) do
368
+ build(:job, schedule: schedule,
369
+ expiration_margin: expiration_margin,
370
+ schedule_expired: schedule_expired)
371
+ end
372
+ before { @next_work_time = job.next_work_time(from) }
373
+
374
+ it 'returns schedule time' do
375
+ expect(@next_work_time).to eq(schedule_time)
376
+ end
377
+ end
378
+ end
379
+
380
+ context 'expiration margin above expiration time' do
381
+ let(:expiration_margin) { expired_by / 2 }
382
+
383
+ context 'calculating from before schedule time' do
384
+ let(:from) { schedule_time - expiration_margin - 60 }
385
+ let(:job) do
386
+ build(:job, schedule: schedule,
387
+ expiration_margin: expiration_margin,
388
+ schedule_expired: schedule_expired)
389
+ end
390
+ before { @next_work_time = job.next_work_time(from) }
391
+
392
+ it 'returns nil' do
393
+ expect(@next_work_time).to be_nil
394
+ end
395
+ end
396
+ end
397
+ end
398
+ end
399
+ end
400
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rekiq::Middleware::Utils do
4
+ class UtilsTestWorker
5
+ include Sidekiq::Worker
6
+ end
7
+
8
+ describe '#call' do
9
+ let(:worker) { UtilsTestWorker.new }
10
+ let(:queue) { UtilsTestWorker.get_sidekiq_options['queue'] }
11
+ let(:scheduled_work_time) { Time.at(Time.now.to_f) }
12
+
13
+ context 'worker responds to scheduled_work_time' do
14
+ context 'msg hash has rq:at key with value Time' do
15
+ let(:msg) { { 'rq:at' => scheduled_work_time.to_f } }
16
+
17
+ it 'yields passed block' do
18
+ expect do |b|
19
+ Rekiq::Middleware::Utils.new
20
+ .call(worker, msg, queue, &b)
21
+ end.to yield_control.once
22
+ end
23
+
24
+ it 'sets scheduled_work_time attribute in worker' do
25
+ Rekiq::Middleware::Utils.new
26
+ .call(worker, msg, queue) {}
27
+
28
+ expect(worker.scheduled_work_time).to eq(scheduled_work_time.utc)
29
+ end
30
+ end
31
+
32
+ context 'msg has no key' do
33
+ let(:msg) { {} }
34
+
35
+ it 'yields passed block' do
36
+ expect do |b|
37
+ Rekiq::Middleware::Utils.new
38
+ .call(worker, msg, queue, &b)
39
+ end.to yield_control.once
40
+ end
41
+
42
+ it 'scheduled_work_time remaing unchanged' do
43
+ expect(worker.scheduled_work_time).to be_nil
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rekiq::Middleware::WorkOverseer do
4
+ class WorkOverseerTestWorker
5
+ include Sidekiq::Worker
6
+
7
+ sidekiq_options queue: 'work_overseer_test_worker'
8
+ end
9
+
10
+ describe '#call' do
11
+ let(:worker) { WorkOverseerTestWorker.new }
12
+ let(:queue) { WorkOverseerTestWorker.get_sidekiq_options['queue'] }
13
+ let(:args) { [] }
14
+ let(:schedule) { IceCube::Schedule.new(Time.new + 3600) }
15
+
16
+ context 'msg with rq:job key (existing job)' do
17
+ let(:job) { build(:job, schedule: schedule) }
18
+ let(:msg) { { 'rq:job' => job.to_short_key_hash, 'args' => args } }
19
+
20
+ it 'yields once' do
21
+ expect do |b|
22
+ Rekiq::Middleware::WorkOverseer.new
23
+ .call(worker, msg, queue, &b)
24
+ end.to yield_control.once
25
+ end
26
+
27
+ it 'schedules job' do
28
+ Rekiq::Middleware::WorkOverseer.new
29
+ .call(worker, msg, queue) {}
30
+
31
+ expect(WorkOverseerTestWorker.jobs.count).to eq(1)
32
+ end
33
+ end
34
+
35
+ context 'msg without rq:job key' do
36
+ let(:msg) { {} }
37
+
38
+ it 'yields once' do
39
+ expect do |b|
40
+ Rekiq::Middleware::WorkOverseer.new
41
+ .call(worker, msg, queue, &b)
42
+ end.to yield_control.once
43
+ end
44
+ end
45
+
46
+ context 'msg with job retry info and rq:job (existing job)' do
47
+ let(:job) { build(:job, schedule: schedule) }
48
+ let(:msg) { { 'rq:job' => job.to_short_key_hash, 'retry_count' => 0,
49
+ 'args' => args } }
50
+
51
+ it 'yields once' do
52
+ expect do |b|
53
+ Rekiq::Middleware::WorkOverseer.new
54
+ .call(worker, msg, queue, &b)
55
+ end.to yield_control.once
56
+ end
57
+
58
+ it 'does not schedule work' do
59
+ Rekiq::Middleware::WorkOverseer.new
60
+ .call(worker, msg, queue) {}
61
+
62
+ expect(WorkOverseerTestWorker.jobs.count).to eq(0)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rekiq::Scheduler do
4
+ describe '#schedule' do
5
+ context 'given existing worker' do
6
+ class SchedulerTestWorker
7
+ include Sidekiq::Worker
8
+ end
9
+
10
+ let(:worker) { SchedulerTestWorker.name }
11
+ let(:queue) { 'test_queue' }
12
+ let(:args) { [] }
13
+
14
+ context 'given valid job' do
15
+ let(:job) { build(:job) }
16
+
17
+ context 'given not nil string as addon argument' do
18
+ let(:addon) { { 'random_key' => Time.now.to_f } }
19
+
20
+ context 'given initialized scheduler instance' do
21
+ let(:scheduler) do
22
+ Rekiq::Scheduler.new(worker, queue, args, job, addon)
23
+ end
24
+ before { @jid, @work_time = scheduler.schedule }
25
+
26
+ it 'creates sidekiq job' do
27
+ expect(SchedulerTestWorker.jobs.count).to eq(1)
28
+ end
29
+
30
+ it 'add key rq:addon in msg' do
31
+ expect(SchedulerTestWorker.jobs[0].key?('rq:addon')).to eq(true)
32
+ end
33
+
34
+ it 'sets addon value in key rq:addon' do
35
+ expect(SchedulerTestWorker.jobs[0]['rq:addon']).to eq(addon)
36
+ end
37
+ end
38
+ end
39
+
40
+ context 'give nil as addon argument' do
41
+ let(:addon) { nil }
42
+
43
+ context 'given initialized scheduler instance' do
44
+ let(:scheduler) do
45
+ Rekiq::Scheduler.new(worker, queue, args, job, addon)
46
+ end
47
+ before { @jid, @work_time = scheduler.schedule }
48
+
49
+ it 'creates sidekiq job' do
50
+ expect(SchedulerTestWorker.jobs.count).to eq(1)
51
+ end
52
+
53
+ it 'does not set key addon in msg' do
54
+ expect(SchedulerTestWorker.jobs[0].key?('addon')).to eq(false)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+ require 'sidekiq'
3
+ require 'rekiq/worker'
4
+
5
+ describe Rekiq::Worker do
6
+ class ExampleWorker
7
+ include Sidekiq::Worker
8
+ end
9
+
10
+ context 'Class includes Sidekiq::Worker module' do
11
+ it 'responds to perform_recurringly' do
12
+ ExampleWorker.respond_to? :perform_recurringly
13
+ end
14
+
15
+ describe '.perform_recurringly' do
16
+ context 'scheduled one hour from now' do
17
+ let(:time) { Time.now + 3600 }
18
+ let(:schedule) { IceCube::Schedule.new(time) }
19
+ before do
20
+ @jid = ExampleWorker.perform_recurringly(schedule)
21
+ end
22
+
23
+ it 'returns created jid' do
24
+ expect(@jid).not_to be_nil
25
+ end
26
+
27
+ it 'schedules worker' do
28
+ expect(ExampleWorker.jobs.count).to eq(1)
29
+ end
30
+
31
+ it 'schedules worker for one hour from now' do
32
+ expect(ExampleWorker.jobs[0]['at']).to eq(time.to_f)
33
+ end
34
+ end
35
+
36
+ context 'scheduled one hour from now ' \
37
+ 'shift set to minus 5 minutes' do
38
+ let(:time) { Time.now + 3600 }
39
+ let(:schedule) { IceCube::Schedule.new(time) }
40
+ let(:shift) { -5 * 60 }
41
+ before do
42
+ @jid = ExampleWorker.perform_recurringly(schedule) do |options|
43
+ options.shift = shift
44
+ end
45
+ end
46
+
47
+ it 'returns created job id' do
48
+ expect(@jid).not_to be_nil
49
+ end
50
+
51
+ it 'schedules worker' do
52
+ expect(ExampleWorker.jobs.count).to eq(1)
53
+ end
54
+
55
+ it 'yields once' do
56
+ expect do |b|
57
+ ExampleWorker.perform_recurringly(schedule, &b)
58
+ end.to yield_control.once
59
+ end
60
+
61
+ it 'sets shift in job' do
62
+ hash = ExampleWorker.jobs[0]['rq:job']
63
+
64
+ expect(hash['sft']).to eq(shift)
65
+ end
66
+
67
+ it 'schedules worker for one hour minus 5 minutes from now' do
68
+ expect(ExampleWorker.jobs[0]['at']).to eq(time.to_f + shift)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,35 @@
1
+ if ENV['CODECLIMATE_REPO_TOKEN'].nil?
2
+ require 'simplecov'
3
+ SimpleCov.start do
4
+ coverage_dir 'tmp/coverage'
5
+ end
6
+ else
7
+ require "codeclimate-test-reporter"
8
+ CodeClimate::TestReporter.start
9
+ end
10
+
11
+ require 'factory_girl'
12
+ require 'pry'
13
+ require 'sidekiq'
14
+ require 'sidekiq/testing'
15
+ require 'rekiq'
16
+
17
+ # configure sidekiq for testing
18
+ Sidekiq::Testing.fake!
19
+ Sidekiq::Logging.logger = nil
20
+
21
+ RSpec.configure do |config|
22
+ config.include FactoryGirl::Syntax::Methods
23
+
24
+ config.before(:each) do
25
+ Sidekiq::Worker.clear_all
26
+ end
27
+
28
+ config.after(:suite) do
29
+ Sidekiq::Worker.clear_all
30
+ end
31
+ end
32
+
33
+ # configure factory girl
34
+ FactoryGirl.definition_file_paths = %w{./spec/factories}
35
+ FactoryGirl.find_definitions