qs 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/bench/config.qs +4 -27
  2. data/bench/dispatcher.qs +24 -0
  3. data/bench/report.rb +80 -10
  4. data/bench/report.txt +10 -3
  5. data/bench/setup.rb +55 -0
  6. data/lib/qs.rb +75 -15
  7. data/lib/qs/client.rb +73 -22
  8. data/lib/qs/daemon.rb +21 -21
  9. data/lib/qs/daemon_data.rb +4 -4
  10. data/lib/qs/dispatch_job.rb +36 -0
  11. data/lib/qs/dispatch_job_handler.rb +79 -0
  12. data/lib/qs/dispatcher_queue.rb +19 -0
  13. data/lib/qs/error_handler.rb +12 -12
  14. data/lib/qs/event.rb +82 -0
  15. data/lib/qs/event_handler.rb +34 -0
  16. data/lib/qs/event_handler_test_helpers.rb +17 -0
  17. data/lib/qs/job.rb +19 -31
  18. data/lib/qs/job_handler.rb +6 -63
  19. data/lib/qs/{test_helpers.rb → job_handler_test_helpers.rb} +2 -2
  20. data/lib/qs/message.rb +29 -0
  21. data/lib/qs/message_handler.rb +84 -0
  22. data/lib/qs/payload.rb +98 -0
  23. data/lib/qs/payload_handler.rb +106 -54
  24. data/lib/qs/queue.rb +39 -6
  25. data/lib/qs/queue_item.rb +33 -0
  26. data/lib/qs/route.rb +7 -7
  27. data/lib/qs/runner.rb +6 -5
  28. data/lib/qs/test_runner.rb +41 -13
  29. data/lib/qs/version.rb +1 -1
  30. data/qs.gemspec +1 -1
  31. data/test/helper.rb +1 -1
  32. data/test/support/app_daemon.rb +77 -11
  33. data/test/support/factory.rb +34 -0
  34. data/test/system/daemon_tests.rb +146 -77
  35. data/test/system/queue_tests.rb +87 -0
  36. data/test/unit/client_tests.rb +184 -45
  37. data/test/unit/daemon_data_tests.rb +4 -4
  38. data/test/unit/daemon_tests.rb +32 -32
  39. data/test/unit/dispatch_job_handler_tests.rb +163 -0
  40. data/test/unit/dispatch_job_tests.rb +75 -0
  41. data/test/unit/dispatcher_queue_tests.rb +42 -0
  42. data/test/unit/error_handler_tests.rb +9 -9
  43. data/test/unit/event_handler_test_helpers_tests.rb +55 -0
  44. data/test/unit/event_handler_tests.rb +63 -0
  45. data/test/unit/event_tests.rb +162 -0
  46. data/test/unit/{test_helper_tests.rb → job_handler_test_helper_tests.rb} +13 -19
  47. data/test/unit/job_handler_tests.rb +17 -210
  48. data/test/unit/job_tests.rb +49 -79
  49. data/test/unit/message_handler_tests.rb +235 -0
  50. data/test/unit/message_tests.rb +64 -0
  51. data/test/unit/payload_handler_tests.rb +285 -86
  52. data/test/unit/payload_tests.rb +139 -0
  53. data/test/unit/qs_runner_tests.rb +6 -6
  54. data/test/unit/qs_tests.rb +167 -28
  55. data/test/unit/queue_item_tests.rb +51 -0
  56. data/test/unit/queue_tests.rb +126 -18
  57. data/test/unit/route_tests.rb +12 -13
  58. data/test/unit/runner_tests.rb +10 -10
  59. data/test/unit/test_runner_tests.rb +117 -24
  60. metadata +51 -21
  61. data/bench/queue.rb +0 -8
  62. data/lib/qs/redis_item.rb +0 -33
  63. data/test/unit/redis_item_tests.rb +0 -49
@@ -2,8 +2,7 @@ require 'assert'
2
2
  require 'qs/payload_handler'
3
3
 
4
4
  require 'qs/daemon_data'
