rekiq 0.9.3 → 1.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.
@@ -0,0 +1,309 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rekiq::Contract do
4
+ describe '.new' do
5
+ context 'when no args' do
6
+ before { @contract = Rekiq::Contract.new }
7
+
8
+ it 'returns an instance of Contract' do
9
+ expect(@contract).not_to be_nil
10
+ end
11
+
12
+ it 'sets attribute work_time_shift as nil' do
13
+ expect(@contract.work_time_shift).to eq(nil)
14
+ end
15
+
16
+ it 'sets schedule_post_work as nil' do
17
+ expect(@contract.schedule_post_work).to eq(nil)
18
+ end
19
+
20
+ it 'sets schedule_expired as nil' do
21
+ expect(@contract.schedule_expired).to eq(nil)
22
+ end
23
+ end
24
+
25
+ context 'when work_time_shift passed as argument' do
26
+ let(:work_time_shift) { 5 * 60 }
27
+ before do
28
+ @contract = Rekiq::Contract.new('work_time_shift' => work_time_shift)
29
+ end
30
+
31
+ it 'sets work_time_shift to passed value' do
32
+ expect(@contract.work_time_shift).to eq(work_time_shift)
33
+ end
34
+ end
35
+
36
+ context 'when schedule_post_work and ' \
37
+ 'schedule_expired passed as true' do
38
+ let(:schedule_post_work) { true }
39
+ let(:schedule_expired) { true }
40
+ before do
41
+ @contract =
42
+ Rekiq::Contract.new \
43
+ 'schedule_post_work' => schedule_post_work,
44
+ 'schedule_expired' => schedule_expired
45
+ end
46
+
47
+ it 'sets schedule_post_work to true' do
48
+ expect(@contract.schedule_post_work).to eq(true)
49
+ end
50
+
51
+ it 'sets schedule_expired to true' do
52
+ expect(@contract.schedule_expired).to eq(true)
53
+ end
54
+ end
55
+ end
56
+
57
+ describe '.to_hash' do
58
+ context 'given an hash returned from Contract#to_hash' do
59
+ let(:original_contract) { build(:contract, :randomized_attributes) }
60
+ let(:hash) { original_contract.to_hash }
61
+ before { @contract = Rekiq::Contract.from_hash(hash) }
62
+
63
+ it 'returns contract instance' do
64
+ expect(@contract.class).to eq(Rekiq::Contract)
65
+ end
66
+
67
+ it 'returns contract with cancel_args value before serialization' do
68
+ expect(@contract.cancel_args).to eq(original_contract.cancel_args)
69
+ end
70
+
71
+ it 'returns contract with addon value before serialization' do
72
+ expect(@contract.addon).to eq(original_contract.addon)
73
+ end
74
+
75
+ it 'returns contract with work_time_shift value before serialization' do
76
+ expect(@contract.work_time_shift).to eq(original_contract.work_time_shift)
77
+ end
78
+
79
+ it 'returns contract with schedule_post_work value before serialization' do
80
+ expect(@contract.schedule_post_work).to eq(original_contract.schedule_post_work)
81
+ end
82
+
83
+ it 'returns contract with schedule_expired value before serialization' do
84
+ expect(@contract.schedule_expired).to eq(original_contract.schedule_expired)
85
+ end
86
+
87
+ it 'returns contract with work_time_tolerance value before serialization' do
88
+ expect(@contract.work_time_tolerance).to eq(original_contract.work_time_tolerance)
89
+ end
90
+
91
+ it 'returns contract with schedule value before serialization' do
92
+ expect(@contract.schedule.class).to eq(original_contract.schedule.class)
93
+ end
94
+
95
+ it 'returns contract with working schedule' do
96
+ time = Time.now
97
+ expect(@contract.schedule.next_occurrence(time))
98
+ .to eq(original_contract.schedule.next_occurrence(time))
99
+ end
100
+ end
101
+ end
102
+
103
+ describe '#to_hash' do
104
+ context 'given contract instance' do
105
+ let(:contract) { build(:contract, :randomized_attributes) }
106
+ before { @val = contract.to_hash }
107
+
108
+ it 'returns an hash' do
109
+ expect(@val.class).to eq(Hash)
110
+ end
111
+
112
+ it 'returns hash with Marshalled schedule under key s' do
113
+ # TODO: expect(@val[0]).to eq(Marshal.dump(contract.schedule))
114
+ end
115
+
116
+ it 'returns hash with cancel_args under key ca' do
117
+ expect(@val['ca']).to eq(contract.cancel_args)
118
+ end
119
+
120
+ it 'returns hash with addon value under key ao' do
121
+ expect(@val['ao']).to eq(contract.addon)
122
+ end
123
+
124
+ it 'returns hash with schedule_post_work value under key pw' do
125
+ expect(@val['pw']).to eq(contract.schedule_post_work)
126
+ end
127
+
128
+ it 'returns hash with work_time_shift value under key ws' do
129
+ expect(@val['ws']).to eq(contract.work_time_shift)
130
+ end
131
+
132
+ it 'returns hash with work_time_tolerance value under key wt' do
133
+ expect(@val['wt']).to eq(contract.work_time_tolerance)
134
+ end
135
+
136
+ it 'returns hash with schedule_expired value under key se' do
137
+ expect(@val['se']).to eq(contract.schedule_expired)
138
+ end
139
+ end
140
+ end
141
+
142
+ describe '#initial_work_time' do
143
+ context 'when invoked with current_time' do
144
+ let(:current_time) { Time.now }
145
+ let(:work_time_shift) { nil }
146
+ let(:work_time_tolerance) { nil }
147
+ let(:schedule_rrule) { nil }
148
+ let(:schedule) do
149
+ IceCube::Schedule.new(start_time) do |s|
150
+ s.rrule(schedule_rrule) unless schedule_rrule.nil?
151
+ end
152
+ end
153
+ let(:contract) do
154
+ build :contract,
155
+ schedule: schedule,
156
+ work_time_shift: work_time_shift,
157
+ work_time_tolerance: work_time_tolerance,
158
+ schedule_expired: schedule_expired
159
+ end
160
+ before { @work_time = contract.initial_work_time(current_time) }
161
+
162
+ context 'with non recurring schedule with start_time in future' do
163
+ let(:exceed_by) { 10 * 60 }
164
+ let(:start_time) { current_time + exceed_by }
165
+
166
+ context 'schedule_expired as true' do
167
+ let(:schedule_expired) { true }
168
+
169
+ it 'returns start_time' do
170
+ expect(@work_time).to eq(start_time)
171
+ end
172
+
173
+ context 'work_time_shift to time between current and start_time' do
174
+ let(:work_time_shift) { - exceed_by / 2 }
175
+
176
+ it 'returns shifted start_time' do
177
+ expect(@work_time).to eq(start_time + work_time_shift)
178
+ end
179
+ end
180
+
181
+ context 'work_time_shift to time after start_time' do
182
+ let(:work_time_shift) { exceed_by * 2 }
183
+
184
+ it 'returns shifted start_time' do
185
+ expect(@work_time).to eq(start_time + work_time_shift)
186
+ end
187
+ end
188
+
189
+ context 'work_time_shift to time before current_time' do
190
+ let(:work_time_shift) { - (exceed_by + 60) }
191
+
192
+ it 'returns shifted start_time' do
193
+ expect(@work_time).to eq(start_time + work_time_shift)
194
+ end
195
+ end
196
+ end
197
+
198
+ context 'schedule expired as false' do
199
+ let(:schedule_expired) { false }
200
+
201
+ it 'returns start_time' do
202
+ expect(@work_time).to eq(start_time)
203
+ end
204
+
205
+ context 'work_time_shift to time between current and start_time' do
206
+ let(:work_time_shift) { - exceed_by / 2 }
207
+
208
+ it 'returns shifted start_time' do
209
+ expect(@work_time).to eq(start_time + work_time_shift)
210
+ end
211
+ end
212
+
213
+ context 'work_time_shift to time after start_time' do
214
+ let(:work_time_shift) { 60 }
215
+
216
+ it 'returns shifted start_time' do
217
+ expect(@work_time).to eq(start_time + work_time_shift)
218
+ end
219
+ end
220
+
221
+ context 'work_time_shift to time before current' do
222
+ let(:work_time_shift) { - (exceed_by + 60) }
223
+
224
+ it 'returns nil' do
225
+ expect(@work_time).to be_nil
226
+ end
227
+ end
228
+
229
+ context 'work_time_tolerance as 10 minutes' do
230
+ let(:work_time_tolerance) { 10 * 60 }
231
+
232
+ it 'returns start_time' do
233
+ expect(@work_time).to eq(start_time)
234
+ end
235
+
236
+ context 'work_time_shift to time between current and start_time' do
237
+ let(:work_time_shift) { - exceed_by / 2 }
238
+
239
+ it 'returns shifted start_time' do
240
+ expect(@work_time).to eq(start_time + work_time_shift)
241
+ end
242
+ end
243
+
244
+ context 'work_time_shift to time after start_time' do
245
+ let(:work_time_shift) { 60 }
246
+
247
+ it 'returns shifted start_time' do
248
+ expect(@work_time).to eq(start_time + work_time_shift)
249
+ end
250
+ end
251
+
252
+ context 'work_time_shift to time inside work_time_tolerance' do
253
+ let(:work_time_shift) { - (exceed_by + work_time_tolerance / 2) }
254
+
255
+ it 'returns shifted start_time' do
256
+ expect(@work_time).to eq(start_time + work_time_shift)
257
+ end
258
+ end
259
+
260
+ context 'work_time_shift to time before work_time_tolerance' do
261
+ let(:work_time_shift) { - (exceed_by + work_time_tolerance * 2) }
262
+
263
+ it 'returns nil' do
264
+ expect(@work_time).to be_nil
265
+ end
266
+ end
267
+ end
268
+ end
269
+ end
270
+
271
+ context 'non recurring schedule with start_time bellow current_time' do
272
+ let(:expired_by) { 10 * 60 }
273
+ let(:start_time) { current_time - expired_by }
274
+
275
+ context 'schedule expired as true' do
276
+ let(:schedule_expired) { true }
277
+
278
+ it 'returns nil' do
279
+ expect(@work_time).to be_nil
280
+ end
281
+
282
+ context 'work_time_shift to time after current_time' do
283
+ let(:work_time_shift) { expired_by * 2 }
284
+
285
+ it 'returns shifted start_time' do
286
+ expect(@work_time).to eq(start_time + work_time_shift)
287
+ end
288
+ end
289
+ end
290
+
291
+ context 'schedule_expired as false' do
292
+ let(:schedule_expired) { false }
293
+
294
+ it 'returns nil' do
295
+ expect(@work_time).to be_nil
296
+ end
297
+
298
+ context 'work_time_tolerance is above calculated expired work_time' do
299
+ let(:work_time_tolerance) { expired_by * 2 }
300
+
301
+ it 'returns start_time' do
302
+ expect(@work_time).to eq(start_time)
303
+ end
304
+ end
305
+ end
306
+ end
307
+ end
308
+ end
309
+ end
@@ -8,22 +8,21 @@ describe Rekiq::Middleware::Utils do
8
8
  describe '#call' do
