diff options
Diffstat (limited to 'actionpack')
17 files changed, 182 insertions, 81 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 7659c35eae..0134bf7cab 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,3 +1,15 @@ +* Fix regression in functional tests. Responses should have default headers + assigned. + + See #18423. + + *Jeremy Kemper*, *Yves Senn* + +* Deprecate AbstractController#skip_action_callback in favor of individual skip_callback methods + (which can be made to raise an error if no callback was removed). + + *Iain Beeston* + * Alias the `ActionDispatch::Request#uuid` method to `ActionDispatch::Request#request_id`. Due to implementation, `config.log_tags = [:request_id]` also works in substitute for `config.log_tags = [:uuid]`. diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb index 69f490b327..f4fd1db36c 100644 --- a/actionpack/lib/abstract_controller/callbacks.rb +++ b/actionpack/lib/abstract_controller/callbacks.rb @@ -63,6 +63,7 @@ module AbstractController # impossible to skip a callback defined using an anonymous proc # using #skip_action_callback def skip_action_callback(*names) + ActiveSupport::Deprecation.warn('`skip_action_callback` is deprecated and will be removed in the next major version of Rails. Please use skip_before_action, skip_after_action or skip_around_action instead.') skip_before_action(*names) skip_after_action(*names) skip_around_action(*names) diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index 4061ea71a3..a895d1ab18 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -113,10 +113,10 @@ module ActionDispatch # :nodoc: # The underlying body, as a streamable object. attr_reader :stream - def initialize(status = 200, header = {}, body = []) + def initialize(status = 200, header = {}, body = [], default_headers: self.class.default_headers) super() - header = merge_default_headers(header, self.class.default_headers) + header = merge_default_headers(header, default_headers) self.body, self.header, self.status = body, header, status @@ -308,9 +308,7 @@ module ActionDispatch # :nodoc: end def merge_default_headers(original, default) - return original unless default.respond_to?(:merge) - - default.merge(original) + default.respond_to?(:merge) ? default.merge(original) : original end def build_buffer(response, body) diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 9b00616968..2fe37c5bd4 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -369,7 +369,7 @@ module ActionDispatch @request_count += 1 @request = ActionDispatch::Request.new(session.last_request.env) response = _mock_session.last_response - @response = ActionDispatch::TestResponse.new(response.status, response.headers, response.body) + @response = ActionDispatch::TestResponse.from_response(response) @html_document = nil @url_options = nil diff --git a/actionpack/lib/action_dispatch/testing/test_response.rb b/actionpack/lib/action_dispatch/testing/test_response.rb index 369ea1467c..a9b88ac5fd 100644 --- a/actionpack/lib/action_dispatch/testing/test_response.rb +++ b/actionpack/lib/action_dispatch/testing/test_response.rb @@ -7,11 +7,7 @@ module ActionDispatch # See Response for more information on controller response objects. class TestResponse < Response def self.from_response(response) - new.tap do |resp| - resp.status = response.status - resp.headers = response.headers - resp.body = response.body - end + new response.status, response.headers, response.body, default_headers: nil end # Was the response successful? @@ -25,12 +21,5 @@ module ActionDispatch # Was there a server-side error? alias_method :error?, :server_error? - - def merge_default_headers(original, *args) - # Default headers are already applied, no need to merge them a second time. - # This makes sure that default headers, removed in controller actions, will - # not be reapplied to the test response. - original - end end end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 2d69ceed3a..918589f916 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -54,23 +54,8 @@ I18n.enforce_available_locales = false # Register danish language for testing I18n.backend.store_translations 'da', {} I18n.backend.store_translations 'pt-BR', {} -ORIGINAL_LOCALES = I18n.available_locales.map(&:to_s).sort FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures') -FIXTURES = Pathname.new(FIXTURE_LOAD_PATH) - -module RackTestUtils - def body_to_string(body) - if body.respond_to?(:each) - str = "" - body.each {|s| str << s } - str - else - body - end - end - extend self -end SharedTestRoutes = ActionDispatch::Routing::RouteSet.new @@ -129,22 +114,6 @@ class RoutedRackApp end end -class BasicController - attr_accessor :request - - def config - @config ||= ActiveSupport::InheritableOptions.new(ActionController::Base.config).tap do |config| - # VIEW TODO: View tests should not require a controller - public_dir = File.expand_path("../fixtures/public", __FILE__) - config.assets_dir = public_dir - config.javascripts_dir = "#{public_dir}/javascripts" - config.stylesheets_dir = "#{public_dir}/stylesheets" - config.assets = ActiveSupport::InheritableOptions.new({ :prefix => "assets" }) - config - end - end -end - class ActionDispatch::IntegrationTest < ActiveSupport::TestCase include ActionDispatch::SharedRoutes diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 4760ec1698..2d6607041d 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -1,5 +1,6 @@ require 'fileutils' require 'abstract_unit' +require 'lib/controller/fake_models' CACHE_DIR = 'test_cache' # Don't change '/../temp/' cavalierly or you might hose something you don't want hosed @@ -349,3 +350,60 @@ class ViewCacheDependencyTest < ActionController::TestCase assert_equal %w(trombone flute), HasDependenciesController.new.view_cache_dependencies end end + +class CollectionCacheController < ActionController::Base + def index + @customers = [Customer.new('david', params[:id] || 1)] + end + + def index_ordered + @customers = [Customer.new('david', 1), Customer.new('david', 2), Customer.new('david', 3)] + render 'index' + end + + def index_explicit_render + @customers = [Customer.new('david', 1)] + render partial: 'customers/customer', collection: @customers + end + + def index_with_comment + @customers = [Customer.new('david', 1)] + render partial: 'customers/commented_customer', collection: @customers, as: :customer + end +end + +class AutomaticCollectionCacheTest < ActionController::TestCase + def setup + super + @controller = CollectionCacheController.new + @controller.perform_caching = true + @controller.cache_store = ActiveSupport::Cache::MemoryStore.new + end + + def test_collection_fetches_cached_views + get :index + + ActionView::PartialRenderer.expects(:collection_with_template).never + get :index + end + + def test_preserves_order_when_reading_from_cache_plus_rendering + get :index, params: { id: 2 } + get :index_ordered + + assert_select ':root', "david, 1\n david, 2\n david, 3" + end + + def test_explicit_render_call_with_options + get :index_explicit_render + + assert_select ':root', "david, 1" + end + + def test_caching_works_with_beginning_comment + get :index_with_comment + + ActionView::PartialRenderer.expects(:collection_with_template).never + get :index_with_comment + end +end diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index b9fb6be4e3..26b94f0db8 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -26,7 +26,6 @@ class ActionController::Base end class FilterTest < ActionController::TestCase - class TestController < ActionController::Base before_action :ensure_login after_action :clean_up @@ -967,8 +966,15 @@ class ControllerWithAllTypesOfFilters < PostsController end class ControllerWithTwoLessFilters < ControllerWithAllTypesOfFilters - skip_action_callback :around_again - skip_action_callback :after + skip_around_action :around_again + skip_after_action :after +end + +class SkipFilterUsingSkipActionCallback < ControllerWithAllTypesOfFilters + ActiveSupport::Deprecation.silence do + skip_action_callback :around_again + skip_action_callback :after + end end class YieldingAroundFiltersTest < ActionController::TestCase @@ -1055,6 +1061,19 @@ class YieldingAroundFiltersTest < ActionController::TestCase assert_equal 3, controller.instance_variable_get(:@try) end + def test_skipping_with_skip_action_callback + test_process(SkipFilterUsingSkipActionCallback,'no_raise') + assert_equal 'before around (before yield) around (after yield)', assigns['ran_filter'].join(' ') + end + + def test_deprecated_skip_action_callback + assert_deprecated do + Class.new(PostsController) do + skip_action_callback :clean_up + end + end + end + protected def test_process(controller, action = "show") @controller = controller.is_a?(Class) ? controller.new : controller diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index 9ab1549e8e..438c044da2 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -397,9 +397,9 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest redirect_to action_url('get') end - def remove_default_header - response.headers.except! 'X-Frame-Options' - head :ok + def remove_header + response.headers.delete params[:header] + head :ok, 'c' => '3' end end @@ -640,25 +640,27 @@ class IntegrationProcessTest < ActionDispatch::IntegrationTest end end - def test_removed_default_headers_on_test_response_are_not_reapplied + def test_respect_removal_of_default_headers_by_a_controller_action with_test_route_set do - begin - header_to_remove = 'X-Frame-Options' - original_default_headers = ActionDispatch::Response.default_headers - ActionDispatch::Response.default_headers = { - 'X-Content-Type-Options' => 'nosniff', - header_to_remove => 'SAMEORIGIN', - } - get '/remove_default_header' - assert_includes headers, 'X-Content-Type-Options' - assert_not_includes headers, header_to_remove, "Should not contain removed default header" - ensure - ActionDispatch::Response.default_headers = original_default_headers + with_default_headers 'a' => '1', 'b' => '2' do + get '/remove_header', params: { header: 'a' } end end + + assert_not_includes @response.headers, 'a', 'Response should not include default header removed by the controller action' + assert_includes @response.headers, 'b' + assert_includes @response.headers, 'c' end private + def with_default_headers(headers) + original = ActionDispatch::Response.default_headers + ActionDispatch::Response.default_headers = headers + yield + ensure + ActionDispatch::Response.default_headers = original + end + def with_test_route_set with_routing do |set| controller = ::IntegrationProcessTest::IntegrationController.clone diff --git a/actionpack/test/controller/new_base/metal_test.rb b/actionpack/test/controller/new_base/metal_test.rb index 45a6619eb4..537b93387a 100644 --- a/actionpack/test/controller/new_base/metal_test.rb +++ b/actionpack/test/controller/new_base/metal_test.rb @@ -18,8 +18,6 @@ module MetalTest end class TestMiddleware < ActiveSupport::TestCase - include RackTestUtils - def setup @app = Rack::Builder.new do use MetalTest::MetalMiddleware @@ -31,14 +29,14 @@ module MetalTest env = Rack::MockRequest.env_for("/authed") response = @app.call(env) - assert_equal "Hello World", body_to_string(response[2]) + assert_equal ["Hello World"], response[2] end test "it can return a response using the normal AC::Metal techniques" do env = Rack::MockRequest.env_for("/") response = @app.call(env) - assert_equal "Not authed!", body_to_string(response[2]) + assert_equal ["Not authed!"], response[2] assert_equal 401, response[0] end end diff --git a/actionpack/test/controller/new_base/middleware_test.rb b/actionpack/test/controller/new_base/middleware_test.rb index 6b7b5e10e3..a30e937bb3 100644 --- a/actionpack/test/controller/new_base/middleware_test.rb +++ b/actionpack/test/controller/new_base/middleware_test.rb @@ -75,7 +75,7 @@ module MiddlewareTest test "middleware that is 'use'd is called as part of the Rack application" do result = @app.call(env_for("/")) - assert_equal "Hello World", RackTestUtils.body_to_string(result[2]) + assert_equal ["Hello World"], result[2] assert_equal "Success", result[1]["Middleware-Test"] end diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb index ca854040b7..e348749f78 100644 --- a/actionpack/test/controller/test_case_test.rb +++ b/actionpack/test/controller/test_case_test.rb @@ -965,6 +965,52 @@ XML end end +class ResponseDefaultHeadersTest < ActionController::TestCase + class TestController < ActionController::Base + def remove_header + headers.delete params[:header] + head :ok, 'C' => '3' + end + end + + setup do + @original = ActionDispatch::Response.default_headers + @defaults = { 'A' => '1', 'B' => '2' } + ActionDispatch::Response.default_headers = @defaults + end + + teardown do + ActionDispatch::Response.default_headers = @original + end + + def setup + super + @controller = TestController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + @request.env['PATH_INFO'] = nil + @routes = ActionDispatch::Routing::RouteSet.new.tap do |r| + r.draw do + get ':controller(/:action(/:id))' + end + end + end + + test "response contains default headers" do + # Response headers start out with the defaults + assert_equal @defaults, response.headers + + get :remove_header, params: { header: 'A' } + assert_response :ok + + # After a request, the response in the test case doesn't have the + # defaults merged on top again. + assert_not_includes response.headers, 'A' + assert_includes response.headers, 'B' + assert_includes response.headers, 'C' + end +end + module EngineControllerTests class Engine < ::Rails::Engine isolate_namespace EngineControllerTests diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index deb289bd57..d65d2e8e8f 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -3489,13 +3489,19 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest def test_head_fetch_with_mount_on_root draw do get '/home' => 'test#index' - mount lambda { |env| [404, {"Content-Type" => "text/html"}, ["testing"]] }, at: '/' + mount lambda { |env| [200, {}, [env['REQUEST_METHOD']]] }, at: '/' end + + # HEAD request matches `get /home` rather than the lower-precedence + # Rack app mounted at `/` head '/home' assert_response :success + assert_equal 'test#index', @response.body - head '/' - assert_response :not_found + # But the Rack app can still respond to its own HEAD requests. + head '/foobar' + assert_response :ok + assert_equal 'HEAD', @response.body end private diff --git a/actionpack/test/fixtures/collection_cache/index.html.erb b/actionpack/test/fixtures/collection_cache/index.html.erb new file mode 100644 index 0000000000..521b1450df --- /dev/null +++ b/actionpack/test/fixtures/collection_cache/index.html.erb @@ -0,0 +1 @@ +<%= render @customers %>
\ No newline at end of file diff --git a/actionpack/test/fixtures/customers/_commented_customer.html.erb b/actionpack/test/fixtures/customers/_commented_customer.html.erb new file mode 100644 index 0000000000..d5f6e3b491 --- /dev/null +++ b/actionpack/test/fixtures/customers/_commented_customer.html.erb @@ -0,0 +1,4 @@ +<%# I'm a comment %> +<% cache customer do %> + <%= customer.name %>, <%= customer.id %> +<% end %>
\ No newline at end of file diff --git a/actionpack/test/fixtures/customers/_customer.html.erb b/actionpack/test/fixtures/customers/_customer.html.erb new file mode 100644 index 0000000000..67e9f6d411 --- /dev/null +++ b/actionpack/test/fixtures/customers/_customer.html.erb @@ -0,0 +1,3 @@ +<% cache customer do %> + <%= customer.name %>, <%= customer.id %> +<% end %>
\ No newline at end of file diff --git a/actionpack/test/fixtures/symlink_parent/symlinked_layout.erb b/actionpack/test/fixtures/symlink_parent/symlinked_layout.erb deleted file mode 100644 index bda57d0fae..0000000000 --- a/actionpack/test/fixtures/symlink_parent/symlinked_layout.erb +++ /dev/null @@ -1,5 +0,0 @@ -This is my layout - -<%= yield %> - -End. |