sanford 0.14.0 → 0.15.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.
@@ -1,6 +1,7 @@
1
1
  require 'assert'
2
2
  require 'sanford/error_handler'
3
3
 
4
+ require 'sanford-protocol'
4
5
  require 'sanford/server_data'
5
6
 
6
7
  class Sanford::ErrorHandler
@@ -8,176 +9,311 @@ class Sanford::ErrorHandler
8
9
  class UnitTests < Assert::Context
9
10
  desc "Sanford::ErrorHandler"
10
11
  setup do
11
- @exception = RuntimeError.new('test')
12
+ @exception = Factory.exception
12
13
  @server_data = Sanford::ServerData.new
13
- @error_handler = Sanford::ErrorHandler.new(@exception, @server_data)
14
+ @request = Sanford::Protocol::Request.new(Factory.string, {
15
+ Factory.string => Factory.string
16
+ })
17
+ @response = Sanford::Protocol::Response.new(Factory.integer)
18
+ @context_hash = {
19
+ :server_data => @server_data,
20
+ :request => @request,
21
+ :handler_class => Factory.string,
22
+ :response => @response
23
+ }
24
+
25
+ @handler_class = Sanford::ErrorHandler
14
26
  end
15
- subject{ @error_handler }
27
+ subject{ @handler_class }
16
28
 
17
- should have_imeths :exception, :server_data, :request, :run
29
+ end
18
30
 
19
- should "return a Sanford::Protocol::Response with `run`" do
20
- assert_instance_of Sanford::Protocol::Response, subject.run
31
+ class InitSetupTests < UnitTests
32
+ desc "when init"
33
+ setup do
34
+ # always make sure there are multiple error procs or tests can be false
35
+ # positives
36
+ @error_proc_spies = (1..(Factory.integer(3) + 1)).map{ ErrorProcSpy.new }
37
+ Assert.stub(@server_data, :error_procs){ @error_proc_spies }
21
38
  end
22
39
 
23
- def generate_exception(exception_class, message = nil)
24
- exception = nil
25
- begin
26
- raise exception_class, message
27
- rescue Exception => exception
28
- end
29
- exception
40
+ end
41
+
42
+ class InitTests < InitSetupTests
43
+ desc "when init"
44
+ setup do
45
+ @handler = @handler_class.new(@exception, @context_hash)
46
+ end
47
+ subject{ @handler }
48
+
49
+ should have_readers :exception, :context
50
+ should have_imeths :run
51
+
52
+ should "know its exception and context" do
53
+ assert_equal @exception, subject.exception
54
+ exp = Sanford::ErrorContext.new(@context_hash)
55
+ assert_equal exp, subject.context
56
+ end
57
+
58
+ should "know its error procs" do
59
+ assert_equal @error_proc_spies.reverse, subject.error_procs
30
60
  end
31
61
 
32
62
  end
33
63
 
34
- class ResponseFromProcTests < UnitTests
35
- desc "generating a respone from an error proc"
64
+ class RunSetupTests < InitTests
65
+ desc "and run"
36
66
 
37
- should "use the return-value of the error proc if it is a protocol response" do
38
- error_proc = proc do |exception, host_data, request|
39
- Sanford::Protocol::Response.new([ 567, 'custom message'], 'custom data')
40
- end
41
- server_data = Sanford::ServerData.new(:error_procs => [ error_proc ])
42
- response = Sanford::ErrorHandler.new(@exception, server_data).run
67
+ end
68
+
69
+ class RunTests < RunSetupTests
70
+ setup do
71
+ @handler.run
72
+ end
43
73
 
44
- assert_equal 567, response.code
45
- assert_equal 'custom message', response.status.message
46
- assert_equal 'custom data', response.data
74
+ should "call each of its procs" do
75
+ subject.error_procs.each_with_index do |spy, index|
76
+ assert_true spy.called
77
+ assert_equal subject.exception, spy.exception
78
+ assert_equal subject.context, spy.context
79
+ end
47
80
  end
