sanford 0.10.1 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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