5
- require 'qs/job'
6
- require 'qs/redis_item'
5
+ require 'qs/queue_item'
7
6
 
8
7
  class Qs::PayloadHandler
9
8
 
@@ -17,31 +16,38 @@ class Qs::PayloadHandler
17
16
 
18
17
  end
19
18
 
20
- class InitTests < UnitTests
19
+ class InitSetupTests < UnitTests
21
20
  desc "when init"
22
- setup do
23
- @route_spy = RouteSpy.new
21
+ subject{ @payload_handler }
22
+
23
+ def setup_for_message(message)
24
+ @route_spy = RouteSpy.new(message.route_id)
24
25
  @daemon_data = Qs::DaemonData.new({
25
26
  :logger => Qs::NullLogger.new,
26
27
  :routes => [@route_spy]
27
28
  })
28
- @job = Qs::Job.new(@route_spy.name, Factory.string => Factory.string)
29
- serialized_payload = Qs.serialize(@job.to_payload)
30
- @redis_item = Qs::RedisItem.new(Factory.string, serialized_payload)
29
+ encoded_payload = Qs::Payload.serialize(message)
30
+ @queue_item = Qs::QueueItem.new(Factory.string, encoded_payload)
31
31
 
32
32
  Assert.stub(Qs::Logger, :new){ |*args| QsLoggerSpy.new(*args) }
33
+ end
33
34
 
34
- @payload_handler = @handler_class.new(@daemon_data, @redis_item)
35
+ end
36
+
37
+ class InitTests < InitSetupTests
38
+ setup do
39
+ @message = Factory.message
40
+ setup_for_message(@message)
41
+ @payload_handler = @handler_class.new(@daemon_data, @queue_item)
35
42
  end
36
- subject{ @payload_handler }
37
43
 
38
- should have_readers :daemon_data, :redis_item
44
+ should have_readers :daemon_data, :queue_item
39
45
  should have_readers :logger
40
46
  should have_imeths :run
41
47
 
42
- should "know its daemon data, redis item and logger" do
48
+ should "know its daemon data, queue item and logger" do
43
49
  assert_equal @daemon_data, subject.daemon_data
44
- assert_equal @redis_item, subject.redis_item
50
+ assert_equal @queue_item, subject.queue_item
45
51
  assert_equal @daemon_data.logger, subject.logger.passed_logger
46
52
  assert_equal @daemon_data.verbose_logging, subject.logger.verbose_logging
47
53
  end
@@ -54,42 +60,17 @@ class Qs::PayloadHandler
54
60
  @payload_handler.run
55
61
  end
56
62
 
57
- should "run a route for the redis item" do
63
+ should "run a route for the queue item" do
58
64
  assert_true @route_spy.run_called
59
- assert_equal @job, @route_spy.job_passed_to_run
65
+ assert_equal @message, @route_spy.message_passed_to_run
60
66
  assert_equal @daemon_data, @route_spy.daemon_data_passed_to_run
61
67
  end
62
68
 
63
- should "build up its redis item as it processes it" do
64
- assert_equal @job, @redis_item.job
65
- assert_equal @route_spy.handler_class, @redis_item.handler_class
66
- assert_nil @redis_item.exception
67
- assert_instance_of Float, @redis_item.time_taken
68
- end
69
-
70
- should "log its processing of the redis item" do
71
- logger_spy = subject.logger
72
- expected = "[Qs] ===== Running job ====="
73
- assert_includes expected, logger_spy.verbose.info_logged
74
- expected = "[Qs] Job: #{@redis_item.job.name.inspect}"
75
- assert_includes expected, logger_spy.verbose.info_logged
76
- expected = "[Qs] Params: #{@redis_item.job.params.inspect}"
77
- assert_includes expected, logger_spy.verbose.info_logged
78
- expected = "[Qs] Handler: #{@redis_item.handler_class}"
79
- assert_includes expected, logger_spy.verbose.info_logged
80
- expected = "[Qs] ===== Completed in #{@redis_item.time_taken}ms ====="
81
- assert_includes expected, logger_spy.verbose.info_logged
82
- assert_empty logger_spy.verbose.error_logged
83
-
84
- expected = SummaryLine.new({
85
- 'time' => @redis_item.time_taken,
86
- 'handler' => @redis_item.handler_class,
87
- 'job' => @redis_item.job.name,
88
- 'params' => @redis_item.job.params
89
- })
90
- assert_equal 1, logger_spy.summary.info_logged.size
91
- assert_equal "[Qs] #{expected}", logger_spy.summary.info_logged.first
92
- assert_empty logger_spy.summary.error_logged
69
+ should "build up its queue item as it processes it" do
70
+ assert_equal @message, @queue_item.message
71
+ assert_equal @route_spy.handler_class, @queue_item.handler_class
72
+ assert_nil @queue_item.exception
73
+ assert_instance_of Float, @queue_item.time_taken
93
74
  end