48
81
 
49
- should "use an integer returned by the error proc to generate a protocol response" do
50
- server_data = Sanford::ServerData.new(:error_procs => [ proc{ 345 } ])
51
- response = Sanford::ErrorHandler.new(@exception, server_data).run
82
+ end
52
83
 
53
- assert_equal 345, response.code
54
- assert_nil response.status.message
55
- assert_nil response.data
84
+ class RunWithNoResponseFromErrorProcSetupTests < RunSetupTests
85
+ desc "without a response being returned from its error procs"
86
+ setup do
87
+ @error_proc_spies.each{ |s| s.response = nil }
56
88
  end
57
89
 
58
- should "use a symbol returned by the error proc to generate a protocol response" do
59
- server_data = Sanford::ServerData.new({
60
- :error_procs => [ proc{ :not_found } ]
61
- })
62
- response = Sanford::ErrorHandler.new(@exception, server_data).run
90
+ end
91
+
92
+ class RunWithBadMessageErrorTests < RunWithNoResponseFromErrorProcSetupTests
93
+ desc "but with a bad message error exception"
94
+ setup do
95
+ @exception = Factory.exception(Sanford::Protocol::BadMessageError)
63
96
 
64
- assert_equal 404, response.code
65
- assert_nil response.status.message
66
- assert_nil response.data
97
+ @handler = @handler_class.new(@exception, @context_hash)
98
+ @response = @handler.run
67
99
  end
100
+ subject{ @response }
68
101
 
69
- should "use the default behavior if the error proc doesn't return a valid response result" do
70
- server_data = Sanford::ServerData.new(:error_procs => [ proc{ true } ])
71
- response = Sanford::ErrorHandler.new(@exception, server_data).run
102
+ should "return a bad request response" do
103
+ exp = Sanford::Protocol::Response.new([:bad_request, @exception.message])
104
+ assert_equal exp, subject
105
+ end
106
+
107
+ end
72
108
 
73
- assert_equal 500, response.code
74
- assert_equal 'An unexpected error occurred.', response.status.message
109
+ class RunWithInvalidRequestErrorTests < RunWithNoResponseFromErrorProcSetupTests
110
+ desc "but with an invalid request error exception"
111
+ setup do
112
+ @exception = Factory.exception(Sanford::Protocol::Request::InvalidError)
113
+
114
+ @handler = @handler_class.new(@exception, @context_hash)
115
+ @response = @handler.run
75
116
  end
117
+ subject{ @response }
76
118
 
77
- should "use the default behavior for an exception raised by the error proc " \
78
- "and ignore the original exception" do
79
- server_data = Sanford::ServerData.new({
80
- :error_procs => [ proc{ raise Sanford::NotFoundError } ]
81
- })
82
- response = Sanford::ErrorHandler.new(@exception, server_data).run
119
+ should "return a bad request response" do
120
+ exp = Sanford::Protocol::Response.new([:bad_request, @exception.message])
121
+ assert_equal exp, subject
122
+ end
83
123
 
84
- assert_equal 404, response.code
85
- assert_nil response.status.message
86
- assert_nil response.data
124
+ end
125
+
126
+ class RunWithNotFoundErrorTests < RunWithNoResponseFromErrorProcSetupTests
127
+ desc "but with a not found error exception"
128
+ setup do
129
+ @exception = Factory.exception(Sanford::NotFoundError)
130
+
131
+ @handler = @handler_class.new(@exception, @context_hash)
132
+ @response = @handler.run
133
+ end
134
+ subject{ @response }
135
+
136
+ should "return a not found response" do
137
+ exp = Sanford::Protocol::Response.new(:not_found)
138
+ assert_equal exp, subject
87
139
  end
88
140
 
89
141
  end
90
142
 
