qs 0.6.1 → 0.7.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.
- checksums.yaml +4 -4
- data/bench/config.qs +1 -0
- data/bench/dispatcher.qs +1 -0
- data/bench/report.rb +2 -0
- data/bench/setup.rb +1 -1
- data/lib/qs.rb +95 -41
- data/lib/qs/client.rb +5 -5
- data/lib/qs/config_file.rb +1 -1
- data/lib/qs/daemon.rb +133 -99
- data/lib/qs/daemon_data.rb +22 -21
- data/lib/qs/message_handler.rb +1 -0
- data/lib/qs/process.rb +20 -10
- data/lib/qs/qs_runner.rb +13 -21
- data/lib/qs/runner.rb +4 -0
- data/lib/qs/test_runner.rb +12 -2
- data/lib/qs/version.rb +1 -1
- data/qs.gemspec +6 -7
- data/test/helper.rb +11 -0
- data/test/support/app_queue.rb +104 -0
- data/test/support/client_spy.rb +2 -2
- data/test/support/config.qs +9 -2
- data/test/support/factory.rb +1 -1
- data/test/system/daemon_tests.rb +117 -36
- data/test/system/queue_tests.rb +1 -1
- data/test/unit/cli_tests.rb +2 -2
- data/test/unit/client_tests.rb +11 -11
- data/test/unit/config_file_tests.rb +2 -2
- data/test/unit/daemon_data_tests.rb +53 -48
- data/test/unit/daemon_tests.rb +221 -214
- data/test/unit/message_handler_tests.rb +14 -1
- data/test/unit/process_tests.rb +50 -25
- data/test/unit/qs_runner_tests.rb +120 -34
- data/test/unit/qs_tests.rb +180 -75
- data/test/unit/queue_tests.rb +5 -5
- data/test/unit/runner_tests.rb +9 -1
- data/test/unit/test_runner_tests.rb +12 -1
- metadata +13 -23
- data/test/support/app_daemon.rb +0 -143
@@ -211,7 +211,7 @@ module Qs::MessageHandler
|
|
211
211
|
@handler.qs_run
|
212
212
|
end
|
213
213
|
|
214
|
-
should "call `run!` and
|
214
|
+
should "call `run!` and its callbacks" do
|
215
215
|
assert_equal 6, subject.first_before_run_call_order
|
216
216
|
assert_equal 7, subject.second_before_run_call_order
|
217
217
|
assert_equal 8, subject.run_call_order
|
@@ -236,12 +236,25 @@ module Qs::MessageHandler
|
|
236
236
|
assert_equal @runner.params, subject.instance_eval{ params }
|
237
237
|
end
|
238
238
|
|
239
|
+
should "call to the runner for its halt helper" do
|
240
|
+
capture_runner_meth_args_for(:halt)
|
241
|
+
subject.instance_eval{ halt }
|
242
|
+
|
243
|
+
assert_equal [], @meth_args
|
244
|
+
end
|
245
|
+
|
239
246
|
private
|
240
247
|
|
241
248
|
def stub_runner_with_something_for(meth)
|
242
249
|
Assert.stub(@runner, meth){ @something }
|
243
250
|
end
|
244
251
|
|
252
|
+
def capture_runner_meth_args_for(meth)
|
253
|
+
Assert.stub(@runner, meth) do |*args|
|
254
|
+
@meth_args = args
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
245
258
|
end
|
246
259
|
|
247
260
|
class TestMessageHandler
|
data/test/unit/process_tests.rb
CHANGED
@@ -2,6 +2,7 @@ require 'assert'
|
|
2
2
|
require 'qs/process'
|
3
3
|
|
4
4
|
require 'qs/daemon'
|
5
|
+
require 'qs/io_pipe'
|
5
6
|
require 'test/support/pid_file_spy'
|
6
7
|
|
7
8
|
class Qs::Process
|
@@ -9,22 +10,31 @@ class Qs::Process
|
|
9
10
|
class UnitTests < Assert::Context
|
10
11
|
desc "Qs::Process"
|
11
12
|
setup do
|
13
|
+
@current_env_skip_daemonize = ENV['QS_SKIP_DAEMONIZE']
|
14
|
+
ENV.delete('QS_SKIP_DAEMONIZE')
|
15
|
+
|
12
16
|
@process_class = Qs::Process
|
13
17
|
end
|
18
|
+
teardown do
|
19
|
+
ENV['QS_SKIP_DAEMONIZE'] = @current_env_skip_daemonize
|
20
|
+
end
|
14
21
|
subject{ @process_class }
|
15
22
|
|
16
23
|
should "know its wait for signals timeout" do
|
17
24
|
assert_equal 15, WAIT_FOR_SIGNALS_TIMEOUT
|
18
25
|
end
|
19
26
|
|
27
|
+
should "know its signal strings" do
|
28
|
+
assert_equal 'H', HALT
|
29
|
+
assert_equal 'S', STOP
|
30
|
+
assert_equal 'R', RESTART
|
31
|
+
end
|
32
|
+
|
20
33
|
end
|
21
34
|
|
22
35
|
class InitTests < UnitTests
|
23
36
|
desc "when init"
|
24
37
|
setup do
|
25
|
-
@current_env_skip_daemonize = ENV['QS_SKIP_DAEMONIZE']
|
26
|
-
ENV.delete('QS_SKIP_DAEMONIZE')
|
27
|
-
|
28
38
|
@daemon_spy = DaemonSpy.new
|
29
39
|
|
30
40
|
@pid_file_spy = PIDFileSpy.new(Factory.integer)
|
@@ -37,9 +47,6 @@ class Qs::Process
|
|
37
47
|
|
38
48
|
@process = @process_class.new(@daemon_spy)
|
39
49
|
end
|
40
|
-
teardown do
|
41
|
-
ENV['QS_SKIP_DAEMONIZE'] = @current_env_skip_daemonize
|
42
|
-
end
|
43
50
|
subject{ @process }
|
44
51
|
|
45
52
|
should have_readers :daemon, :name
|
@@ -51,7 +58,9 @@ class Qs::Process
|
|
51
58
|
end
|
52
59
|
|
53
60
|
should "know its name, pid file, signal io and restart cmd" do
|
54
|
-
|
61
|
+
exp = "qs: #{@daemon_spy.process_label}"
|
62
|
+
assert_equal exp, subject.name
|
63
|
+
|
55
64
|
assert_equal @pid_file_spy, subject.pid_file
|
56
65
|
assert_instance_of Qs::IOPipe, subject.signal_io
|
57
66
|
assert_equal @restart_cmd_spy, subject.restart_cmd
|
@@ -109,12 +118,12 @@ class Qs::Process
|
|
109
118
|
@wait_timeout = nil
|
110
119
|
Assert.stub(@process.signal_io, :wait) do |timeout|
|
111
120
|
@wait_timeout = timeout
|
112
|
-
sleep
|
121
|
+
sleep 2*JOIN_SECONDS
|
113
122
|
false
|
114
123
|
end
|
115
124
|
|
116
125
|
@thread = Thread.new{ @process.run }
|
117
|
-
@thread.join(
|
126
|
+
@thread.join(JOIN_SECONDS)
|
118
127
|
end
|
119
128
|
teardown do
|
120
129
|
# manually unstub or the process thread will hang forever
|
@@ -177,7 +186,7 @@ class Qs::Process
|
|
177
186
|
setup do
|
178
187
|
Assert.stub(@process, :daemonize?){ true }
|
179
188
|
@thread = Thread.new{ @process.run }
|
180
|
-
@thread.join(
|
189
|
+
@thread.join(JOIN_SECONDS)
|
181
190
|
end
|
182
191
|
|
183
192
|
should "daemonize the process" do
|
@@ -190,8 +199,9 @@ class Qs::Process
|
|
190
199
|
desc "and run with a halt signal"
|
191
200
|
setup do
|
192
201
|
@thread = Thread.new{ @process.run }
|
202
|
+
@thread.join(JOIN_SECONDS)
|
193
203
|
@process.signal_io.write(HALT)
|
194
|
-
@thread.join(
|
204
|
+
@thread.join(JOIN_SECONDS)
|
195
205
|
end
|
196
206
|
|
197
207
|
should "halt its daemon" do
|
@@ -217,8 +227,9 @@ class Qs::Process
|
|
217
227
|
desc "and run with a stop signal"
|
218
228
|
setup do
|
219
229
|
@thread = Thread.new{ @process.run }
|
230
|
+
@thread.join(JOIN_SECONDS)
|
220
231
|
@process.signal_io.write(STOP)
|
221
|
-
@thread.join(
|
232
|
+
@thread.join(JOIN_SECONDS)
|
222
233
|
end
|
223
234
|
|
224
235
|
should "stop its daemon" do
|
@@ -244,8 +255,9 @@ class Qs::Process
|
|
244
255
|
desc "and run with a restart signal"
|
245
256
|
setup do
|
246
257
|
@thread = Thread.new{ @process.run }
|
258
|
+
@thread.join(JOIN_SECONDS)
|
247
259
|
@process.signal_io.write(RESTART)
|
248
|
-
@thread.join(
|
260
|
+
@thread.join(JOIN_SECONDS)
|
249
261
|
end
|
250
262
|
|
251
263
|
should "stop its daemon" do
|
@@ -253,10 +265,6 @@ class Qs::Process
|
|
253
265
|
assert_equal [true], @daemon_spy.stop_args
|
254
266
|
end
|
255
267
|
|
256
|
-
should "set the env var to skip daemonize" do
|
257
|
-
assert_equal 'yes', ENV['QS_SKIP_DAEMONIZE']
|
258
|
-
end
|
259
|
-
|
260
268
|
should "run the restart cmd" do
|
261
269
|
assert_true @restart_cmd_spy.run_called
|
262
270
|
end
|
@@ -266,15 +274,16 @@ class Qs::Process
|
|
266
274
|
class RunWithDaemonCrashTests < RunSetupTests
|
267
275
|
desc "and run with the daemon crashing"
|
268
276
|
setup do
|
269
|
-
# lower the time it sleeps so it loops and restarts the daemon quicker
|
270
277
|
Assert.stub(@process.signal_io, :wait) do |timeout|
|
271
|
-
sleep 0.
|
278
|
+
sleep JOIN_SECONDS * 0.5 # ensure this has time to run before the thread
|
279
|
+
# joins below
|
272
280
|
false
|
273
281
|
end
|
274
282
|
|
275
283
|
@thread = Thread.new{ @process.run }
|
284
|
+
@thread.join(JOIN_SECONDS)
|
276
285
|
@daemon_spy.start_called = false
|
277
|
-
@thread.join(
|
286
|
+
@thread.join(JOIN_SECONDS)
|
278
287
|
end
|
279
288
|
teardown do
|
280
289
|
# manually unstub or the process thread will hang forever
|
@@ -294,7 +303,7 @@ class Qs::Process
|
|
294
303
|
Assert.stub(::Signal, :trap){ raise ArgumentError }
|
295
304
|
|
296
305
|
@thread = Thread.new{ @process.run }
|
297
|
-
@thread.join(
|
306
|
+
@thread.join(JOIN_SECONDS)
|
298
307
|
end
|
299
308
|
|
300
309
|
should "start normally" do
|
@@ -343,10 +352,26 @@ class Qs::Process
|
|
343
352
|
assert_equal [Gem.ruby, $0, ARGV].flatten, subject.argv
|
344
353
|
end
|
345
354
|
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
355
|
+
if RUBY_VERSION == '1.8.7'
|
356
|
+
|
357
|
+
should "set env vars, change the dir and kernel exec when run" do
|
358
|
+
subject.run
|
359
|
+
|
360
|
+
assert_equal 'yes', ENV['QS_SKIP_DAEMONIZE']
|
361
|
+
assert_equal [subject.dir], @chdir_called_with
|
362
|
+
assert_equal subject.argv, @exec_called_with
|
363
|
+
end
|
364
|
+
|
365
|
+
else
|
366
|
+
|
367
|
+
should "kernel exec when run" do
|
368
|
+
subject.run
|
369
|
+
|
370
|
+
env = { 'QS_SKIP_DAEMONIZE' => 'yes' }
|
371
|
+
options = { :chdir => subject.dir }
|
372
|
+
assert_equal ([env] + subject.argv + [options]), @exec_called_with
|
373
|
+
end
|
374
|
+
|
350
375
|
end
|
351
376
|
|
352
377
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'assert'
|
2
2
|
require 'qs/qs_runner'
|
3
3
|
|
4
|
+
require 'much-timeout'
|
4
5
|
require 'qs'
|
5
6
|
require 'qs/message_handler'
|
6
7
|
|
@@ -23,6 +24,10 @@ class Qs::QsRunner
|
|
23
24
|
assert_true subject < Qs::Runner
|
24
25
|
end
|
25
26
|
|
27
|
+
should "know its TimeoutInterrupt" do
|
28
|
+
assert_true TimeoutInterrupt < Interrupt
|
29
|
+
end
|
30
|
+
|
26
31
|
end
|
27
32
|
|
28
33
|
class InitTests < UnitTests
|
@@ -47,9 +52,9 @@ class Qs::QsRunner
|
|
47
52
|
class RunSetupTests < InitTests
|
48
53
|
desc "and run"
|
49
54
|
setup do
|
50
|
-
@
|
51
|
-
Assert.stub(
|
52
|
-
@
|
55
|
+
@optional_timeout_called_with = nil
|
56
|
+
Assert.stub(MuchTimeout, :optional_timeout) do |*args, &block|
|
57
|
+
@optional_timeout_called_with = args
|
53
58
|
block.call
|
54
59
|
end
|
55
60
|
end
|
@@ -63,7 +68,8 @@ class Qs::QsRunner
|
|
63
68
|
end
|
64
69
|
|
65
70
|
should "run the handler in an optional timeout" do
|
66
|
-
|
71
|
+
exp = [@runner.timeout, TimeoutInterrupt]
|
72
|
+
assert_equal exp, @optional_timeout_called_with
|
67
73
|
end
|
68
74
|
|
69
75
|
should "run the handler's before callbacks" do
|
@@ -83,50 +89,124 @@ class Qs::QsRunner
|
|
83
89
|
|
84
90
|
end
|
85
91
|
|
86
|
-
class
|
92
|
+
class RunWithInitHaltTests < UnitTests
|
93
|
+
desc "with a handler that halts on init"
|
87
94
|
setup do
|
88
|
-
|
95
|
+
@runner = @runner_class.new(@handler_class, :params => {
|
96
|
+
'halt' => 'init'
|
97
|
+
})
|
98
|
+
@handler = @runner.handler
|
99
|
+
@response = @runner.run
|
89
100
|
end
|
101
|
+
subject{ @runner }
|
90
102
|
|
91
|
-
should "
|
92
|
-
|
93
|
-
|
103
|
+
should "run the before and after callbacks despite the halt" do
|
104
|
+
assert_not_nil @handler.first_before_call_order
|
105
|
+
assert_not_nil @handler.second_before_call_order
|
106
|
+
assert_not_nil @handler.first_after_call_order
|
107
|
+
assert_not_nil @handler.second_after_call_order
|
108
|
+
end
|
94
109
|
|
95
|
-
|
96
|
-
|
97
|
-
|
110
|
+
should "stop processing when the halt is called" do
|
111
|
+
assert_not_nil @handler.init_call_order
|
112
|
+
assert_nil @handler.run_call_order
|
98
113
|
end
|
99
114
|
|
100
115
|
end
|
101
116
|
|
102
|
-
class
|
103
|
-
desc "
|
117
|
+
class RunWithRunHaltTests < UnitTests
|
118
|
+
desc "when run with a handler that halts on run"
|
104
119
|
setup do
|
105
|
-
@
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
120
|
+
@runner = @runner_class.new(@handler_class, :params => {
|
121
|
+
'halt' => 'run'
|
122
|
+
})
|
123
|
+
@handler = @runner.handler
|
124
|
+
@response = @runner.run
|
110
125
|
end
|
111
|
-
subject{
|
126
|
+
subject{ @runner }
|
112
127
|
|
113
|
-
should
|
128
|
+
should "run the before and after callbacks despite the halt" do
|
129
|
+
assert_not_nil @handler.first_before_call_order
|
130
|
+
assert_not_nil @handler.second_before_call_order
|
131
|
+
assert_not_nil @handler.first_after_call_order
|
132
|
+
assert_not_nil @handler.second_after_call_order
|
133
|
+
end
|
114
134
|
|
115
|
-
should "
|
116
|
-
|
117
|
-
|
135
|
+
should "stop processing when the halt is called" do
|
136
|
+
assert_not_nil @handler.init_call_order
|
137
|
+
assert_not_nil @handler.run_call_order
|
138
|
+
end
|
118
139
|
|
119
|
-
|
120
|
-
|
121
|
-
|
140
|
+
end
|
141
|
+
|
142
|
+
class RunWithBeforeHaltTests < UnitTests
|
143
|
+
desc "when run with a handler that halts in an after callback"
|
144
|
+
setup do
|
145
|
+
@runner = @runner_class.new(@handler_class, :params => {
|
146
|
+
'halt' => 'before'
|
147
|
+
})
|
148
|
+
@handler = @runner.handler
|
149
|
+
@response = @runner.run
|
122
150
|
end
|
151
|
+
subject{ @runner }
|
123
152
|
|
124
|
-
should "
|
125
|
-
|
153
|
+
should "stop processing when the halt is called" do
|
154
|
+
assert_not_nil @handler.first_before_call_order
|
155
|
+
assert_nil @handler.second_before_call_order
|
156
|
+
end
|
126
157
|
|
127
|
-
|
128
|
-
assert_nil @
|
129
|
-
|
158
|
+
should "not run the after callbacks b/c of the halt" do
|
159
|
+
assert_nil @handler.first_after_call_order
|
160
|
+
assert_nil @handler.second_after_call_order
|
161
|
+
end
|
162
|
+
|
163
|
+
should "not run the handler's init and run b/c of the halt" do
|
164
|
+
assert_nil @handler.init_call_order
|
165
|
+
assert_nil @handler.run_call_order
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
class RunWithAfterHaltTests < UnitTests
|
171
|
+
desc "when run with a handler that halts in an after callback"
|
172
|
+
setup do
|
173
|
+
@runner = @runner_class.new(@handler_class, :params => {
|
174
|
+
'halt' => 'after'
|
175
|
+
})
|
176
|
+
@handler = @runner.handler
|
177
|
+
@response = @runner.run
|
178
|
+
end
|
179
|
+
subject{ @runner }
|
180
|
+
|
181
|
+
should "run the before callback despite the halt" do
|
182
|
+
assert_not_nil @handler.first_before_call_order
|
183
|
+
assert_not_nil @handler.second_before_call_order
|
184
|
+
end
|
185
|
+
|
186
|
+
should "run the handler's init and run despite the halt" do
|
187
|
+
assert_not_nil @handler.init_call_order
|
188
|
+
assert_not_nil @handler.run_call_order
|
189
|
+
end
|
190
|
+
|
191
|
+
should "stop processing when the halt is called" do
|
192
|
+
assert_not_nil @handler.first_after_call_order
|
193
|
+
assert_nil @handler.second_after_call_order
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
class RunWithTimeoutInterruptTests < RunSetupTests
|
199
|
+
setup do
|
200
|
+
Assert.stub(MuchTimeout, :optional_timeout){ raise TimeoutInterrupt }
|
201
|
+
end
|
202
|
+
|
203
|
+
should "raise a timeout error with a good message" do
|
204
|
+
exception = assert_raises(Qs::TimeoutError) do
|
205
|
+
@runner.run
|
206
|
+
end
|
207
|
+
|
208
|
+
exp = "#{@handler_class} timed out (#{@runner.timeout}s)"
|
209
|
+
assert_equal exp, exception.message
|
130
210
|
end
|
131
211
|
|
132
212
|
end
|
@@ -141,24 +221,30 @@ class Qs::QsRunner
|
|
141
221
|
|
142
222
|
timeout Factory.integer
|
143
223
|
|
144
|
-
before{ @first_before_call_order = next_call_order }
|
224
|
+
before{ @first_before_call_order = next_call_order; halt_if('before') }
|
145
225
|
before{ @second_before_call_order = next_call_order }
|
146
226
|
|
147
|
-
after{ @first_after_call_order = next_call_order }
|
227
|
+
after{ @first_after_call_order = next_call_order; halt_if('after') }
|
148
228
|
after{ @second_after_call_order = next_call_order }
|
149
229
|
|
150
230
|
def init!
|
151
231
|
@init_call_order = next_call_order
|
232
|
+
halt_if('init')
|
152
233
|
end
|
153
234
|
|
154
235
|
def run!
|
155
236
|
@run_call_order = next_call_order
|
237
|
+
halt_if('run')
|
156
238
|
end
|
157
239
|
|
158
240
|
private
|
159
241
|
|
160
242
|
def next_call_order; @order ||= 0; @order += 1; end
|
161
243
|
|
244
|
+
def halt_if(value)
|
245
|
+
halt if params['halt'] == value
|
246
|
+
end
|
247
|
+
|
162
248
|
end
|
163
249
|
|
164
250
|
end
|
data/test/unit/qs_tests.rb
CHANGED
@@ -2,7 +2,6 @@ require 'assert'
|
|
2
2
|
require 'qs'
|
3
3
|
|
4
4
|
require 'hella-redis/connection_spy'
|
5
|
-
require 'ns-options/assert_macros'
|
6
5
|
require 'qs/queue'
|
7
6
|
|
8
7
|
module Qs
|
@@ -24,7 +23,7 @@ module Qs
|
|
24
23
|
should have_imeths :encode, :decode
|
25
24
|
should have_imeths :sync_subscriptions, :clear_subscriptions
|
26
25
|
should have_imeths :event_subscribers
|
27
|
-
should have_imeths :client, :redis, :
|
26
|
+
should have_imeths :client, :redis, :redis_connect_hash
|
28
27
|
should have_imeths :dispatcher_queue, :dispatcher_job_name
|
29
28
|
should have_imeths :event_publisher
|
30
29
|
should have_imeths :published_events
|
@@ -33,20 +32,23 @@ module Qs
|
|
33
32
|
assert_instance_of Config, subject.config
|
34
33
|
end
|
35
34
|
|
36
|
-
should "
|
35
|
+
should "configure its config" do
|
37
36
|
yielded = nil
|
38
37
|
subject.configure{ |c| yielded = c }
|
39
38
|
assert_same subject.config, yielded
|
40
39
|
end
|
41
40
|
|
42
|
-
should "
|
43
|
-
|
41
|
+
should "have a null client by default" do
|
42
|
+
assert_instance_of NullClient, subject.client
|
43
|
+
end
|
44
|
+
|
45
|
+
should "not have a redis connection by default" do
|
44
46
|
assert_nil subject.redis
|
45
47
|
end
|
46
48
|
|
47
49
|
should "know its redis config" do
|
48
|
-
|
49
|
-
assert_equal
|
50
|
+
exp = subject.config.redis_connect_hash
|
51
|
+
assert_equal exp, subject.redis_connect_hash
|
50
52
|
end
|
51
53
|
|
52
54
|
end
|
@@ -56,9 +58,9 @@ module Qs
|
|
56
58
|
setup do
|
57
59
|
@module.config.encoder = proc{ |v| v.to_s }
|
58
60
|
@module.config.decoder = proc{ |v| v.to_i }
|
59
|
-
@module.config.
|
60
|
-
@module.config.
|
61
|
-
@module.config.
|
61
|
+
@module.config.redis_ip = Factory.string
|
62
|
+
@module.config.redis_port = Factory.integer
|
63
|
+
@module.config.redis_db = Factory.integer
|
62
64
|
|
63
65
|
@dispatcher_queue_spy = nil
|
64
66
|
Assert.stub(DispatcherQueue, :new) do |*args|
|
@@ -73,30 +75,26 @@ module Qs
|
|
73
75
|
@module.init
|
74
76
|
end
|
75
77
|
|
76
|
-
should "
|
77
|
-
|
78
|
-
subject.config.redis.ip,
|
79
|
-
subject.config.redis.port,
|
80
|
-
subject.config.redis.db
|
81
|
-
)
|
82
|
-
assert_equal expected, subject.config.redis.url
|
78
|
+
should "validate its config" do
|
79
|
+
assert_true subject.config.valid?
|
83
80
|
end
|
84
81
|
|
85
82
|
should "build a dispatcher queue" do
|
86
83
|
assert_equal @dispatcher_queue_spy, subject.dispatcher_queue
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
assert_equal
|
91
|
-
assert_equal
|
92
|
-
|
93
|
-
assert_equal
|
84
|
+
|
85
|
+
c = subject.config
|
86
|
+
spy = @dispatcher_queue_spy
|
87
|
+
assert_equal c.dispatcher_queue_class, spy.queue_class
|
88
|
+
assert_equal c.dispatcher_queue_name, spy.queue_name
|
89
|
+
assert_equal c.dispatcher_job_name, spy.job_name
|
90
|
+
assert_equal c.dispatcher_job_handler_class_name, spy.job_handler_class_name
|
94
91
|
end
|
95
92
|
|
96
93
|
should "build a client" do
|
97
|
-
assert_equal @client_spy,
|
98
|
-
assert_equal @client_spy.redis,
|
99
|
-
|
94
|
+
assert_equal @client_spy, subject.client
|
95
|
+
assert_equal @client_spy.redis, subject.redis
|
96
|
+
|
97
|
+
assert_equal subject.redis_connect_hash, @client_spy.redis_connect_hash
|
100
98
|
end
|
101
99
|
|
102
100
|
should "call enqueue on its client using `enqueue`" do
|
@@ -149,14 +147,12 @@ module Qs
|
|
149
147
|
|
150
148
|
should "use the configured encoder using `encode`" do
|
151
149
|
value = Factory.integer
|
152
|
-
|
153
|
-
assert_equal value.to_s, result
|
150
|
+
assert_equal value.to_s, subject.encode(value)
|
154
151
|
end
|
155
152
|
|
156
153
|
should "use the configured decoder using `decode`" do
|
157
154
|
value = Factory.integer.to_s
|
158
|
-
|
159
|
-
assert_equal value.to_i, result
|
155
|
+
assert_equal value.to_i, subject.decode(value)
|
160
156
|
end
|
161
157
|
|
162
158
|
should "demeter its clients subscription methods" do
|
@@ -180,24 +176,28 @@ module Qs
|
|
180
176
|
end
|
181
177
|
|
182
178
|
should "know its dispatcher job name and event publisher" do
|
183
|
-
exp = subject.config.
|
179
|
+
exp = subject.config.dispatcher_job_name
|
184
180
|
assert_equal exp, subject.dispatcher_job_name
|
181
|
+
|
185
182
|
exp = subject.config.event_publisher
|
186
183
|
assert_equal exp, subject.event_publisher
|
187
184
|
end
|
188
185
|
|
189
186
|
should "return the dispatcher queue published events using `published_events`" do
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
assert_equal
|
187
|
+
exp = Factory.integer(3).times.map{ Factory.string }
|
188
|
+
Assert.stub(subject.dispatcher_queue, :published_events){ exp }
|
189
|
+
|
190
|
+
assert_equal exp, subject.published_events
|
194
191
|
end
|
195
192
|
|
196
193
|
should "not reset its attributes when init again" do
|
194
|
+
config = subject.config
|
197
195
|
queue = subject.dispatcher_queue
|
198
196
|
client = subject.client
|
199
197
|
redis = subject.redis
|
200
198
|
subject.init
|
199
|
+
|
200
|
+
assert_same config, subject.config
|
201
201
|
assert_same queue, subject.dispatcher_queue
|
202
202
|
assert_same client, subject.client
|
203
203
|
assert_same redis, subject.redis
|
@@ -205,10 +205,11 @@ module Qs
|
|
205
205
|
|
206
206
|
should "reset itself using `reset!`" do
|
207
207
|
subject.reset!
|
208
|
-
|
208
|
+
|
209
|
+
assert_false subject.config.valid?
|
209
210
|
assert_nil subject.dispatcher_queue
|
210
|
-
assert_nil subject.client
|
211
211
|
assert_nil subject.redis
|
212
|
+
assert_instance_of NullClient, subject.client
|
212
213
|
assert_raises(NoMethodError){ subject.encode(Factory.integer) }
|
213
214
|
assert_raises(NoMethodError){ subject.decode(Factory.integer) }
|
214
215
|
end
|
@@ -216,54 +217,115 @@ module Qs
|
|
216
217
|
end
|
217
218
|
|
218
219
|
class ConfigTests < UnitTests
|
219
|
-
include NsOptions::AssertMacros
|
220
|
-
|
221
220
|
desc "Config"
|
222
221
|
setup do
|
223
222
|
@config = Config.new
|
224
223
|
end
|
225
224
|
subject{ @config }
|
226
225
|
|
227
|
-
should
|
228
|
-
should
|
229
|
-
should
|
230
|
-
should have_accessors :
|
226
|
+
should have_accessors :encoder, :decoder, :timeout, :event_publisher
|
227
|
+
should have_accessors :dispatcher_queue_class, :dispatcher_queue_name
|
228
|
+
should have_accessors :dispatcher_job_name, :dispatcher_job_handler_class_name
|
229
|
+
should have_accessors :redis_ip, :redis_port, :redis_db, :redis_ns
|
230
|
+
should have_accessors :redis_driver, :redis_timeout, :redis_size, :redis_url
|
231
|
+
should have_imeths :redis_connect_hash, :valid?, :validate!
|
231
232
|
|
232
|
-
should "know its default
|
233
|
+
should "know its default attr values" do
|
233
234
|
payload = { Factory.string => Factory.string }
|
234
235
|
|
235
236
|
exp = JSON.dump(payload)
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
237
|
+
assert_equal exp, Config::DEFAULT_ENCODER.call(payload)
|
238
|
+
|
239
|
+
encoded_payload = exp
|
240
|
+
exp = JSON.load(encoded_payload)
|
241
|
+
assert_equal exp, Config::DEFAULT_DECODER.call(encoded_payload)
|
242
|
+
|
243
|
+
assert_equal Queue, Config::DEFAULT_DISPATCHER_QUEUE_CLASS
|
244
|
+
assert_equal 'dispatcher', Config::DEFAULT_DISPATCHER_QUEUE_NAME
|
245
|
+
assert_equal 'run_dispatch_job', Config::DEFAULT_DISPATCHER_JOB_NAME
|
246
|
+
|
247
|
+
exp = DispatcherQueue::RunDispatchJob.to_s
|
248
|
+
assert_equal exp, Config::DEFAULT_DISPATCHER_JOB_HANDLER_CLASS_NAME
|
249
|
+
|
250
|
+
assert_equal '127.0.0.1', Config::DEFAULT_REDIS_IP
|
251
|
+
assert_equal 6379, Config::DEFAULT_REDIS_PORT
|
252
|
+
assert_equal 0, Config::DEFAULT_REDIS_DB
|
253
|
+
assert_equal 'qs', Config::DEFAULT_REDIS_NS
|
254
|
+
assert_equal 'ruby', Config::DEFAULT_REDIS_DRIVER
|
255
|
+
assert_equal 1, Config::DEFAULT_REDIS_TIMEOUT
|
256
|
+
assert_equal 4, Config::DEFAULT_REDIS_SIZE
|
240
257
|
end
|
241
258
|
|
242
|
-
should "
|
259
|
+
should "default its attrs" do
|
260
|
+
c = subject.class
|
261
|
+
|
262
|
+
assert_equal c::DEFAULT_ENCODER, subject.encoder
|
263
|
+
assert_equal c::DEFAULT_DECODER, subject.decoder
|
264
|
+
|
243
265
|
assert_nil subject.timeout
|
266
|
+
assert_nil subject.event_publisher
|
267
|
+
|
268
|
+
assert_equal c::DEFAULT_DISPATCHER_QUEUE_CLASS, subject.dispatcher_queue_class
|
269
|
+
assert_equal c::DEFAULT_DISPATCHER_QUEUE_NAME, subject.dispatcher_queue_name
|
270
|
+
assert_equal c::DEFAULT_DISPATCHER_JOB_NAME, subject.dispatcher_job_name
|
271
|
+
|
272
|
+
exp = c::DEFAULT_DISPATCHER_JOB_HANDLER_CLASS_NAME
|
273
|
+
assert_equal exp, subject.dispatcher_job_handler_class_name
|
274
|
+
|
275
|
+
assert_equal c::DEFAULT_REDIS_IP, subject.redis_ip
|
276
|
+
assert_equal c::DEFAULT_REDIS_PORT, subject.redis_port
|
277
|
+
assert_equal c::DEFAULT_REDIS_DB, subject.redis_db
|
278
|
+
assert_equal c::DEFAULT_REDIS_NS, subject.redis_ns
|
279
|
+
assert_equal c::DEFAULT_REDIS_DRIVER, subject.redis_driver
|
280
|
+
assert_equal c::DEFAULT_REDIS_TIMEOUT, subject.redis_timeout
|
281
|
+
assert_equal c::DEFAULT_REDIS_SIZE, subject.redis_size
|
282
|
+
|
283
|
+
assert_nil subject.redis_url
|
244
284
|
end
|
245
285
|
|
246
|
-
should "
|
247
|
-
|
286
|
+
should "know its redis connect hash" do
|
287
|
+
exp = {
|
288
|
+
:ip => subject.redis_ip,
|
289
|
+
:port => subject.redis_port,
|
290
|
+
:db => subject.redis_db,
|
291
|
+
:redis_ns => subject.redis_ns,
|
292
|
+
:driver => subject.redis_driver,
|
293
|
+
:timeout => subject.redis_timeout,
|
294
|
+
:size => subject.redis_size,
|
295
|
+
:url => subject.redis_url
|
296
|
+
}
|
297
|
+
assert_equal exp, subject.redis_connect_hash
|
248
298
|
end
|
249
299
|
|
250
|
-
should "
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
assert_equal exp, subject.dispatcher.job_handler_class_name
|
300
|
+
should "not be valid until validate! has been called" do
|
301
|
+
assert_false subject.valid?
|
302
|
+
|
303
|
+
subject.validate!
|
304
|
+
assert_true subject.valid?
|
256
305
|
end
|
257
306
|
|
258
|
-
should "
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
assert_equal
|
264
|
-
|
265
|
-
|
266
|
-
|
307
|
+
should "set its redis url on validate!" do
|
308
|
+
assert_nil subject.redis_url
|
309
|
+
subject.validate!
|
310
|
+
|
311
|
+
exp = RedisUrl.new(subject.redis_ip, subject.redis_port, subject.redis_db)
|
312
|
+
assert_equal exp, subject.redis_url
|
313
|
+
end
|
314
|
+
|
315
|
+
should "only be able to be validated once" do
|
316
|
+
subject.validate!
|
317
|
+
|
318
|
+
exp = RedisUrl.new(subject.redis_ip, subject.redis_port, subject.redis_db)
|
319
|
+
assert_equal exp, subject.redis_url
|
320
|
+
|
321
|
+
new_ip = Factory.string
|
322
|
+
subject.redis_ip = new_ip
|
323
|
+
subject.validate!
|
324
|
+
|
325
|
+
orig_exp = exp
|
326
|
+
new_exp = RedisUrl.new(new_ip, subject.redis_port, subject.redis_db)
|
327
|
+
assert_not_equal new_exp, subject.redis_url
|
328
|
+
assert_equal orig_exp, subject.redis_url
|
267
329
|
end
|
268
330
|
|
269
331
|
end
|
@@ -276,8 +338,8 @@ module Qs
|
|
276
338
|
ip = Factory.string
|
277
339
|
port = Factory.integer
|
278
340
|
db = Factory.integer
|
279
|
-
|
280
|
-
assert_equal
|
341
|
+
exp = "redis://#{ip}:#{port}/#{db}"
|
342
|
+
assert_equal exp, subject.new(ip, port, db)
|
281
343
|
end
|
282
344
|
|
283
345
|
should "not return a url with an ip, port or db" do
|
@@ -288,6 +350,49 @@ module Qs
|
|
288
350
|
|
289
351
|
end
|
290
352
|
|
353
|
+
class NullClientTests < UnitTests
|
354
|
+
desc "NullClient"
|
355
|
+
setup do
|
356
|
+
@null_client = NullClient.new
|
357
|
+
end
|
358
|
+
subject{ @null_client }
|
359
|
+
|
360
|
+
should have_imeths :enqueue, :publish, :publish_as, :push
|
361
|
+
should have_imeths :sync_subscriptions, :clear_subscriptions
|
362
|
+
should have_imeths :event_subscribers
|
363
|
+
|
364
|
+
should "raise uninitialized errors" do
|
365
|
+
queue = Qs::Queue.new{ name Factory.string }
|
366
|
+
job_name = Factory.string
|
367
|
+
job_params = { Factory.string => Factory.string }
|
368
|
+
assert_raises(UninitializedError) do
|
369
|
+
subject.enqueue(queue, job_name, job_params)
|
370
|
+
end
|
371
|
+
|
372
|
+
event_channel = Factory.string
|
373
|
+
event_name = Factory.string
|
374
|
+
event_params = { Factory.string => Factory.string }
|
375
|
+
assert_raises(UninitializedError) do
|
376
|
+
subject.publish(event_channel, event_name, event_params)
|
377
|
+
end
|
378
|
+
|
379
|
+
event_publisher = Factory.string
|
380
|
+
assert_raises(UninitializedError) do
|
381
|
+
subject.publish_as(event_publisher, event_channel, event_name, event_params)
|
382
|
+
end
|
383
|
+
|
384
|
+
payload = { Factory.string => Factory.string }
|
385
|
+
assert_raises(UninitializedError){ subject.push(queue.name, payload) }
|
386
|
+
|
387
|
+
assert_raises(UninitializedError){ subject.sync_subscriptions(queue) }
|
388
|
+
assert_raises(UninitializedError){ subject.clear_subscriptions(queue) }
|
389
|
+
|
390
|
+
event = Factory.event
|
391
|
+
assert_raises(UninitializedError){ subject.event_subscribers(event) }
|
392
|
+
end
|
393
|
+
|
394
|
+
end
|
395
|
+
|
291
396
|
class DispatcherQueueSpy
|
292
397
|
attr_reader :queue_class, :queue_name
|
293
398
|
attr_reader :job_name, :job_handler_class_name
|
@@ -302,17 +407,17 @@ module Qs
|
|
302
407
|
end
|
303
408
|
|
304
409
|
class ClientSpy
|
305
|
-
attr_reader :
|
410
|
+
attr_reader :redis_connect_hash, :redis
|
306
411
|
attr_reader :enqueue_calls, :publish_calls, :push_calls
|
307
412
|
attr_reader :sync_subscriptions_calls, :clear_subscriptions_calls
|
308
413
|
attr_reader :event_subscribers_calls
|
309
414
|
|
310
415
|
def initialize(redis_confg)
|
311
|
-
@
|
312
|
-
@redis
|
313
|
-
@enqueue_calls
|
314
|
-
@publish_calls
|
315
|
-
@push_calls
|
416
|
+
@redis_connect_hash = redis_confg
|
417
|
+
@redis = Factory.string
|
418
|
+
@enqueue_calls = []
|
419
|
+
@publish_calls = []
|
420
|
+
@push_calls = []
|
316
421
|
@sync_subscriptions_calls = []
|
317
422
|
@clear_subscriptions_calls = []
|
318
423
|
@event_subscribers_calls = []
|