powerhome-resque-status 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,358 @@
1
+ require 'test_helper'
2
+
3
+ class TestResquePluginsStatus < Minitest::Test
4
+
5
+ describe "Resque::Plugins::Status" do
6
+ before do
7
+ Resque.redis.flushall
8
+ end
9
+
10
+ describe ".create" do
11
+ describe "not inline" do
12
+ before do
13
+ @uuid = WorkingJob.create('num' => 100)
14
+ end
15
+
16
+ it "add the job to the queue" do
17
+ assert_equal 1, Resque.size(:statused)
18
+ end
19
+
20
+ it "set the queued object to the current class" do
21
+ job = Resque.pop(:statused)
22
+ assert_equal @uuid, job['args'].first
23
+ assert_equal "WorkingJob", job['class']
24
+ end
25
+
26
+ it "add the uuid to the statuses" do
27
+ assert_includes Resque::Plugins::Status::Hash.status_ids, @uuid
28
+ end
29
+
30
+ it "return a UUID" do
31
+ assert_match(/^\w{32}$/, @uuid)
32
+ end
33
+ end
34
+
35
+ describe "inline" do
36
+ before do
37
+ Resque.stubs(:inline?).returns(true)
38
+ end
39
+
40
+ it "not queue a job" do
41
+ @uuid = WorkingJob.create('num' => 100)
42
+ assert_equal 0, Resque.size(:statused)
43
+ end
44
+
45
+ it "call perform" do
46
+ WorkingJob.any_instance.expects(:perform).once
47
+ @uuid = WorkingJob.create('num' => 100)
48
+ end
49
+ end
50
+ end
51
+
52
+ describe ".create with a failing before_enqueue hook" do
53
+ before do
54
+ @size = Resque.size(:statused)
55
+ @status_ids_size = Resque::Plugins::Status::Hash.status_ids.length
56
+ @res = NeverQueuedJob.create(:num => 100)
57
+ end
58
+
59
+ it "return nil" do
60
+ assert_equal nil, @res
61
+ end
62
+
63
+ it "not create a status" do
64
+ assert_equal @size, Resque.size(:statused)
65
+ end
66
+
67
+ it "not add the uuid to the statuses" do
68
+ assert_equal @status_ids_size, Resque::Plugins::Status::Hash.status_ids.length
69
+ end
70
+ end
71
+
72
+ describe ".scheduled" do
73
+ before do
74
+ @job_args = {'num' => 100}
75
+ @uuid = WorkingJob.scheduled(:queue_name, WorkingJob, @job_args)
76
+ end
77
+
78
+ it "create the job with the provided arguments" do
79
+ job = Resque.pop(:queue_name)
80
+ assert_equal @job_args, job['args'].last
81
+ end
82
+ end
83
+
84
+ describe ".enqueue" do
85
+ it "delegate to enqueue_to, filling in the queue from the class" do
86
+ @uuid = BasicJob.enqueue(WorkingJob, :num => 100)
87
+ @payload = Resque.pop(:statused)
88
+ assert_equal "WorkingJob", @payload['class']
89
+ end
90
+ end
91
+
92
+ describe ".enqueue_to" do
93
+ before do
94
+ @uuid = BasicJob.enqueue_to(:new_queue, WorkingJob, :num => 100)
95
+ @payload = Resque.pop(:new_queue)
96
+ end
97
+
98
+ it "add the job with the specific class to the queue" do
99
+ assert_equal "WorkingJob", @payload['class']
100
+ end
101
+
102
+ it "add the arguments to the options hash" do
103
+ assert_equal @uuid, @payload['args'].first
104
+ end
105
+
106
+ it "add the uuid to the statuses" do
107
+ assert_includes Resque::Plugins::Status::Hash.status_ids, @uuid
108
+ end
109
+
110
+ it "return UUID" do
111
+ assert_match(/^\w{32}$/, @uuid)
112
+ end
113
+
114
+ end
115
+
116
+ describe ".dequeue" do
117
+ before do
118
+ @uuid1 = BasicJob.enqueue(WorkingJob, :num => 100)
119
+ @uuid2 = BasicJob.enqueue(WorkingJob, :num => 100)
120
+ end
121
+
122
+ it "dequeue the job with the uuid from the correct queue" do
123
+ size = Resque.size(:statused)
124
+ BasicJob.dequeue(WorkingJob, @uuid2)
125
+ assert_equal size-1, Resque.size(:statused)
126
+ end
127
+ it "not dequeue any jobs with different uuids for same class name" do
128
+ BasicJob.dequeue(WorkingJob, @uuid2)
129
+ assert_equal @uuid1, Resque.pop(:statused)['args'].first
130
+ end
131
+ end
132
+
133
+ describe ".perform" do
134
+ let(:expectation) { }
135
+
136
+ before do
137
+ expectation
138
+ @uuid = WorkingJob.create(:num => 100)
139
+ @payload = Resque.pop(:statused)
140
+ @performed = WorkingJob.perform(*@payload['args'])
141
+ end
142
+
143
+ it "load load a new instance of the klass" do
144
+ assert @performed.is_a?(WorkingJob)
145
+ end
146
+
147
+ it "set the uuid" do
148
+ assert_equal @uuid, @performed.uuid
149
+ end
150
+
151
+ it "set the status" do
152
+ assert @performed.status.is_a?(Resque::Plugins::Status::Hash)
153
+ assert_equal 'WorkingJob({"num"=>100})', @performed.status.name
154
+ end
155
+
156
+ describe "before" do
157
+ let(:expectation) { WorkingJob.any_instance.expects(:perform).once }
158
+ it("call perform on the inherited class") {}
159
+ end
160
+ end
161
+
162
+ describe "manually failing a job" do
163
+ before do
164
+ @uuid = FailureJob.create(:num => 100)
165
+ @payload = Resque.pop(:statused)
166
+ @performed = FailureJob.perform(*@payload['args'])
167
+ end
168
+
169
+ it "load load a new instance of the klass" do
170
+ assert @performed.is_a?(FailureJob)
171
+ end
172
+
173
+ it "set the uuid" do
174
+ assert_equal @uuid, @performed.uuid
175
+ end
176
+
177
+ it "set the status" do
178
+ assert @performed.status.is_a?(Resque::Plugins::Status::Hash)
179
+ assert_equal 'FailureJob({"num"=>100})', @performed.status.name
180
+ end
181
+
182
+ it "be failed" do
183
+ assert_match(/failure/, @performed.status.message)
184
+ assert @performed.status.failed?
185
+ end
186
+
187
+ end
188
+
189
+ describe "killing a job" do
190
+ before do
191
+ @uuid = KillableJob.create(:num => 100)
192
+ @payload = Resque.pop(:statused)
193
+ Resque::Plugins::Status::Hash.kill(@uuid)
194
+ assert_includes Resque::Plugins::Status::Hash.kill_ids, @uuid
195
+ @performed = KillableJob.perform(*@payload['args'])
196
+ @status = Resque::Plugins::Status::Hash.get(@uuid)
197
+ end
198
+
199
+ it "set the status to killed" do
200
+ assert @status.killed?
201
+ assert !@status.completed?
202
+ end
203
+
204
+ it "only perform iterations up to kill" do
205
+ assert_equal 1, Resque.redis.get("#{@uuid}:iterations").to_i
206
+ end
207
+
208
+ it "not persist the kill key" do
209
+ refute_includes Resque::Plugins::Status::Hash.kill_ids, @uuid
210
+ end
211
+ end
212
+
213
+ describe "killing all jobs" do
214
+ before do
215
+ @uuid1 = KillableJob.create(:num => 100)
216
+ @uuid2 = KillableJob.create(:num => 100)
217
+
218
+ Resque::Plugins::Status::Hash.killall
219
+
220
+ assert_includes Resque::Plugins::Status::Hash.kill_ids, @uuid1
221
+ assert_includes Resque::Plugins::Status::Hash.kill_ids, @uuid2
222
+
223
+ @payload1 = Resque.pop(:statused)
224
+ @payload2 = Resque.pop(:statused)
225
+
226
+ @performed = KillableJob.perform(*@payload1['args'])
227
+ @performed = KillableJob.perform(*@payload2['args'])
228
+
229
+ @status1, @status2 = Resque::Plugins::Status::Hash.mget([@uuid1, @uuid2])
230
+ end
231
+
232
+ it "set the status to killed" do
233
+ assert @status1.killed?
234
+ assert !@status1.completed?
235
+ assert @status2.killed?
236
+ assert !@status2.completed?
237
+ end
238
+
239
+ it "only perform iterations up to kill" do
240
+ assert_equal 1, Resque.redis.get("#{@uuid1}:iterations").to_i
241
+ assert_equal 1, Resque.redis.get("#{@uuid2}:iterations").to_i
242
+ end
243
+
244
+ it "not persist the kill key" do
245
+ refute_includes Resque::Plugins::Status::Hash.kill_ids, @uuid1
246
+ refute_includes Resque::Plugins::Status::Hash.kill_ids, @uuid2
247
+ end
248
+
249
+ end
250
+
251
+ describe "invoking killall jobs to kill a range" do
252
+ before do
253
+ @uuid1 = KillableJob.create(:num => 100)
254
+ @uuid2 = KillableJob.create(:num => 100)
255
+
256
+ Resque::Plugins::Status::Hash.killall(0,0) # only @uuid2 it be killed
257
+
258
+ refute_includes Resque::Plugins::Status::Hash.kill_ids, @uuid1
259
+ assert_includes Resque::Plugins::Status::Hash.kill_ids, @uuid2
260
+
261
+ @payload1 = Resque.pop(:statused)
262
+ @payload2 = Resque.pop(:statused)
263
+
264
+ @performed = KillableJob.perform(*@payload1['args'])
265
+ @performed = KillableJob.perform(*@payload2['args'])
266
+
267
+ @status1, @status2 = Resque::Plugins::Status::Hash.mget([@uuid1, @uuid2])
268
+ end
269
+
270
+ it "set the status to killed" do
271
+ assert !@status1.killed?
272
+ assert @status1.completed?
273
+ assert @status2.killed?
274
+ assert !@status2.completed?
275
+ end
276
+
277
+ it "only perform iterations up to kill" do
278
+ assert_equal 100, Resque.redis.get("#{@uuid1}:iterations").to_i
279
+ assert_equal 1, Resque.redis.get("#{@uuid2}:iterations").to_i
280
+ end
281
+
282
+ it "not persist the kill key" do
283
+ refute_includes Resque::Plugins::Status::Hash.kill_ids, @uuid1
284
+ refute_includes Resque::Plugins::Status::Hash.kill_ids, @uuid2
285
+ end
286
+
287
+ end
288
+
289
+ describe "with an invoked job" do
290
+ before do
291
+ @job = WorkingJob.new('123', {'num' => 100})
292
+ end
293
+
294
+ describe "#at" do
295
+ before do
296
+ @job.at(50, 100, "At 50%")
297
+ end
298
+
299
+ it "calculate percent" do
300
+ assert_equal 50, @job.status.pct_complete
301
+ end
302
+
303
+ it "set status" do
304
+ assert @job.status.working?
305
+ end
306
+
307
+ it "save message" do
308
+ assert_equal "At 50%", @job.status.message
309
+ end
310
+ end
311
+
312
+ describe "#failed" do
313
+ before do
314
+ @job.failed("OOOOPS!")
315
+ end
316
+
317
+ it "set status" do
318
+ assert @job.status.failed?
319
+ end
320
+
321
+ it "set message" do
322
+ assert_equal "OOOOPS!", @job.status.message
323
+ end
324
+ end
325
+
326
+ describe "#completed" do
327
+ before do
328
+ @job.completed
329
+ end
330
+
331
+ it "set status" do
332
+ assert @job.status.completed?
333
+ end
334
+
335
+ it "set message" do
336
+ assert_match(/complete/i, @job.status.message)
337
+ end
338
+
339
+ end
340
+
341
+ describe "#safe_perform!" do
342
+ before do
343
+ @job = ErrorJob.new("123")
344
+ assert_raises(RuntimeError) do
345
+ @job.safe_perform!
346
+ end
347
+ end
348
+
349
+ it "set status as failed" do
350
+ assert @job.status.failed?
351
+ end
352
+ end
353
+
354
+ end
355
+
356
+ end
357
+
358
+ end
@@ -0,0 +1,222 @@
1
+ require 'test_helper'
2
+
3
+ class TestResquePluginsStatusHash < Minitest::Test
4
+
5
+ describe "Resque::Plugins::Status::Hash" do
6
+ before do
7
+ Resque.redis.flushall
8
+ Resque::Plugins::Status::Hash.expire_in = nil
9
+ @uuid = Resque::Plugins::Status::Hash.create(Resque::Plugins::Status::Hash.generate_uuid)
10
+ Resque::Plugins::Status::Hash.set(@uuid, "my status")
11
+ @uuid_with_json = Resque::Plugins::Status::Hash.create(Resque::Plugins::Status::Hash.generate_uuid, {"im" => "json"})
12
+ end
13
+
14
+ describe ".get" do
15
+ it "return the status as a Resque::Plugins::Status::Hash for the uuid" do
16
+ status = Resque::Plugins::Status::Hash.get(@uuid)
17
+ assert status.is_a?(Resque::Plugins::Status::Hash)
18
+ assert_equal 'my status', status.message
19
+ end
20
+
21
+ it "return nil if the status is not set" do
22
+ assert_nil Resque::Plugins::Status::Hash.get('invalid_uuid')
23
+ end
24
+
25
+ it "decode encoded json" do
26
+ assert_equal("json", Resque::Plugins::Status::Hash.get(@uuid_with_json)['im'])
27
+ end
28
+ end
29
+
30
+ describe ".mget" do
31
+ it "return statuses as array of Resque::Plugins::Status::Hash for the uuids" do
32
+ uuid2 = Resque::Plugins::Status::Hash.create(Resque::Plugins::Status::Hash.generate_uuid)
33
+ Resque::Plugins::Status::Hash.set(uuid2, "my status2")
34
+ statuses = Resque::Plugins::Status::Hash.mget([@uuid, uuid2])
35
+ assert_equal 2, statuses.size
36
+ assert statuses.all?{|s| s.is_a?(Resque::Plugins::Status::Hash) }
37
+ assert_equal ['my status', 'my status2'], statuses.map(&:message)
38
+ end
39
+
40
+ it "return nil if a status is not set" do
41
+ statuses = Resque::Plugins::Status::Hash.mget(['invalid_uuid', @uuid])
42
+ assert_equal 2, statuses.size
43
+ assert_nil statuses[0]
44
+ assert statuses[1].is_a?(Resque::Plugins::Status::Hash)
45
+ assert_equal 'my status', statuses[1].message
46
+ end
47
+
48
+ it "decode encoded json" do
49
+ assert_equal ['json'],
50
+ Resque::Plugins::Status::Hash.mget([@uuid_with_json]).map{|h| h['im']}
51
+ end
52
+ end
53
+
54
+ describe ".set" do
55
+
56
+ it "set the status for the uuid" do
57
+ assert Resque::Plugins::Status::Hash.set(@uuid, "updated")
58
+ assert_equal "updated", Resque::Plugins::Status::Hash.get(@uuid).message
59
+ end
60
+
61
+ it "return the status" do
62
+ assert Resque::Plugins::Status::Hash.set(@uuid, "updated").is_a?(Resque::Plugins::Status::Hash)
63
+ end
64
+
65
+ end
66
+
67
+ describe ".create" do
68
+ it "add an item to a key set" do
69
+ before = Resque::Plugins::Status::Hash.status_ids.length
70
+ Resque::Plugins::Status::Hash.create(Resque::Plugins::Status::Hash.generate_uuid)
71
+ after = Resque::Plugins::Status::Hash.status_ids.length
72
+ assert_equal 1, after - before
73
+ end
74
+
75
+ it "return a uuid" do
76
+ assert_match(/^\w{32}$/, Resque::Plugins::Status::Hash.create(Resque::Plugins::Status::Hash.generate_uuid))
77
+ end
78
+
79
+ it "store any status passed" do
80
+ uuid = Resque::Plugins::Status::Hash.create(Resque::Plugins::Status::Hash.generate_uuid, "initial status")
81
+ status = Resque::Plugins::Status::Hash.get(uuid)
82
+ assert status.is_a?(Resque::Plugins::Status::Hash)
83
+ assert_equal "initial status", status.message
84
+ end
85
+
86
+ it "expire keys if expire_in is set" do
87
+ Resque::Plugins::Status::Hash.expire_in = 1
88
+ uuid = Resque::Plugins::Status::Hash.create(Resque::Plugins::Status::Hash.generate_uuid, "new status")
89
+ assert_includes Resque::Plugins::Status::Hash.status_ids, uuid
90
+ assert_equal "new status", Resque::Plugins::Status::Hash.get(uuid).message
91
+ sleep 2
92
+ Resque::Plugins::Status::Hash.create(Resque::Plugins::Status::Hash.generate_uuid)
93
+ refute_includes Resque::Plugins::Status::Hash.status_ids, uuid
94
+ assert_nil Resque::Plugins::Status::Hash.get(uuid)
95
+ end
96
+
97
+ it "store the options for the job created" do
98
+ uuid = Resque::Plugins::Status::Hash.create(Resque::Plugins::Status::Hash.generate_uuid, "new", :options => {'test' => '123'})
99
+ assert uuid
100
+ status = Resque::Plugins::Status::Hash.get(uuid)
101
+ assert status.is_a?(Resque::Plugins::Status::Hash)
102
+ assert_equal '123', status.options['test']
103
+ end
104
+ end
105
+
106
+ describe ".clear" do
107
+ before do
108
+ Resque::Plugins::Status::Hash.clear
109
+ end
110
+
111
+ it "clear any statuses" do
112
+ assert_nil Resque::Plugins::Status::Hash.get(@uuid)
113
+ end
114
+
115
+ it "clear any recent statuses" do
116
+ assert Resque::Plugins::Status::Hash.status_ids.empty?
117
+ end
118
+
119
+ end
120
+
121
+ describe ".clear_completed" do
122
+ before do
123
+ @completed_status_id = Resque::Plugins::Status::Hash.create(Resque::Plugins::Status::Hash.generate_uuid, {'status' => "completed"})
124
+ @not_completed_status_id = Resque::Plugins::Status::Hash.create(Resque::Plugins::Status::Hash.generate_uuid)
125
+ Resque::Plugins::Status::Hash.clear_completed
126
+ end
127
+
128
+ it "clear completed status" do
129
+ assert_nil Resque::Plugins::Status::Hash.get(@completed_status_id)
130
+ end
131
+
132
+ it "not clear not-completed status" do
133
+ status = Resque::Plugins::Status::Hash.get(@not_completed_status_id)
134
+ assert status.is_a?(Resque::Plugins::Status::Hash)
135
+ end
136
+ end
137
+
138
+ describe ".clear_failed" do
139
+ before do
140
+ @failed_status_id = Resque::Plugins::Status::Hash.create(Resque::Plugins::Status::Hash.generate_uuid, {'status' => "failed"})
141
+ @not_failed_status_id = Resque::Plugins::Status::Hash.create(Resque::Plugins::Status::Hash.generate_uuid)
142
+ Resque::Plugins::Status::Hash.clear_failed
143
+ end
144
+
145
+ it "clear failed status" do
146
+ assert_nil Resque::Plugins::Status::Hash.get(@failed_status_id)
147
+ end
148
+
149
+ it "not clear not-failed status" do
150
+ status = Resque::Plugins::Status::Hash.get(@not_failed_status_id)
151
+ assert status.is_a?(Resque::Plugins::Status::Hash)
152
+ end
153
+ end
154
+
155
+ describe ".remove" do
156
+ before do
157
+ Resque::Plugins::Status::Hash.remove(@uuid)
158
+ end
159
+
160
+ it "clear specify status" do
161
+ assert_nil Resque::Plugins::Status::Hash.get(@uuid)
162
+ end
163
+ end
164
+
165
+ describe ".status_ids" do
166
+
167
+ before do
168
+ @uuids = []
169
+ 30.times{ Resque::Plugins::Status::Hash.create(Resque::Plugins::Status::Hash.generate_uuid) }
170
+ end
171
+
172
+ it "return an array of job ids" do
173
+ assert Resque::Plugins::Status::Hash.status_ids.is_a?(Array)
174
+ assert_equal 32, Resque::Plugins::Status::Hash.status_ids.size # 30 + 2
175
+ end
176
+
177
+ it "let you paginate through the statuses" do
178
+ assert_equal Resque::Plugins::Status::Hash.status_ids[0, 10], Resque::Plugins::Status::Hash.status_ids(0, 9)
179
+ assert_equal Resque::Plugins::Status::Hash.status_ids[10, 10], Resque::Plugins::Status::Hash.status_ids(10, 19)
180
+ # assert_equal Resque::Plugins::Status::Hash.status_ids.reverse[0, 10], Resque::Plugins::Status::Hash.status_ids(0, 10)
181
+ end
182
+ end
183
+
184
+ describe ".statuses" do
185
+
186
+ it "return an array status objects" do
187
+ statuses = Resque::Plugins::Status::Hash.statuses
188
+ assert statuses.is_a?(Array)
189
+ assert_equal [@uuid_with_json, @uuid].sort, statuses.map(&:uuid).sort
190
+ end
191
+
192
+ it "return an empty array when no statuses are available" do
193
+ Resque.redis.flushall
194
+ statuses = Resque::Plugins::Status::Hash.statuses
195
+ assert_equal [], statuses
196
+ end
197
+
198
+ end
199
+
200
+ Resque::Plugins::Status::STATUSES.each do |status_code|
201
+ describe ".#{status_code}?" do
202
+
203
+ before do
204
+ uuid = Resque::Plugins::Status::Hash.create(Resque::Plugins::Status::Hash.generate_uuid, {'status' => status_code})
205
+ @status = Resque::Plugins::Status::Hash.get(uuid)
206
+ end
207
+
208
+ it "return true for the current status" do
209
+ assert @status.send("#{status_code}?"), status_code
210
+ end
211
+
212
+ it "return false for other statuses" do
213
+ (Resque::Plugins::Status::STATUSES - [status_code]).each do |other_status_code|
214
+ assert !@status.send("#{other_status_code}?"), other_status_code
215
+ end
216
+ end
217
+
218
+ end
219
+ end
220
+ end
221
+
222
+ end