91
- class ResponseFromExceptionTests < UnitTests
92
- desc "generating a respone from an exception"
143
+ class RunWithTimeoutErrorTests < RunWithNoResponseFromErrorProcSetupTests
144
+ desc "but with a timeout error exception"
145
+ setup do
146
+ @exception = Factory.exception(Sanford::Protocol::TimeoutError)
93
147
 
94
- should "build a 400 response with a protocol BadMessageError" do
95
- exception = generate_exception(Sanford::Protocol::BadMessageError, 'bad message')
96
- response = Sanford::ErrorHandler.new(exception, @server_data).run
148
+ @handler = @handler_class.new(@exception, @context_hash)
149
+ @response = @handler.run
150
+ end
151
+ subject{ @response }
97
152
 
98
- assert_equal 400, response.code
99
- assert_equal 'bad message', response.status.message
153
+ should "return a timeout response" do
154
+ exp = Sanford::Protocol::Response.new(:timeout)
155
+ assert_equal exp, subject
100
156
  end
101
157
 
102
- should "build a 400 response with a protocol request invalid error" do
103
- exception = generate_exception(Sanford::Protocol::Request::InvalidError, 'bad request')
104
- response = Sanford::ErrorHandler.new(exception, @server_data).run
158
+ end
159
+
160
+ class RunWithGenericErrorTests < RunWithNoResponseFromErrorProcSetupTests
161
+ desc "but with a generic error"
162
+ setup do
163
+ @exception = Factory.exception
164
+
165
+ @handler = @handler_class.new(@exception, @context_hash)
166
+ @response = @handler.run
167
+ end
168
+ subject{ @response }
105
169
 
106
- assert_equal 400, response.code
107
- assert_equal 'bad request', response.status.message
170
+ should "return an error response" do
171
+ exp = Sanford::Protocol::Response.new([:error, "An unexpected error occurred."])
172
+ assert_equal exp, subject
108
173
  end
109
174
 
110
- should "build a 404 response with a NotFoundError" do
111
- exception = generate_exception(Sanford::NotFoundError, 'not found')
112
- response = Sanford::ErrorHandler.new(exception, @server_data).run
175
+ end
176
+
177
+ class RunWithErrorProcExceptionsTests < InitSetupTests
178
+ desc "and run with error procs that throw exceptions"
179
+ setup do
180
+ @proc_exceptions = @error_proc_spies.reverse.map do |spy|
181
+ exception = Factory.exception(RuntimeError, @error_proc_spies.index(spy).to_s)
182
+ spy.raise_exception = exception
183
+ exception
184
+ end
113
185
 
114
- assert_equal 404, response.code
115
- assert_nil response.status.message
186
+ @handler = @handler_class.new(@exception, @context_hash)
187
+ @response = @handler.run
116
188
  end
189
+ subject{ @handler }
117
190
 
118
- should "build a 500 response with all other exceptions" do
119
- response = Sanford::ErrorHandler.new(RuntimeError.new('test'), @server_data).run
191
+ should "pass the previously raised exception to the next proc" do
192
+ exp = [@exception] + @proc_exceptions[0..-2]
193
+ assert_equal exp, subject.error_procs.map(&:exception)
194
+ end
195
+
196
+ should "set its exception to the last exception thrown by the procs" do
197
+ assert_equal @proc_exceptions.last, subject.exception
198
+ end
120
199
 
121
- assert_equal 500, response.code
122
- assert_equal 'An unexpected error occurred.', response.status.message
200
+ should "return an error response" do
201
+ exp = Sanford::Protocol::Response.new([:error, "An unexpected error occurred."])
202
+ assert_equal exp, @response
123
203
  end
124
204
 
125
205
  end
126
206
 
127
- class MultipleErrorProcsTests < ResponseFromProcTests
128
- desc "with multiple error procs"
207
+ class RunWithProtocolResponseFromErrorProcTests < RunSetupTests
208
+ desc "with a protocol response returned from an error proc"
129
209
  setup do
