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
@@ -0,0 +1,51 @@
1
+ require 'assert'
2
+ require 'qs/queue_item'
3
+
4
+ require 'qs/queue'
5
+
6
+ class Qs::QueueItem
7
+
8
+ class UnitTests < Assert::Context
9
+ desc "Qs::QueueItem"
10
+ setup do
11
+ @queue_redis_key = Factory.string
12
+ @encoded_payload = Factory.string
13
+ @queue_item = Qs::QueueItem.new(@queue_redis_key, @encoded_payload)
14
+ end
15
+ subject{ @queue_item }
16
+
17
+ should have_readers :queue_redis_key, :encoded_payload
18
+ should have_accessors :started, :finished
19
+ should have_accessors :message, :handler_class
20
+ should have_accessors :exception, :time_taken
21
+
22
+ should "know its queue redis key and encoded payload" do
23
+ assert_equal @queue_redis_key, subject.queue_redis_key
24
+ assert_equal @encoded_payload, subject.encoded_payload
25
+ end
26
+
27
+ should "defaults its other attributes" do
28
+ assert_false subject.started
29
+ assert_false subject.finished
30
+
31
+ assert_nil subject.message
32
+ assert_nil subject.handler_class
33
+ assert_nil subject.exception
34
+ assert_nil subject.time_taken
35
+ end
36
+
37
+ should "know if it equals another item" do
38
+ exp = Qs::QueueItem.new(@queue_redis_key, @encoded_payload)
39
+ assert_equal exp, subject
40
+
41
+ redis_key = Qs::Queue::RedisKey.new(Factory.string)
42
+ exp = Qs::QueueItem.new(redis_key, @encoded_payload)
43
+ assert_not_equal exp, subject
44
+
45
+ exp = Qs::QueueItem.new(@queue_redis_key, Factory.string)
46
+ assert_not_equal exp, subject
47
+ end
48
+
49
+ end
50
+
51
+ end
@@ -8,22 +8,21 @@ class Qs::Queue
8
8
  class UnitTests < Assert::Context
9
9
  desc "Qs::Queue"
10
10
  setup do
11
- @queue = Qs::Queue.new do
12
- name Factory.string
13
- end
11
+ @queue = Qs::Queue.new{ name Factory.string }
14
12
  end
15
13
  subject{ @queue }
16
14
 
17
- should have_readers :routes, :enqueued_jobs
18
- should have_imeths :name, :redis_key, :job_handler_ns, :job
15
+ should have_readers :routes, :event_route_names, :enqueued_jobs
16
+ should have_imeths :name, :redis_key
17
+ should have_imeths :job_handler_ns, :job
18
+ should have_imeths :event_handler_ns, :event
19
19
  should have_imeths :enqueue, :add
20
- should have_imeths :reset!
20
+ should have_imeths :sync_subscriptions, :clear_subscriptions
21
+ should have_imeths :published_events, :reset!
21
22
 
22
- should "default its routes to an empty array" do
23
+ should "default its routes, event route names and enqueued jobs" do
23
24
  assert_equal [], subject.routes
24
- end
25
-
26
- should "default its enqueued jobs to an empty array" do
25
+ assert_equal [], subject.event_route_names
27
26
  assert_equal [], subject.enqueued_jobs
28
27
  end
29
28
 
@@ -49,35 +48,124 @@ class Qs::Queue
49
48
  assert_equal namespace, subject.job_handler_ns
50
49
  end
51
50
 
52
- should "allow adding routes using `job`" do
53
- job_name = Factory.string
51
+ should "not have an event handler ns by default" do
52
+ assert_nil subject.event_handler_ns
53
+ end
54
+
55
+ should "allow setting its event handler ns" do
56
+ namespace = Factory.string
57
+ subject.event_handler_ns namespace
58
+ assert_equal namespace, subject.event_handler_ns
59
+ end
60
+
61
+ should "allow adding job routes using `job`" do
62
+ job_name = Factory.string
54
63
  handler_name = Factory.string
55
64
  subject.job job_name, handler_name
56
65
 
57
66
  route = subject.routes.last
58
67
  assert_instance_of Qs::Route, route
