resque_sqs 1.25.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.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/HISTORY.md +467 -0
  3. data/LICENSE +20 -0
  4. data/README.markdown +866 -0
  5. data/Rakefile +70 -0
  6. data/bin/resque-sqs +81 -0
  7. data/bin/resque-sqs-web +27 -0
  8. data/lib/resque_sqs/errors.rb +13 -0
  9. data/lib/resque_sqs/failure/airbrake.rb +33 -0
  10. data/lib/resque_sqs/failure/base.rb +73 -0
  11. data/lib/resque_sqs/failure/multiple.rb +59 -0
  12. data/lib/resque_sqs/failure/redis.rb +108 -0
  13. data/lib/resque_sqs/failure/redis_multi_queue.rb +89 -0
  14. data/lib/resque_sqs/failure.rb +113 -0
  15. data/lib/resque_sqs/helpers.rb +107 -0
  16. data/lib/resque_sqs/job.rb +346 -0
  17. data/lib/resque_sqs/log_formatters/quiet_formatter.rb +7 -0
  18. data/lib/resque_sqs/log_formatters/verbose_formatter.rb +7 -0
  19. data/lib/resque_sqs/log_formatters/very_verbose_formatter.rb +8 -0
  20. data/lib/resque_sqs/logging.rb +18 -0
  21. data/lib/resque_sqs/plugin.rb +66 -0
  22. data/lib/resque_sqs/server/helpers.rb +52 -0
  23. data/lib/resque_sqs/server/public/favicon.ico +0 -0
  24. data/lib/resque_sqs/server/public/idle.png +0 -0
  25. data/lib/resque_sqs/server/public/jquery-1.3.2.min.js +19 -0
  26. data/lib/resque_sqs/server/public/jquery.relatize_date.js +95 -0
  27. data/lib/resque_sqs/server/public/poll.png +0 -0
  28. data/lib/resque_sqs/server/public/ranger.js +78 -0
  29. data/lib/resque_sqs/server/public/reset.css +44 -0
  30. data/lib/resque_sqs/server/public/style.css +91 -0
  31. data/lib/resque_sqs/server/public/working.png +0 -0
  32. data/lib/resque_sqs/server/test_helper.rb +19 -0
  33. data/lib/resque_sqs/server/views/error.erb +1 -0
  34. data/lib/resque_sqs/server/views/failed.erb +29 -0
  35. data/lib/resque_sqs/server/views/failed_job.erb +50 -0
  36. data/lib/resque_sqs/server/views/failed_queues_overview.erb +24 -0
  37. data/lib/resque_sqs/server/views/key_sets.erb +19 -0
  38. data/lib/resque_sqs/server/views/key_string.erb +11 -0
  39. data/lib/resque_sqs/server/views/layout.erb +44 -0
  40. data/lib/resque_sqs/server/views/next_more.erb +22 -0
  41. data/lib/resque_sqs/server/views/overview.erb +4 -0
  42. data/lib/resque_sqs/server/views/queues.erb +58 -0
  43. data/lib/resque_sqs/server/views/stats.erb +62 -0
  44. data/lib/resque_sqs/server/views/workers.erb +109 -0
  45. data/lib/resque_sqs/server/views/working.erb +72 -0
  46. data/lib/resque_sqs/server.rb +271 -0
  47. data/lib/resque_sqs/stat.rb +57 -0
  48. data/lib/resque_sqs/tasks.rb +83 -0
  49. data/lib/resque_sqs/vendor/utf8_util/utf8_util_18.rb +91 -0
  50. data/lib/resque_sqs/vendor/utf8_util/utf8_util_19.rb +5 -0
  51. data/lib/resque_sqs/vendor/utf8_util.rb +20 -0
  52. data/lib/resque_sqs/version.rb +3 -0
  53. data/lib/resque_sqs/worker.rb +779 -0
  54. data/lib/resque_sqs.rb +479 -0
  55. data/lib/tasks/redis_sqs.rake +161 -0
  56. data/lib/tasks/resque_sqs.rake +2 -0
  57. data/test/airbrake_test.rb +27 -0
  58. data/test/failure_base_test.rb +15 -0
  59. data/test/job_hooks_test.rb +465 -0
  60. data/test/job_plugins_test.rb +230 -0
  61. data/test/logging_test.rb +24 -0
  62. data/test/plugin_test.rb +116 -0
  63. data/test/redis-test-cluster.conf +115 -0
  64. data/test/redis-test.conf +115 -0
  65. data/test/resque-web_test.rb +59 -0
  66. data/test/resque_failure_redis_test.rb +19 -0
  67. data/test/resque_hook_test.rb +165 -0
  68. data/test/resque_test.rb +278 -0
  69. data/test/stdout +42 -0
  70. data/test/test_helper.rb +228 -0
  71. data/test/worker_test.rb +1080 -0
  72. metadata +202 -0