130
- @first_called, @second_called, @third_called = nil, nil, nil
131
- @server_data = Sanford::ServerData.new({
132
- :error_procs => [ first_proc, second_proc, third_proc ]
133
- })
210
+ @proc_response = Sanford::Protocol::Response.new(Factory.integer)
211
+ @error_proc_spies.choice.response = @proc_response
212
+
213
+ @response = @handler.run
134
214
  end
215
+ subject{ @response }
135
216
 
136
- should "call every error proc" do
137
- exception = RuntimeError.new('test')
138
- @error_handler = Sanford::ErrorHandler.new(exception, @server_data)
139
- @error_handler.run
217
+ should "return the protocol response from the error proc" do
218
+ assert_equal @proc_response, subject
219
+ end
220
+
221
+ end
222
+
223
+ class RunWithResponseCodeFromErrorProcTests < RunSetupTests
224
+ desc "with a response code returned from an error proc"
225
+ setup do
226
+ @response_code = Factory.integer
227
+ @error_proc_spies.choice.response = @response_code
140
228
 
141
- assert_equal true, @first_called
142
- assert_equal true, @second_called
143
- assert_equal true, @third_called
229
+ @response = @handler.run
144
230
  end
231
+ subject{ @response }
145
232
 
146
- should "should return the response of the last configured error proc " \
147
- "that returned a valid response" do
148
- exception = RuntimeError.new('test')
149
- @error_handler = Sanford::ErrorHandler.new(exception, @server_data)
150
- response = @error_handler.run
233
+ should "use the response code to build a response and return it" do
234
+ exp = Sanford::Protocol::Response.new(@response_code)
235
+ assert_equal exp, subject
236
+ end
151
237
 
152
- # use the second proc's generated response
153
- assert_equal 987, response.code
238
+ end
154
239
 
155
- exception = generate_exception(Sanford::NotFoundError, 'not found')
156
- @error_handler = Sanford::ErrorHandler.new(exception, @server_data)
157
- response = @error_handler.run
240
+ class RunWithSymbolFromErrorProcTests < RunSetupTests
241
+ desc "with a response symbol returned from an error proc"
242
+ setup do
243
+ @response_symbol = [:not_found, :bad_request, :error].choice
244
+ @error_proc_spies.choice.response = @response_symbol
158
245
 
159
- # use the third proc's generated response
160
- assert_equal 876, response.code
246
+ @response = @handler.run
161
247
  end
248
+ subject{ @response }
162
249
 
163
- def first_proc
164
- proc{ @first_called = true }
250
+ should "use the response symbol to build a response and return it" do
251
+ exp = Sanford::Protocol::Response.new(@response_symbol)
252
+ assert_equal exp, subject
165
253
  end
166
254
 
167
- def second_proc
168
- proc do |exception, server_data, request|
169
- @second_called = true
170
- 987
255
+ end
256
+
257
+ class RunWithMultipleResponseFromErrorProcTests < RunSetupTests
258
+ desc "with responses from multiple error procs"
259
+ setup do
260
+ @error_proc_spies.each do |spy|
261
+ spy.response = Sanford::Protocol::Response.new(Factory.integer)
171
262
  end
263
+
264
+ @response = @handler.run
172
265
  end
266
+ subject{ @response }
173
267
 
174
- def third_proc
175
- proc do |exception, server_data, request|
176
- @third_called = true
177
- 876 if exception.kind_of?(Sanford::NotFoundError)
178
- end
268
+ should "return the last response from its error procs" do
269
+ assert_equal @error_proc_spies.last.response, subject
270
+ end
271
+
272
+ end
273
+
274
+ class ErrorContextTests < UnitTests
275
+ desc "ErrorContext"
276
+ setup do
277
+ @context = Sanford::ErrorContext.new(@context_hash)
278
+ end
279
+ subject{ @context }
280
+
281
+ should have_readers :server_data
282
+ should have_readers :request, :handler_class, :response
283
+
284
+ should "know its attributes" do
285
+ assert_equal @context_hash[:server_data], subject.server_data
286
+ assert_equal @context_hash[:request], subject.request
287
+ assert_equal @context_hash[:handler_class], subject.handler_class
288
+ assert_equal @context_hash[:response], subject.response
179
289
  end
