resque-loner 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,14 +1,30 @@
1
1
  require 'rubygems'
2
2
  require 'bundler/setup'
3
+
4
+ require 'codeclimate-test-reporter'
5
+ CodeClimate::TestReporter.start
6
+
7
+ require 'English'
8
+ require 'simplecov'
9
+
3
10
  require 'rspec'
4
11
 
5
- require 'ruby-debug'
6
- require 'mock_redis'
7
12
  require 'resque'
8
13
  require 'resque-loner'
9
14
 
15
+ module Support
16
+ class << self
17
+ attr_accessor :redis_pid
18
+ end
19
+ end
20
+
10
21
  RSpec.configure do |config|
11
22
  config.before(:suite) do
12
- Resque.redis = MockRedis.new
23
+ unless ENV['RESQUE_LONER_DISABLE_TEST_REDIS_SERVER']
24
+ # Start our own Redis when the tests start. RedisInstance will take care of
25
+ # starting and stopping.
26
+ require File.expand_path('../support/redis_instance', __FILE__)
27
+ RedisInstance.run!
28
+ end
13
29
  end
14
30
  end
@@ -0,0 +1,133 @@
1
+ # vim:fileencoding=utf-8
2
+ require 'socket'
3
+ require 'timeout'
4
+ require 'fileutils'
5
+
6
+ class RedisInstance # rubocop:disable ClassLength
7
+ class << self
8
+ @running = false
9
+ @port = nil
10
+ @pid = nil
11
+ @waiting = false
12
+
13
+ def run_if_needed!
14
+ run! unless @running
15
+ end
16
+
17
+ def run!
18
+ ensure_redis_server_present!
19
+ ensure_pid_directory
20
+ reassign_redis_clients
21
+ start_redis_server
22
+ post_boot_waiting_and_such
23
+
24
+ @running = true
25
+ end
26
+
27
+ def stop!
28
+ $stdout.puts "Sending TERM to Redis (#{pid})..."
29
+ Process.kill('TERM', pid)
30
+
31
+ @port = nil
32
+ @running = false
33
+ @pid = nil
34
+ end
35
+
36
+ private
37
+
38
+ def post_boot_waiting_and_such
39
+ wait_for_pid
40
+ puts "Booted isolated Redis on #{port} with PID #{pid}."
41
+
42
+ wait_for_redis_boot
43
+
44
+ # Ensure we tear down Redis on Ctrl+C / test failure.
45
+ at_exit { stop! }
46
+ end
47
+
48
+ def ensure_redis_server_present!
49
+ unless system('redis-server -v')
50
+ fail "** can't find `redis-server` in your path"
51
+ end
52
+ end
53
+
54
+ def wait_for_redis_boot
55
+ Timeout.timeout(10) do
56
+ loop do
57
+ begin
58
+ break if Resque.redis.ping == 'PONG'
59
+ rescue Redis::CannotConnectError
60
+ @waiting = true
61
+ end
62
+ end
63
+ @waiting = false
64
+ end
65
+ end
66
+
67
+ def ensure_pid_directory
68
+ FileUtils.mkdir_p(File.dirname(pid_file))
69
+ end
70
+
71
+ def reassign_redis_clients
72
+ Resque.redis = Redis.new(
73
+ hostname: '127.0.0.1', port: port, thread_safe: true
74
+ )
75
+ end
76
+
77
+ def start_redis_server
78
+ IO.popen('redis-server -', 'w+') do |server|
79
+ server.write(config)
80
+ server.close_write
81
+ end
82
+ end
83
+
84
+ def pid
85
+ @pid ||= File.read(pid_file).to_i
86
+ end
87
+
88
+ def wait_for_pid
89
+ Timeout.timeout(10) do
90
+ loop { break if File.exist?(pid_file) }
91
+ end
92
+ end
93
+
94
+ def port
95
+ @port ||= random_port
96
+ end
97
+
98
+ def pid_file
99
+ '/tmp/redis-loner-test.pid'
100
+ end
101
+
102
+ def config
103
+ <<-EOF
104
+ daemonize yes
105
+ pidfile #{pid_file}
106
+ port #{port}
107
+ EOF
108
+ end
109
+
110
+ # Returns a random port in the upper (10000-65535) range.
111
+ def random_port
112
+ ports = (10_000..65_535).to_a
113
+
114
+ loop do
115
+ port = ports[rand(ports.size)]
116
+ return port if port_available?('127.0.0.1', port)
117
+ end
118
+ end
119
+
120
+ def port_available?(ip, port, seconds = 1)
121
+ Timeout.timeout(seconds) do
122
+ begin
123
+ TCPSocket.new(ip, port).close
124
+ false
125
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
126
+ true
127
+ end
128
+ end
129
+ rescue Timeout::Error
130
+ true
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,27 @@
1
+
2
+ require 'test_helper'
3
+
4
+ begin
5
+ require 'airbrake'
6
+ rescue LoadError
7
+ warn 'Install airbrake gem to run Airbrake tests.'
8
+ end
9
+
10
+ if defined? Airbrake
11
+ require 'resque/failure/airbrake'
12
+ context 'Airbrake' do
13
+ test 'should be notified of an error' do
14
+ exception = StandardError.new('BOOM')
15
+ worker = Resque::Worker.new(:test)
16
+ queue = 'test'
17
+ payload = { 'class' => Object, 'args' => 66 }
18
+
19
+ Airbrake.expects(:notify_or_ignore).with(
20
+ exception,
21
+ parameters: { payload_class: 'Object', payload_args: '66' })
22
+
23
+ backend = Resque::Failure::Airbrake.new(exception, worker, queue, payload)
24
+ backend.save
25
+ end
26
+ end
27
+ end
Binary file
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- context "Resque::Job before_perform" do
3
+ context 'Resque::Job before_perform' do
4
4
  include PerformJob