94
75
 
95
76
  end
@@ -114,26 +95,18 @@ class Qs::PayloadHandler
114
95
  should "run an error handler" do
115
96
  assert_equal @route_exception, @error_handler_spy.passed_exception
116
97
  exp = {
117
- :daemon_data => @daemon_data,
118
- :queue_redis_key => @redis_item.queue_redis_key,
119
- :serialized_payload => @redis_item.serialized_payload,
120
- :job => @redis_item.job,
121
- :handler_class => @redis_item.handler_class
98
+ :daemon_data => @daemon_data,
99
+ :queue_redis_key => @queue_item.queue_redis_key,
100
+ :encoded_payload => @queue_item.encoded_payload,
101
+ :message => @queue_item.message,
102
+ :handler_class => @queue_item.handler_class
122
103
  }
123
104
  assert_equal exp, @error_handler_spy.context_hash
124
105
  assert_true @error_handler_spy.run_called
125
106
  end
126
107
 
127
- should "store the exception on the redis item" do
128
- assert_equal @error_handler_spy.exception, @redis_item.exception
129
- end
130
-
131
- should "log its processing of the redis item" do
132
- logger_spy = subject.logger
133
- exception = @redis_item.exception
134
- backtrace = exception.backtrace.join("\n")
135
- exp = "[Qs] #{exception.class}: #{exception.message}\n#{backtrace}"
136
- assert_equal exp, logger_spy.verbose.error_logged.first
108
+ should "store the exception on the queue item" do
109
+ assert_equal @error_handler_spy.exception, @queue_item.exception
137
110
  end
138
111
 
139
112
  end
@@ -145,8 +118,8 @@ class Qs::PayloadHandler
145
118
  Assert.stub(@route_spy, :run){ raise @shutdown_error }
146
119
  end
147
120
 
148
- should "run an error handler if the redis item was started" do
149
- Assert.stub(@redis_item, :started){ true }
121
+ should "run an error handler if the queue item was started" do
122
+ Assert.stub(@queue_item, :started){ true }
150
123
  assert_raises{ @payload_handler.run }
151
124
 
152
125
  passed_exception = @error_handler_spy.passed_exception
@@ -156,8 +129,8 @@ class Qs::PayloadHandler
156
129
  assert_true @error_handler_spy.run_called
157
130
  end
158
131
 
159
- should "not run an error handler if the redis item was started" do
160
- Assert.stub(@redis_item, :started){ false }
132
+ should "not run an error handler if the queue item was started" do
133
+ Assert.stub(@queue_item, :started){ false }
161
134
  assert_raises{ @payload_handler.run }
162
135
 
163
136
  assert_nil @error_handler_spy
@@ -184,39 +157,265 @@ class Qs::PayloadHandler
184
157
 
185
158
  end
186
159
 