@@ -0,0 +1,278 @@
1
+ require 'test_helper'
2
+
3
+ context "Resque" do
4
+ setup do
5
+ ResqueSqs.redis.flushall
6
+
7
+ ResqueSqs.push(:people, { 'name' => 'chris' })
8
+ ResqueSqs.push(:people, { 'name' => 'bob' })
9
+ ResqueSqs.push(:people, { 'name' => 'mark' })
10
+ @original_redis = ResqueSqs.redis
11
+ end
12
+
13
+ teardown do
14
+ ResqueSqs.redis = @original_redis
15
+ end
16
+
17
+ test "can set a namespace through a url-like string" do
18
+ assert ResqueSqs.redis
19
+ assert_equal :resque, ResqueSqs.redis.namespace
20
+ ResqueSqs.redis = 'localhost:9736/namespace'
21
+ assert_equal 'namespace', ResqueSqs.redis.namespace
22
+ end
23
+
24
+ test "redis= works correctly with a Redis::Namespace param" do
25
+ new_redis = Redis.new(:host => "localhost", :port => 9736)
26
+ new_namespace = Redis::Namespace.new("namespace", :redis => new_redis)
27
+ ResqueSqs.redis = new_namespace
28
+ assert_equal new_namespace, ResqueSqs.redis
29
+
30
+ ResqueSqs.redis = 'localhost:9736/namespace'
31
+ end
32
+
33
+ test "can put jobs on a queue" do
34
+ assert ResqueSqs::Job.create(:jobs, 'SomeJob', 20, '/tmp')
35
+ assert ResqueSqs::Job.create(:jobs, 'SomeJob', 20, '/tmp')
36
+ end
37
+
38
+ test "can grab jobs off a queue" do
39
+ ResqueSqs::Job.create(:jobs, 'some-job', 20, '/tmp')
40
+
41
+ job = ResqueSqs.reserve(:jobs)
42
+
43
+ assert_kind_of ResqueSqs::Job, job
44
+ assert_equal SomeJob, job.payload_class
45
+ assert_equal 20, job.args[0]
46
+ assert_equal '/tmp', job.args[1]
47
+ end
48
+
49
+ test "can re-queue jobs" do
50
+ ResqueSqs::Job.create(:jobs, 'some-job', 20, '/tmp')
51
+
52
+ job = ResqueSqs.reserve(:jobs)
53
+ job.recreate
54
+
55
+ assert_equal job, ResqueSqs.reserve(:jobs)
56
+ end
57
+
58
+ test "can put jobs on a queue by way of an ivar" do
59
+ assert_equal 0, ResqueSqs.size(:ivar)
60
+ assert ResqueSqs.enqueue(SomeIvarJob, 20, '/tmp')
61
+ assert ResqueSqs.enqueue(SomeIvarJob, 20, '/tmp')
62
+
63
+ job = ResqueSqs.reserve(:ivar)
64
+
65
+ assert_kind_of ResqueSqs::Job, job
66
+ assert_equal SomeIvarJob, job.payload_class
67
+ assert_equal 20, job.args[0]
68
+ assert_equal '/tmp', job.args[1]
69
+
70
+ assert ResqueSqs.reserve(:ivar)
71
+ assert_equal nil, ResqueSqs.reserve(:ivar)
72
+ end
73
+
74
+ test "can remove jobs from a queue by way of an ivar" do
75
+ assert_equal 0, ResqueSqs.size(:ivar)
76
+ assert ResqueSqs.enqueue(SomeIvarJob, 20, '/tmp')
77
+ assert ResqueSqs.enqueue(SomeIvarJob, 30, '/tmp')
78
+ assert ResqueSqs.enqueue(SomeIvarJob, 20, '/tmp')
79
+ assert ResqueSqs::Job.create(:ivar, 'blah-job', 20, '/tmp')
80
+ assert ResqueSqs.enqueue(SomeIvarJob, 20, '/tmp')
81
+ assert_equal 5, ResqueSqs.size(:ivar)
82
+
83
+ assert_equal 1, ResqueSqs.dequeue(SomeIvarJob, 30, '/tmp')
84
+ assert_equal 4, ResqueSqs.size(:ivar)
85
+ assert_equal 3, ResqueSqs.dequeue(SomeIvarJob)
86
+ assert_equal 1, ResqueSqs.size(:ivar)
87
+ end
88
+
89
+ test "jobs have a nice #inspect" do
90
+ assert ResqueSqs::Job.create(:jobs, 'SomeJob', 20, '/tmp')
91
+ job = ResqueSqs.reserve(:jobs)
92
+ assert_equal '(Job{jobs} | SomeJob | [20, "/tmp"])', job.inspect
93
+ end
94
+
95
+ test "jobs can be destroyed" do
96
+ assert ResqueSqs::Job.create(:jobs, 'SomeJob', 20, '/tmp')
97
+ assert ResqueSqs::Job.create(:jobs, 'BadJob', 20, '/tmp')
98
+ assert ResqueSqs::Job.create(:jobs, 'SomeJob', 20, '/tmp')
99
+ assert ResqueSqs::Job.create(:jobs, 'BadJob', 30, '/tmp')
100
+ assert ResqueSqs::Job.create(:jobs, 'BadJob', 20, '/tmp')
101
+
102
+ assert_equal 5, ResqueSqs.size(:jobs)
103
+ assert_equal 2, ResqueSqs::Job.destroy(:jobs, 'SomeJob')
104
+ assert_equal 3, ResqueSqs.size(:jobs)
105
+ assert_equal 1, ResqueSqs::Job.destroy(:jobs, 'BadJob', 30, '/tmp')
106
+ assert_equal 2, ResqueSqs.size(:jobs)
107
+ end
108
+
109
+ test "jobs can test for equality" do
110
+ assert ResqueSqs::Job.create(:jobs, 'SomeJob', 20, '/tmp')
111
+ assert ResqueSqs::Job.create(:jobs, 'some-job', 20, '/tmp')
112
+ assert_equal ResqueSqs.reserve(:jobs), ResqueSqs.reserve(:jobs)
113
+
114
+ assert ResqueSqs::Job.create(:jobs, 'SomeMethodJob', 20, '/tmp')
115
+ assert ResqueSqs::Job.create(:jobs, 'SomeJob', 20, '/tmp')
116
+ assert_not_equal ResqueSqs.reserve(:jobs), ResqueSqs.reserve(:jobs)
117
+
118
+ assert ResqueSqs::Job.create(:jobs, 'SomeJob', 20, '/tmp')
119
+ assert ResqueSqs::Job.create(:jobs, 'SomeJob', 30, '/tmp')
120
+ assert_not_equal ResqueSqs.reserve(:jobs), ResqueSqs.reserve(:jobs)
121
+ end
122
+
123
+ test "can put jobs on a queue by way of a method" do
124
+ assert_equal 0, ResqueSqs.size(:method)
125
+ assert ResqueSqs.enqueue(SomeMethodJob, 20, '/tmp')
126
+ assert ResqueSqs.enqueue(SomeMethodJob, 20, '/tmp')
127
+
128
+ job = ResqueSqs.reserve(:method)
129
+
130
+ assert_kind_of ResqueSqs::Job, job
131
+ assert_equal SomeMethodJob, job.payload_class
132
+ assert_equal 20, job.args[0]
133
+ assert_equal '/tmp', job.args[1]
134
+
135
+ assert ResqueSqs.reserve(:method)
136
+ assert_equal nil, ResqueSqs.reserve(:method)
137
+ end
138
+
139
+ test "can define a queue for jobs by way of a method" do
140
+ assert_equal 0, ResqueSqs.size(:method)
141
+ assert ResqueSqs.enqueue_to(:new_queue, SomeMethodJob, 20, '/tmp')
142
+
143
+ job = ResqueSqs.reserve(:new_queue)
144
+ assert_equal SomeMethodJob, job.payload_class
145
+ assert_equal 20, job.args[0]
146
+ assert_equal '/tmp', job.args[1]
147
+ end
148
+
149
+ test "needs to infer a queue with enqueue" do
150
+ assert_raises ResqueSqs::NoQueueError do
151
+ ResqueSqs.enqueue(SomeJob, 20, '/tmp')
152
+ end
153
+ end
154
+
155
+ test "validates job for queue presence" do
156
+ assert_raises ResqueSqs::NoQueueError do
157
+ ResqueSqs.validate(SomeJob)
158
+ end
159
+ end
160
+
161
+ test "can put items on a queue" do
162
+ assert ResqueSqs.push(:people, { 'name' => 'jon' })
163
+ end
164
+
165
+ test "can pull items off a queue" do
166
+ assert_equal({ 'name' => 'chris' }, ResqueSqs.pop(:people))
167
+ assert_equal({ 'name' => 'bob' }, ResqueSqs.pop(:people))
168
+ assert_equal({ 'name' => 'mark' }, ResqueSqs.pop(:people))
169
+ assert_equal nil, ResqueSqs.pop(:people)
170
+ end
171
+
172
+ test "knows how big a queue is" do
173
+ assert_equal 3, ResqueSqs.size(:people)
174
+
175
+ assert_equal({ 'name' => 'chris' }, ResqueSqs.pop(:people))
176
+ assert_equal 2, ResqueSqs.size(:people)
177
+
178
+ assert_equal({ 'name' => 'bob' }, ResqueSqs.pop(:people))
179
+ assert_equal({ 'name' => 'mark' }, ResqueSqs.pop(:people))
180
+ assert_equal 0, ResqueSqs.size(:people)
181
+ end
182
+
183
+ test "can peek at a queue" do
184
+ assert_equal({ 'name' => 'chris' }, ResqueSqs.peek(:people))
185
+ assert_equal 3, ResqueSqs.size(:people)
186
+ end
187
+
188
+ test "can peek multiple items on a queue" do
189
+ assert_equal({ 'name' => 'bob' }, ResqueSqs.peek(:people, 1, 1))
190
+
191
+ assert_equal([{ 'name' => 'bob' }, { 'name' => 'mark' }], ResqueSqs.peek(:people, 1, 2))
192
+ assert_equal([{ 'name' => 'chris' }, { 'name' => 'bob' }], ResqueSqs.peek(:people, 0, 2))
193
+ assert_equal([{ 'name' => 'chris' }, { 'name' => 'bob' }, { 'name' => 'mark' }], ResqueSqs.peek(:people, 0, 3))
194
+ assert_equal({ 'name' => 'mark' }, ResqueSqs.peek(:people, 2, 1))
195
+ assert_equal nil, ResqueSqs.peek(:people, 3)
196
+ assert_equal [], ResqueSqs.peek(:people, 3, 2)
197
+ end
198
+
199
+ test "knows what queues it is managing" do
200
+ assert_equal %w( people ), ResqueSqs.queues
201
+ ResqueSqs.push(:cars, { 'make' => 'bmw' })
202
+ assert_equal %w( cars people ).sort, ResqueSqs.queues.sort
203
+ end
204
+
205
+ test "queues are always a list" do
206
+ ResqueSqs.redis.flushall
207
+ assert_equal [], ResqueSqs.queues
208
+ end
209
+
210
+ test "can delete a queue" do
211
+ ResqueSqs.push(:cars, { 'make' => 'bmw' })
212
+ assert_equal %w( cars people ).sort, ResqueSqs.queues.sort
213
+ ResqueSqs.remove_queue(:people)
214
+ assert_equal %w( cars ), ResqueSqs.queues
215
+ assert_equal nil, ResqueSqs.pop(:people)
216
+ end
217
+
218
+ test "keeps track of resque keys" do
219
+ assert_equal ["queue:people", "queues"].sort, ResqueSqs.keys.sort
220
+ end
221
+
222
+ test "badly wants a class name, too" do
223
+ assert_raises ResqueSqs::NoClassError do
224
+ ResqueSqs::Job.create(:jobs, nil)
225
+ end
226
+ end
227
+
228
+ test "keeps stats" do
229
+ ResqueSqs::Job.create(:jobs, SomeJob, 20, '/tmp')
230
+ ResqueSqs::Job.create(:jobs, BadJob)
231
+ ResqueSqs::Job.create(:jobs, GoodJob)
232
+
233
+ ResqueSqs::Job.create(:others, GoodJob)
234
+ ResqueSqs::Job.create(:others, GoodJob)
235
+
236
+ stats = ResqueSqs.info
237
+ assert_equal 8, stats[:pending]
238
+
239
+ @worker = ResqueSqs::Worker.new(:jobs)
240
+ @worker.register_worker
241
+ 2.times { @worker.process }
242
+
243
+ job = @worker.reserve
244
+ @worker.working_on job
245
+
246
+ stats = ResqueSqs.info
247
+ assert_equal 1, stats[:working]
248
+ assert_equal 1, stats[:workers]
249
+
250
+ @worker.done_working
251
+
252
+ stats = ResqueSqs.info
253
+ assert_equal 3, stats[:queues]
254
+ assert_equal 3, stats[:processed]
255
+ assert_equal 1, stats[:failed]
256
+ if ENV.key? 'RESQUE_DISTRIBUTED'
257
+ assert_equal [ResqueSqs.redis.respond_to?(:server) ? 'localhost:9736, localhost:9737' : 'redis://localhost:9736/0, redis://localhost:9737/0'], stats[:servers]
258
+ else
259
+ assert_equal [ResqueSqs.redis.respond_to?(:server) ? 'localhost:9736' : 'redis://localhost:9736/0'], stats[:servers]
260
+ end
261
+ end
262
+
263
+ test "decode bad json" do
264
+ assert_raises ResqueSqs::Helpers::DecodeException do
265
+ ResqueSqs.decode("{\"error\":\"Module not found \\u002\"}")
266
+ end
267
+ end
268
+
269
+ test "inlining jobs" do
270
+ begin
271
+ ResqueSqs.inline = true
272
+ ResqueSqs.enqueue(SomeIvarJob, 20, '/tmp')
273
+ assert_equal 0, ResqueSqs.size(:ivar)
274
+ ensure
275
+ ResqueSqs.inline = false
276
+ end
277
+ end
278
+ end
data/test/stdout ADDED
@@ -0,0 +1,42 @@
1
+ 44230:C 06 Jun 2023 22:35:11.139 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
2
+ 44230:C 06 Jun 2023 22:35:11.139 # Redis version=7.0.4, bits=64, commit=00000000, modified=0, pid=44230, just started
3
+ 44230:C 06 Jun 2023 22:35:11.140 # Configuration loaded
4
+ 44230:M 06 Jun 2023 22:35:11.141 * monotonic clock: POSIX clock_gettime
5
+ 44230:M 06 Jun 2023 22:35:11.142 # Warning: Could not create server TCP listening socket *:9736: bind: Address already in use
6
+ 44230:M 06 Jun 2023 22:35:11.142 # Failed listening on port 9736 (TCP), aborting.
7
+ 45908:C 06 Jun 2023 22:36:39.405 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
8
+ 45908:C 06 Jun 2023 22:36:39.406 # Redis version=7.0.4, bits=64, commit=00000000, modified=0, pid=45908, just started
9
+ 45908:C 06 Jun 2023 22:36:39.406 # Configuration loaded
10
+ 45908:M 06 Jun 2023 22:36:39.407 * monotonic clock: POSIX clock_gettime
11
+ 45908:M 06 Jun 2023 22:36:39.408 # Warning: Could not create server TCP listening socket *:9736: bind: Address already in use
12
+ 45908:M 06 Jun 2023 22:36:39.409 # Failed listening on port 9736 (TCP), aborting.
13
+ 47480:C 06 Jun 2023 22:38:34.680 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
14
+ 47480:C 06 Jun 2023 22:38:34.680 # Redis version=7.0.4, bits=64, commit=00000000, modified=0, pid=47480, just started
15
+ 47480:C 06 Jun 2023 22:38:34.681 # Configuration loaded
16
+ 47480:M 06 Jun 2023 22:38:34.682 * monotonic clock: POSIX clock_gettime
17
+ 47480:M 06 Jun 2023 22:38:34.683 # Warning: Could not create server TCP listening socket *:9736: bind: Address already in use
18
+ 47480:M 06 Jun 2023 22:38:34.683 # Failed listening on port 9736 (TCP), aborting.
19
+ 48049:C 06 Jun 2023 22:39:10.214 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
20
+ 48049:C 06 Jun 2023 22:39:10.214 # Redis version=7.0.4, bits=64, commit=00000000, modified=0, pid=48049, just started
21
+ 48049:C 06 Jun 2023 22:39:10.215 # Configuration loaded
22
+ 48049:M 06 Jun 2023 22:39:10.216 * monotonic clock: POSIX clock_gettime
23
+ 48049:M 06 Jun 2023 22:39:10.217 # Warning: Could not create server TCP listening socket *:9736: bind: Address already in use
24
+ 48049:M 06 Jun 2023 22:39:10.218 # Failed listening on port 9736 (TCP), aborting.
25
+ 50184:C 06 Jun 2023 22:41:05.634 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
26
+ 50184:C 06 Jun 2023 22:41:05.634 # Redis version=7.0.4, bits=64, commit=00000000, modified=0, pid=50184, just started
27
+ 50184:C 06 Jun 2023 22:41:05.635 # Configuration loaded
28
+ 50184:M 06 Jun 2023 22:41:05.636 * monotonic clock: POSIX clock_gettime
29
+ 50184:M 06 Jun 2023 22:41:05.637 # Warning: Could not create server TCP listening socket *:9736: bind: Address already in use
30
+ 50184:M 06 Jun 2023 22:41:05.638 # Failed listening on port 9736 (TCP), aborting.
31
+ 64893:C 06 Jun 2023 22:52:57.094 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
32
+ 64893:C 06 Jun 2023 22:52:57.095 # Redis version=7.0.4, bits=64, commit=00000000, modified=0, pid=64893, just started
33
+ 64893:C 06 Jun 2023 22:52:57.096 # Configuration loaded
34
+ 64893:M 06 Jun 2023 22:52:57.097 * monotonic clock: POSIX clock_gettime
35
+ 64893:M 06 Jun 2023 22:52:57.098 # Warning: Could not create server TCP listening socket *:9736: bind: Address already in use
36
+ 64893:M 06 Jun 2023 22:52:57.098 # Failed listening on port 9736 (TCP), aborting.
37
+ 66616:C 06 Jun 2023 22:54:52.542 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
38
+ 66616:C 06 Jun 2023 22:54:52.543 # Redis version=7.0.4, bits=64, commit=00000000, modified=0, pid=66616, just started
39
+ 66616:C 06 Jun 2023 22:54:52.544 # Configuration loaded
40
+ 66616:M 06 Jun 2023 22:54:52.545 * monotonic clock: POSIX clock_gettime
41
+ 66616:M 06 Jun 2023 22:54:52.546 # Warning: Could not create server TCP listening socket *:9736: bind: Address already in use
42
+ 66616:M 06 Jun 2023 22:54:52.547 # Failed listening on port 9736 (TCP), aborting.
@@ -0,0 +1,228 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'minitest/autorun'
4
+ require 'redis/namespace'
5
+
6
+ require 'mocha/setup'
7
+
8
+ $dir = File.dirname(File.expand_path(__FILE__))
9
+ $LOAD_PATH.unshift $dir + '/../lib'
10
+ require 'resque_sqs'
11
+ $TESTING = true
12
+ $TEST_PID=Process.pid
13
+
14
+ begin
15
+ require 'leftright'
16
+ rescue LoadError
17
+ end
18
+
19
+
20
+ #
21
+ # make sure we can run redis
22
+ #
23
+
24
+ if !system("which redis-server")
25
+ puts '', "** can't find `redis-server` in your path"
26
+ puts "** try running `sudo rake install`"
27
+ abort ''
28
+ end
29
+
30
+
31
+ #
32
+ # start our own redis when the tests start,
33
+ # kill it when they end
34
+ #
35
+
36
+ MiniTest::Unit.after_tests do
37
+ if Process.pid == $TEST_PID
38
+ processes = `ps -A -o pid,command | grep [r]edis-test`.split("\n")
39
+ pids = processes.map { |process| process.split(" ")[0] }
40
+ puts "Killing test redis server..."
41
+ pids.each { |pid| Process.kill("TERM", pid.to_i) }
42
+ system("rm -f #{$dir}/dump.rdb #{$dir}/dump-cluster.rdb")
43
+ end
44
+ end
45
+
46
+ if ENV.key? 'RESQUE_DISTRIBUTED'
47
+ require 'redis/distributed'
48
+ puts "Starting redis for testing at localhost:9736 and localhost:9737..."
49
+ `redis-server #{$dir}/redis-test.conf`
50
+ `redis-server #{$dir}/redis-test-cluster.conf`
51
+ r = Redis::Distributed.new(['redis://localhost:9736', 'redis://localhost:9737'])
52
+ ResqueSqs.redis = Redis::Namespace.new :resque, :redis => r
53
+ else
54
+ puts "Starting redis for testing at localhost:9736..."
55
+ `redis-server #{$dir}/redis-test.conf`
56
+ ResqueSqs.redis = 'localhost:9736'
57
+ end
58
+
59
+
60
+ ##
61
+ # test/spec/mini 3
62
+ # http://gist.github.com/25455
63
+ # chris@ozmm.org
64
+ #
65
+ def context(*args, &block)
66
+ return super unless (name = args.first) && block
67
+ require 'test/unit'
68
+ klass = Class.new(defined?(ActiveSupport::TestCase) ? ActiveSupport::TestCase : Test::Unit::TestCase) do
69
+ def self.test(name, &block)
70
+ define_method("test_#{name.gsub(/\W/,'_')}", &block) if block
71
+ end
72
+ def self.xtest(*args) end
73
+ def self.setup(&block) define_method(:setup, &block) end
74
+ def self.teardown(&block) define_method(:teardown, &block) end
75
+ end
76
+ (class << klass; self end).send(:define_method, :name) { name.gsub(/\W/,'_') }
77
+ klass.class_eval &block
78
+ # XXX: In 1.8.x, not all tests will run unless anonymous classes are kept in scope.
79
+ ($test_classes ||= []) << klass
80
+ end
81
+
82
+ ##
83
+ # Helper to perform job classes
84
+ #
85
+ module PerformJob
86
+ def perform_job(klass, *args)
87
+ resque_job = ResqueSqs::Job.new(:testqueue, 'class' => klass, 'args' => args)
88
+ resque_job.perform
89
+ end
90
+ end
91
+
92
+ ##
93
+ # Helper to make Minitest::Assertion exceptions work properly
94
+ # in the block given to ResqueSqs::Worker#work.
95
+ #
96
+ module AssertInWorkBlock
97
+ # if a block is given, ensure that it is run, and that any assertion
98
+ # failures that occur inside it propagate up to the test.
99
+ def work(*args, &block)
100
+ return super unless block_given?
101
+
102
+ ex = catch(:exception_in_block) do
103
+ block_called = nil
104
+ retval = super(*args) do |*bargs|
105
+ begin
106
+ block_called = true
107
+ block.call(*bargs)
108
+ rescue MiniTest::Assertion => ex
109
+ throw :exception_in_block, ex
110
+ end
111
+ end
112
+
113
+ raise "assertion block not called!" unless block_called
114
+
115
+ return retval
116
+ end
117
+
118
+ ex && raise(ex)
119
+ end
120
+ end
121
+
122
+ #
123
+ # fixture classes
124
+ #
125
+
126
+ class SomeJob
127
+ def self.perform(repo_id, path)
128
+ end
129
+ end
130
+
131
+ class SomeIvarJob < SomeJob
132
+ @queue = :ivar
133
+ end
134
+
135
+ class SomeMethodJob < SomeJob
136
+ def self.queue
137
+ :method
138
+ end
139
+ end
140
+
141
+ class BadJob
142
+ def self.perform
143
+ raise "Bad job!"
144
+ end
145
+ end
146
+
147
+ class GoodJob
148
+ def self.perform(name)
149
+ "Good job, #{name}"
150
+ end
151
+ end
152
+
153
+ class AtExitJob
154
+ def self.perform(filename)
155
+ at_exit do
156
+ File.open(filename, "w") {|file| file.puts "at_exit"}
157
+ end
158
+ "at_exit job"
159
+ end
160
+ end
161
+
162
+ class BadJobWithSyntaxError
163
+ def self.perform
164
+ raise SyntaxError, "Extra Bad job!"
165
+ end
166
+ end
167
+
168
+ class BadFailureBackend < ResqueSqs::Failure::Base
169
+ def save
170
+ raise Exception.new("Failure backend error")
171
+ end
172
+ end
173
+
174
+ def with_failure_backend(failure_backend, &block)
175
+ previous_backend = ResqueSqs::Failure.backend
176
+ ResqueSqs::Failure.backend = failure_backend
177
+ yield block
178
+ ensure
179
+ ResqueSqs::Failure.backend = previous_backend
180
+ end
181
+
182
+ require 'time'
183
+
184
+ class Time
185
+ # Thanks, Timecop
186
+ class << self
187
+ attr_accessor :fake_time
188
+
189
+ alias_method :now_without_mock_time, :now
190
+
191
+ def now
192
+ fake_time || now_without_mock_time
193
+ end
194
+ end
195
+
196
+ self.fake_time = nil
197
+ end
198
+
199
+ # From minitest/unit
200
+ def capture_io
201
+ require 'stringio'
202
+
203
+ orig_stdout, orig_stderr = $stdout, $stderr
204
+ captured_stdout, captured_stderr = StringIO.new, StringIO.new
205
+ $stdout, $stderr = captured_stdout, captured_stderr
206
+
207
+ yield
208
+
209
+ return captured_stdout.string, captured_stderr.string
210
+ ensure
211
+ $stdout = orig_stdout
212
+ $stderr = orig_stderr
213
+ end
214
+
215
+ # Log to log/test.log
216
+ def reset_logger
217
+ $test_logger ||= MonoLogger.new(File.open(File.expand_path("../../log/test.log", __FILE__), "w"))
218
+ ResqueSqs.logger = $test_logger
219
+ end
220
+
221
+ reset_logger
222
+
223
+ def suppress_warnings
224
+ old_verbose, $VERBOSE = $VERBOSE, nil
225
+ yield
226
+ ensure
227
+ $VERBOSE = old_verbose
228
+ end