roundhouse-x 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.travis.yml +16 -0
- data/3.0-Upgrade.md +70 -0
- data/Changes.md +1127 -0
- data/Gemfile +27 -0
- data/LICENSE +7 -0
- data/README.md +52 -0
- data/Rakefile +9 -0
- data/bin/roundhouse +19 -0
- data/bin/roundhousectl +93 -0
- data/lib/generators/roundhouse/templates/worker.rb.erb +9 -0
- data/lib/generators/roundhouse/templates/worker_spec.rb.erb +6 -0
- data/lib/generators/roundhouse/templates/worker_test.rb.erb +8 -0
- data/lib/generators/roundhouse/worker_generator.rb +49 -0
- data/lib/roundhouse/actor.rb +39 -0
- data/lib/roundhouse/api.rb +859 -0
- data/lib/roundhouse/cli.rb +396 -0
- data/lib/roundhouse/client.rb +210 -0
- data/lib/roundhouse/core_ext.rb +105 -0
- data/lib/roundhouse/exception_handler.rb +30 -0
- data/lib/roundhouse/fetch.rb +154 -0
- data/lib/roundhouse/launcher.rb +98 -0
- data/lib/roundhouse/logging.rb +104 -0
- data/lib/roundhouse/manager.rb +236 -0
- data/lib/roundhouse/middleware/chain.rb +149 -0
- data/lib/roundhouse/middleware/i18n.rb +41 -0
- data/lib/roundhouse/middleware/server/active_record.rb +13 -0
- data/lib/roundhouse/middleware/server/logging.rb +40 -0
- data/lib/roundhouse/middleware/server/retry_jobs.rb +206 -0
- data/lib/roundhouse/monitor.rb +124 -0
- data/lib/roundhouse/paginator.rb +42 -0
- data/lib/roundhouse/processor.rb +159 -0
- data/lib/roundhouse/rails.rb +24 -0
- data/lib/roundhouse/redis_connection.rb +77 -0
- data/lib/roundhouse/scheduled.rb +115 -0
- data/lib/roundhouse/testing/inline.rb +28 -0
- data/lib/roundhouse/testing.rb +193 -0
- data/lib/roundhouse/util.rb +68 -0
- data/lib/roundhouse/version.rb +3 -0
- data/lib/roundhouse/web.rb +264 -0
- data/lib/roundhouse/web_helpers.rb +249 -0
- data/lib/roundhouse/worker.rb +90 -0
- data/lib/roundhouse.rb +177 -0
- data/roundhouse.gemspec +27 -0
- data/test/config.yml +9 -0
- data/test/env_based_config.yml +11 -0
- data/test/fake_env.rb +0 -0
- data/test/fixtures/en.yml +2 -0
- data/test/helper.rb +49 -0
- data/test/test_api.rb +521 -0
- data/test/test_cli.rb +389 -0
- data/test/test_client.rb +294 -0
- data/test/test_exception_handler.rb +55 -0
- data/test/test_fetch.rb +206 -0
- data/test/test_logging.rb +34 -0
- data/test/test_manager.rb +169 -0
- data/test/test_middleware.rb +160 -0
- data/test/test_monitor.rb +258 -0
- data/test/test_processor.rb +176 -0
- data/test/test_rails.rb +23 -0
- data/test/test_redis_connection.rb +127 -0
- data/test/test_retry.rb +390 -0
- data/test/test_roundhouse.rb +87 -0
- data/test/test_scheduled.rb +120 -0
- data/test/test_scheduling.rb +75 -0
- data/test/test_testing.rb +78 -0
- data/test/test_testing_fake.rb +240 -0
- data/test/test_testing_inline.rb +65 -0
- data/test/test_util.rb +18 -0
- data/test/test_web.rb +605 -0
- data/test/test_web_helpers.rb +52 -0
- data/web/assets/images/bootstrap/glyphicons-halflings-white.png +0 -0
- data/web/assets/images/bootstrap/glyphicons-halflings.png +0 -0
- data/web/assets/images/logo.png +0 -0
- data/web/assets/images/status/active.png +0 -0
- data/web/assets/images/status/idle.png +0 -0
- data/web/assets/images/status-sd8051fd480.png +0 -0
- data/web/assets/javascripts/application.js +83 -0
- data/web/assets/javascripts/dashboard.js +300 -0
- data/web/assets/javascripts/locales/README.md +27 -0
- data/web/assets/javascripts/locales/jquery.timeago.ar.js +96 -0
- data/web/assets/javascripts/locales/jquery.timeago.bg.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.bs.js +49 -0
- data/web/assets/javascripts/locales/jquery.timeago.ca.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.cs.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.cy.js +20 -0
- data/web/assets/javascripts/locales/jquery.timeago.da.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.de.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.el.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.en-short.js +20 -0
- data/web/assets/javascripts/locales/jquery.timeago.en.js +20 -0
- data/web/assets/javascripts/locales/jquery.timeago.es.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.et.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.fa.js +22 -0
- data/web/assets/javascripts/locales/jquery.timeago.fi.js +28 -0
- data/web/assets/javascripts/locales/jquery.timeago.fr-short.js +16 -0
- data/web/assets/javascripts/locales/jquery.timeago.fr.js +17 -0
- data/web/assets/javascripts/locales/jquery.timeago.he.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.hr.js +49 -0
- data/web/assets/javascripts/locales/jquery.timeago.hu.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.hy.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.id.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.it.js +16 -0
- data/web/assets/javascripts/locales/jquery.timeago.ja.js +19 -0
- data/web/assets/javascripts/locales/jquery.timeago.ko.js +17 -0
- data/web/assets/javascripts/locales/jquery.timeago.lt.js +20 -0
- data/web/assets/javascripts/locales/jquery.timeago.mk.js +20 -0
- data/web/assets/javascripts/locales/jquery.timeago.nl.js +20 -0
- data/web/assets/javascripts/locales/jquery.timeago.no.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.pl.js +31 -0
- data/web/assets/javascripts/locales/jquery.timeago.pt-br.js +16 -0
- data/web/assets/javascripts/locales/jquery.timeago.pt.js +16 -0
- data/web/assets/javascripts/locales/jquery.timeago.ro.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.rs.js +49 -0
- data/web/assets/javascripts/locales/jquery.timeago.ru.js +34 -0
- data/web/assets/javascripts/locales/jquery.timeago.sk.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.sl.js +44 -0
- data/web/assets/javascripts/locales/jquery.timeago.sv.js +18 -0
- data/web/assets/javascripts/locales/jquery.timeago.th.js +20 -0
- data/web/assets/javascripts/locales/jquery.timeago.tr.js +16 -0
- data/web/assets/javascripts/locales/jquery.timeago.uk.js +34 -0
- data/web/assets/javascripts/locales/jquery.timeago.uz.js +19 -0
- data/web/assets/javascripts/locales/jquery.timeago.zh-cn.js +20 -0
- data/web/assets/javascripts/locales/jquery.timeago.zh-tw.js +20 -0
- data/web/assets/stylesheets/application.css +746 -0
- data/web/assets/stylesheets/bootstrap.css +9 -0
- data/web/locales/cs.yml +68 -0
- data/web/locales/da.yml +68 -0
- data/web/locales/de.yml +69 -0
- data/web/locales/el.yml +68 -0
- data/web/locales/en.yml +77 -0
- data/web/locales/es.yml +69 -0
- data/web/locales/fr.yml +69 -0
- data/web/locales/hi.yml +75 -0
- data/web/locales/it.yml +69 -0
- data/web/locales/ja.yml +69 -0
- data/web/locales/ko.yml +68 -0
- data/web/locales/nl.yml +68 -0
- data/web/locales/no.yml +69 -0
- data/web/locales/pl.yml +59 -0
- data/web/locales/pt-br.yml +68 -0
- data/web/locales/pt.yml +67 -0
- data/web/locales/ru.yml +75 -0
- data/web/locales/sv.yml +68 -0
- data/web/locales/ta.yml +75 -0
- data/web/locales/zh-cn.yml +68 -0
- data/web/locales/zh-tw.yml +68 -0
- data/web/views/_footer.erb +22 -0
- data/web/views/_job_info.erb +84 -0
- data/web/views/_nav.erb +66 -0
- data/web/views/_paging.erb +23 -0
- data/web/views/_poll_js.erb +5 -0
- data/web/views/_poll_link.erb +7 -0
- data/web/views/_status.erb +4 -0
- data/web/views/_summary.erb +40 -0
- data/web/views/busy.erb +90 -0
- data/web/views/dashboard.erb +75 -0
- data/web/views/dead.erb +34 -0
- data/web/views/layout.erb +31 -0
- data/web/views/morgue.erb +71 -0
- data/web/views/queue.erb +45 -0
- data/web/views/queues.erb +27 -0
- data/web/views/retries.erb +74 -0
- data/web/views/retry.erb +34 -0
- data/web/views/scheduled.erb +54 -0
- data/web/views/scheduled_job_info.erb +8 -0
- metadata +404 -0
data/test/test_web.rb
ADDED
@@ -0,0 +1,605 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require_relative 'helper'
|
3
|
+
require 'roundhouse'
|
4
|
+
require 'roundhouse/web'
|
5
|
+
require 'rack/test'
|
6
|
+
require 'tilt/erubis'
|
7
|
+
|
8
|
+
class TestWeb < Roundhouse::Test
|
9
|
+
|
10
|
+
describe 'roundhouse web' do
|
11
|
+
include Rack::Test::Methods
|
12
|
+
|
13
|
+
def app
|
14
|
+
Roundhouse::Web
|
15
|
+
end
|
16
|
+
|
17
|
+
def job_params(job, score)
|
18
|
+
"#{score}-#{job['jid']}"
|
19
|
+
end
|
20
|
+
|
21
|
+
before do
|
22
|
+
Roundhouse.redis = REDIS
|
23
|
+
Roundhouse.redis {|c| c.flushdb }
|
24
|
+
end
|
25
|
+
|
26
|
+
class WebWorker
|
27
|
+
include Roundhouse::Worker
|
28
|
+
|
29
|
+
def perform(a, b)
|
30
|
+
a + b
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'can show text with any locales' do
|
35
|
+
rackenv = {'HTTP_ACCEPT_LANGUAGE' => 'ru,en'}
|
36
|
+
get '/', {}, rackenv
|
37
|
+
assert_match(/Панель управления/, last_response.body)
|
38
|
+
rackenv = {'HTTP_ACCEPT_LANGUAGE' => 'es,en'}
|
39
|
+
get '/', {}, rackenv
|
40
|
+
assert_match(/Panel de Control/, last_response.body)
|
41
|
+
rackenv = {'HTTP_ACCEPT_LANGUAGE' => 'en-us'}
|
42
|
+
get '/', {}, rackenv
|
43
|
+
assert_match(/Dashboard/, last_response.body)
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'busy' do
|
47
|
+
|
48
|
+
it 'can display workers' do
|
49
|
+
Roundhouse.redis do |conn|
|
50
|
+
conn.incr('busy')
|
51
|
+
conn.sadd('processes', 'foo:1234')
|
52
|
+
conn.hmset('foo:1234', 'info', Roundhouse.dump_json('hostname' => 'foo', 'started_at' => Time.now.to_f, "queues" => []), 'at', Time.now.to_f, 'busy', 4)
|
53
|
+
identity = 'foo:1234:workers'
|
54
|
+
hash = {:queue => 'critical', :payload => { 'class' => WebWorker.name, 'args' => [1,'abc'] }, :run_at => Time.now.to_i }
|
55
|
+
conn.hmset(identity, 1001, Roundhouse.dump_json(hash))
|
56
|
+
end
|
57
|
+
assert_equal ['1001'], Roundhouse::Workers.new.map { |pid, tid, data| tid }
|
58
|
+
|
59
|
+
get '/busy'
|
60
|
+
assert_equal 200, last_response.status
|
61
|
+
assert_match(/status-active/, last_response.body)
|
62
|
+
assert_match(/critical/, last_response.body)
|
63
|
+
assert_match(/WebWorker/, last_response.body)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'can quiet a process' do
|
67
|
+
identity = 'identity'
|
68
|
+
signals_key = "#{identity}-signals"
|
69
|
+
|
70
|
+
assert_nil Roundhouse.redis { |c| c.lpop signals_key }
|
71
|
+
post '/busy', 'quiet' => '1', 'identity' => identity
|
72
|
+
assert_equal 302, last_response.status
|
73
|
+
assert_equal 'USR1', Roundhouse.redis { |c| c.lpop signals_key }
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'can stop a process' do
|
77
|
+
identity = 'identity'
|
78
|
+
signals_key = "#{identity}-signals"
|
79
|
+
|
80
|
+
assert_nil Roundhouse.redis { |c| c.lpop signals_key }
|
81
|
+
post '/busy', 'stop' => '1', 'identity' => identity
|
82
|
+
assert_equal 302, last_response.status
|
83
|
+
assert_equal 'TERM', Roundhouse.redis { |c| c.lpop signals_key }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'can display queues' do
|
88
|
+
assert Roundhouse::Client.push('queue_id' => 100, 'class' => WebWorker, 'args' => [1, 3])
|
89
|
+
|
90
|
+
get '/queues'
|
91
|
+
assert_equal 200, last_response.status
|
92
|
+
assert_match(/100/, last_response.body)
|
93
|
+
refute_match(/HardWorker/, last_response.body)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'handles queue view' do
|
97
|
+
get '/queues/default'
|
98
|
+
assert_equal 200, last_response.status
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'can delete a queue' do
|
102
|
+
Roundhouse.redis do |conn|
|
103
|
+
conn.rpush('queue:100', '{}')
|
104
|
+
Roundhouse::Monitor.activate(conn, 100)
|
105
|
+
end
|
106
|
+
|
107
|
+
get '/queues/100'
|
108
|
+
assert_equal 200, last_response.status
|
109
|
+
|
110
|
+
post '/queues/100'
|
111
|
+
assert_equal 302, last_response.status
|
112
|
+
|
113
|
+
Roundhouse.redis do |conn|
|
114
|
+
refute conn.hexists(Roundhouse::Monitor.status_bucket(100), 100)
|
115
|
+
refute conn.exists('queue:100')
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'can delete a job' do
|
120
|
+
Roundhouse.redis do |conn|
|
121
|
+
conn.rpush('queue:foo', "{}")
|
122
|
+
conn.rpush('queue:foo', "{\"foo\":\"bar\"}")
|
123
|
+
conn.rpush('queue:foo', "{\"foo2\":\"bar2\"}")
|
124
|
+
end
|
125
|
+
|
126
|
+
get '/queues/foo'
|
127
|
+
assert_equal 200, last_response.status
|
128
|
+
|
129
|
+
post '/queues/foo/delete', key_val: "{\"foo\":\"bar\"}"
|
130
|
+
assert_equal 302, last_response.status
|
131
|
+
|
132
|
+
Roundhouse.redis do |conn|
|
133
|
+
refute conn.lrange('queue:foo', 0, -1).include?("{\"foo\":\"bar\"}")
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'can display retries' do
|
138
|
+
get '/retries'
|
139
|
+
assert_equal 200, last_response.status
|
140
|
+
assert_match(/found/, last_response.body)
|
141
|
+
refute_match(/HardWorker/, last_response.body)
|
142
|
+
|
143
|
+
add_retry
|
144
|
+
|
145
|
+
get '/retries'
|
146
|
+
assert_equal 200, last_response.status
|
147
|
+
refute_match(/found/, last_response.body)
|
148
|
+
assert_match(/HardWorker/, last_response.body)
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'can display a single retry' do
|
152
|
+
params = add_retry
|
153
|
+
get '/retries/0-shouldntexist'
|
154
|
+
assert_equal 302, last_response.status
|
155
|
+
get "/retries/#{job_params(*params)}"
|
156
|
+
assert_equal 200, last_response.status
|
157
|
+
assert_match(/HardWorker/, last_response.body)
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'handles missing retry' do
|
161
|
+
get "/retries/0-shouldntexist"
|
162
|
+
assert_equal 302, last_response.status
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'can delete a single retry' do
|
166
|
+
params = add_retry
|
167
|
+
post "/retries/#{job_params(*params)}", 'delete' => 'Delete'
|
168
|
+
assert_equal 302, last_response.status
|
169
|
+
assert_equal 'http://example.org/retries', last_response.header['Location']
|
170
|
+
|
171
|
+
get "/retries"
|
172
|
+
assert_equal 200, last_response.status
|
173
|
+
refute_match(/#{params.first['args'][2]}/, last_response.body)
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'can delete all retries' do
|
177
|
+
3.times { add_retry }
|
178
|
+
|
179
|
+
post "/retries/all/delete", 'delete' => 'Delete'
|
180
|
+
assert_equal 0, Roundhouse::RetrySet.new.size
|
181
|
+
assert_equal 302, last_response.status
|
182
|
+
assert_equal 'http://example.org/retries', last_response.header['Location']
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'can retry a single retry now' do
|
186
|
+
params = add_retry
|
187
|
+
post "/retries/#{job_params(*params)}", 'retry' => 'Retry'
|
188
|
+
assert_equal 302, last_response.status
|
189
|
+
assert_equal 'http://example.org/retries', last_response.header['Location']
|
190
|
+
|
191
|
+
get '/queues/100'
|
192
|
+
assert_equal 200, last_response.status
|
193
|
+
assert_match(/#{params.first['args'][2]}/, last_response.body)
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'can kill a single retry now' do
|
197
|
+
params = add_retry
|
198
|
+
post "/retries/#{job_params(*params)}", 'kill' => 'Kill'
|
199
|
+
assert_equal 302, last_response.status
|
200
|
+
assert_equal 'http://example.org/retries', last_response.header['Location']
|
201
|
+
|
202
|
+
get '/morgue'
|
203
|
+
assert_equal 200, last_response.status
|
204
|
+
assert_match(/#{params.first['args'][2]}/, last_response.body)
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'can display scheduled' do
|
208
|
+
get '/scheduled'
|
209
|
+
assert_equal 200, last_response.status
|
210
|
+
assert_match(/found/, last_response.body)
|
211
|
+
refute_match(/HardWorker/, last_response.body)
|
212
|
+
|
213
|
+
add_scheduled
|
214
|
+
|
215
|
+
get '/scheduled'
|
216
|
+
assert_equal 200, last_response.status
|
217
|
+
refute_match(/found/, last_response.body)
|
218
|
+
assert_match(/HardWorker/, last_response.body)
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'can display a single scheduled job' do
|
222
|
+
params = add_scheduled
|
223
|
+
get '/scheduled/0-shouldntexist'
|
224
|
+
assert_equal 302, last_response.status
|
225
|
+
get "/scheduled/#{job_params(*params)}"
|
226
|
+
assert_equal 200, last_response.status
|
227
|
+
assert_match(/HardWorker/, last_response.body)
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'handles missing scheduled job' do
|
231
|
+
get "/scheduled/0-shouldntexist"
|
232
|
+
assert_equal 302, last_response.status
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'can add to queue a single scheduled job' do
|
236
|
+
params = add_scheduled
|
237
|
+
post "/scheduled/#{job_params(*params)}", 'add_to_queue' => true
|
238
|
+
assert_equal 302, last_response.status
|
239
|
+
assert_equal 'http://example.org/scheduled', last_response.header['Location']
|
240
|
+
|
241
|
+
get '/queues/100'
|
242
|
+
assert_equal 200, last_response.status
|
243
|
+
assert_match(/#{params.first['args'][2]}/, last_response.body)
|
244
|
+
end
|
245
|
+
|
246
|
+
it 'can delete a single scheduled job' do
|
247
|
+
params = add_scheduled
|
248
|
+
post "/scheduled/#{job_params(*params)}", 'delete' => 'Delete'
|
249
|
+
assert_equal 302, last_response.status
|
250
|
+
assert_equal 'http://example.org/scheduled', last_response.header['Location']
|
251
|
+
|
252
|
+
get "/scheduled"
|
253
|
+
assert_equal 200, last_response.status
|
254
|
+
refute_match(/#{params.first['args'][2]}/, last_response.body)
|
255
|
+
end
|
256
|
+
|
257
|
+
it 'can delete scheduled' do
|
258
|
+
params = add_scheduled
|
259
|
+
Roundhouse.redis do |conn|
|
260
|
+
assert_equal 1, conn.zcard('schedule')
|
261
|
+
post '/scheduled', 'key' => [job_params(*params)], 'delete' => 'Delete'
|
262
|
+
assert_equal 302, last_response.status
|
263
|
+
assert_equal 'http://example.org/scheduled', last_response.header['Location']
|
264
|
+
assert_equal 0, conn.zcard('schedule')
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
it "can move scheduled to a queue" do
|
269
|
+
q = Roundhouse::Queue.new(100)
|
270
|
+
params = add_scheduled
|
271
|
+
Roundhouse.redis do |conn|
|
272
|
+
assert_equal 1, conn.zcard('schedule')
|
273
|
+
assert_equal 0, q.size
|
274
|
+
post '/scheduled', 'key' => [job_params(*params)], 'add_to_queue' => 'AddToQueue'
|
275
|
+
assert_equal 302, last_response.status
|
276
|
+
assert_equal 'http://example.org/scheduled', last_response.header['Location']
|
277
|
+
assert_equal 0, conn.zcard('schedule')
|
278
|
+
assert_equal 1, q.size
|
279
|
+
get '/queues/100'
|
280
|
+
assert_equal 200, last_response.status
|
281
|
+
assert_match(/#{params[0]['args'][2]}/, last_response.body)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
it 'can retry all retries' do
|
286
|
+
msg = add_retry.first
|
287
|
+
add_retry
|
288
|
+
|
289
|
+
post "/retries/all/retry", 'retry' => 'Retry'
|
290
|
+
assert_equal 302, last_response.status
|
291
|
+
assert_equal 'http://example.org/retries', last_response.header['Location']
|
292
|
+
assert_equal 2, Roundhouse::Queue.new(100).size
|
293
|
+
|
294
|
+
get '/queues/100'
|
295
|
+
assert_equal 200, last_response.status
|
296
|
+
assert_match(/#{msg['args'][2]}/, last_response.body)
|
297
|
+
end
|
298
|
+
|
299
|
+
it 'calls updatePage() once when polling' do
|
300
|
+
get '/busy?poll=true'
|
301
|
+
assert_equal 200, last_response.status
|
302
|
+
assert_equal 1, last_response.body.scan('updatePage(').count
|
303
|
+
end
|
304
|
+
|
305
|
+
it 'escape job args and error messages' do
|
306
|
+
# on /retries page
|
307
|
+
params = add_xss_retry
|
308
|
+
get '/retries'
|
309
|
+
assert_equal 200, last_response.status
|
310
|
+
assert_match(/FailWorker/, last_response.body)
|
311
|
+
|
312
|
+
assert last_response.body.include?( "fail message: <a>hello</a>" )
|
313
|
+
assert !last_response.body.include?( "fail message: <a>hello</a>" )
|
314
|
+
|
315
|
+
assert last_response.body.include?( "args\">"<a>hello</a>"<" )
|
316
|
+
assert !last_response.body.include?( "args\"><a>hello</a><" )
|
317
|
+
|
318
|
+
# on /workers page
|
319
|
+
Roundhouse.redis do |conn|
|
320
|
+
pro = 'foo:1234'
|
321
|
+
conn.sadd('processes', pro)
|
322
|
+
conn.hmset(pro, 'info', Roundhouse.dump_json('started_at' => Time.now.to_f, 'labels' => ['frumduz'], 'queues' =>[]), 'busy', 1, 'beat', Time.now.to_f)
|
323
|
+
identity = "#{pro}:workers"
|
324
|
+
hash = {:queue => 'critical', :payload => { 'class' => "FailWorker", 'args' => ["<a>hello</a>"] }, :run_at => Time.now.to_i }
|
325
|
+
conn.hmset(identity, 100001, Roundhouse.dump_json(hash))
|
326
|
+
conn.incr('busy')
|
327
|
+
end
|
328
|
+
|
329
|
+
get '/busy'
|
330
|
+
assert_equal 200, last_response.status
|
331
|
+
assert_match(/FailWorker/, last_response.body)
|
332
|
+
assert_match(/frumduz/, last_response.body)
|
333
|
+
assert last_response.body.include?( "<a>hello</a>" )
|
334
|
+
assert !last_response.body.include?( "<a>hello</a>" )
|
335
|
+
|
336
|
+
|
337
|
+
# on /queues page
|
338
|
+
params = add_xss_retry # sorry, don't know how to easily make this show up on queues page otherwise.
|
339
|
+
post "/retries/#{job_params(*params)}", 'retry' => 'Retry'
|
340
|
+
assert_equal 302, last_response.status
|
341
|
+
|
342
|
+
get '/queues/100'
|
343
|
+
assert_equal 200, last_response.status
|
344
|
+
assert last_response.body.include?( "<a>hello</a>" )
|
345
|
+
assert !last_response.body.include?( "<a>hello</a>" )
|
346
|
+
end
|
347
|
+
|
348
|
+
it 'can show user defined tab' do
|
349
|
+
begin
|
350
|
+
Roundhouse::Web.tabs['Custom Tab'] = '/custom'
|
351
|
+
|
352
|
+
get '/'
|
353
|
+
assert_match 'Custom Tab', last_response.body
|
354
|
+
|
355
|
+
ensure
|
356
|
+
Roundhouse::Web.tabs.delete 'Custom Tab'
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
it 'can display home' do
|
361
|
+
get '/'
|
362
|
+
assert_equal 200, last_response.status
|
363
|
+
end
|
364
|
+
|
365
|
+
Roundhouse::Web.settings.locales << File.join(File.dirname(__FILE__), "fixtures")
|
366
|
+
it 'can show user defined tab with custom locales' do
|
367
|
+
begin
|
368
|
+
Roundhouse::Web.tabs['Custom Tab'] = '/custom'
|
369
|
+
Roundhouse::Web.get('/custom') do
|
370
|
+
t('translated_text')
|
371
|
+
end
|
372
|
+
|
373
|
+
get '/custom'
|
374
|
+
assert_match(/Changed text/, last_response.body)
|
375
|
+
|
376
|
+
ensure
|
377
|
+
Roundhouse::Web.tabs.delete 'Custom Tab'
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
describe 'dashboard/stats' do
|
382
|
+
it 'redirects to stats' do
|
383
|
+
get '/dashboard/stats'
|
384
|
+
assert_equal 302, last_response.status
|
385
|
+
assert_equal 'http://example.org/stats', last_response.header['Location']
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
describe 'stats' do
|
390
|
+
include Roundhouse::Util
|
391
|
+
|
392
|
+
before do
|
393
|
+
Roundhouse.redis do |conn|
|
394
|
+
conn.set("stat:processed", 5)
|
395
|
+
conn.set("stat:failed", 2)
|
396
|
+
conn.sadd("queues", "default")
|
397
|
+
end
|
398
|
+
2.times { add_retry }
|
399
|
+
3.times { add_scheduled }
|
400
|
+
4.times { add_worker }
|
401
|
+
|
402
|
+
get '/stats'
|
403
|
+
@response = Roundhouse.load_json(last_response.body)
|
404
|
+
end
|
405
|
+
|
406
|
+
it 'can refresh dashboard stats' do
|
407
|
+
assert_equal 200, last_response.status
|
408
|
+
end
|
409
|
+
|
410
|
+
describe "for roundhouse" do
|
411
|
+
it 'are namespaced' do
|
412
|
+
assert_includes @response.keys, "roundhouse"
|
413
|
+
end
|
414
|
+
|
415
|
+
it 'reports processed' do
|
416
|
+
assert_equal 5, @response["roundhouse"]["processed"]
|
417
|
+
end
|
418
|
+
|
419
|
+
it 'reports failed' do
|
420
|
+
assert_equal 2, @response["roundhouse"]["failed"]
|
421
|
+
end
|
422
|
+
|
423
|
+
it 'reports busy' do
|
424
|
+
assert_equal 4, @response["roundhouse"]["busy"]
|
425
|
+
end
|
426
|
+
|
427
|
+
it 'reports processes' do
|
428
|
+
assert_equal 1, @response["roundhouse"]["processes"]
|
429
|
+
end
|
430
|
+
|
431
|
+
it 'reports retries' do
|
432
|
+
assert_equal 2, @response["roundhouse"]["retries"]
|
433
|
+
end
|
434
|
+
|
435
|
+
it 'reports scheduled' do
|
436
|
+
assert_equal 3, @response["roundhouse"]["scheduled"]
|
437
|
+
end
|
438
|
+
|
439
|
+
it 'reports latency' do
|
440
|
+
skip 'no default latency'
|
441
|
+
assert_equal 0, @response["roundhouse"]["default_latency"]
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
describe "for redis" do
|
446
|
+
it 'are namespaced' do
|
447
|
+
assert_includes @response.keys, "redis"
|
448
|
+
end
|
449
|
+
|
450
|
+
it 'reports version' do
|
451
|
+
assert_includes @response["redis"].keys, "redis_version"
|
452
|
+
end
|
453
|
+
|
454
|
+
it 'reports uptime' do
|
455
|
+
assert_includes @response["redis"].keys, "uptime_in_days"
|
456
|
+
end
|
457
|
+
|
458
|
+
it 'reports connected clients' do
|
459
|
+
assert_includes @response["redis"].keys, "connected_clients"
|
460
|
+
end
|
461
|
+
|
462
|
+
it 'reports user memory' do
|
463
|
+
assert_includes @response["redis"].keys, "used_memory_human"
|
464
|
+
end
|
465
|
+
|
466
|
+
it 'reports memory peak' do
|
467
|
+
assert_includes @response["redis"].keys, "used_memory_peak_human"
|
468
|
+
end
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
describe 'stats/queues' do
|
473
|
+
include Roundhouse::Util
|
474
|
+
|
475
|
+
before do
|
476
|
+
Roundhouse.redis do |conn|
|
477
|
+
conn.set("stat:processed", 5)
|
478
|
+
conn.set("stat:failed", 2)
|
479
|
+
conn.sadd("queues", "default")
|
480
|
+
conn.sadd("queues", "queue2")
|
481
|
+
end
|
482
|
+
2.times { add_retry }
|
483
|
+
3.times { add_scheduled }
|
484
|
+
4.times { add_worker }
|
485
|
+
|
486
|
+
get '/stats/queues'
|
487
|
+
@response = Roundhouse.load_json(last_response.body)
|
488
|
+
end
|
489
|
+
|
490
|
+
it 'reports the queue depth' do
|
491
|
+
assert_equal 0, @response["default"]
|
492
|
+
assert_equal 0, @response["queue2"]
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
describe 'dead jobs' do
|
497
|
+
it 'shows empty index' do
|
498
|
+
get 'morgue'
|
499
|
+
assert_equal 200, last_response.status
|
500
|
+
end
|
501
|
+
|
502
|
+
it 'shows index with jobs' do
|
503
|
+
(_, score) = add_dead
|
504
|
+
get 'morgue'
|
505
|
+
assert_equal 200, last_response.status
|
506
|
+
assert_match(/#{score}/, last_response.body)
|
507
|
+
end
|
508
|
+
|
509
|
+
it 'can delete all dead' do
|
510
|
+
3.times { add_dead }
|
511
|
+
|
512
|
+
assert_equal 3, Roundhouse::DeadSet.new.size
|
513
|
+
post "/morgue/all/delete", 'delete' => 'Delete'
|
514
|
+
assert_equal 0, Roundhouse::DeadSet.new.size
|
515
|
+
assert_equal 302, last_response.status
|
516
|
+
assert_equal 'http://example.org/morgue', last_response.header['Location']
|
517
|
+
end
|
518
|
+
|
519
|
+
it 'can retry a dead job' do
|
520
|
+
params = add_dead
|
521
|
+
post "/morgue/#{job_params(*params)}", 'retry' => 'Retry'
|
522
|
+
assert_equal 302, last_response.status
|
523
|
+
assert_equal 'http://example.org/morgue', last_response.header['Location']
|
524
|
+
|
525
|
+
get '/queues/100'
|
526
|
+
assert_equal 200, last_response.status
|
527
|
+
assert_match(/#{params.first['args'][2]}/, last_response.body)
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
def add_scheduled
|
532
|
+
score = Time.now.to_f
|
533
|
+
msg = { 'class' => 'HardWorker',
|
534
|
+
'queue_id' => 100,
|
535
|
+
'args' => ['bob', 1, Time.now.to_f],
|
536
|
+
'jid' => SecureRandom.hex(12) }
|
537
|
+
Roundhouse.redis do |conn|
|
538
|
+
conn.zadd('schedule', score, Roundhouse.dump_json(msg))
|
539
|
+
end
|
540
|
+
[msg, score]
|
541
|
+
end
|
542
|
+
|
543
|
+
def add_retry
|
544
|
+
msg = { 'class' => 'HardWorker',
|
545
|
+
'args' => ['bob', 1, Time.now.to_f],
|
546
|
+
'queue_id' => 100,
|
547
|
+
'error_message' => 'Some fake message',
|
548
|
+
'error_class' => 'RuntimeError',
|
549
|
+
'retry_count' => 0,
|
550
|
+
'failed_at' => Time.now.to_f,
|
551
|
+
'jid' => SecureRandom.hex(12) }
|
552
|
+
score = Time.now.to_f
|
553
|
+
Roundhouse.redis do |conn|
|
554
|
+
conn.zadd('retry', score, Roundhouse.dump_json(msg))
|
555
|
+
end
|
556
|
+
[msg, score]
|
557
|
+
end
|
558
|
+
|
559
|
+
def add_dead
|
560
|
+
msg = { 'class' => 'HardWorker',
|
561
|
+
'queue_id' => 100,
|
562
|
+
'args' => ['bob', 1, Time.now.to_f],
|
563
|
+
'queue' => 'foo',
|
564
|
+
'error_message' => 'Some fake message',
|
565
|
+
'error_class' => 'RuntimeError',
|
566
|
+
'retry_count' => 0,
|
567
|
+
'failed_at' => Time.now.utc,
|
568
|
+
'jid' => SecureRandom.hex(12) }
|
569
|
+
score = Time.now.to_f
|
570
|
+
Roundhouse.redis do |conn|
|
571
|
+
conn.zadd('dead', score, Roundhouse.dump_json(msg))
|
572
|
+
end
|
573
|
+
[msg, score]
|
574
|
+
end
|
575
|
+
|
576
|
+
def add_xss_retry
|
577
|
+
msg = { 'class' => 'FailWorker',
|
578
|
+
'queue_id' => 100,
|
579
|
+
'args' => ['<a>hello</a>'],
|
580
|
+
'queue' => 'foo',
|
581
|
+
'error_message' => 'fail message: <a>hello</a>',
|
582
|
+
'error_class' => 'RuntimeError',
|
583
|
+
'retry_count' => 0,
|
584
|
+
'failed_at' => Time.now.to_f,
|
585
|
+
'jid' => SecureRandom.hex(12) }
|
586
|
+
score = Time.now.to_f
|
587
|
+
Roundhouse.redis do |conn|
|
588
|
+
conn.zadd('retry', score, Roundhouse.dump_json(msg))
|
589
|
+
end
|
590
|
+
[msg, score]
|
591
|
+
end
|
592
|
+
|
593
|
+
def add_worker
|
594
|
+
key = "#{hostname}:#{$$}"
|
595
|
+
msg = "{\"queue\":\"default\",\"payload\":{\"retry\":true,\"queue\":\"default\",\"timeout\":20,\"backtrace\":5,\"class\":\"HardWorker\",\"args\":[\"bob\",10,5],\"jid\":\"2b5ad2b016f5e063a1c62872\"},\"run_at\":1361208995}"
|
596
|
+
Roundhouse.redis do |conn|
|
597
|
+
conn.multi do
|
598
|
+
conn.sadd("processes", key)
|
599
|
+
conn.hmset(key, 'info', Roundhouse.dump_json('hostname' => 'foo', 'started_at' => Time.now.to_f, "queues" => []), 'at', Time.now.to_f, 'busy', 4)
|
600
|
+
conn.hmset("#{key}:workers", Time.now.to_f, msg)
|
601
|
+
end
|
602
|
+
end
|
603
|
+
end
|
604
|
+
end
|
605
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
require 'roundhouse'
|
3
|
+
require 'roundhouse/web_helpers'
|
4
|
+
|
5
|
+
class TestWebHelpers < Roundhouse::Test
|
6
|
+
|
7
|
+
class Helpers
|
8
|
+
include Roundhouse::WebHelpers
|
9
|
+
|
10
|
+
def initialize(params={})
|
11
|
+
@thehash = default.merge(params)
|
12
|
+
end
|
13
|
+
|
14
|
+
def request
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def settings
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def locales
|
23
|
+
['web/locales']
|
24
|
+
end
|
25
|
+
|
26
|
+
def env
|
27
|
+
@thehash
|
28
|
+
end
|
29
|
+
|
30
|
+
def default
|
31
|
+
{
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_locale_determination
|
37
|
+
obj = Helpers.new
|
38
|
+
assert_equal 'en', obj.locale
|
39
|
+
|
40
|
+
obj = Helpers.new('HTTP_ACCEPT_LANGUAGE' => 'fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4,ru;q=0.2')
|
41
|
+
assert_equal 'fr', obj.locale
|
42
|
+
|
43
|
+
obj = Helpers.new('HTTP_ACCEPT_LANGUAGE' => 'zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4,ru;q=0.2')
|
44
|
+
assert_equal 'zh-cn', obj.locale
|
45
|
+
|
46
|
+
obj = Helpers.new('HTTP_ACCEPT_LANGUAGE' => 'en-us; *')
|
47
|
+
assert_equal 'en', obj.locale
|
48
|
+
|
49
|
+
obj = Helpers.new('HTTP_ACCEPT_LANGUAGE' => '*')
|
50
|
+
assert_equal 'en', obj.locale
|
51
|
+
end
|
52
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|