187
- class SummaryLineTests < UnitTests
188
- desc "SummaryLine"
160
+ class LoggingJobSetupTests < InitSetupTests
161
+ desc "and run with a job queue item"
162
+ setup do
163
+ @job = Factory.job
164
+ setup_for_message(@job)
165
+ @payload_handler = @handler_class.new(@daemon_data, @queue_item)
166
+ end
167
+
168
+ end
169
+
170
+ class LoggingJobTests < LoggingJobSetupTests
171
+ setup do
172
+ @payload_handler.run
173
+ end
174
+
175
+ should "log its processing of the job queue item" do
176
+ logger_spy = subject.logger
177
+ exp = "[Qs] ===== Received message ====="
178
+ assert_includes exp, logger_spy.verbose.info_logged
179
+ exp = "[Qs] Job: #{@job.route_name.inspect}"
180
+ assert_includes exp, logger_spy.verbose.info_logged
181
+ exp = "[Qs] Params: #{@job.params.inspect}"
182
+ assert_includes exp, logger_spy.verbose.info_logged
183
+ exp = "[Qs] Handler: #{@queue_item.handler_class}"
184
+ assert_includes exp, logger_spy.verbose.info_logged
185
+ exp = "[Qs] ===== Completed in #{@queue_item.time_taken}ms ====="
186
+ assert_includes exp, logger_spy.verbose.info_logged
187
+ assert_empty logger_spy.verbose.error_logged
188
+
189
+ exp = JobSummaryLine.new(@job, {
190
+ 'time' => @queue_item.time_taken,
191
+ 'handler' => @queue_item.handler_class,
192
+ 'params' => @queue_item.message.params
193
+ })
194
+ assert_equal 1, logger_spy.summary.info_logged.size
195
+ assert_equal "[Qs] #{exp}", logger_spy.summary.info_logged.first
196
+ assert_empty logger_spy.summary.error_logged
197
+ end
198
+
199
+ end
200
+
201
+ class LoggingJobErrorTests < LoggingJobSetupTests
202
+ desc "that errors while being processed"
203
+ setup do
204
+ @route_exception = Factory.exception
205
+ Assert.stub(@route_spy, :run){ raise @route_exception }
206
+
207
+ @payload_handler.run
208
+ end
209
+
210
+ should "log the error" do
211
+ logger_spy = subject.logger
212
+ exception = @queue_item.exception
213
+ backtrace = exception.backtrace.join("\n")
214
+ exp = "[Qs] #{exception.class}: #{exception.message}\n#{backtrace}"
215
+ assert_equal exp, logger_spy.verbose.error_logged.first
216
+
217
+ exp = JobSummaryLine.new(@job, {
218
+ 'time' => @queue_item.time_taken,
219
+ 'handler' => @queue_item.handler_class,
220
+ 'params' => @queue_item.message.params,
221
+ 'error' => "#{exception.class}: #{exception.message}"
222
+ })
223
+ assert_equal 1, logger_spy.summary.info_logged.size
224
+ assert_equal "[Qs] #{exp}", logger_spy.summary.info_logged.first
225
+ assert_empty logger_spy.summary.error_logged
226
+ end
227
+
228
+ end
229
+
230
+ class LoggingEventSetupTests < InitSetupTests
231
+ desc "and run with a event queue item"
232
+ setup do
233
+ @event = Factory.event
234
+ setup_for_message(@event)
235
+ @payload_handler = @handler_class.new(@daemon_data, @queue_item)
236
+ end
237
+
238
+ end
239
+
240
+ class LoggingEventTests < LoggingEventSetupTests
241
+ setup do
242
+ @payload_handler.run
243
+ end
244
+
245
+ should "log its processing of the event queue item" do
246
+ logger_spy = subject.logger
247
+ exp = "[Qs] ===== Received message ====="
248
+ assert_includes exp, logger_spy.verbose.info_logged
249
+ exp = "[Qs] Event: #{@event.route_name.inspect}"
250
+ assert_includes exp, logger_spy.verbose.info_logged
251
+ exp = "[Qs] Publisher: #{@event.publisher.inspect}"
252
+ assert_includes exp, logger_spy.verbose.info_logged
253
+ exp = "[Qs] Params: #{@event.params.inspect}"
254
+ assert_includes exp, logger_spy.verbose.info_logged
255
+ exp = "[Qs] Handler: #{@queue_item.handler_class}"
256
+ assert_includes exp, logger_spy.verbose.info_logged
257
+ exp = "[Qs] ===== Completed in #{@queue_item.time_taken}ms ====="
258
+ assert_includes exp, logger_spy.verbose.info_logged
259
+ assert_empty logger_spy.verbose.error_logged
260
+
261
+ exp = EventSummaryLine.new(@event, {
262
+ 'time' => @queue_item.time_taken,
263
+ 'handler' => @queue_item.handler_class,
264
+ 'params' => @queue_item.message.params
265
+ })
266
+ assert_equal 1, logger_spy.summary.info_logged.size
267
+ assert_equal "[Qs] #{exp}", logger_spy.summary.info_logged.first
268
+ assert_empty logger_spy.summary.error_logged
269
+ end
270
+
271
+ end
272
+
273
+ class LoggingEventErrorTests < LoggingEventSetupTests
274
+ desc "that errors while being processed"
275
+ setup do
276
+ @route_exception = Factory.exception
277
+ Assert.stub(@route_spy, :run){ raise @route_exception }
278
+
279
+ @payload_handler.run
280
+ end
281
+
282
+ should "log the error" do
283
+ logger_spy = subject.logger
284
+ exception = @queue_item.exception
285
+ backtrace = exception.backtrace.join("\n")
286
+ exp = "[Qs] #{exception.class}: #{exception.message}\n#{backtrace}"
287
+ assert_equal exp, logger_spy.verbose.error_logged.first
288
+
289
+ exp = EventSummaryLine.new(@event, {
290
+ 'time' => @queue_item.time_taken,
291
+ 'handler' => @queue_item.handler_class,
292
+ 'params' => @queue_item.message.params,
293
+ 'error' => "#{exception.class}: #{exception.message}"
294
+ })
295
+ assert_equal 1, logger_spy.summary.info_logged.size
296
+ assert_equal "[Qs] #{exp}", logger_spy.summary.info_logged.first
297
+ assert_empty logger_spy.summary.error_logged
298
+ end
299
+
300
+ end
301
+
302
+ class LoggingUnknownTests < InitSetupTests
303
+ desc "and run with an unknown type of queue item"
304
+ setup do
305
+ @message = Factory.message
306
+ setup_for_message(@message)
307
+
308
+ Assert.stub(Qs::Payload, :deserialize){ raise Factory.exception }
309
+
310
+ @payload_handler = @handler_class.new(@daemon_data, @queue_item)
311
+ @payload_handler.run
312
+ end
313
+
314
+ should "log its processing of the job queue item" do
315
+ logger_spy = subject.logger
316
+ exp = "[Qs] ===== Received message ====="
317
+ assert_includes exp, logger_spy.verbose.info_logged
318
+ exp = "[Qs] ===== Completed in #{@queue_item.time_taken}ms ====="
319
+ assert_includes exp, logger_spy.verbose.info_logged
320
+
321
+ logger_spy = subject.logger
322
+ exception = @queue_item.exception
323
+ backtrace = exception.backtrace.join("\n")
324
+ exp = "[Qs] #{exception.class}: #{exception.message}\n#{backtrace}"
325
+ assert_equal exp, logger_spy.verbose.error_logged.first
326
+
327
+ exp = UnknownSummaryLine.new({
328
+ 'time' => @queue_item.time_taken,
329
+ 'handler' => @queue_item.handler_class,
330
+ 'error' => "#{exception.class}: #{exception.message}"
331
+ })
332
+ assert_equal 1, logger_spy.summary.info_logged.size
333
+ assert_equal "[Qs] #{exp}", logger_spy.summary.info_logged.first
334
+ assert_empty logger_spy.summary.error_logged
335
+ end
336
+
337
+ end
338
+
339
+ class UnknownSummaryLineTests < UnitTests
340
+ desc "UnknownSummaryLine"
341
+ setup do
342
+ @attrs = {
343
+ 'time' => Factory.integer,
344
+ 'handler' => Factory.string,
345
+ 'error' => Factory.string
346
+ }
347
+ @summary_line = UnknownSummaryLine.new(@attrs)
348
+ end
349
+ subject{ @summary_line }
350
+
351
+ should "build an ordered string of the attributes with their values" do
352
+ exp = "time=#{@attrs['time'].inspect} " \
353
+ "handler=#{@attrs['handler'].inspect} " \
354
+ "error=#{@attrs['error'].inspect}"
355
+ assert_equal exp, subject
356
+ end
357
+
358
+ end
359
+
360
+ class JobSummaryLineTests < UnitTests
361
+ desc "JobSummaryLine"
362
+ setup do
363
+ @job = Factory.job
364
+ @attrs = {
365
+ 'time' => Factory.integer,
366
+ 'handler' => Factory.string,
367
+ 'params' => { Factory.string => Factory.string },
368
+ 'error' => Factory.string
369
+ }
370
+ @summary_line = JobSummaryLine.new(@job, @attrs)
371
+ end
372
+ subject{ @summary_line }
373
+
374
+ should "build an ordered string of the attributes with their values" do
375
+ exp = "time=#{@attrs['time'].inspect} " \
376
+ "handler=#{@attrs['handler'].inspect} " \
377
+ "job=#{@job.route_name.inspect} " \
378
+ "params=#{@attrs['params'].inspect} " \
379
+ "error=#{@attrs['error'].inspect}"
380
+ assert_equal exp, subject
381
+ end
382
+
383
+ end
384
+
385
+ class EventSummaryLineTests < UnitTests
386
+ desc "EventSummaryLine"
189
387
  setup do