59
- assert_equal job_name, route.name
68
+ exp = Qs::Message::RouteId.new(Qs::Job::PAYLOAD_TYPE, job_name)
69
+ assert_equal exp, route.id
60
70
  assert_equal handler_name, route.handler_class_name
61
71
  end
62
72
 
63
- should "use its job handler ns when adding routes" do
73
+ should "use its job handler ns when adding job routes" do
64
74
  namespace = Factory.string
65
75
  subject.job_handler_ns namespace
66
76
 
67
- job_name = Factory.string
77
+ job_name = Factory.string
68
78
  handler_name = Factory.string
69
79
  subject.job job_name, handler_name
70
80
 
71
81
  route = subject.routes.last
72
- expected = "#{namespace}::#{handler_name}"
73
- assert_equal expected, route.handler_class_name
82
+ exp = "#{namespace}::#{handler_name}"
83
+ assert_equal exp, route.handler_class_name
84
+ end
85
+
86
+ should "not use its job handler ns with a top-level handler name" do
87
+ namespace = Factory.string
88
+ subject.job_handler_ns namespace
89
+
90
+ job_name = Factory.string
91
+ handler_name = "::#{Factory.string}"
92
+ subject.job job_name, handler_name
93
+
94
+ route = subject.routes.last
95
+ assert_equal handler_name, route.handler_class_name
96
+ end
97
+
98
+ should "allow adding event routes using `event`" do
99
+ event_channel = Factory.string
100
+ event_name = Factory.string
101
+ handler_name = Factory.string
102
+ subject.event event_channel, event_name, handler_name
103
+
104
+ route = subject.routes.last
105
+ assert_instance_of Qs::Route, route
106
+ route_name = Qs::Event::RouteName.new(event_channel, event_name)
107
+ exp = Qs::Message::RouteId.new(Qs::Event::PAYLOAD_TYPE, route_name)
108
+ assert_equal exp, route.id
109
+ assert_equal handler_name, route.handler_class_name
110
+ end
111
+
112
+ should "use its event handler ns when adding event routes" do
113
+ namespace = Factory.string
114
+ subject.event_handler_ns namespace
115
+
116
+ event_channel = Factory.string
117
+ event_name = Factory.string
118
+ handler_name = Factory.string
119
+ subject.event event_channel, event_name, handler_name
120
+
121
+ route = subject.routes.last
122
+ exp = "#{namespace}::#{handler_name}"
123
+ assert_equal exp, route.handler_class_name
124
+ end
125
+
126
+ should "not use its event handler ns with a top-level handler name" do
127
+ namespace = Factory.string
128
+ subject.event_handler_ns namespace
129
+
130
+ event_channel = Factory.string
131
+ event_name = Factory.string
132
+ handler_name = "::#{Factory.string}"
133
+ subject.event event_channel, event_name, handler_name
134
+
135
+ route = subject.routes.last
136
+ assert_equal handler_name, route.handler_class_name
137
+ end
138
+
139
+ should "track its configured event route names" do
140
+ event_channel = Factory.string
141
+ event_name = Factory.string
142
+ handler_name = Factory.string
143
+ subject.event event_channel, event_name, handler_name
144
+
145
+ exp = Qs::Event::RouteName.new(event_channel, event_name)
146
+ assert_equal [exp], subject.event_route_names
147
+ end
148
+
149
+ should "return the enqueued jobs events using `published_events`" do
150
+ dispatch_jobs = Factory.integer(3).times.map do
151
+ Factory.dispatch_job.tap{ |j| subject.enqueued_jobs << j }
152
+ end
153
+ assert_equal dispatch_jobs.map(&:event), subject.published_events
154
+ end
155
+
156
+ should "clear its enqueued jobs when reset" do
157
+ Factory.integer(3).times.map{ subject.enqueued_jobs << Factory.job }
158
+ assert_not_empty subject.enqueued_jobs
159
+ subject.reset!
160
+ assert_empty subject.enqueued_jobs
74
161
  end
75
162
 
76
163
  should "know its custom inspect" do
77
164
  reference = '0x0%x' % (subject.object_id << 1)
78
165
  expected = "#<#{subject.class}:#{reference} " \
79
166
  "@name=#{subject.name.inspect} " \