9
9
  let(:worker) { UtilsTestWorker.new }
10
10
  let(:queue) { UtilsTestWorker.get_sidekiq_options['queue'] }
11
+ let(:utils) { Rekiq::Middleware::Utils.new }
11
12
  let(:scheduled_work_time) { Time.at(Time.now.to_f) }
12
13
 
13
14
  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 } }
15
+ context 'msg hash contains keys rq:ctr and rq:at' do
16
+ let(:msg) { { 'rq:ctr' => nil, 'rq:at' => scheduled_work_time.to_f } }
16
17
 
17
18
  it 'yields passed block' do
18
19
  expect do |b|
19
- Rekiq::Middleware::Utils.new
20
- .call(worker, msg, queue, &b)
20
+ utils.call(worker, msg, queue, &b)
21
21
  end.to yield_control.once
22
22
  end
23
23
 
24
24
  it 'sets scheduled_work_time attribute in worker' do
25
- Rekiq::Middleware::Utils.new
26
- .call(worker, msg, queue) {}
25
+ utils.call(worker, msg, queue) {}
27
26
 
28
27
  expect(worker.scheduled_work_time).to eq(scheduled_work_time.utc)
29
28
  end
@@ -34,12 +33,11 @@ describe Rekiq::Middleware::Utils do
34
33
 