180
290
 
291
+ should "know if it equals another context" do
292
+ exp = Sanford::ErrorContext.new(@context_hash)
293
+ assert_equal exp, subject
294
+
295
+ exp = Sanford::ErrorContext.new({})
296
+ assert_not_equal exp, subject
297
+ end
298
+
299
+ end
300
+
301
+ class ErrorProcSpy
302
+ attr_reader :called, :exception, :context
303
+ attr_accessor :response, :raise_exception
304
+
305
+ def initialize
306
+ @called = false
307
+ end
308
+
309
+ def call(exception, context)
310
+ @called = true
311
+ @exception = exception
312
+ @context = context
313
+
314
+ raise self.raise_exception if self.raise_exception
315
+ @response
316
+ end
181
317
  end
182
318
 
183
319
  end
@@ -18,13 +18,9 @@ class Sanford::Process
18
18
  class InitTests < UnitTests
19
19
  desc "when init"
20
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']
21
+ @current_env_server_fd = ENV['SANFORD_SERVER_FD']
22
+ @current_env_client_fds = ENV['SANFORD_CLIENT_FDS']
25
23
  @current_env_skip_daemonize = ENV['SANFORD_SKIP_DAEMONIZE']
26
- ENV.delete('SANFORD_IP')
27
- ENV.delete('SANFORD_PORT')
28
24
  ENV.delete('SANFORD_SERVER_FD')
29
25
  ENV.delete('SANFORD_CLIENT_FDS')
30
26
  ENV.delete('SANFORD_SKIP_DAEMONIZE')
@@ -43,10 +39,8 @@ class Sanford::Process
43
39
  end
44
40
  teardown do
45
41
  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
42
+ ENV['SANFORD_CLIENT_FDS'] = @current_env_client_fds
43
+ ENV['SANFORD_SERVER_FD'] = @current_env_server_fd
50
44
  end
51
45
  subject{ @process }
52
46
 
@@ -72,23 +66,17 @@ class Sanford::Process
72
66
  assert_nil subject.server_fd
73
67
  end
74
68
 
75
- should "set its server ip, port and file descriptor using env vars" do
76
- ENV['SANFORD_IP'] = Factory.string
77
- ENV['SANFORD_PORT'] = Factory.integer.to_s
69
+ should "allow overriding its file descriptor using an env var" do
78
70
  ENV['SANFORD_SERVER_FD'] = Factory.integer.to_s
79
71
  process = @process_class.new(@server_spy)
80
- assert_equal ENV['SANFORD_IP'], process.server_ip
81
- assert_equal ENV['SANFORD_PORT'].to_i, process.server_port
82
72
  assert_equal ENV['SANFORD_SERVER_FD'].to_i, process.server_fd
83
- end
84
73
 
85
- should "ignore blank env values for its server ip, port and fd" do
86
- ENV['SANFORD_IP'] = ''
87
- ENV['SANFORD_PORT'] = ''
88
74
  ENV['SANFORD_SERVER_FD'] = ''
89
75
  process = @process_class.new(@server_spy)
90
- assert_equal @server_spy.configured_ip, process.server_ip
91
- assert_equal @server_spy.configured_port, process.server_port
76
+ assert_nil process.server_fd
77
+
78
+ ENV.delete('SANFORD_SERVER_FD')
79
+ process = @process_class.new(@server_spy)
92
80
  assert_nil process.server_fd
93
81
  end
94
82
 
@@ -97,7 +85,7 @@ class Sanford::Process
97
85
  end
98
86
 
99
87
  should "set its client file descriptors using an env var" do