80
- "@job_handler_ns=#{subject.job_handler_ns.inspect}>"
167
+ "@job_handler_ns=#{subject.job_handler_ns.inspect} " \
168
+ "@event_handler_ns=#{subject.event_handler_ns.inspect}>"
81
169
  assert_equal expected, subject.inspect
82
170
  end
83
171
 
@@ -112,6 +200,26 @@ class Qs::Queue
112
200
 
113
201
  end
114
202
 
203
+ class SubscriptionsTests < UnitTests
204
+ setup do
205
+ @sync_args = nil
206
+ Assert.stub(Qs, :sync_subscriptions){ |*args| @sync_args = args }
207
+ @clear_args = nil
208
+ Assert.stub(Qs, :clear_subscriptions){ |*args| @clear_args = args }
209
+ end
210
+
211
+ should "use Qs to sync its subscriptions" do
212
+ subject.sync_subscriptions
213
+ assert_equal [subject], @sync_args
214
+ end
215
+
216
+ should "use Qs to clear its subscriptions" do
217
+ subject.clear_subscriptions
218
+ assert_equal [subject], @clear_args
219
+ end
220
+
221
+ end
222
+
115
223
  class RedisKeyTests < UnitTests
116
224
  desc "RedisKey"
117
225
  subject{ RedisKey }
@@ -3,7 +3,6 @@ require 'qs/route'
3
3
 
4
4
  require 'qs/daemon_data'
5
5
  require 'qs/logger'
6
- require 'qs/job'
7
6
  require 'test/support/runner_spy'
8
7
 
9
8
  class Qs::Route
@@ -11,17 +10,17 @@ class Qs::Route
11
10
  class UnitTests < Assert::Context
12
11
  desc "Qs::Route"
13
12
  setup do
14
- @name = Factory.string
13
+ @id = Factory.string
15
14
  @handler_class_name = TestHandler.to_s
16
- @route = Qs::Route.new(@name, @handler_class_name)
15
+ @route = Qs::Route.new(@id, @handler_class_name)
17
16
  end
18
17
  subject{ @route }
19
18
 
20
- should have_readers :name, :handler_class_name, :handler_class
19
+ should have_readers :id, :handler_class_name, :handler_class
21
20
  should have_imeths :validate!, :run
22
21
 
23
- should "know its name and handler class name" do
24
- assert_equal @name, subject.name
22
+ should "know its id and handler class name" do
23
+ assert_equal @id, subject.id
25
24
  assert_equal @handler_class_name, subject.handler_class_name
26
25
  end
27
26
 
@@ -39,7 +38,7 @@ class Qs::Route
39
38
  class RunTests < UnitTests
40
39
  desc "when run"
41
40
  setup do
42
- @job = Qs::Job.new(Factory.string, Factory.string => Factory.string)
41
+ @message = Factory.message
43
42
  @daemon_data = Qs::DaemonData.new(:logger => Qs::NullLogger.new)
44
43
 
45
44
  @runner_spy = nil
@@ -47,18 +46,18 @@ class Qs::Route
47
46
  @runner_spy = RunnerSpy.new(*args)
48
47
  end
49
48
 
50
- @route.run(@job, @daemon_data)
49
+ @route.run(@message, @daemon_data)
51
50
  end
52
51
 
53
52
  should "build and run a qs runner" do
54
53
  assert_not_nil @runner_spy
55
54
  assert_equal @route.handler_class, @runner_spy.handler_class