5
5
 
6
6
  class ::BeforePerformJob
@@ -13,48 +13,48 @@ context "Resque::Job before_perform" do
13
13
  end
14
14
  end
15
15
 
16
- test "it runs before_perform before perform" do
17
- result = perform_job(BeforePerformJob, history=[])
18
- assert_equal true, result, "perform returned true"
16
+ test 'it runs before_perform before perform' do
17
+ result = perform_job(BeforePerformJob, history = [])
18
+ assert_equal true, result, 'perform returned true'
19
19
  assert_equal history, [:before_perform, :perform]
20
20
  end
21
21
 
22
22
  class ::BeforePerformJobFails
23
23
  def self.before_perform_fail_job(history)
24
24
  history << :before_perform
25
- raise StandardError
25
+ fail StandardError
26
26
  end
27
27
  def self.perform(history)
28
28
  history << :perform
29
29
  end
30
30
  end
31
31
 
32
- test "raises an error and does not perform if before_perform fails" do
32
+ test 'raises an error and does not perform if before_perform fails' do
33
33
  history = []
34
34
  assert_raises StandardError do
35
35
  perform_job(BeforePerformJobFails, history)
36
36
  end
37
- assert_equal history, [:before_perform], "Only before_perform was run"
37
+ assert_equal history, [:before_perform], 'Only before_perform was run'
38
38
  end
39
39
 
40
40
  class ::BeforePerformJobAborts
41
41
  def self.before_perform_abort(history)
42
42
  history << :before_perform
43
- raise Resque::Job::DontPerform
43
+ fail Resque::Job::DontPerform
44
44
  end
45
45
  def self.perform(history)
46
46
  history << :perform
47
47
  end
48
48
  end
49
49
 
50
- test "does not perform if before_perform raises Resque::Job::DontPerform" do
51
- result = perform_job(BeforePerformJobAborts, history=[])
52
- assert_equal false, result, "perform returned false"
53
- assert_equal history, [:before_perform], "Only before_perform was run"
50
+ test 'does not perform if before_perform raises Resque::Job::DontPerform' do
51
+ result = perform_job(BeforePerformJobAborts, history = [])
52
+ assert_equal false, result, 'perform returned false'
53
+ assert_equal history, [:before_perform], 'Only before_perform was run'
54
54
  end
55
55
  end
56
56
 
57
- context "Resque::Job after_perform" do
57
+ context 'Resque::Job after_perform' do
58
58
  include PerformJob
59
59
 
60
60
  class ::AfterPerformJob
@@ -66,9 +66,9 @@ context "Resque::Job after_perform" do
66
66
  end
67
67
  end
68
68
 
69
- test "it runs after_perform after perform" do
70
- result = perform_job(AfterPerformJob, history=[])
71
- assert_equal true, result, "perform returned true"
69
+ test 'it runs after_perform after perform' do
70
+ result = perform_job(AfterPerformJob, history = [])
71
+ assert_equal true, result, 'perform returned true'
72
72
  assert_equal history, [:perform, :after_perform]
73
73
  end
74
74
 
@@ -78,20 +78,20 @@ context "Resque::Job after_perform" do
78
78
  end
