Merged updates from trunk into stable branch
[feedcatcher.git] / vendor / rails / actionpack / test / controller / rescue_test.rb
1 require 'abstract_unit'
2
3 class RescueController < ActionController::Base
4 class NotAuthorized < StandardError
5 end
6 class NotAuthorizedToRescueAsString < StandardError
7 end
8
9 class RecordInvalid < StandardError
10 end
11 class RecordInvalidToRescueAsString < StandardError
12 end
13
14 class NotAllowed < StandardError
15 end
16 class NotAllowedToRescueAsString < StandardError
17 end
18
19 class InvalidRequest < StandardError
20 end
21 class InvalidRequestToRescueAsString < StandardError
22 end
23
24 class BadGateway < StandardError
25 end
26 class BadGatewayToRescueAsString < StandardError
27 end
28
29 class ResourceUnavailable < StandardError
30 end
31 class ResourceUnavailableToRescueAsString < StandardError
32 end
33
34 # We use a fully-qualified name in some strings, and a relative constant
35 # name in some other to test correct handling of both cases.
36
37 rescue_from NotAuthorized, :with => :deny_access
38 rescue_from 'RescueController::NotAuthorizedToRescueAsString', :with => :deny_access
39
40 rescue_from RecordInvalid, :with => :show_errors
41 rescue_from 'RescueController::RecordInvalidToRescueAsString', :with => :show_errors
42
43 rescue_from NotAllowed, :with => proc { head :forbidden }
44 rescue_from 'RescueController::NotAllowedToRescueAsString', :with => proc { head :forbidden }
45
46 rescue_from InvalidRequest, :with => proc { |exception| render :text => exception.message }
47 rescue_from 'InvalidRequestToRescueAsString', :with => proc { |exception| render :text => exception.message }
48
49 rescue_from BadGateway do
50 head :status => 502
51 end
52 rescue_from 'BadGatewayToRescueAsString' do
53 head :status => 502
54 end
55
56 rescue_from ResourceUnavailable do |exception|
57 render :text => exception.message
58 end
59 rescue_from 'ResourceUnavailableToRescueAsString' do |exception|
60 render :text => exception.message
61 end
62
63 # This is a Dispatcher exception and should be in ApplicationController.
64 rescue_from ActionController::RoutingError do
65 render :text => 'no way'
66 end
67
68 before_filter(:only => :before_filter_raises) { raise 'umm nice' }
69
70 def before_filter_raises
71 end
72
73 def raises
74 render :text => 'already rendered'
75 raise "don't panic!"
76 end
77
78 def method_not_allowed
79 raise ActionController::MethodNotAllowed.new(:get, :head, :put)
80 end
81
82 def not_implemented
83 raise ActionController::NotImplemented.new(:get, :put)
84 end
85
86 def not_authorized
87 raise NotAuthorized
88 end
89 def not_authorized_raise_as_string
90 raise NotAuthorizedToRescueAsString
91 end
92
93 def not_allowed
94 raise NotAllowed
95 end
96 def not_allowed_raise_as_string
97 raise NotAllowedToRescueAsString
98 end
99
100 def invalid_request
101 raise InvalidRequest
102 end
103 def invalid_request_raise_as_string
104 raise InvalidRequestToRescueAsString
105 end
106
107 def record_invalid
108 raise RecordInvalid
109 end
110 def record_invalid_raise_as_string
111 raise RecordInvalidToRescueAsString
112 end
113
114 def bad_gateway
115 raise BadGateway
116 end
117 def bad_gateway_raise_as_string
118 raise BadGatewayToRescueAsString
119 end
120
121 def resource_unavailable
122 raise ResourceUnavailable
123 end
124 def resource_unavailable_raise_as_string
125 raise ResourceUnavailableToRescueAsString
126 end
127
128 def missing_template
129 end
130
131 protected
132 def deny_access
133 head :forbidden
134 end
135
136 def show_errors(exception)
137 head :unprocessable_entity
138 end
139 end
140
141 class RescueControllerTest < ActionController::TestCase
142 FIXTURE_PUBLIC = "#{File.dirname(__FILE__)}/../fixtures".freeze
143
144 setup :set_all_requests_local
145 setup :populate_exception_object
146
147 def set_all_requests_local
148 RescueController.consider_all_requests_local = true
149 @request.remote_addr = '1.2.3.4'
150 @request.host = 'example.com'
151 end
152
153 def populate_exception_object
154 begin
155 raise 'foo'
156 rescue => @exception
157 end
158 end
159
160 def test_rescue_exceptions_raised_by_filters
161 with_rails_root FIXTURE_PUBLIC do
162 with_all_requests_local false do
163 get :before_filter_raises
164 end
165 end
166
167 assert_response :internal_server_error
168 end
169
170 def test_rescue_action_locally_if_all_requests_local
171 @controller.expects(:local_request?).never
172 @controller.expects(:rescue_action_locally).with(@exception)
173 @controller.expects(:rescue_action_in_public).never
174
175 with_all_requests_local do
176 @controller.send :rescue_action, @exception
177 end
178 end
179
180 def test_rescue_action_locally_if_remote_addr_is_localhost
181 @controller.expects(:local_request?).returns(true)
182 @controller.expects(:rescue_action_locally).with(@exception)
183 @controller.expects(:rescue_action_in_public).never
184
185 with_all_requests_local false do
186 @controller.send :rescue_action, @exception
187 end
188 end
189
190 def test_rescue_action_in_public_otherwise
191 @controller.expects(:local_request?).returns(false)
192 @controller.expects(:rescue_action_locally).never
193 @controller.expects(:rescue_action_in_public).with(@exception)
194
195 with_all_requests_local false do
196 @controller.send :rescue_action, @exception
197 end
198 end
199
200 def test_rescue_action_in_public_with_localized_error_file
201 # Change locale
202 old_locale = I18n.locale
203 I18n.locale = :da
204
205 with_rails_root FIXTURE_PUBLIC do
206 with_all_requests_local false do
207 get :raises
208 end
209 end
210
211 assert_response :internal_server_error
212 body = File.read("#{FIXTURE_PUBLIC}/public/500.da.html")
213 assert_equal body, @response.body
214 ensure
215 I18n.locale = old_locale
216 end
217
218 def test_rescue_action_in_public_with_error_file
219 with_rails_root FIXTURE_PUBLIC do
220 with_all_requests_local false do
221 get :raises
222 end
223 end
224
225 assert_response :internal_server_error
226 body = File.read("#{FIXTURE_PUBLIC}/public/500.html")
227 assert_equal body, @response.body
228 end
229
230 def test_rescue_action_in_public_without_error_file
231 with_rails_root '/tmp' do
232 with_all_requests_local false do
233 get :raises
234 end
235 end
236
237 assert_response :internal_server_error
238 assert_equal ' ', @response.body
239 end
240
241 def test_rescue_unknown_action_in_public_with_error_file
242 with_rails_root FIXTURE_PUBLIC do
243 with_all_requests_local false do
244 get :foobar_doesnt_exist
245 end
246 end
247
248 assert_response :not_found
249 body = File.read("#{FIXTURE_PUBLIC}/public/404.html")
250 assert_equal body, @response.body
251 end
252
253 def test_rescue_unknown_action_in_public_without_error_file
254 with_rails_root '/tmp' do
255 with_all_requests_local false do
256 get :foobar_doesnt_exist
257 end
258 end
259
260 assert_response :not_found
261 assert_equal ' ', @response.body
262 end
263
264 def test_rescue_missing_template_in_public
265 with_rails_root FIXTURE_PUBLIC do
266 with_all_requests_local true do
267 get :missing_template
268 end
269 end
270
271 assert_response :internal_server_error
272 assert @response.body.include?('missing_template'), "Response should include the template name."
273 end
274
275 def test_rescue_action_locally
276 get :raises
277 assert_response :internal_server_error
278 assert_template 'diagnostics.erb'
279 assert @response.body.include?('RescueController#raises'), "Response should include controller and action."
280 assert @response.body.include?("don't panic"), "Response should include exception message."
281 end
282
283 def test_local_request_when_remote_addr_is_localhost
284 @controller.expects(:request).returns(@request).at_least_once
285 with_remote_addr '127.0.0.1' do
286 assert @controller.send(:local_request?)
287 end
288 end
289
290 def test_local_request_when_remote_addr_isnt_locahost
291 @controller.expects(:request).returns(@request)
292 with_remote_addr '1.2.3.4' do
293 assert !@controller.send(:local_request?)
294 end
295 end
296
297 def test_rescue_responses
298 responses = ActionController::Base.rescue_responses
299
300 assert_equal ActionController::Rescue::DEFAULT_RESCUE_RESPONSE, responses.default
301 assert_equal ActionController::Rescue::DEFAULT_RESCUE_RESPONSE, responses[Exception.new]
302
303 assert_equal :not_found, responses[ActionController::RoutingError.name]
304 assert_equal :not_found, responses[ActionController::UnknownAction.name]
305 assert_equal :not_found, responses['ActiveRecord::RecordNotFound']
306 assert_equal :conflict, responses['ActiveRecord::StaleObjectError']
307 assert_equal :unprocessable_entity, responses['ActiveRecord::RecordInvalid']
308 assert_equal :unprocessable_entity, responses['ActiveRecord::RecordNotSaved']
309 assert_equal :method_not_allowed, responses['ActionController::MethodNotAllowed']
310 assert_equal :not_implemented, responses['ActionController::NotImplemented']
311 end
312
313 def test_rescue_templates
314 templates = ActionController::Base.rescue_templates
315
316 assert_equal ActionController::Rescue::DEFAULT_RESCUE_TEMPLATE, templates.default
317 assert_equal ActionController::Rescue::DEFAULT_RESCUE_TEMPLATE, templates[Exception.new]
318
319 assert_equal 'missing_template', templates[ActionView::MissingTemplate.name]
320 assert_equal 'routing_error', templates[ActionController::RoutingError.name]
321 assert_equal 'unknown_action', templates[ActionController::UnknownAction.name]
322 assert_equal 'template_error', templates[ActionView::TemplateError.name]
323 end
324
325 def test_not_implemented
326 with_all_requests_local false do
327 with_rails_public_path(".") do
328 head :not_implemented
329 end
330 end
331 assert_response :not_implemented
332 assert_equal "GET, PUT", @response.headers['Allow']
333 end
334
335 def test_method_not_allowed
336 with_all_requests_local false do
337 with_rails_public_path(".") do
338 get :method_not_allowed
339 end
340 end
341 assert_response :method_not_allowed
342 assert_equal "GET, HEAD, PUT", @response.headers['Allow']
343 end
344
345 def test_rescue_handler
346 get :not_authorized
347 assert_response :forbidden
348 end
349 def test_rescue_handler_string
350 get :not_authorized_raise_as_string
351 assert_response :forbidden
352 end
353
354 def test_rescue_handler_with_argument
355 @controller.expects(:show_errors).once.with { |e| e.is_a?(Exception) }
356 get :record_invalid
357 end
358 def test_rescue_handler_with_argument_as_string
359 @controller.expects(:show_errors).once.with { |e| e.is_a?(Exception) }
360 get :record_invalid_raise_as_string
361 end
362
363 def test_proc_rescue_handler
364 get :not_allowed
365 assert_response :forbidden
366 end
367 def test_proc_rescue_handler_as_string
368 get :not_allowed_raise_as_string
369 assert_response :forbidden
370 end
371
372 def test_proc_rescue_handle_with_argument
373 get :invalid_request
374 assert_equal "RescueController::InvalidRequest", @response.body
375 end
376 def test_proc_rescue_handle_with_argument_as_string
377 get :invalid_request_raise_as_string
378 assert_equal "RescueController::InvalidRequestToRescueAsString", @response.body
379 end
380
381 def test_block_rescue_handler
382 get :bad_gateway
383 assert_response 502
384 end
385 def test_block_rescue_handler_as_string
386 get :bad_gateway_raise_as_string
387 assert_response 502
388 end
389
390 def test_block_rescue_handler_with_argument
391 get :resource_unavailable
392 assert_equal "RescueController::ResourceUnavailable", @response.body
393 end
394
395 def test_block_rescue_handler_with_argument_as_string
396 get :resource_unavailable_raise_as_string
397 assert_equal "RescueController::ResourceUnavailableToRescueAsString", @response.body
398 end
399
400 def test_rescue_dispatcher_exceptions
401 env = @request.env
402 env["action_controller.rescue.request"] = @request
403 env["action_controller.rescue.response"] = @response
404
405 RescueController.call_with_exception(env, ActionController::RoutingError.new("Route not found"))
406 assert_equal "no way", @response.body
407 end
408
409 def test_rescue_dispatcher_exceptions_without_request_set
410 @request.env['REQUEST_URI'] = '/no_way'
411 response = RescueController.call_with_exception(@request.env, ActionController::RoutingError.new("Route not found"))
412 assert_kind_of ActionController::Response, response
413 assert_equal "no way", response.body
414 end
415
416 protected
417 def with_all_requests_local(local = true)
418 old_local, ActionController::Base.consider_all_requests_local =
419 ActionController::Base.consider_all_requests_local, local
420 yield
421 ensure
422 ActionController::Base.consider_all_requests_local = old_local
423 end
424
425 def with_remote_addr(addr)
426 old_remote_addr, @request.remote_addr = @request.remote_addr, addr
427 yield
428 ensure
429 @request.remote_addr = old_remote_addr
430 end
431
432 def with_rails_public_path(rails_root)
433 old_rails = Object.const_get(:Rails) rescue nil
434 mod = Object.const_set(:Rails, Module.new)
435 (class << mod; self; end).instance_eval do
436 define_method(:public_path) { "#{rails_root}/public" }
437 end
438 yield
439 ensure
440 Object.module_eval { remove_const(:Rails) } if defined?(Rails)
441 Object.const_set(:Rails, old_rails) if old_rails
442 end
443
444 def with_rails_root(path = nil,&block)
445 old_rails_root = RAILS_ROOT if defined?(RAILS_ROOT)
446 if path
447 silence_warnings { Object.const_set(:RAILS_ROOT, path) }
448 else
449 Object.remove_const(:RAILS_ROOT) rescue nil
450 end
451
452 with_rails_public_path(path, &block)
453
454 ensure
455 if old_rails_root
456 silence_warnings { Object.const_set(:RAILS_ROOT, old_rails_root) }
457 else
458 Object.remove_const(:RAILS_ROOT) rescue nil
459 end
460 end
461 end
462
463 class ExceptionInheritanceRescueController < ActionController::Base
464
465 class ParentException < StandardError
466 end
467
468 class ChildException < ParentException
469 end
470
471 class GrandchildException < ChildException
472 end
473
474 rescue_from ChildException, :with => lambda { head :ok }
475 rescue_from ParentException, :with => lambda { head :created }
476 rescue_from GrandchildException, :with => lambda { head :no_content }
477
478 def raise_parent_exception
479 raise ParentException
480 end
481
482 def raise_child_exception
483 raise ChildException
484 end
485
486 def raise_grandchild_exception
487 raise GrandchildException
488 end
489 end
490
491 class ExceptionInheritanceRescueControllerTest < ActionController::TestCase
492 def test_bottom_first
493 get :raise_grandchild_exception
494 assert_response :no_content
495 end
496
497 def test_inheritance_works
498 get :raise_child_exception
499 assert_response :created
500 end
501 end
502
503 class ControllerInheritanceRescueController < ExceptionInheritanceRescueController
504 class FirstExceptionInChildController < StandardError
505 end
506
507 class SecondExceptionInChildController < StandardError
508 end
509
510 rescue_from FirstExceptionInChildController, 'SecondExceptionInChildController', :with => lambda { head :gone }
511
512 def raise_first_exception_in_child_controller
513 raise FirstExceptionInChildController
514 end
515
516 def raise_second_exception_in_child_controller
517 raise SecondExceptionInChildController
518 end
519 end
520
521 class ControllerInheritanceRescueControllerTest < ActionController::TestCase
522 def test_first_exception_in_child_controller
523 get :raise_first_exception_in_child_controller
524 assert_response :gone
525 end
526
527 def test_second_exception_in_child_controller
528 get :raise_second_exception_in_child_controller
529 assert_response :gone
530 end
531
532 def test_exception_in_parent_controller
533 get :raise_parent_exception
534 assert_response :created
535 end
536 end