56
- expected = {
57
- :job => @job,
58
- :params => @job.params,
59
- :logger => @daemon_data.logger
55
+ exp = {
56
+ :message => @message,
57
+ :params => @message.params,
58
+ :logger => @daemon_data.logger
60
59
  }
61
- assert_equal expected, @runner_spy.args
60
+ assert_equal exp, @runner_spy.args
62
61
  assert_true @runner_spy.run_called
63
62
  end
64
63
 
@@ -24,7 +24,7 @@ class Qs::Runner
24
24
  subject{ @runner }
25
25
 
26
26
  should have_readers :handler_class, :handler
27
- should have_readers :job, :params, :logger
27
+ should have_readers :message, :params, :logger
28
28
  should have_imeths :run
29
29
 
30
30
  should "know its handler class and handler" do
@@ -32,22 +32,22 @@ class Qs::Runner
32
32
  assert_instance_of @handler_class, subject.handler
33
33
  end
34
34
 
35
- should "not set its job, params or logger by default" do
36
- assert_nil subject.job
35
+ should "not set its message, params or logger by default" do
36
+ assert_nil subject.message
37
37
  assert_equal({}, subject.params)
38
38
  assert_instance_of Qs::NullLogger, subject.logger
39
39
  end
40
40
 
41
- should "allow passing a job, params and logger" do
41
+ should "allow passing a message, params and logger" do
42
42
  args = {
43
- :job => Factory.string,
44
- :params => Factory.string,
45
- :logger => Factory.string
43
+ :message => Factory.string,
44
+ :params => Factory.string,
45
+ :logger => Factory.string
46
46
  }
47
47
  runner = @runner_class.new(@handler_class, args)
48
- assert_equal args[:job], runner.job
49
- assert_equal args[:params], runner.params
50
- assert_equal args[:logger], runner.logger
48
+ assert_equal args[:message], runner.message
49
+ assert_equal args[:params], runner.params
50
+ assert_equal args[:logger], runner.logger
51
51
  end
52
52
 
53
53
  should "raise a not implemented error when run" do
@@ -2,6 +2,7 @@ require 'assert'
2
2
  require 'qs/test_runner'
3
3
 
4
4
  require 'qs'
5
+ require 'qs/event'
5
6
 
6
7
  class Qs::TestRunner
7
8
 
@@ -25,28 +26,28 @@ class Qs::TestRunner
25
26
  class InitTests < UnitTests
26
27
  desc "when init"
27
28
  setup do
28
- @handler_class = TestJobHandler
29
+ @handler_class = TestMessageHandler
29
30
  @args = {
30
- :job => Factory.string,
31
- :params => { Factory.string => Factory.string },
32
- :logger => Factory.string,
33
- :flag => Factory.boolean
31
+ :message => Factory.message,
32
+ :params => { Factory.string => Factory.string },
33
+ :logger => Factory.string,
34
+ :flag => Factory.boolean
34
35
  }
35
36
  @original_args = @args.dup
36
- @runner = @runner_class.new(@handler_class, @args)
37
+ @runner = @runner_class.new(@handler_class, @args)
37
38
  @handler = @runner.handler
38
39
  end
39
40
  subject{ @runner }
40
41
 
41
42
  should have_imeths :run
42
43
 
43
- should "know its job, params and logger" do
44
- assert_equal @args[:job], subject.job
45
- assert_equal @args[:params], subject.params
46
- assert_equal @args[:logger], subject.logger
44
+ should "know its message, params and logger" do
45
+ assert_equal @args[:message], subject.message
46
+ assert_equal @args[:params], subject.params
47
+ assert_equal @args[:logger], subject.logger
47
48
  end
48
49
 
49
- should "write extra args to its job handler" do
50
+ should "write extra args to its message handler" do
50
51
  assert_equal @args[:flag], @handler.flag
51
52
  end
52
53
 
@@ -54,23 +55,23 @@ class Qs::TestRunner
54
55
  assert_equal @original_args, @args
55
56
  end
56
57
 
57
- should "not call its job handler's before callbacks" do
58
+ should "not call its message handler's before callbacks" do
58
59
  assert_nil @handler.before_called
59
60
  end
60
61
 
61
- should "call its job handler's init" do
62
+ should "call its message handler's init" do
62
63
  assert_true @handler.init_called
63
64
  end
64
65
 
65
- should "not run its job handler" do
66
+ should "not run its message handler" do
66
67
  assert_nil @handler.run_called
67
68
  end
68
69
 
69
- should "not call its job handler's after callbacks" do
70
+ should "not call its message handler's after callbacks" do
70
71
  assert_nil @handler.after_called
71
72
  end
72
73
 
73
- should "stringify and serialize the params passed to it" do
74
+ should "stringify and encode the params passed to it" do
74
75
  key, value = Factory.string.to_sym, Factory.string
75
76
  params = {
76
77
  key => value,
@@ -84,10 +85,6 @@ class Qs::TestRunner
84
85
  assert_equal exp, runner.params
85
86
  end
86
87
 
87
- should "raise an invalid error when not passed a job handler" do
88
- assert_raises(Qs::InvalidJobHandlerError){ @runner_class.new(Class.new) }
89
- end
90
-
91
88
  end
92
89
 
93
90
  class RunTests < InitTests
@@ -96,18 +93,104 @@ class Qs::TestRunner
96
93
  @runner.run
97
94
  end
98
95
 
99
- should "run its job handler" do
96
+ should "run its message handler" do
100
97
  assert_true @handler.run_called
101
98
  end
102
99
 
103
- should "not call its job handler's after callbacks" do
100
+ should "not call its message handler's after callbacks" do
104
101
  assert_nil @handler.after_called
105
102
  end
106
103
 
107
104
  end
108
105
 
109
- class TestJobHandler
110
- include Qs::JobHandler
106
+ class JobTestRunnerTests < UnitTests
107
+ desc "JobTestRunner"
108
+ setup do
109
+ @runner_class = Qs::JobTestRunner
110
+ end
111
+ subject{ @runner_class }
112
+
113
+ should "be a test runner" do
114
+ assert_true subject < Qs::TestRunner
115
+ end
116
+
117
+ end
118
+
119
+ class JobTestRunnerInitTests < JobTestRunnerTests
120
+ desc "when init"
121
+ setup do
122
+ @handler_class = TestJobHandler
123
+ @args = { :job => Factory.job }
124
+ @original_args = @args.dup
125
+ @runner = @runner_class.new(@handler_class, @args)
126
+ end
127
+ subject{ @runner }
128
+
129
+ should "allow passing a job as its message" do
130
+ assert_equal @args[:job], subject.message
131
+ end
132
+
133
+ should "use job over message if both are provided" do
134
+ @args[:message] = Factory.message
135
+ runner = @runner_class.new(@handler_class, @args)
136
+ assert_equal @args[:job], runner.message
137
+ end
138
+
139
+ should "not alter the args passed to it" do
140
+ assert_equal @original_args, @args
141
+ end
142
+
143
+ should "raise an invalid error when not passed a job handler" do
144
+ assert_raises(Qs::InvalidJobHandlerError){ @runner_class.new(Class.new) }
145
+ end
146
+
147
+ end
148
+
149
+ class EventTestRunnerTests < UnitTests
150
+ desc "EventTestRunner"
151
+ setup do
152
+ @runner_class = Qs::EventTestRunner
153
+ end
154
+ subject{ @runner_class }
155
+
156
+ should "be a test runner" do
157
+ assert_true subject < Qs::TestRunner
158
+ end
159
+
160
+ end
161
+
162
+ class EventTestRunnerInitTests < EventTestRunnerTests
163
+ desc "when init"
164
+ setup do
165
+ @handler_class = TestEventHandler
166
+ @args = { :event => Factory.event }
167
+ @original_args = @args.dup
168
+ @runner = @runner_class.new(@handler_class, @args)
169
+ end
170
+ subject{ @runner }
171
+
172
+ should "allow passing an event as its message" do
173
+ assert_equal @args[:event], subject.message
174
+ end
175
+
176
+ should "use event over message if both are provided" do
177
+ @args[:message] = Factory.message
178
+ runner = @runner_class.new(@handler_class, @args)
179
+ assert_equal @args[:event], runner.message
180
+ end
181
+
182
+ should "not alter the args passed to it" do
183
+ assert_equal @original_args, @args
184
+ end
185
+
186
+ should "raise an invalid error when not passed an event handler" do
187
+ assert_raises(Qs::InvalidEventHandlerError){ @runner_class.new(Class.new) }
188
+ end
189
+
190
+ end
191
+
192
+ class TestMessageHandler
193
+ include Qs::MessageHandler
111
194
 
112
195
  attr_reader :before_called, :after_called
113
196
  attr_reader :init_called, :run_called
@@ -125,4 +208,14 @@ class Qs::TestRunner
125
208
  end
126
209
  end
127
210
 
211
+ class TestJobHandler
212
+ include Qs::JobHandler
213
+
214
+ end
215
+
216
+ class TestEventHandler
217
+ include Qs::EventHandler
218
+
219
+ end
220
+
128
221
  end