1 require 'abstract_unit'
5 class RescueController
< ActionController
::Base
6 class NotAuthorized
< StandardError
8 class NotAuthorizedToRescueAsString
< StandardError
11 class RecordInvalid
< StandardError
13 class RecordInvalidToRescueAsString
< StandardError
16 class NotAllowed
< StandardError
18 class NotAllowedToRescueAsString
< StandardError
21 class InvalidRequest
< StandardError
23 class InvalidRequestToRescueAsString
< StandardError
26 class BadGateway
< StandardError
28 class BadGatewayToRescueAsString
< StandardError
31 class ResourceUnavailable
< StandardError
33 class ResourceUnavailableToRescueAsString
< StandardError
36 # We use a fully-qualified name in some strings, and a relative constant
37 # name in some other to test correct handling of both cases.
39 rescue_from NotAuthorized
, :with => :deny_access
40 rescue_from
'RescueController::NotAuthorizedToRescueAsString', :with => :deny_access
42 rescue_from RecordInvalid
, :with => :show_errors
43 rescue_from
'RescueController::RecordInvalidToRescueAsString', :with => :show_errors
45 rescue_from NotAllowed
, :with => proc
{ head
:forbidden }
46 rescue_from
'RescueController::NotAllowedToRescueAsString', :with => proc
{ head
:forbidden }
48 rescue_from InvalidRequest
, :with => proc
{ |exception
| render
:text => exception
.message
}
49 rescue_from
'InvalidRequestToRescueAsString', :with => proc
{ |exception
| render
:text => exception
.message
}
51 rescue_from BadGateway
do
54 rescue_from
'BadGatewayToRescueAsString' do
58 rescue_from ResourceUnavailable
do |exception
|
59 render
:text => exception
.message
61 rescue_from
'ResourceUnavailableToRescueAsString' do |exception
|
62 render
:text => exception
.message
65 # This is a Dispatcher exception and should be in ApplicationController.
66 rescue_from ActionController
::RoutingError do
67 render
:text => 'no way'
71 render
:text => 'already rendered'
75 def method_not_allowed
76 raise ActionController
::MethodNotAllowed.new(:get, :head, :put)
80 raise ActionController
::NotImplemented.new(:get, :put)
86 def not_authorized_raise_as_string
87 raise NotAuthorizedToRescueAsString
93 def not_allowed_raise_as_string
94 raise NotAllowedToRescueAsString
100 def invalid_request_raise_as_string
101 raise InvalidRequestToRescueAsString
107 def record_invalid_raise_as_string
108 raise RecordInvalidToRescueAsString
114 def bad_gateway_raise_as_string
115 raise BadGatewayToRescueAsString
118 def resource_unavailable
119 raise ResourceUnavailable
121 def resource_unavailable_raise_as_string
122 raise ResourceUnavailableToRescueAsString
133 def show_errors(exception
)
134 head
:unprocessable_entity
138 class RescueControllerTest
< ActionController
::TestCase
139 FIXTURE_PUBLIC
= "#{File.dirname(__FILE__)}/../fixtures".freeze
141 setup
:set_all_requests_local
142 setup
:populate_exception_object
144 def set_all_requests_local
145 RescueController
.consider_all_requests_local
= true
146 @request.remote_addr
= '1.2.3.4'
147 @request.host
= 'example.com'
150 def populate_exception_object
157 def test_rescue_action_locally_if_all_requests_local
158 @controller.expects(:local_request?).never
159 @controller.expects(:rescue_action_locally).with(@exception)
160 @controller.expects(:rescue_action_in_public).never
162 with_all_requests_local
do
163 @controller.send
:rescue_action, @exception
167 def test_rescue_action_locally_if_remote_addr_is_localhost
168 @controller.expects(:local_request?).returns(true)
169 @controller.expects(:rescue_action_locally).with(@exception)
170 @controller.expects(:rescue_action_in_public).never
172 with_all_requests_local
false do
173 @controller.send
:rescue_action, @exception
177 def test_rescue_action_in_public_otherwise
178 @controller.expects(:local_request?).returns(false)
179 @controller.expects(:rescue_action_locally).never
180 @controller.expects(:rescue_action_in_public).with(@exception)
182 with_all_requests_local
false do
183 @controller.send
:rescue_action, @exception
187 def test_rescue_action_in_public_with_error_file
188 with_rails_root FIXTURE_PUBLIC
do
189 with_all_requests_local
false do
194 assert_response
:internal_server_error
195 body
= File
.read("#{FIXTURE_PUBLIC}/public/500.html")
196 assert_equal body
, @response.body
199 def test_rescue_action_in_public_without_error_file
200 with_rails_root
'/tmp' do
201 with_all_requests_local
false do
206 assert_response
:internal_server_error
207 assert_equal
' ', @response.body
210 def test_rescue_unknown_action_in_public_with_error_file
211 with_rails_root FIXTURE_PUBLIC
do
212 with_all_requests_local
false do
213 get
:foobar_doesnt_exist
217 assert_response
:not_found
218 body
= File
.read("#{FIXTURE_PUBLIC}/public/404.html")
219 assert_equal body
, @response.body
222 def test_rescue_unknown_action_in_public_without_error_file
223 with_rails_root
'/tmp' do
224 with_all_requests_local
false do
225 get
:foobar_doesnt_exist
229 assert_response
:not_found
230 assert_equal
' ', @response.body
233 def test_rescue_missing_template_in_public
234 with_rails_root FIXTURE_PUBLIC
do
235 with_all_requests_local
true do
236 get
:missing_template
240 assert_response
:internal_server_error
241 assert
@response.body
.include?('missing_template'), "Response should include the template name."
244 def test_rescue_action_locally
246 assert_response
:internal_server_error
247 assert_template
'diagnostics.erb'
248 assert
@response.body
.include?('RescueController#raises'), "Response should include controller and action."
249 assert
@response.body
.include?("don't panic"), "Response should include exception message."
252 def test_local_request_when_remote_addr_is_localhost
253 @controller.expects(:request).returns(@request).at_least_once
254 with_remote_addr
'127.0.0.1' do
255 assert
@controller.send(:local_request?)
259 def test_local_request_when_remote_addr_isnt_locahost
260 @controller.expects(:request).returns(@request)
261 with_remote_addr
'1.2.3.4' do
262 assert
!@controller.send(:local_request?)
266 def test_rescue_responses
267 responses
= ActionController
::Base.rescue_responses
269 assert_equal ActionController
::Rescue::DEFAULT_RESCUE_RESPONSE, responses
.default
270 assert_equal ActionController
::Rescue::DEFAULT_RESCUE_RESPONSE, responses
[Exception
.new
]
272 assert_equal
:not_found, responses
[ActionController
::RoutingError.name
]
273 assert_equal
:not_found, responses
[ActionController
::UnknownAction.name
]
274 assert_equal
:not_found, responses
['ActiveRecord::RecordNotFound']
275 assert_equal
:conflict, responses
['ActiveRecord::StaleObjectError']
276 assert_equal
:unprocessable_entity, responses
['ActiveRecord::RecordInvalid']
277 assert_equal
:unprocessable_entity, responses
['ActiveRecord::RecordNotSaved']
278 assert_equal
:method_not_allowed, responses
['ActionController::MethodNotAllowed']
279 assert_equal
:not_implemented, responses
['ActionController::NotImplemented']
282 def test_rescue_templates
283 templates
= ActionController
::Base.rescue_templates
285 assert_equal ActionController
::Rescue::DEFAULT_RESCUE_TEMPLATE, templates
.default
286 assert_equal ActionController
::Rescue::DEFAULT_RESCUE_TEMPLATE, templates
[Exception
.new
]
288 assert_equal
'missing_template', templates
[ActionView
::MissingTemplate.name
]
289 assert_equal
'routing_error', templates
[ActionController
::RoutingError.name
]
290 assert_equal
'unknown_action', templates
[ActionController
::UnknownAction.name
]
291 assert_equal
'template_error', templates
[ActionView
::TemplateError.name
]
294 def test_clean_backtrace
295 with_rails_root
nil do
296 # No action if RAILS_ROOT isn't set.
297 cleaned
= @controller.send(:clean_backtrace, @exception)
298 assert_equal
@exception.backtrace
, cleaned
301 with_rails_root Dir
.pwd
do
302 # RAILS_ROOT is removed from backtrace.
303 cleaned
= @controller.send(:clean_backtrace, @exception)
304 expected
= @exception.backtrace
.map
{ |line
| line
.sub(RAILS_ROOT
, '') }
305 assert_equal expected
, cleaned
307 # No action if backtrace is nil.
308 assert_nil
@controller.send(:clean_backtrace, Exception
.new
)
312 def test_not_implemented
313 with_all_requests_local
false do
314 with_rails_public_path(".") do
315 head
:not_implemented
318 assert_response
:not_implemented
319 assert_equal
"GET, PUT", @response.headers
['Allow']
322 def test_method_not_allowed
323 with_all_requests_local
false do
324 with_rails_public_path(".") do
325 get
:method_not_allowed
328 assert_response
:method_not_allowed
329 assert_equal
"GET, HEAD, PUT", @response.headers
['Allow']
332 def test_rescue_handler
334 assert_response
:forbidden
336 def test_rescue_handler_string
337 get
:not_authorized_raise_as_string
338 assert_response
:forbidden
341 def test_rescue_handler_with_argument
342 @controller.expects(:show_errors).once
.with
{ |e
| e
.is_a
?(Exception
) }
345 def test_rescue_handler_with_argument_as_string
346 @controller.expects(:show_errors).once
.with
{ |e
| e
.is_a
?(Exception
) }
347 get
:record_invalid_raise_as_string
350 def test_proc_rescue_handler
352 assert_response
:forbidden
354 def test_proc_rescue_handler_as_string
355 get
:not_allowed_raise_as_string
356 assert_response
:forbidden
359 def test_proc_rescue_handle_with_argument
361 assert_equal
"RescueController::InvalidRequest", @response.body
363 def test_proc_rescue_handle_with_argument_as_string
364 get
:invalid_request_raise_as_string
365 assert_equal
"RescueController::InvalidRequestToRescueAsString", @response.body
368 def test_block_rescue_handler
372 def test_block_rescue_handler_as_string
373 get
:bad_gateway_raise_as_string
377 def test_block_rescue_handler_with_argument
378 get
:resource_unavailable
379 assert_equal
"RescueController::ResourceUnavailable", @response.body
382 def test_block_rescue_handler_with_argument_as_string
383 get
:resource_unavailable_raise_as_string
384 assert_equal
"RescueController::ResourceUnavailableToRescueAsString", @response.body
387 def test_rescue_dispatcher_exceptions
388 RescueController
.process_with_exception(@request, @response, ActionController
::RoutingError.new("Route not found"))
389 assert_equal
"no way", @response.body
393 def with_all_requests_local(local
= true)
394 old_local
, ActionController
::Base.consider_all_requests_local
=
395 ActionController
::Base.consider_all_requests_local
, local
398 ActionController
::Base.consider_all_requests_local
= old_local
401 def with_remote_addr(addr
)
402 old_remote_addr
, @request.remote_addr
= @request.remote_addr
, addr
405 @request.remote_addr
= old_remote_addr
408 def with_rails_public_path(rails_root
)
409 old_rails
= Object
.const_get(:Rails) rescue nil
410 mod
= Object
.const_set(:Rails, Module
.new
)
411 (class << mod
; self; end).instance_eval
do
412 define_method(:public_path) { "#{rails_root}/public" }
416 Object
.module_eval
{ remove_const(:Rails) } if defined?(Rails
)
417 Object
.const_set(:Rails, old_rails
) if old_rails
420 def with_rails_root(path
= nil,&block
)
421 old_rails_root
= RAILS_ROOT
if defined?(RAILS_ROOT
)
423 silence_warnings
{ Object
.const_set(:RAILS_ROOT, path
) }
425 Object
.remove_const(:RAILS_ROOT) rescue nil
428 with_rails_public_path(path
, &block
)
432 silence_warnings
{ Object
.const_set(:RAILS_ROOT, old_rails_root
) }
434 Object
.remove_const(:RAILS_ROOT) rescue nil
439 class ExceptionInheritanceRescueController
< ActionController
::Base
441 class ParentException
< StandardError
444 class ChildException
< ParentException
447 class GrandchildException
< ChildException
450 rescue_from ChildException
, :with => lambda
{ head
:ok }
451 rescue_from ParentException
, :with => lambda
{ head
:created }
452 rescue_from GrandchildException
, :with => lambda
{ head
:no_content }
454 def raise_parent_exception
455 raise ParentException
458 def raise_child_exception
462 def raise_grandchild_exception
463 raise GrandchildException
467 class ExceptionInheritanceRescueControllerTest
< ActionController
::TestCase
468 def test_bottom_first
469 get
:raise_grandchild_exception
470 assert_response
:no_content
473 def test_inheritance_works
474 get
:raise_child_exception
475 assert_response
:created
479 class ControllerInheritanceRescueController
< ExceptionInheritanceRescueController
480 class FirstExceptionInChildController
< StandardError
483 class SecondExceptionInChildController
< StandardError
486 rescue_from FirstExceptionInChildController
, 'SecondExceptionInChildController', :with => lambda
{ head
:gone }
488 def raise_first_exception_in_child_controller
489 raise FirstExceptionInChildController
492 def raise_second_exception_in_child_controller
493 raise SecondExceptionInChildController
497 class ControllerInheritanceRescueControllerTest
< ActionController
::TestCase
498 def test_first_exception_in_child_controller
499 get
:raise_first_exception_in_child_controller
500 assert_response
:gone
503 def test_second_exception_in_child_controller
504 get
:raise_second_exception_in_child_controller
505 assert_response
:gone
508 def test_exception_in_parent_controller
509 get
:raise_parent_exception
510 assert_response
:created