35
34
  it 'yields passed block' do
36
35
  expect do |b|
37
- Rekiq::Middleware::Utils.new
38
- .call(worker, msg, queue, &b)
36
+ utils.call(worker, msg, queue, &b)
39
37
  end.to yield_control.once
40
38
  end
41
39
 
42
- it 'scheduled_work_time remaing unchanged' do
40
+ it 'scheduled_work_time is unchanged (nil)' do
43
41
  expect(worker.scheduled_work_time).to be_nil
44
42
  end
45
43
  end
@@ -19,19 +19,22 @@ describe Rekiq::Middleware::WorkOverseer do
19
19
  end
20
20
 
21
21
  describe '#call' do
22
- let(:args) { [] }
23
- let(:schedule) { IceCube::Schedule.new(Time.new + 3600) }
24
- let(:job) { build(:job, schedule: schedule) }
25
- let(:overseer) { Rekiq::Middleware::WorkOverseer.new }
22
+ let(:args) { [] }
23
+ let(:schedule) { IceCube::Schedule.new(Time.new + 3600) }
24
+ let(:overseer) { Rekiq::Middleware::WorkOverseer.new }
25
+ let(:cancel_args) { nil }
26
+ let(:contract) do
27
+ build :contract, schedule: schedule, cancel_args: cancel_args
28
+ end
26
29
 