100
- client_fds = [ Factory.integer, Factory.integer ]
88
+ client_fds = [Factory.integer, Factory.integer]
101
89
  ENV['SANFORD_CLIENT_FDS'] = client_fds.join(',')
102
90
  process = @process_class.new(@server_spy)
103
91
  assert_equal client_fds, process.client_fds
@@ -19,36 +19,47 @@ class Sanford::ServerData
19
19
  @logger = Factory.string
20
20
  @template_source = Factory.string
21
21
 
22
- @init_procs = [ proc{} ]
23
- @error_procs = [ proc{} ]
22
+ @init_procs = Factory.integer(3).times.map{ proc{} }
23
+ @error_procs = Factory.integer(3).times.map{ proc{} }
24
+
25
+ @start_procs = Factory.integer(3).times.map{ proc{} }
26
+ @shutdown_procs = Factory.integer(3).times.map{ proc{} }
27
+ @sleep_procs = Factory.integer(3).times.map{ proc{} }
28
+ @wakeup_procs = Factory.integer(3).times.map{ proc{} }
24
29
 
25
30
  @router = Factory.string
26
31
  @route = Sanford::Route.new(Factory.string, TestHandler.to_s).tap(&:validate!)
27
32
 
28
33
  @server_data = Sanford::ServerData.new({
29
- :name => @name,
30
- :ip => @ip,
31
- :port => @port,
32
- :pid_file => @pid_file,
33
- :receives_keep_alive => @receives_keep_alive,
34
- :verbose_logging => @verbose_logging,
35
- :logger => @logger,
36
- :template_source => @template_source,
37
- :init_procs => @init_procs,
38
- :error_procs => @error_procs,
39
- :router => @router,
40
- :routes => [ @route ]
34
+ :name => @name,
35
+ :ip => @ip,
36
+ :port => @port,
37
+ :pid_file => @pid_file,
38
+ :receives_keep_alive => @receives_keep_alive,
39
+ :verbose_logging => @verbose_logging,
40
+ :logger => @logger,
41
+ :template_source => @template_source,
42
+ :init_procs => @init_procs,
43
+ :error_procs => @error_procs,
44
+ :worker_start_procs => @start_procs,
45
+ :worker_shutdown_procs => @shutdown_procs,
46
+ :worker_sleep_procs => @sleep_procs,
47
+ :worker_wakeup_procs => @wakeup_procs,
48
+ :router => @router,
49
+ :routes => [@route]
41
50
  })
42
51
  end
43
52
  subject{ @server_data }
44
53
 
45
54
  should have_readers :name
46
- should have_readers :ip, :port
47
55
  should have_readers :pid_file
48
56
  should have_readers :receives_keep_alive
49
57
  should have_readers :verbose_logging, :logger, :template_source
50
58
  should have_readers :init_procs, :error_procs
59
+ should have_readers :worker_start_procs, :worker_shutdown_procs
60
+ should have_readers :worker_sleep_procs, :worker_wakeup_procs
51
61
  should have_readers :router, :routes
62
+ should have_accessors :ip, :port
52
63
 
53
64
  should "know its attributes" do
54
65
  assert_equal @name, subject.name
@@ -62,9 +73,14 @@ class Sanford::ServerData
62
73
  assert_equal @logger, subject.logger
63
74
  assert_equal @template_source, subject.template_source
64
75
 
65
- assert_equal @init_procs, subject.error_procs
76
+ assert_equal @init_procs, subject.init_procs
66
77
  assert_equal @error_procs, subject.error_procs
67
78
 
79
+ assert_equal @start_procs, subject.worker_start_procs
80
+ assert_equal @shutdown_procs, subject.worker_shutdown_procs
81
+ assert_equal @sleep_procs, subject.worker_sleep_procs
82
+ assert_equal @wakeup_procs, subject.worker_wakeup_procs
83
+
68
84
  assert_equal @router, subject.router
69
85
  end
70
86