aboutsummaryrefslogblamecommitdiffstats
path: root/actionpack/test/controller/rescue_test.rb
blob: 6756e226c311cdc5ab7f57135064b99b27bbc110 (plain) (tree)
1
2
3
4
5
6
7
8
9
                                                    
 
                      





                                               







                                                                   

                           



                                       


















                                                                 


                                                                






                                                            


                                                                






                                                 


                                                                  






















































                                                             











                                                                                                    


                                          
                                     





                                                                                                               
                                                                 





                                                       
                                                   













                                                                                            
                                                                      


                                                                                 

                                                                                     































                                                                                            















                                                             


































                                                                          

                
require File.dirname(__FILE__) + '/../abstract_unit'

uses_mocha 'rescue' do

class RescueController < ActionController::Base
  def raises
    render :text => 'already rendered'
    raise "don't panic!"
  end

  def method_not_allowed
    raise ActionController::MethodNotAllowed.new(:get, :head, :put)
  end
  
  def not_implemented
    raise ActionController::NotImplemented.new(:get, :put)
  end
  
  def missing_template; end
end


class RescueTest < Test::Unit::TestCase
  FIXTURE_PUBLIC = "#{File.dirname(__FILE__)}/../fixtures".freeze

  def setup
    @controller = RescueController.new
    @request    = ActionController::TestRequest.new
    @response   = ActionController::TestResponse.new

    RescueController.consider_all_requests_local = true
    @request.remote_addr = '1.2.3.4'
    @request.host = 'example.com'

    begin
      raise 'foo'
    rescue => @exception
    end
  end


  def test_rescue_action_locally_if_all_requests_local
    @controller.expects(:local_request?).never
    @controller.expects(:rescue_action_locally).with(@exception)
    @controller.expects(:rescue_action_in_public).never

    with_all_requests_local do
      @controller.send :rescue_action, @exception
    end
  end

  def test_rescue_action_locally_if_remote_addr_is_localhost
    @controller.expects(:local_request?).returns(true)
    @controller.expects(:rescue_action_locally).with(@exception)
    @controller.expects(:rescue_action_in_public).never

    with_all_requests_local false do
      @controller.send :rescue_action, @exception
    end
  end

  def test_rescue_action_in_public_otherwise
    @controller.expects(:local_request?).returns(false)
    @controller.expects(:rescue_action_locally).never
    @controller.expects(:rescue_action_in_public).with(@exception)

    with_all_requests_local false do
      @controller.send :rescue_action, @exception
    end
  end


  def test_rescue_action_in_public_with_error_file
    with_rails_root FIXTURE_PUBLIC do
      with_all_requests_local false do
        get :raises
      end
    end

    assert_response :internal_server_error
    body = File.read("#{FIXTURE_PUBLIC}/public/500.html")
    assert_equal body, @response.body
  end

  def test_rescue_action_in_public_without_error_file
    with_rails_root '/tmp' do
      with_all_requests_local false do
        get :raises
      end
    end

    assert_response :internal_server_error
    assert_equal ' ', @response.body
  end


  def test_rescue_unknown_action_in_public_with_error_file
    with_rails_root FIXTURE_PUBLIC do
      with_all_requests_local false do
        get :foobar_doesnt_exist
      end
    end

    assert_response :not_found
    body = File.read("#{FIXTURE_PUBLIC}/public/404.html")
    assert_equal body, @response.body
  end

  def test_rescue_unknown_action_in_public_without_error_file
    with_rails_root '/tmp' do
      with_all_requests_local false do
        get :foobar_doesnt_exist
      end
    end

    assert_response :not_found
    assert_equal ' ', @response.body
  end


  def test_rescue_missing_template_in_public
    with_rails_root FIXTURE_PUBLIC do
      with_all_requests_local true do
        get :missing_template
      end
    end

    assert_response :internal_server_error
    assert @response.body.include?('missing_template'), "Response should include the template name."
  end


  def test_rescue_action_locally
    get :raises
    assert_response :internal_server_error
    assert_template 'diagnostics.erb'
    assert @response.body.include?('RescueController#raises'), "Response should include controller and action."
    assert @response.body.include?("don't panic"), "Response should include exception message."
  end


  def test_local_request_when_remote_addr_is_localhost
    @controller.expects(:request).returns(@request).at_least_once
    with_remote_addr '127.0.0.1' do
      assert @controller.send(:local_request?)
    end
  end

  def test_local_request_when_remote_addr_isnt_locahost
    @controller.expects(:request).returns(@request)
    with_remote_addr '1.2.3.4' do
      assert !@controller.send(:local_request?)
    end
  end


  def test_rescue_responses
    responses = ActionController::Base.rescue_responses

    assert_equal ActionController::Rescue::DEFAULT_RESCUE_RESPONSE, responses.default
    assert_equal ActionController::Rescue::DEFAULT_RESCUE_RESPONSE, responses[Exception.new]

    assert_equal :not_found, responses[ActionController::RoutingError.name]
    assert_equal :not_found, responses[ActionController::UnknownAction.name]
    assert_equal :not_found, responses['ActiveRecord::RecordNotFound']
    assert_equal :conflict, responses['ActiveRecord::StaleObjectError']
    assert_equal :unprocessable_entity, responses['ActiveRecord::RecordInvalid']
    assert_equal :unprocessable_entity, responses['ActiveRecord::RecordNotSaved']
    assert_equal :method_not_allowed, responses['ActionController::MethodNotAllowed']
    assert_equal :not_implemented, responses['ActionController::NotImplemented']
  end

  def test_rescue_templates
    templates = ActionController::Base.rescue_templates

    assert_equal ActionController::Rescue::DEFAULT_RESCUE_TEMPLATE, templates.default
    assert_equal ActionController::Rescue::DEFAULT_RESCUE_TEMPLATE, templates[Exception.new]

    assert_equal 'missing_template',  templates[ActionController::MissingTemplate.name]
    assert_equal 'routing_error',     templates[ActionController::RoutingError.name]
    assert_equal 'unknown_action',    templates[ActionController::UnknownAction.name]
    assert_equal 'template_error',    templates[ActionView::TemplateError.name]
  end


  def test_clean_backtrace
    with_rails_root nil do
      # No action if RAILS_ROOT isn't set.
      cleaned = @controller.send(:clean_backtrace, @exception)
      assert_equal @exception.backtrace, cleaned
    end

    with_rails_root Dir.pwd do
      # RAILS_ROOT is removed from backtrace.
      cleaned = @controller.send(:clean_backtrace, @exception)
      expected = @exception.backtrace.map { |line| line.sub(RAILS_ROOT, '') }
      assert_equal expected, cleaned

      # No action if backtrace is nil.
      assert_nil @controller.send(:clean_backtrace, Exception.new)
    end
  end
  
  def test_not_implemented
    with_all_requests_local false do
      head :not_implemented
    end
    assert_response :not_implemented
    assert_equal "GET, PUT", @response.headers['Allow']
  end

  def test_method_not_allowed
    with_all_requests_local false do
      get :method_not_allowed
    end
    assert_response :method_not_allowed
    assert_equal "GET, HEAD, PUT", @response.headers['Allow']
  end

  protected
    def with_all_requests_local(local = true)
      old_local, ActionController::Base.consider_all_requests_local =
        ActionController::Base.consider_all_requests_local, local
      yield
    ensure
      ActionController::Base.consider_all_requests_local = old_local
    end

    def with_remote_addr(addr)
      old_remote_addr, @request.remote_addr = @request.remote_addr, addr
      yield
    ensure
      @request.remote_addr = old_remote_addr
    end

    def with_rails_root(path = nil)
      old_rails_root = RAILS_ROOT if defined?(RAILS_ROOT)
      if path
        silence_warnings { Object.const_set(:RAILS_ROOT, path) }
      else
        Object.remove_const(:RAILS_ROOT) rescue nil
      end

      yield

    ensure
      if old_rails_root
        silence_warnings { Object.const_set(:RAILS_ROOT, old_rails_root) }
      else
        Object.remove_const(:RAILS_ROOT) rescue nil
      end
    end
end

end # uses_mocha