27
- context 'worker does not have rekiq_cancel_method set' do
28
- let(:worker) { WorkOverseerTestWorker.new }
29
- let(:queue) { WorkOverseerTestWorker.get_sidekiq_options['queue'] }
30
+ context 'worker without rekiq_cancel_method configured' do
31
+ let(:worker) { WorkOverseerTestWorker.new }
32
+ let(:queue) { WorkOverseerTestWorker.get_sidekiq_options['queue'] }
30
33
 
31
- context 'msg with rq:job key (existing job), ' \
32
- 'with rq:schdlr key (value is irrelevant)' do
34
+ context 'msg with rq:ctr key (existing contract), ' \
35
+ 'with rq:sdl key (value is irrelevant)' do
33
36
  let(:msg) do
34
- { 'rq:job' => job.to_array, 'args' => args, 'rq:schdlr' => nil }
37
+ { 'rq:ctr' => contract.to_hash, 'args' => args, 'rq:sdl' => nil }
35
38
  end
36
39
 
37
40
  it 'yields once' do
@@ -40,20 +43,20 @@ describe Rekiq::Middleware::WorkOverseer do
40
43
  end.to yield_control.once
41
44
  end
42
45
 
43
- it 'schedules job' do
46
+ it 'schedules worker' do
44
47
  overseer.call(worker, msg, queue) {}
45
48
 
46
49
  expect(WorkOverseerTestWorker.jobs.count).to eq(1)
47
50
  end
48
51
 
49
- it 'removes key rq:schdlr from message after invocation' do
52
+ it 'removes key rq:sdl from message after invocation' do
50
53
  overseer.call(worker, msg, queue) {}
51
54
 
52
- expect(msg.key?('rq:schdlr')).to eq(false)
55
+ expect(msg.key?('rq:sdl')).to eq(false)
53
56
  end
54
57
  end
55
58
 
56
- context 'msg without rq:job key' do
59
+ context 'msg without rq:ctr key' do
57
60
  let(:msg) { {} }