79
79
  def self.after_perform_fail_job(history)
80
80
  history << :after_perform
81
- raise StandardError
81
+ fail StandardError
82
82
  end
83
83
  end
84
84
 
85
- test "raises an error but has already performed if after_perform fails" do
85
+ test 'raises an error but has already performed if after_perform fails' do
86
86
  history = []
87
87
  assert_raises StandardError do
88
88
  perform_job(AfterPerformJobFails, history)
89
89
  end
90
- assert_equal history, [:perform, :after_perform], "Only after_perform was run"
90
+ assert_equal history, [:perform, :after_perform], 'Only after_perform was run'
91
91
  end
92
92
  end
93
93
 
94
- context "Resque::Job around_perform" do
94
+ context 'Resque::Job around_perform' do
95
95
  include PerformJob
96
96
 
97
97
  class ::AroundPerformJob
@@ -105,9 +105,9 @@ context "Resque::Job around_perform" do
105
105
  end
106
106
  end
107
107
 
108
- test "it runs around_perform then yields in order to perform" do
109
- result = perform_job(AroundPerformJob, history=[])
110
- assert_equal true, result, "perform returned true"
108
+ test 'it runs around_perform then yields in order to perform' do
109
+ result = perform_job(AroundPerformJob, history = [])
110
+ assert_equal true, result, 'perform returned true'
111
111
  assert_equal history, [:start_around_perform, :perform, :finish_around_perform]
112
112
  end
113
113
 
@@ -117,24 +117,24 @@ context "Resque::Job around_perform" do
117
117
  end
118
118
  def self.around_perform_fail(history)
119
119
  history << :start_around_perform
120
- raise StandardError
120
+ fail StandardError
121
121
  yield
122
122
  history << :finish_around_perform
123
123
  end
124
124
  end
125
125
 
126
- test "raises an error and does not perform if around_perform fails before yielding" do
126
+ test 'raises an error and does not perform if around_perform fails before yielding' do
127
127
  history = []
128
128
  assert_raises StandardError do
129
129
  perform_job(AroundPerformJobFailsBeforePerforming, history)
130
130
  end
131
- assert_equal history, [:start_around_perform], "Only part of around_perform was run"
131
+ assert_equal history, [:start_around_perform], 'Only part of around_perform was run'
132
132
  end
133
133
 
134
134
  class ::AroundPerformJobFailsWhilePerforming
135
135
  def self.perform(history)
136
136
  history << :perform
137
- raise StandardError
137
+ fail StandardError
138
138
  end
139
139
  def self.around_perform_fail_in_yield(history)
140
140
  history << :start_around_perform
@@ -147,12 +147,12 @@ context "Resque::Job around_perform" do
147
147
  end
148
148
  end
149
149
 
150
- test "raises an error but may handle exceptions if perform fails" do
150
+ test 'raises an error but may handle exceptions if perform fails' do
151
151
  history = []
152
152
  assert_raises StandardError do
153
153
  perform_job(AroundPerformJobFailsWhilePerforming, history)
154
154
  end
155
- assert_equal history, [:start_around_perform, :perform, :ensure_around_perform], "Only part of around_perform was run"
155
+ assert_equal history, [:start_around_perform, :perform, :ensure_around_perform], 'Only part of around_perform was run'
156
156
  end
157
157
 
158
158
  class ::AroundPerformJobDoesNotHaveToYield
@@ -165,15 +165,15 @@ context "Resque::Job around_perform" do
165
165
  end
166
166
  end
167
167
 
168
- test "around_perform is not required to yield" do
168
+ test 'around_perform is not required to yield' do
169
169
  history = []
170
170
  result = perform_job(AroundPerformJobDoesNotHaveToYield, history)
171
- assert_equal false, result, "perform returns false"
172
- assert_equal history, [:start_around_perform, :finish_around_perform], "perform was not run"
171
+ assert_equal false, result, 'perform returns false'
172
+ assert_equal history, [:start_around_perform, :finish_around_perform], 'perform was not run'
173
173
  end
174
174
  end
175
175
 
176
- context "Resque::Job on_failure" do
176
+ context 'Resque::Job on_failure' do
177
177
  include PerformJob
178
178
 
179
179
  class ::FailureJobThatDoesNotFail
@@ -185,50 +185,50 @@ context "Resque::Job on_failure" do
185
185
  end
186
186
  end
187
187
 
