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