sanford 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/Gemfile +1 -1
  2. data/README.md +41 -56
  3. data/Rakefile +0 -1
  4. data/bench/client.rb +8 -3
  5. data/bench/{services.rb → config.sanford} +11 -6
  6. data/bench/{runner.rb → report.rb} +2 -2
  7. data/bench/report.txt +32 -32
  8. data/lib/sanford/cli.rb +42 -28
  9. data/lib/sanford/config_file.rb +79 -0
  10. data/lib/sanford/{worker.rb → connection_handler.rb} +28 -20
  11. data/lib/sanford/error_handler.rb +7 -7
  12. data/lib/sanford/pid_file.rb +42 -0
  13. data/lib/sanford/process.rb +136 -0
  14. data/lib/sanford/process_signal.rb +20 -0
  15. data/lib/sanford/route.rb +48 -0
  16. data/lib/sanford/router.rb +36 -0
  17. data/lib/sanford/runner.rb +30 -58
  18. data/lib/sanford/sanford_runner.rb +19 -9
  19. data/lib/sanford/server.rb +211 -42
  20. data/lib/sanford/server_data.rb +47 -0
  21. data/lib/sanford/service_handler.rb +8 -46
  22. data/lib/sanford/template_source.rb +19 -2
  23. data/lib/sanford/test_runner.rb +27 -28
  24. data/lib/sanford/version.rb +1 -1
  25. data/lib/sanford.rb +1 -23
  26. data/sanford.gemspec +4 -5
  27. data/test/helper.rb +3 -20
  28. data/test/support/app_server.rb +142 -0
  29. data/test/support/config.sanford +7 -0
  30. data/test/support/config_invalid_run.sanford +3 -0
  31. data/test/support/config_no_run.sanford +0 -0
  32. data/test/support/fake_server_connection.rb +58 -0
  33. data/test/support/pid_file_spy.rb +19 -0
  34. data/test/support/template.erb +1 -0
  35. data/test/system/server_tests.rb +378 -0
  36. data/test/system/service_handler_tests.rb +224 -0
  37. data/test/unit/cli_tests.rb +187 -0
  38. data/test/unit/config_file_tests.rb +59 -0
  39. data/test/unit/connection_handler_tests.rb +254 -0
  40. data/test/unit/error_handler_tests.rb +30 -35
  41. data/test/unit/pid_file_tests.rb +70 -0
  42. data/test/unit/process_signal_tests.rb +61 -0
  43. data/test/unit/process_tests.rb +428 -0
  44. data/test/unit/route_tests.rb +92 -0
  45. data/test/unit/router_tests.rb +65 -0
  46. data/test/unit/runner_tests.rb +61 -15
  47. data/test/unit/sanford_runner_tests.rb +162 -28
  48. data/test/unit/sanford_tests.rb +0 -8
  49. data/test/unit/server_data_tests.rb +87 -0
  50. data/test/unit/server_tests.rb +502 -21
  51. data/test/unit/service_handler_tests.rb +114 -219
  52. data/test/unit/template_engine_tests.rb +1 -1
  53. data/test/unit/template_source_tests.rb +56 -16
  54. data/test/unit/test_runner_tests.rb +206 -0
  55. metadata +67 -67
  56. data/bench/tasks.rb +0 -41
  57. data/lib/sanford/config.rb +0 -28
  58. data/lib/sanford/host.rb +0 -129
  59. data/lib/sanford/host_data.rb +0 -65
  60. data/lib/sanford/hosts.rb +0 -38
  61. data/lib/sanford/manager.rb +0 -275
  62. data/test/support/fake_connection.rb +0 -36
  63. data/test/support/helpers.rb +0 -17
  64. data/test/support/service_handlers.rb +0 -154
  65. data/test/support/services.rb +0 -123
  66. data/test/support/simple_client.rb +0 -62
  67. data/test/system/request_handling_tests.rb +0 -306
  68. data/test/unit/config_tests.rb +0 -56
  69. data/test/unit/host_data_tests.rb +0 -71
  70. data/test/unit/host_tests.rb +0 -141
  71. data/test/unit/hosts_tests.rb +0 -50
  72. data/test/unit/manager_tests.rb +0 -195
  73. data/test/unit/worker_tests.rb +0 -24
