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.
@@ -211,7 +211,7 @@ module Qs::MessageHandler
211
211
  @handler.qs_run
212
212
  end
213
213
 
214
- should "call `run!` and it's callbacks" do
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
@@ -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
- assert_equal "qs: #{@daemon_spy.process_label}", subject.name
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 0.1
121
+ sleep 2*JOIN_SECONDS
113
122
  false
114
123
  end
115
124
 
116
125
  @thread = Thread.new{ @process.run }
117
- @thread.join(0.1)
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(0.1)
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(0.1)
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(0.1)
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(0.1)
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.1
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(0.1)
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(0.1)
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
- should "change the dir and run a kernel exec when run" do
347
- subject.run
348
- assert_equal [subject.dir], @chdir_called_with
349
- assert_equal subject.argv, @exec_called_with
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
- @timeout_called_with = nil
51
- Assert.stub(OptionalTimeout, :new) do |*args, &block|
52
- @timeout_called_with = args
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
- assert_equal [@runner.timeout], @timeout_called_with
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 RunWithTimeoutErrorTests < RunSetupTests
92
+ class RunWithInitHaltTests < UnitTests
93
+ desc "with a handler that halts on init"
87
94
  setup do
88
- Assert.stub(OptionalTimeout, :new){ raise Qs::TimeoutError }
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 "raise a timeout error with a good message" do
92
- exception = nil
93
- begin; @runner.run; rescue StandardError => exception; end
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
- assert_kind_of Qs::TimeoutError, exception
96
- exp = "#{@handler_class} timed out (#{@runner.timeout}s)"
97
- assert_equal exp, exception.message
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 OptionalTimeoutTests < UnitTests
103
- desc "OptionalTimeout"
117
+ class RunWithRunHaltTests < UnitTests
118
+ desc "when run with a handler that halts on run"
104
119
  setup do
105
- @timeout_called_with = nil
106
- Assert.stub(SystemTimer, :timeout_after) do |*args, &block|
107
- @timeout_called_with = args
108
- block.call
109
- end
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{ OptionalTimeout }
126
+ subject{ @runner }
112
127
 
113
- should have_imeths :new
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 "use a system timer timeout when provided a non-`nil` value" do
116
- value = Factory.integer
117
- block_run = false
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
- subject.new(value){ block_run = true }
120
- assert_equal [value, Qs::TimeoutError], @timeout_called_with
121
- assert_true block_run
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 "call the block when provided a `nil` value" do
125
- block_run = false
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
- subject.new(nil){ block_run = true }
128
- assert_nil @timeout_called_with
129
- assert_true block_run
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
@@ -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, :redis_config
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 "allow configuring its config" do
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 "not have a client or redis connection by default" do
43
- assert_nil subject.client
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
- expected = subject.config.redis.to_hash
49
- assert_equal expected, subject.redis_config
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.redis.ip = Factory.string
60
- @module.config.redis.port = Factory.integer
61
- @module.config.redis.db = Factory.integer
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 "set its configured redis url" do
77
- expected = RedisUrl.new(
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
- exp = subject.config.dispatcher_queue_class
88
- assert_equal exp, @dispatcher_queue_spy.queue_class
89
- dispatcher_config = subject.config.dispatcher
90
- assert_equal dispatcher_config.queue_name, @dispatcher_queue_spy.queue_name
91
- assert_equal dispatcher_config.job_name, @dispatcher_queue_spy.job_name
92
- exp = dispatcher_config.job_handler_class_name
93
- assert_equal exp, @dispatcher_queue_spy.job_handler_class_name
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, subject.client
98
- assert_equal @client_spy.redis, subject.redis
99
- assert_equal subject.redis_config, @client_spy.redis_config
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
- result = subject.encode(value)
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
- result = subject.decode(value)
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.dispatcher.job_name
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
- queue = subject.dispatcher_queue
191
- published_events = Factory.integer(3).times.map{ Factory.string }
192
- Assert.stub(queue, :published_events){ published_events }
193
- assert_equal queue.published_events, subject.published_events
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
- assert_nil subject.config.redis.url
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 have_options :encoder, :decoder, :timeout
228
- should have_options :event_publisher
229
- should have_namespace :dispatcher, :redis
230
- should have_accessors :dispatcher_queue_class
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 decoder/encoder" do
233
+ should "know its default attr values" do
233
234
  payload = { Factory.string => Factory.string }
234
235
 
235
236
  exp = JSON.dump(payload)
236
- encoded_payload = subject.encoder.call(payload)
237
- assert_equal exp, encoded_payload
238
- exp = JSON.load(exp)
239
- assert_equal exp, subject.decoder.call(encoded_payload)
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 "know its default timeout" do
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 "not have a default event publisher" do
247
- assert_nil subject.event_publisher
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 "know its default dispatcher options" do
251
- assert_equal Queue, subject.dispatcher_queue_class
252
- assert_equal 'dispatcher', subject.dispatcher.queue_name
253
- assert_equal 'run_dispatch_job', subject.dispatcher.job_name
254
- exp = DispatcherQueue::RunDispatchJob.to_s
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 "know its default redis options" do
259
- assert_equal '127.0.0.1', subject.redis.ip
260
- assert_equal 6379, subject.redis.port
261
- assert_equal 0, subject.redis.db
262
- assert_equal 'qs', subject.redis.redis_ns
263
- assert_equal 'ruby', subject.redis.driver
264
- assert_equal 1, subject.redis.timeout
265
- assert_equal 4, subject.redis.size
266
- assert_nil subject.redis.url
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
- expected = "redis://#{ip}:#{port}/#{db}"
280
- assert_equal expected, subject.new(ip, port, db)
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 :redis_config, :redis
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
- @redis_config = redis_confg
312
- @redis = Factory.string
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 = []