188
- test "it does not call on_failure if no failures occur" do
189
- result = perform_job(FailureJobThatDoesNotFail, history=[])
190
- assert_equal true, result, "perform returned true"
188
+ test 'it does not call on_failure if no failures occur' do
189
+ result = perform_job(FailureJobThatDoesNotFail, history = [])
190
+ assert_equal true, result, 'perform returned true'
191
191
  assert_equal history, [:perform]
192
192
  end
193
193
 
194
194
  class ::FailureJobThatFails
195
195
  def self.perform(history)
196
196
  history << :perform
197
- raise StandardError, "oh no"
197
+ fail StandardError, 'oh no'
198
198
  end
199
199
  def self.on_failure_record_failure(exception, history)
200
200
  history << exception.message
201
201
  end
202
202
  end
203
203
 
204
- test "it calls on_failure with the exception and then re-raises the exception" do
204
+ test 'it calls on_failure with the exception and then re-raises the exception' do
205
205
  history = []
206
206
  assert_raises StandardError do
207
207
  perform_job(FailureJobThatFails, history)
208
208
  end
209
- assert_equal history, [:perform, "oh no"]
209
+ assert_equal history, [:perform, 'oh no']
210
210
  end
211
211
 
212
212
  class ::FailureJobThatFailsBadly
213
213
  def self.perform(history)
214
214
  history << :perform
215
- raise SyntaxError, "oh no"
215
+ fail SyntaxError, 'oh no'
216
216
  end
217
217
  def self.on_failure_record_failure(exception, history)
218
218
  history << exception.message
219
219
  end
220
220
  end
221
221
 
222
- test "it calls on_failure even with bad exceptions" do
222
+ test 'it calls on_failure even with bad exceptions' do
223
223
  history = []
224
224
  assert_raises SyntaxError do
225
225
  perform_job(FailureJobThatFailsBadly, history)
226
226
  end
227
- assert_equal history, [:perform, "oh no"]
227
+ assert_equal history, [:perform, 'oh no']
228
228
  end
229
229
  end
230
230
 
231
- context "Resque::Job after_enqueue" do
231
+ context 'Resque::Job after_enqueue' do
232
232
  include PerformJob
233
233
 
234
234
  class ::AfterEnqueueJob
@@ -241,16 +241,114 @@ context "Resque::Job after_enqueue" do
241
241
  end
242
242
  end
243
243
 
244
- test "the after enqueue hook should run" do
244
+ test 'the after enqueue hook should run' do
245
245
  history = []
246
246
  @worker = Resque::Worker.new(:jobs)
247
247
  Resque.enqueue(AfterEnqueueJob, history)
248
248
  @worker.work(0)
249
- assert_equal history, [:after_enqueue], "after_enqueue was not run"
249
+ assert_equal history, [:after_enqueue], 'after_enqueue was not run'
250
250
  end
251
251
  end
252
252
 
253
- context "Resque::Job all hooks" do
253
+ context 'Resque::Job before_enqueue' do
254
+ include PerformJob
255
+
256
+ class ::BeforeEnqueueJob
257
+ @queue = :jobs
258
+ def self.before_enqueue_record_history(history)
259
+ history << :before_enqueue
260
+ end
261
+
262
+ def self.perform(history)
263
+ end
264
+ end
265
+
266
+ class ::BeforeEnqueueJobAbort
267
+ @queue = :jobs
268
+ def self.before_enqueue_abort(history)
269
+ false
270
+ end
271
+
272
+ def self.perform(history)
273
+ end
274
+ end
275
+
276
+ test 'the before enqueue hook should run' do
277
+ history = []
278
+ @worker = Resque::Worker.new(:jobs)
279
+ assert Resque.enqueue(BeforeEnqueueJob, history)
280
+ @worker.work(0)
281
+ assert_equal history, [:before_enqueue], 'before_enqueue was not run'
282
+ end
283
+
284
+ test 'a before enqueue hook that returns false should prevent the job from getting queued' do
285
+ history = []
286
+ @worker = Resque::Worker.new(:jobs)
287
+ assert_nil Resque.enqueue(BeforeEnqueueJobAbort, history)
288
+ assert_equal 0, Resque.size(:jobs)
289
+ end
290
+ end
291
+
292
+ context 'Resque::Job after_dequeue' do
293
+ include PerformJob
294
+
295
+ class ::AfterDequeueJob
296
+ @queue = :jobs
297
+ def self.after_dequeue_record_history(history)
298
+ history << :after_dequeue
299
+ end
300
+
301
+ def self.perform(history)
302
+ end
303
+ end
304
+
305
+ test 'the after dequeue hook should run' do
306
+ history = []
307
+ @worker = Resque::Worker.new(:jobs)
308
+ Resque.dequeue(AfterDequeueJob, history)
309
+ @worker.work(0)
310
+ assert_equal history, [:after_dequeue], 'after_dequeue was not run'
311
+ end
312
+ end
313
+
314
+ context 'Resque::Job before_dequeue' do
315
+ include PerformJob
316
+
317
+ class ::BeforeDequeueJob
318
+ @queue = :jobs
319
+ def self.before_dequeue_record_history(history)
320
+ history << :before_dequeue
321
+ end
322
+
323
+ def self.perform(history)
324
+ end
325
+ end
326
+
327
+ class ::BeforeDequeueJobAbort
328
+ @queue = :jobs
329
+ def self.before_dequeue_abort(history)
330
+ false
331
+ end
332
+
333
+ def self.perform(history)
334
+ end
335
+ end
336
+
337
+ test 'the before dequeue hook should run' do
338
+ history = []
339
+ @worker = Resque::Worker.new(:jobs)
340
+ Resque.dequeue(BeforeDequeueJob, history)
341
+ @worker.work(0)
342
+ assert_equal history, [:before_dequeue], 'before_dequeue was not run'
343
+ end
344
+
345
+ test 'a before dequeue hook that returns false should prevent the job from getting dequeued' do
346
+ history = []
347
+ assert_equal nil, Resque.dequeue(BeforeDequeueJobAbort, history)
348
+ end
349
+ end
350
+
351
+ context 'Resque::Job all hooks' do
254
352
  include PerformJob