58
61
 
59
62
  it 'yields once' do
@@ -61,10 +64,16 @@ describe Rekiq::Middleware::WorkOverseer do
61
64
  overseer.call(worker, msg, queue, &b)
62
65
  end.to yield_control.once
63
66
  end
67
+
68
+ it 'does not schedule worker' do
69
+ overseer.call(worker, msg, queue) {}
70
+
71
+ expect(WorkOverseerTestWorker.jobs.count).to eq(0)
72
+ end
64
73
  end
65
74
 
66
- context 'msg without rq:schdlr and rq:job (existing job)' do
67
- let(:msg) { { 'rq:job' => job.to_array, 'args' => args } }
75
+ context 'msg without key rq:sdl but with key rq:ctr' do
76
+ let(:msg) { { 'rq:ctr' => contract.to_hash, 'args' => args } }
68
77
 
69
78
  it 'yields once' do
70
79
  expect do |b|
@@ -80,51 +89,64 @@ describe Rekiq::Middleware::WorkOverseer do
80
89
  end
81
90
  end
82
91
 
83
- context 'worker has rekiq_cancel_method method set' do
92
+ context 'worker with rekiq_cancel_method configured' do
84
93
  let(:worker) { WorkOverseerCancelTestWorker.new }
85
94
  let(:queue) { WorkOverseerCancelTestWorker.get_sidekiq_options['queue'] }
86
95
 
87
- context 'msg with rq:ca key with value to cancel worker' do
96
+ context 'msg with keys rc:ctr and rc:sdl' do
88
97
  let(:msg) do
89
- { 'rq:job' => job.to_array, 'args' => args, 'rq:ca' => true }
98
+ { 'rq:ctr' => contract.to_hash, 'args' => args, 'rq:sdl' => nil }
90
99
  end
91
100
 
92
- it 'does not yield' do
93
- expect do |b|
94
- overseer.call(worker, msg, queue, &b)
95
- end.not_to yield_control
96
- end
101
+ context 'work is cancelled by cancel method' do
102
+ let(:cancel_args) { true }
97
103
 
98
- it 'does not schedule worker' do
99
- expect(WorkOverseerCancelTestWorker.jobs.count).to eq(0)
100
- end
101
- end
104
+ it 'does not yield' do
105
+ expect do |b|
106
+ overseer.call(worker, msg, queue, &b)
107
+ end.not_to yield_control
108
+ end
102
109
 
103
- context 'msg with rq:ca key with value that does not cancel worker' do
104
- let(:msg) do
105
- { 'rq:job' => job.to_array, 'args' => args, 'rq:ca' => false }
106
- end
110
+ it 'does not schedule next work' do
111
+ overseer.call(worker, msg, queue) {}
107
112
 
108
- it 'yields given block' do
109
- expect do |b|
110
- overseer.call(worker, msg, queue, &b)
111
- end.to yield_control.once
113
+ expect(WorkOverseerCancelTestWorker.jobs.count).to eq(0)
114
+ end
112
115
  end
113
116
 
114
- it 'does not schedule worker' do
115
- expect(WorkOverseerCancelTestWorker.jobs.count).to eq(0)
116
- end
117
- end
117
+ context 'work is not cancelled by cancel method' do
118
+ let(:cancel_args) { false }
118
119
 
119
- context 'msg with rq:ca key with different arity from cancel method' do
120
- let(:msg) do
121
- { 'rq:job' => job.to_array, 'args' => args, 'rq:ca' => [true, true] }
120
+ it 'yields given block' do
121
+ expect do |b|
122
+ overseer.call(worker, msg, queue, &b)
123
+ end.to yield_control.once
124
+ end
125
+
126
+ it 'it schedules work' do
127
+ overseer.call(worker, msg, queue) {}
128
+
129
+ expect(WorkOverseerCancelTestWorker.jobs.count).to eq(1)
130
+ end
131
+
132
+ it 'removes key rq:sdl from message after invocation' do
133
+ overseer.call(worker, msg, queue) {}
134
+
135
+ expect(msg.key?('rq:sdl')).to eq(false)
136
+ end
122
137
  end
