qs 0.3.0 → 0.4.0

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 (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