255
353
 
256
354
  class ::VeryHookyJob
@@ -273,9 +371,9 @@ context "Resque::Job all hooks" do
273
371
  end
274
372
  end
275
373
 
276
- test "the complete hook order" do
277
- result = perform_job(VeryHookyJob, history=[])
278
- assert_equal true, result, "perform returned true"
374
+ test 'the complete hook order' do
375
+ result = perform_job(VeryHookyJob, history = [])
376
+ assert_equal true, result, 'perform returned true'
279
377
  assert_equal history, [
280
378
  :before_perform,
281
379
  :start_around_perform,
@@ -299,14 +397,14 @@ context "Resque::Job all hooks" do
299
397
  end
300
398
  def self.after_perform_record_history(history)
301
399
  history << :after_perform
302
- raise StandardError, "oh no"
400
+ fail StandardError, 'oh no'
303
401
  end
304
402
  def self.on_failure_record_history(exception, history)
305
403
  history << exception.message
306
404
  end
307
405
  end
308
406
 
309
- test "the complete hook order with a failure at the last minute" do
407
+ test 'the complete hook order with a failure at the last minute' do
310
408
  history = []
311
409
  assert_raises StandardError do
312
410
  perform_job(VeryHookyJobThatFails, history)
@@ -317,7 +415,48 @@ context "Resque::Job all hooks" do
317
415
  :perform,
318
416
  :finish_around_perform,
319
417
  :after_perform,
320
- "oh no"
418
+ 'oh no'
321
419
  ]
322
420
  end
421
+
422
+ class ::CallbacksInline
423
+ @queue = :callbacks_inline
424
+
425
+ def self.before_perform_record_history(history, count)
426
+ history << :before_perform
427
+ count['count'] += 1
428
+ end
429
+
430
+ def self.after_perform_record_history(history, count)
431
+ history << :after_perform
432
+ count['count'] += 1
433
+ end
434
+
435
+ def self.around_perform_record_history(history, count)
436
+ history << :start_around_perform
437
+ count['count'] += 1
438
+ yield
439
+ history << :finish_around_perform
440
+ count['count'] += 1
441
+ end
442
+
443
+ def self.perform(history, count)
444
+ history << :perform
445
+ $history = history
446
+ $count = count
447
+ end
448
+ end
449
+
450
+ test 'it runs callbacks when inline is true' do
451
+ begin
452
+ Resque.inline = true
453
+ # Sending down two parameters that can be passed and updated by reference
454
+ result = Resque.enqueue(CallbacksInline, [], 'count' => 0)
455
+ assert_equal true, result, 'perform returned true'
456
+ assert_equal $history, [:before_perform, :start_around_perform, :perform, :finish_around_perform, :after_perform]
457
+ assert_equal 4, $count['count']
458
+ ensure
459
+ Resque.inline = false
460
+ end
461
+ end
323
462
  end