123
138
 
124
- it 'raises error' do
125
- expect do |b|
126
- overseer.call(worker, msg, queue, &b)
127
- end.to raise_error
139
+ context 'contract with incorrect arity of cancel_args' do
140
+ let(:cancel_args) { [true, false] }
141
+ let(:msg) do
142
+ { 'rq:ctr' => contract.to_hash, 'args' => args }
143
+ end
144
+
145
+ it 'raises error' do
146
+ expect do |b|
147
+ overseer.call(worker, msg, queue, &b)
148
+ end.to raise_error
149
+ end
128
150
  end
129
151
  end
130
152
  end
@@ -1,75 +1,27 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Rekiq::Scheduler do
4
- describe '#schedule' do
4
+ describe '#schedule_initial_work' do
5
5
  context 'given existing worker' do
6
6
  class SchedulerTestWorker
7
7
  include Sidekiq::Worker
8
8
  end
9
9
 
10
- let(:worker) { SchedulerTestWorker.name }
11
- let(:queue) { 'test_queue' }
12
- let(:args) { [] }
13
- let(:addon) { nil }
14
- let(:c_args) { nil }
10
+ let(:worker_name) { SchedulerTestWorker.name }
11
+ let(:queue) { 'test_queue' }
12
+ let(:args) { [] }
15
13
  let(:scheduler) do
16
- Rekiq::Scheduler.new(worker, queue, args, job, addon, c_args)
14
+ Rekiq::Scheduler.new(worker_name, queue, args, contract)
17
15
  end
18
- before { @jid, @work_time = scheduler.schedule }
16
+ before { @jid, @work_time = scheduler.schedule_initial_work }
19
17
 
20
- context 'given valid job' do
21
- let(:job) { build(:job) }
22
-
23
- context 'give nil as addon argument' do
24
- it 'creates sidekiq job' do
25
- expect(SchedulerTestWorker.jobs.count).to eq(1)
26
- end
27
-
28
- it 'does not set key rq:addon in msg' do
29
- expect(SchedulerTestWorker.jobs[0].key?('rq:addon')).to eq(false)
30
- end
31
- end
32
-
33
- context 'given not nil string as addon argument' do
34
- let(:addon) { { 'random_key' => Time.now.to_f } }
35
-
36
- it 'creates sidekiq job' do
37
- expect(SchedulerTestWorker.jobs.count).to eq(1)
38
- end
39
-
40
- it 'add key rq:addon in msg' do
41
- expect(SchedulerTestWorker.jobs[0].key?('rq:addon')).to eq(true)
42
- end
43
-
44
- it 'sets addon value in key rq:addon' do
45
- expect(SchedulerTestWorker.jobs[0]['rq:addon']).to eq(addon)
46
- end
47
- end
18
+ context 'given valid contract' do
19
+ let(:contract) { build :contract }
48
20
 
49
21
  context 'given nil as rekiq_cancel_args' do
50
22
  it 'creates sidekiq job' do
51
23
  expect(SchedulerTestWorker.jobs.count).to eq(1)
52
24
  end
53
-
54
- it 'does not set key rq:ca in msg' do
55
- expect(SchedulerTestWorker.jobs[0].key?('rq:ca')).to eq(false)
56
- end
57
- end
58
-
59
- context 'given non empty array as rekiq_cancel_args' do
60
- let(:c_args) { [1, 2, 3] }
61
-
62
- it 'creates sidekiq job' do
63
- expect(SchedulerTestWorker.jobs.count).to eq(1)
64
- end
65
-
66
- it 'sets key rq:ca in msg' do
67
- expect(SchedulerTestWorker.jobs[0].key?('rq:ca')).to eq(true)
68
- end
69
-
70
- it 'sets key rq:ca in msg with passed value' do
71
- expect(SchedulerTestWorker.jobs[0]['rq:ca']).to eq(c_args)
72
- end
73
25
  end
74
26
  end
75
27
  end