388
+ @event = Factory.event(:publisher => Factory.string)
190
389
  @attrs = {
191
- 'time' => Factory.string,
192
- 'handler' => Factory.string,
193
- 'job' => Factory.string,
194
- 'params' => Factory.string,
195
- 'error' => Factory.string
390
+ 'time' => Factory.integer,
391
+ 'handler' => Factory.string,
392
+ 'params' => { Factory.string => Factory.string },
393
+ 'error' => Factory.string
196
394
  }
197
- @summary_line = SummaryLine.new(@attrs)
395
+ @summary_line = EventSummaryLine.new(@event, @attrs)
198
396
  end
199
397
  subject{ @summary_line }
200
398
 
201
- should "build a string of all the attributes ordered with their values" do
202
- expected = "time=#{@attrs['time'].inspect} " \
203
- "handler=#{@attrs['handler'].inspect} " \
204
- "job=#{@attrs['job'].inspect} " \
205
- "params=#{@attrs['params'].inspect} " \
206
- "error=#{@attrs['error'].inspect}"
207
- assert_equal expected, subject
399
+ should "build an ordered string of the attributes with their values" do
400
+ exp = "time=#{@attrs['time'].inspect} " \
401
+ "handler=#{@attrs['handler'].inspect} " \
402
+ "event=#{@event.route_name.inspect} " \
403
+ "publisher=#{@event.publisher.inspect} " \
404
+ "params=#{@attrs['params'].inspect} " \
405
+ "error=#{@attrs['error'].inspect}"
406
+ assert_equal exp, subject
208
407
  end
209
408
 
210
409
  end
211
410
 
212
411
  class RouteSpy
213
- attr_reader :name
214
- attr_reader :job_passed_to_run, :daemon_data_passed_to_run
412
+ attr_reader :id
413
+ attr_reader :message_passed_to_run, :daemon_data_passed_to_run
215
414
  attr_reader :run_called
216
415
 
217
- def initialize
218
- @name = Factory.string
219
- @job_passed_to_run = nil
416
+ def initialize(message_route_id)
417
+ @id = message_route_id
418
+ @message_passed_to_run = nil
220
419
  @daemon_data_passed_to_run = nil
221
420
  @run_called = false
222
421
  end
@@ -225,8 +424,8 @@ class Qs::PayloadHandler
225
424
  TestHandler
226
425
  end
227
426
 
228
- def run(job, daemon_data)
229
- @job_passed_to_run = job
427
+ def run(message, daemon_data)
428
+ @message_passed_to_run = message
230
429
  @daemon_data_passed_to_run = daemon_data
231
430
  @run_called = true
232
431
  end