@@ -0,0 +1,70 @@
1
+ require 'assert'
2
+ require 'sanford/pid_file'
3
+
4
+ class Sanford::PIDFile
5
+
6
+ class UnitTests < Assert::Context
7
+ desc "Sanford::PIDFile"
8
+ setup do
9
+ @path = ROOT_PATH.join('tmp/pid_file_tests.pid').to_s
10
+ @pid_file = Sanford::PIDFile.new(@path)
11
+ end
12
+ teardown do
13
+ FileUtils.rm_rf(@path)
14
+ end
15
+ subject{ @pid_file }
16
+
17
+ should have_readers :path
18
+ should have_imeths :pid, :write, :remove, :to_s
19
+
20
+ should "know its path" do
21
+ assert_equal @path, subject.path
22
+ end
23
+
24
+ should "default its path" do
25
+ pid_file = Sanford::PIDFile.new(nil)
26
+ assert_equal '/dev/null', pid_file.path
27
+ end
28
+
29
+ should "know its string format" do
30
+ assert_equal @path, subject.to_s
31
+ end
32
+
33
+ should "read a PID from its file" do
34
+ pid = Factory.integer
35
+ File.open(@path, 'w'){ |f| f.puts pid }
36
+ assert_equal pid, subject.pid
37
+ end
38
+
39
+ should "raise an invalid error when it can't read from its file" do
40
+ FileUtils.rm_rf(@path)
41
+ assert_raises(InvalidError){ subject.pid }
42
+ end
43
+
44
+ should "raise an invalid error when the file doesn't have a PID in it" do
45
+ File.open(@path, 'w'){ |f| f.puts '' }
46
+ assert_raises(InvalidError){ subject.pid }
47
+ end
48
+
49
+ should "write the process PID to its file" do
50
+ assert_false File.exists?(@path)
51
+ subject.write
52
+ assert_true File.exists?(@path)
53
+ assert_equal "#{::Process.pid}\n", File.read(@path)
54
+ end
55
+
56
+ should "raise an invalid error when it can't write its file" do
57
+ Assert.stub(File, :open){ raise "can't open file" }
58
+ assert_raises(InvalidError){ subject.write }
59
+ end
60
+
61
+ should "remove its file" do
62
+ FileUtils.touch(@path)
63
+ assert_true File.exists?(@path)
64
+ subject.remove
65
+ assert_false File.exists?(@path)
66
+ end
67
+
68
+ end
69
+
70
+ end
@@ -0,0 +1,61 @@
1
+ require 'assert'
2
+ require 'sanford/process_signal'
3
+
4
+ require 'sanford/server'
5
+ require 'test/support/pid_file_spy'
6
+
7
+ class Sanford::ProcessSignal
8
+
9
+ class UnitTests < Assert::Context
10
+ desc "Sanford::ProcessSignal"
11
+ setup do
12
+ @server = TestServer.new
13
+ @signal = Factory.string
14
+
15
+ @pid_file_spy = PIDFileSpy.new(Factory.integer)
16
+ Assert.stub(Sanford::PIDFile, :new).with(@server.pid_file) do
17
+ @pid_file_spy
18
+ end
19
+
20
+ @process_signal = Sanford::ProcessSignal.new(@server, @signal)
21
+ end
22
+ subject{ @process_signal }
23
+
24
+ should have_readers :signal, :pid
25
+ should have_imeths :send
26
+
27
+ should "know its signal and pid" do
28
+ assert_equal @signal, subject.signal
29
+ assert_equal @pid_file_spy.pid, subject.pid
30
+ end
31
+
32
+ end
33
+
34
+ class SendTests < UnitTests
35
+ desc "when sent"
36
+ setup do
37
+ @kill_called = false
38
+ Assert.stub(::Process, :kill).with(@signal, @pid_file_spy.pid) do
39
+ @kill_called = true
40
+ end
41
+
42
+ @process_signal.send
43
+ end
44
+
45
+ should "have used process kill to send the signal to the PID" do
46
+ assert_true @kill_called
47
+ end
48
+
49
+ end
50
+
51
+ class TestServer
52
+ include Sanford::Server
53
+
54
+ name Factory.string
55
+ ip Factory.string
56
+ port Factory.integer
57
+ pid_file Factory.file_path
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,428 @@
1
+ require 'assert'
2
+ require 'sanford/process'
3
+
4
+ require 'sanford/server'
5
+ require 'test/support/pid_file_spy'
6
+
7
+ class Sanford::Process
8
+
9
+ class UnitTests < Assert::Context
10
+ desc "Sanford::Process"
11
+ setup do
12
+ @process_class = Sanford::Process
13
+ end
14
+ subject{ @process_class }
15
+
16
+ end
17
+
18
+ class InitTests < UnitTests
19
+ desc "when init"
20
+ setup do
21
+ @current_env_ip = ENV['SANFORD_IP']
22
+ @current_env_port = ENV['SANFORD_PORT']
23
+ @current_env_server_fd = ENV['SANFORD_SERVER_FD']
24
+ @current_env_client_fds = ENV['SANFORD_CLIENT_FDS']
25
+ @current_env_skip_daemonize = ENV['SANFORD_SKIP_DAEMONIZE']
26
+ ENV.delete('SANFORD_IP')
27
+ ENV.delete('SANFORD_PORT')
28
+ ENV.delete('SANFORD_SERVER_FD')
29
+ ENV.delete('SANFORD_CLIENT_FDS')
30
+ ENV.delete('SANFORD_SKIP_DAEMONIZE')
31
+
32
+ @server_spy = ServerSpy.new
33
+
34
+ @pid_file_spy = PIDFileSpy.new(Factory.integer)
35
+ Assert.stub(Sanford::PIDFile, :new).with(@server_spy.pid_file) do
36
+ @pid_file_spy
37
+ end
38
+
39
+ @restart_cmd_spy = RestartCmdSpy.new
40
+ Assert.stub(Sanford::RestartCmd, :new){ @restart_cmd_spy }
41
+
42
+ @process = @process_class.new(@server_spy)
43
+ end
44
+ teardown do
45
+ ENV['SANFORD_SKIP_DAEMONIZE'] = @current_env_skip_daemonize
46
+ ENV['SANFORD_CLIENT_FDS'] = @current_env_client_fds
47
+ ENV['SANFORD_SERVER_FD'] = @current_env_server_fd
48
+ ENV['SANFORD_PORT'] = @current_env_ip
49
+ ENV['SANFORD_IP'] = @current_env_port
50
+ end
51
+ subject{ @process }
52
+
53
+ should have_readers :server, :name, :pid_file, :restart_cmd
54
+ should have_readers :server_ip, :server_port, :server_fd, :client_fds
55
+ should have_imeths :run, :daemonize?
56
+
57
+ should "know its server" do
58
+ assert_equal @server_spy, subject.server
59
+ end
60
+
61
+ should "know its name, pid file and restart cmd" do
62
+ assert_equal "sanford-#{@server_spy.name}", subject.name
63
+ assert_equal @pid_file_spy, subject.pid_file
64
+ assert_equal @restart_cmd_spy, subject.restart_cmd
65
+ end
66
+
67
+ should "know its server ip, port and file descriptor" do
68
+ assert_nil subject.server_ip
69
+ assert_nil subject.server_port
70
+ assert_nil subject.server_fd
71
+ end
72
+
73
+ should "set its server ip, port and file descriptor using env vars" do
74
+ ENV['SANFORD_IP'] = Factory.string
75
+ ENV['SANFORD_PORT'] = Factory.integer.to_s
76
+ ENV['SANFORD_SERVER_FD'] = Factory.integer.to_s
77
+ process = @process_class.new(@server_spy)
78
+ assert_equal ENV['SANFORD_IP'], process.server_ip
79
+ assert_equal ENV['SANFORD_PORT'].to_i, process.server_port
80
+ assert_equal ENV['SANFORD_SERVER_FD'].to_i, process.server_fd
81
+ end
82
+
83
+ should "ignore blank env values for its server ip, port and fd" do
84
+ ENV['SANFORD_IP'] = ''
85
+ ENV['SANFORD_PORT'] = ''
86
+ ENV['SANFORD_SERVER_FD'] = ''
87
+ process = @process_class.new(@server_spy)
88
+ assert_nil process.server_ip
89
+ assert_nil process.server_port
90
+ assert_nil process.server_fd
91
+ end
92
+
93
+ should "know its client file descriptors" do
94
+ assert_equal [], subject.client_fds
95
+ end
96
+
97
+ should "set its client file descriptors using an env var" do
98
+ client_fds = [ Factory.integer, Factory.integer ]
99
+ ENV['SANFORD_CLIENT_FDS'] = client_fds.join(',')
100
+ process = @process_class.new(@server_spy)
101
+ assert_equal client_fds, process.client_fds
102
+ end
103
+
104
+ should "not daemonize by default" do
105
+ process = @process_class.new(@server_spy)
106
+ assert_false subject.daemonize?
107
+ end
108
+
109
+ should "daemonize if turned on" do
110
+ process = @process_class.new(@server_spy, :daemonize => true)
111
+ assert_true process.daemonize?
112
+ end
113
+
114
+ should "not daemonize if skipped via the env var" do
115
+ ENV['SANFORD_SKIP_DAEMONIZE'] = 'yes'
116
+ process = @process_class.new(@server_spy)
117
+ assert_false process.daemonize?
118
+ process = @process_class.new(@server_spy, :daemonize => true)
119
+ assert_false process.daemonize?
120
+ end
121
+
122
+ should "ignore blank env values for skip daemonize" do
123
+ ENV['SANFORD_SKIP_DAEMONIZE'] = ''
124
+ process = @process_class.new(@server_spy, :daemonize => true)
125
+ assert_true process.daemonize?
126
+ end
127
+
128
+ end
129
+
130
+ class RunSetupTests < InitTests
131
+ setup do
132
+ @daemonize_called = false
133
+ Assert.stub(::Process, :daemon).with(true){ @daemonize_called = true }
134
+
135
+ @current_process_name = $0
136
+
137
+ @term_signal_trap_block = nil
138
+ @term_signal_trap_called = false
139
+ Assert.stub(::Signal, :trap).with("TERM") do |&block|
140
+ @term_signal_trap_block = block
141
+ @term_signal_trap_called = true
142
+ end
143
+
144
+ @int_signal_trap_block = nil
145
+ @int_signal_trap_called = false
146
+ Assert.stub(::Signal, :trap).with("INT") do |&block|
147
+ @int_signal_trap_block = block
148
+ @int_signal_trap_called = true
149
+ end
150
+
151
+ @usr2_signal_trap_block = nil
152
+ @usr2_signal_trap_called = false
153
+ Assert.stub(::Signal, :trap).with("USR2") do |&block|
154
+ @usr2_signal_trap_block = block
155
+ @usr2_signal_trap_called = true
156
+ end
157
+ end
158
+ teardown do
159
+ $0 = @current_process_name
160
+ end
161
+
162
+ end
163
+
164
+ class RunTests < RunSetupTests
165
+ desc "and run"
166
+ setup do
167
+ @process.run
168
+ end
169
+
170
+ should "not have daemonized the process" do
171
+ assert_false @daemonize_called
172
+ end
173
+
174
+ should "have started the server listening" do
175
+ assert_true @server_spy.listen_called
176
+ assert_equal [], @server_spy.listen_args
177
+ end
178
+
179
+ should "have set the process name" do
180
+ assert_equal $0, subject.name
181
+ end
182
+
183
+ should "have written the PID file" do
184
+ assert_true @pid_file_spy.write_called
185
+ end
186
+
187
+ should "have trapped signals" do
188
+ assert_true @term_signal_trap_called
189
+ assert_false @server_spy.stop_called
190
+ @term_signal_trap_block.call
191
+ assert_true @server_spy.stop_called
192
+
193
+ assert_true @int_signal_trap_called
194
+ assert_false @server_spy.halt_called
195
+ @int_signal_trap_block.call
196
+ assert_true @server_spy.halt_called
197
+
198
+ assert_true @usr2_signal_trap_called
199
+ assert_false @server_spy.pause_called
200
+ @usr2_signal_trap_block.call
201
+ assert_true @server_spy.pause_called
202
+ end
203
+
204
+ should "have started the server" do
205
+ assert_true @server_spy.start_called
206
+ end
207
+
208
+ should "have joined the server thread" do
209
+ assert_true @server_spy.thread.join_called
210
+ end
211
+
212
+ should "not have exec'd the restart cmd" do
213
+ assert_false @restart_cmd_spy.exec_called
214
+ end
215
+
216
+ should "have removed the PID file" do
217
+ assert_true @pid_file_spy.remove_called
218
+ end
219
+
220
+ end
221
+
222
+ class RunWithDaemonizeTests < RunSetupTests
223
+ desc "that should daemonize is run"
224
+ setup do
225
+ Assert.stub(@process, :daemonize?){ true }
226
+ @process.run
227
+ end
228
+
229
+ should "have daemonized the process" do
230
+ assert_true @daemonize_called
231
+ end
232
+
233
+ end
234
+
235
+ class RunWithIPAndPortTests < RunSetupTests
236
+ desc "with a custom IP and port is run"
237
+ setup do
238
+ ENV['SANFORD_IP'] = Factory.string
239
+ ENV['SANFORD_PORT'] = Factory.integer.to_s
240
+ @process = @process_class.new(@server_spy)
241
+ @process.run
242
+ end
243
+
244
+ should "have used the custom IP and port when listening" do
245
+ assert_true @server_spy.listen_called
246
+ expected = [ @process.server_ip, @process.server_port ]
247
+ assert_equal expected, @server_spy.listen_args
248
+ end
249
+
250
+ end
251
+
252
+ class RunWithServerFDTests < RunSetupTests
253
+ desc "with a server file descriptor is run"
254
+ setup do
255
+ ENV['SANFORD_SERVER_FD'] = Factory.integer.to_s
256
+ @process = @process_class.new(@server_spy)
257
+ @process.run
258
+ end
259
+
260
+ should "have used the file descriptor when listening" do
261
+ assert_true @server_spy.listen_called
262
+ expected = [ @process.server_fd ]
263
+ assert_equal expected, @server_spy.listen_args
264
+ end
265
+
266
+ end
267
+
268
+ class RunWithClientFDsTests < RunSetupTests
269
+ desc "with client file descriptors is run"
270
+ setup do
271
+ @client_fds = [ Factory.integer, Factory.integer ]
272
+ ENV['SANFORD_CLIENT_FDS'] = @client_fds.join(',')
273
+ @process = @process_class.new(@server_spy)
274
+ @process.run
275
+ end
276
+
277
+ should "have used the client file descriptors when starting" do
278
+ assert_true @server_spy.start_called
279
+ assert_equal [ @client_fds ], @server_spy.start_args
280
+ end
281
+
282
+ end
283
+
284
+ class RunAndServerPausedTests < RunSetupTests
285
+ desc "then run and then paused"
286
+ setup do
287
+ server_fd = Factory.integer
288
+ Assert.stub(@server_spy, :file_descriptor){ server_fd }
289
+ client_fds = [ Factory.integer, Factory.integer ]
290
+ Assert.stub(@server_spy, :client_file_descriptors){ client_fds }
291
+
292
+ # mimicing pause being called by a signal, after the thread is joined
293
+ @server_spy.thread.on_join{ @server_spy.pause }
294
+ @process.run
295
+ end
296
+
297
+ should "have set env vars for execing the restart cmd" do
298
+ assert_equal @server_spy.file_descriptor.to_s, ENV['SANFORD_SERVER_FD']
299
+ expected = @server_spy.client_file_descriptors.join(',')
300
+ assert_equal expected, ENV['SANFORD_CLIENT_FDS']
301
+ assert_equal 'yes', ENV['SANFORD_SKIP_DAEMONIZE']
302
+ end
303
+
304
+ should "have exec'd the restart cmd" do
305
+ assert_true @restart_cmd_spy.exec_called
306
+ end
307
+
308
+ end
309
+
310
+ class RestartCmdTests < UnitTests
311
+ desc "RestartCmd"
312
+ setup do
313
+ @restart_cmd = Sanford::RestartCmd.new
314
+
315
+ @chdir_called = false
316
+ Assert.stub(Dir, :chdir).with(@restart_cmd.dir){ @chdir_called = true }
317
+
318
+ @exec_called = false
319
+ Assert.stub(Kernel, :exec).with(*@restart_cmd.argv){ @exec_called = true }
320
+ end
321
+ subject{ @restart_cmd }
322
+
323
+ should have_readers :argv, :dir
324
+
325
+ should "know its argv and dir" do
326
+ expected = [ Gem.ruby, $0, ARGV ].flatten
327
+ assert_equal expected, subject.argv
328
+ assert_equal Dir.pwd, subject.dir
329
+ end
330
+
331
+ should "change the dir when exec'd" do
332
+ subject.exec
333
+ assert_true @chdir_called
334
+ end
335
+
336
+ should "kernel exec its argv when exec'd" do
337
+ subject.exec
338
+ assert_true @exec_called
339
+ end
340
+
341
+ end
342
+
343
+ class ServerSpy
344
+ include Sanford::Server
345
+
346
+ name Factory.string
347
+ ip Factory.string
348
+ port Factory.integer
349
+ pid_file Factory.file_path
350
+
351
+ attr_reader :listen_called, :start_called
352
+ attr_reader :stop_called, :halt_called, :pause_called
353
+ attr_reader :listen_args, :start_args
354
+ attr_reader :thread
355
+
356
+ def initialize(*args)
357
+ super
358
+ @listen_called = false
359
+ @start_called = false
360
+ @stop_called = false
361
+ @halt_called = false
362
+ @pause_called = false
363
+
364
+ @listen_args = nil
365
+ @start_args = nil
366
+
367
+ @thread = ThreadSpy.new
368
+ end
369
+
370
+ def listen(*args)
371
+ @listen_args = args
372
+ @listen_called = true
373
+ end
374
+
375
+ def start(*args)
376
+ @start_args = args
377
+ @start_called = true
378
+ @thread
379
+ end
380
+
381
+ def stop(*args)
382
+ @stop_called = true
383
+ end
384
+
385
+ def halt(*args)
386
+ @halt_called = true
387
+ end
388
+
389
+ def pause(*args)
390
+ @pause_called = true
391
+ end
392
+
393
+ def paused?
394
+ @pause_called
395
+ end
396
+ end
397
+
398
+ class ThreadSpy
399
+ attr_reader :join_called, :on_join_proc
400
+
401
+ def initialize
402
+ @join_called = false
403
+ @on_join_proc = proc{ }
404
+ end
405
+
406
+ def on_join(&block)
407
+ @on_join_proc = block
408
+ end
409
+
410
+ def join
411
+ @join_called = true
412
+ @on_join_proc.call
413
+ end
414
+ end
415
+
416
+ class RestartCmdSpy
417
+ attr_reader :exec_called
418
+
419
+ def initialize
420
+ @exec_called = false
421
+ end
422
+
423
+ def exec
424
+ @exec_called = true
425
+ end
426
+ end
427
+
428
+ end
@@ -0,0 +1,92 @@
1
+ require 'assert'
2
+ require 'sanford/route'
3
+
4
+ require 'sanford/server_data'
5
+ require 'sanford/service_handler'
6
+
7
+ class Sanford::Route
8
+
9
+ class UnitTests < Assert::Context
10
+ desc "Sanford::Route"
11
+ setup do
12
+ @name = Factory.string
13
+ @handler_class_name = TestHandler.to_s
14
+ @route = Sanford::Route.new(@name, @handler_class_name)
15
+ end
16
+ subject{ @route }
17
+
18
+ should have_readers :name, :handler_class_name, :handler_class
19
+
20
+ should "know its name and handler class name" do
21
+ assert_equal @name, subject.name
22
+ assert_equal @handler_class_name, subject.handler_class_name
23
+ end
24
+
25
+ should "not know its handler class by default" do
26
+ assert_nil subject.handler_class
27
+ end
28
+
29
+ should "constantize its handler class after being validated" do
30
+ subject.validate!
31
+ assert_equal TestHandler, subject.handler_class
32
+ end
33
+
34
+ end
35
+
36
+ class RunTests < UnitTests
37
+ desc "when run"
38
+ setup do
39
+ @route.validate!
40
+ @request = Factory.string
41
+ @server_data = Sanford::ServerData.new
42
+
43
+ @runner_spy = RunnerSpy.new(Factory.text)
44
+ Assert.stub(Sanford::SanfordRunner, :new).with(
45
+ @route.handler_class,
46
+ @request,
47
+ @server_data
48
+ ){ @runner_spy }
49
+
50
+ @response = @route.run(@request, @server_data)
51
+ end
52
+ subject{ @response }
53
+
54
+ should "build and run a sanford runner" do
55
+ assert_true @runner_spy.run_called
56
+ end
57
+
58
+ should "return the response from the running the runner" do
59
+ assert_equal @runner_spy.response, subject
60
+ end
61
+
62
+ end
63
+
64
+ class InvalidHandlerClassNameTests < UnitTests
65
+ desc "with an invalid handler class name"
66
+ setup do
67
+ @route = Sanford::Route.new(@name, Factory.string)
68
+ end
69
+
70
+ should "raise a no handler class error when validated" do
71
+ assert_raises(Sanford::NoHandlerClassError){ subject.validate! }
72
+ end
73
+
74
+ end
75
+
76
+ TestHandler = Class.new
77
+
78
+ class RunnerSpy
79
+ attr_reader :response, :run_called
80
+
81
+ def initialize(response)
82
+ @response = response
83
+ @run_called = false
84
+ end
85
+
86
+ def run
87
+ @run_called = true
88
+ @response
89
+ end
90
+ end
91
+
92
+ end
@@ -0,0 +1,65 @@
1
+ require 'assert'
2
+ require 'sanford/router'
3
+
4
+ require 'test/support/factory'
5
+
6
+ class Sanford::Router
7
+
8
+ class UnitTests < Assert::Context
9
+ desc "Sanford::Host"
10
+ setup do
11
+ @router = Sanford::Router.new
12
+ end
13
+ subject{ @router }
14
+
15
+ should have_readers :routes
16
+ should have_imeths :service_handler_ns, :service
17
+
18
+ should "build an empty array for its routes by default" do
19
+ assert_equal [], subject.routes
20
+ end
21
+
22
+ should "not have a service handler ns by default" do
23
+ assert_nil subject.service_handler_ns
24
+ end
25
+
26
+ should "allow setting its service handler ns" do
27
+ namespace = Factory.string
28
+ subject.service_handler_ns namespace
29
+ assert_equal namespace, subject.service_handler_ns
30
+ end
31
+
32
+ should "allow adding routes using `service`" do
33
+ service_name = Factory.string
34
+ handler_name = Factory.string
35
+ subject.service service_name, handler_name
36
+
37
+ route = subject.routes.last
38
+ assert_instance_of Sanford::Route, route
39
+ assert_equal service_name, route.name
40
+ assert_equal handler_name, route.handler_class_name
41
+ end
42
+
43
+ should "use its service handler ns when adding routes" do
44
+ namespace = Factory.string
45
+ subject.service_handler_ns namespace
46
+
47
+ service_name = Factory.string
48
+ handler_name = Factory.string
49
+ subject.service service_name, handler_name
50
+
51
+ route = subject.routes.last
52
+ expected = "#{namespace}::#{handler_name}"
53
+ assert_equal expected, route.handler_class_name
54
+ end
55
+
56
+ should "know its custom inspect" do
57
+ reference = '0x0%x' % (subject.object_id << 1)
58
+ expected = "#<#{subject.class}:#{reference} " \
59
+ "@service_handler_ns=#{subject.service_handler_ns.inspect}>"
60
+ assert_equal expected, subject.inspect
61
+ end
62
+
63
+ end
64
+
65
+ end