2017-07-24 16:20:53 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
require "abstract_unit"
|
|
|
|
require "controller/fake_models"
|
2004-11-23 20:04:44 -05:00
|
|
|
|
2012-08-29 16:06:30 -04:00
|
|
|
class TestControllerWithExtraEtags < ActionController::Base
|
2019-06-29 10:41:27 -04:00
|
|
|
self.view_paths = [ActionView::FixtureResolver.new(
|
|
|
|
"test/with_implicit_template.erb" => "Hello explicitly!",
|
|
|
|
"test/hello_world.erb" => "Hello world!"
|
|
|
|
)]
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
def self.controller_name; "test"; end
|
|
|
|
def self.controller_path; "test"; end
|
2016-06-27 16:59:49 -04:00
|
|
|
|
2012-08-29 16:06:30 -04:00
|
|
|
etag { nil }
|
2016-08-06 12:54:50 -04:00
|
|
|
etag { "ab" }
|
2012-08-29 16:06:30 -04:00
|
|
|
etag { :cde }
|
|
|
|
etag { [:f] }
|
|
|
|
etag { nil }
|
|
|
|
|
|
|
|
def fresh
|
2016-08-06 12:54:50 -04:00
|
|
|
render plain: "stale" if stale?(etag: "123", template: false)
|
2012-08-29 16:06:30 -04:00
|
|
|
end
|
2013-05-07 08:37:20 -04:00
|
|
|
|
|
|
|
def array
|
2015-07-17 21:48:00 -04:00
|
|
|
render plain: "stale" if stale?(etag: %w(1 2 3), template: false)
|
2014-08-16 18:06:20 -04:00
|
|
|
end
|
|
|
|
|
2016-03-31 20:47:00 -04:00
|
|
|
def strong
|
2016-08-06 12:54:50 -04:00
|
|
|
render plain: "stale" if stale?(strong_etag: "strong", template: false)
|
2016-03-31 20:47:00 -04:00
|
|
|
end
|
|
|
|
|
2014-08-16 18:06:20 -04:00
|
|
|
def with_template
|
2016-08-06 12:54:50 -04:00
|
|
|
if stale? template: "test/hello_world"
|
|
|
|
render plain: "stale"
|
2014-08-16 18:06:20 -04:00
|
|
|
end
|
2013-05-07 08:37:20 -04:00
|
|
|
end
|
2016-06-27 16:59:49 -04:00
|
|
|
|
|
|
|
def with_implicit_template
|
2016-08-06 12:54:50 -04:00
|
|
|
fresh_when(etag: "123")
|
2016-06-27 16:59:49 -04:00
|
|
|
end
|
2012-08-29 16:06:30 -04:00
|
|
|
end
|
|
|
|
|
2015-06-02 16:08:53 -04:00
|
|
|
class ImplicitRenderTestController < ActionController::Base
|
2019-06-29 10:41:27 -04:00
|
|
|
self.view_paths = [ActionView::FixtureResolver.new(
|
|
|
|
"implicit_render_test/hello_world.erb" => "Hello world!",
|
|
|
|
"implicit_render_test/empty_action_with_template.html.erb" => "<h1>Empty action rendered this implicitly.</h1>\n"
|
|
|
|
)]
|
|
|
|
|
2015-06-02 16:08:53 -04:00
|
|
|
def empty_action
|
|
|
|
end
|
Lock down new `ImplicitRender` behavior for 5.0 RC
1. Conceptually revert #20276
The feature was implemented for the `responders` gem. In the end,
they did not need that feature, and have found a better fix (see
plataformatec/responders#131).
`ImplicitRender` is the place where Rails specifies our default
policies for the case where the user did not explicitly tell us
what to render, essentially describing a set of heuristics. If
the gem (or the user) knows exactly what they want, they could
just perform the correct `render` to avoid falling through to
here, as `responders` did (the user called `respond_with`).
Reverting the patch allows us to avoid exploding the complexity
and defining “the fallback for a fallback” policies.
2. `respond_to` and templates are considered exhaustive enumerations
If the user specified a list of formats/variants in a `respond_to`
block, anything that is not explicitly included should result
in an `UnknownFormat` error (which is then caught upstream to
mean “406 Not Acceptable” by default). This is already how it
works before this commit.
Same goes for templates – if the user defined a set of templates
(usually in the file system), that set is now considered exhaustive,
which means that “missing” templates are considered `UnknownFormat`
errors (406).
3. To keep API endpoints simple, the implicit render behavior for
actions with no templates defined at all (regardless of formats,
locales, variants, etc) are defaulted to “204 No Content”. This
is a strictly narrower version of the feature landed in #19036 and
#19377.
4. To avoid confusion when interacting in the browser, these actions
will raise an `UnknownFormat` error for “interactive” requests
instead. (The precise definition of “interactive” requests might
change – the spirit here is to give helpful messages and avoid
confusions.)
Closes #20666, #23062, #23077, #23564
[Godfrey Chan, Jon Moss, Kasper Timm Hansen, Mike Clark, Matthew Draper]
2016-02-23 12:41:26 -05:00
|
|
|
|
|
|
|
def empty_action_with_template
|
|
|
|
end
|
2015-06-02 16:08:53 -04:00
|
|
|
end
|
|
|
|
|
2016-07-13 15:07:49 -04:00
|
|
|
module Namespaced
|
|
|
|
class ImplicitRenderTestController < ActionController::Base
|
2019-06-29 10:41:27 -04:00
|
|
|
self.view_paths = [ActionView::FixtureResolver.new(
|
|
|
|
"namespaced/implicit_render_test/hello_world.erb" => "Hello world!"
|
|
|
|
)]
|
|
|
|
|
2016-07-13 15:07:49 -04:00
|
|
|
def hello_world
|
2016-08-06 12:54:50 -04:00
|
|
|
fresh_when(etag: "abc")
|
2016-07-13 15:07:49 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2005-02-14 20:45:35 -05:00
|
|
|
class TestController < ActionController::Base
|
2008-12-25 14:28:08 -05:00
|
|
|
protect_from_forgery
|
|
|
|
|
2012-12-07 14:46:06 -05:00
|
|
|
before_action :set_variable_for_layout
|
2011-12-20 07:37:20 -05:00
|
|
|
|
2008-08-29 14:25:21 -04:00
|
|
|
class LabellingFormBuilder < ActionView::Helpers::FormBuilder
|
|
|
|
end
|
|
|
|
|
2005-02-14 20:45:35 -05:00
|
|
|
layout :determine_layout
|
2004-11-23 20:04:44 -05:00
|
|
|
|
2010-03-18 18:52:43 -04:00
|
|
|
def name
|
|
|
|
nil
|
|
|
|
end
|
|
|
|
|
|
|
|
private :name
|
|
|
|
helper_method :name
|
|
|
|
|
2005-02-14 20:45:35 -05:00
|
|
|
def hello_world
|
|
|
|
end
|
2004-11-23 20:04:44 -05:00
|
|
|
|
2008-07-16 07:32:15 -04:00
|
|
|
def conditional_hello
|
2016-08-06 13:35:13 -04:00
|
|
|
if stale?(last_modified: Time.now.utc.beginning_of_day, etag: [:foo, 123])
|
|
|
|
render action: "hello_world"
|
2008-08-08 02:43:12 -04:00
|
|
|
end
|
2008-07-16 07:32:15 -04:00
|
|
|
end
|
2009-12-08 17:52:26 -05:00
|
|
|
|
2011-12-01 13:09:22 -05:00
|
|
|
def conditional_hello_with_record
|
2011-12-01 14:45:47 -05:00
|
|
|
record = Struct.new(:updated_at, :cache_key).new(Time.now.utc.beginning_of_day, "foo/123")
|
2012-01-14 15:25:11 -05:00
|
|
|
|
2011-12-01 13:09:22 -05:00
|
|
|
if stale?(record)
|
2016-08-06 13:35:13 -04:00
|
|
|
render action: "hello_world"
|
2008-08-29 14:25:21 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-01-20 13:39:19 -05:00
|
|
|
def dynamic_render
|
2016-01-27 04:19:15 -05:00
|
|
|
render params[:id] # => String, AC::Params
|
2016-01-20 13:39:19 -05:00
|
|
|
end
|
|
|
|
|
2016-01-26 21:00:05 -05:00
|
|
|
def dynamic_render_permit
|
|
|
|
render params[:id].permit(:file)
|
|
|
|
end
|
|
|
|
|
2016-01-20 13:39:19 -05:00
|
|
|
def dynamic_render_with_file
|
|
|
|
# This is extremely bad, but should be possible to do.
|
2016-01-27 04:19:15 -05:00
|
|
|
file = params[:id] # => String, AC::Params
|
2016-01-20 13:39:19 -05:00
|
|
|
render file: file
|
|
|
|
end
|
|
|
|
|
2015-01-06 15:14:49 -05:00
|
|
|
class Collection
|
|
|
|
def initialize(records)
|
|
|
|
@records = records
|
|
|
|
end
|
|
|
|
|
|
|
|
def maximum(attribute)
|
|
|
|
@records.max_by(&attribute).public_send(attribute)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def conditional_hello_with_collection_of_records
|
|
|
|
ts = Time.now.utc.beginning_of_day
|
|
|
|
|
|
|
|
record = Struct.new(:updated_at, :cache_key).new(ts, "foo/123")
|
|
|
|
old_record = Struct.new(:updated_at, :cache_key).new(ts - 1.day, "bar/123")
|
|
|
|
|
|
|
|
if stale?(Collection.new([record, old_record]))
|
2016-08-06 12:54:50 -04:00
|
|
|
render action: "hello_world"
|
2015-01-06 15:14:49 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def conditional_hello_with_expires_in
|
|
|
|
expires_in 60.1.seconds
|
2016-08-06 13:35:13 -04:00
|
|
|
render action: "hello_world"
|
2008-08-29 14:25:21 -04:00
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def conditional_hello_with_expires_in_with_public
|
2016-08-06 13:35:13 -04:00
|
|
|
expires_in 1.minute, public: true
|
|
|
|
render action: "hello_world"
|
2008-08-29 14:25:21 -04:00
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def conditional_hello_with_expires_in_with_must_revalidate
|
2016-08-06 13:35:13 -04:00
|
|
|
expires_in 1.minute, must_revalidate: true
|
|
|
|
render action: "hello_world"
|
2008-07-16 07:32:15 -04:00
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def conditional_hello_with_expires_in_with_public_and_must_revalidate
|
2016-08-06 13:35:13 -04:00
|
|
|
expires_in 1.minute, public: true, must_revalidate: true
|
|
|
|
render action: "hello_world"
|
2012-03-26 16:37:36 -04:00
|
|
|
end
|
|
|
|
|
2018-06-13 12:08:24 -04:00
|
|
|
def conditional_hello_with_expires_in_with_stale_while_revalidate
|
|
|
|
expires_in 1.minute, public: true, stale_while_revalidate: 5.minutes
|
|
|
|
render action: "hello_world"
|
|
|
|
end
|
|
|
|
|
|
|
|
def conditional_hello_with_expires_in_with_stale_if_error
|
|
|
|
expires_in 1.minute, public: true, stale_if_error: 5.minutes
|
|
|
|
render action: "hello_world"
|
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def conditional_hello_with_expires_in_with_public_with_more_keys
|
2016-08-06 12:54:50 -04:00
|
|
|
expires_in 1.minute, :public => true, "s-maxage" => 5.hours
|
2016-08-06 13:35:13 -04:00
|
|
|
render action: "hello_world"
|
2008-07-16 07:32:15 -04:00
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def conditional_hello_with_expires_in_with_public_with_more_keys_old_syntax
|
2016-08-06 12:54:50 -04:00
|
|
|
expires_in 1.minute, :public => true, :private => nil, "s-maxage" => 5.hours
|
2016-08-06 13:35:13 -04:00
|
|
|
render action: "hello_world"
|
2008-08-29 14:25:21 -04:00
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def conditional_hello_with_expires_now
|
|
|
|
expires_now
|
2016-08-06 13:35:13 -04:00
|
|
|
render action: "hello_world"
|
2012-03-17 10:08:49 -04:00
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def conditional_hello_with_cache_control_headers
|
2016-08-06 12:54:50 -04:00
|
|
|
response.headers["Cache-Control"] = "no-transform"
|
2013-08-05 17:58:20 -04:00
|
|
|
expires_now
|
2016-08-06 13:35:13 -04:00
|
|
|
render action: "hello_world"
|
2012-03-17 10:08:49 -04:00
|
|
|
end
|
|
|
|
|
2017-08-22 14:45:22 -04:00
|
|
|
def conditional_hello_with_expires_and_confliciting_cache_control_headers
|
|
|
|
response.headers["Cache-Control"] = "no-cache, must-revalidate"
|
|
|
|
expires_now
|
|
|
|
render action: "hello_world"
|
|
|
|
end
|
|
|
|
|
|
|
|
def conditional_hello_without_expires_and_confliciting_cache_control_headers
|
|
|
|
response.headers["Cache-Control"] = "no-cache, must-revalidate"
|
|
|
|
render action: "hello_world"
|
|
|
|
end
|
|
|
|
|
2019-01-02 03:11:59 -05:00
|
|
|
def conditional_hello_without_expires_and_public_header
|
|
|
|
response.headers["Cache-Control"] = "public, no-cache"
|
|
|
|
render action: "hello_world"
|
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def conditional_hello_with_bangs
|
2016-08-06 13:35:13 -04:00
|
|
|
render action: "hello_world"
|
2012-03-17 10:08:49 -04:00
|
|
|
end
|
2016-08-06 13:35:13 -04:00
|
|
|
before_action :handle_last_modified_and_etags, only: :conditional_hello_with_bangs
|
2012-03-17 10:08:49 -04:00
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def handle_last_modified_and_etags
|
2016-08-06 13:35:13 -04:00
|
|
|
fresh_when(last_modified: Time.now.utc.beginning_of_day, etag: [ :foo, 123 ])
|
2008-08-29 14:25:21 -04:00
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def head_created
|
|
|
|
head :created
|
2008-08-29 14:25:21 -04:00
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def head_created_with_application_json_content_type
|
2016-08-06 13:35:13 -04:00
|
|
|
head :created, content_type: "application/json"
|
2012-10-04 14:55:02 -04:00
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def head_ok_with_image_png_content_type
|
2016-08-06 13:35:13 -04:00
|
|
|
head :ok, content_type: "image/png"
|
2008-08-29 14:25:21 -04:00
|
|
|
end
|
|
|
|
|
2019-08-01 00:09:12 -04:00
|
|
|
def head_ok_with_string_key_content_type
|
|
|
|
head :ok, "Content-Type" => "application/pdf"
|
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def head_with_location_header
|
2016-08-06 13:35:13 -04:00
|
|
|
head :ok, location: "/foo"
|
2012-11-13 16:02:41 -05:00
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def head_with_location_object
|
2016-08-06 13:35:13 -04:00
|
|
|
head :ok, location: Customer.new("david", 1)
|
2008-08-29 14:25:21 -04:00
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def head_with_symbolic_status
|
2015-06-15 16:53:45 -04:00
|
|
|
head params[:status].intern
|
2008-08-29 14:25:21 -04:00
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def head_with_integer_status
|
2015-06-15 16:53:45 -04:00
|
|
|
head params[:status].to_i
|
2008-08-29 14:25:21 -04:00
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def head_with_string_status
|
2015-06-15 16:53:45 -04:00
|
|
|
head params[:status]
|
2008-08-29 14:25:21 -04:00
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def head_with_custom_header
|
2016-08-06 13:35:13 -04:00
|
|
|
head :ok, x_custom_header: "something"
|
2009-03-07 15:05:18 -05:00
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def head_with_www_authenticate_header
|
2016-08-06 12:54:50 -04:00
|
|
|
head :ok, "WWW-Authenticate" => "something"
|
2009-03-07 15:05:18 -05:00
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def head_with_status_code_first
|
2016-08-06 13:35:13 -04:00
|
|
|
head :forbidden, x_custom_header: "something"
|
2008-08-29 14:25:21 -04:00
|
|
|
end
|
|
|
|
|
2015-03-11 14:31:14 -04:00
|
|
|
def head_and_return
|
2016-09-01 17:41:49 -04:00
|
|
|
head(:ok) && return
|
2016-08-06 12:54:50 -04:00
|
|
|
raise "should not reach this line"
|
2015-03-11 14:31:14 -04:00
|
|
|
end
|
|
|
|
|
2014-12-31 06:21:55 -05:00
|
|
|
def head_with_no_content
|
|
|
|
# Fill in the headers with dummy data to make
|
|
|
|
# sure they get removed during the testing
|
|
|
|
response.headers["Content-Type"] = "dummy"
|
|
|
|
response.headers["Content-Length"] = 42
|
|
|
|
|
|
|
|
head 204
|
|
|
|
end
|
|
|
|
|
2017-04-30 11:05:20 -04:00
|
|
|
def head_default_content_type
|
|
|
|
# simulating path like "/1.foobar"
|
|
|
|
request.formats = []
|
|
|
|
|
|
|
|
respond_to do |format|
|
|
|
|
format.any { head 200 }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
private
|
|
|
|
def set_variable_for_layout
|
|
|
|
@variable_for_layout = nil
|
2008-08-29 14:25:21 -04:00
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def determine_layout
|
|
|
|
case action_name
|
2016-08-06 14:20:22 -04:00
|
|
|
when "hello_world", "layout_test", "rendering_without_layout",
|
2013-08-05 17:58:20 -04:00
|
|
|
"rendering_nothing_on_layout", "render_text_hello_world",
|
|
|
|
"render_text_hello_world_with_layout",
|
|
|
|
"hello_world_with_layout_false",
|
|
|
|
"partial_only", "accessing_params_in_template",
|
|
|
|
"accessing_params_in_template_with_layout",
|
|
|
|
"render_with_explicit_template",
|
|
|
|
"render_with_explicit_string_template",
|
|
|
|
"update_page", "update_page_with_instance_variables"
|
|
|
|
|
2016-08-06 14:20:22 -04:00
|
|
|
"layouts/standard"
|
|
|
|
when "action_talk_to_layout", "layout_overriding_layout"
|
|
|
|
"layouts/talk_from_action"
|
|
|
|
when "render_implicit_html_template_from_xhr_request"
|
|
|
|
(request.xhr? ? "layouts/xhr" : "layouts/standard")
|
2013-08-05 17:58:20 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-07-13 15:07:49 -04:00
|
|
|
module TemplateModificationHelper
|
|
|
|
private
|
|
|
|
def modify_template(name)
|
2019-06-29 10:41:27 -04:00
|
|
|
hash = @controller.view_paths.first.instance_variable_get(:@hash)
|
|
|
|
key = name + ".erb"
|
|
|
|
original = hash[key]
|
|
|
|
hash[key] = "#{original} Modified!"
|
2016-07-13 15:07:49 -04:00
|
|
|
ActionView::LookupContext::DetailsKey.clear
|
|
|
|
yield
|
|
|
|
ensure
|
2019-06-29 10:41:27 -04:00
|
|
|
hash[key] = original
|
|
|
|
ActionView::LookupContext::DetailsKey.clear
|
2016-07-13 15:07:49 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
class MetalTestController < ActionController::Metal
|
|
|
|
include AbstractController::Rendering
|
|
|
|
include ActionView::Rendering
|
|
|
|
include ActionController::Rendering
|
2008-08-29 14:25:21 -04:00
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def accessing_logger_in_template
|
2016-08-06 13:35:13 -04:00
|
|
|
render inline: "<%= logger.class %>"
|
2008-07-18 21:14:12 -04:00
|
|
|
end
|
2008-07-16 07:32:15 -04:00
|
|
|
end
|
|
|
|
|
2009-02-27 13:24:52 -05:00
|
|
|
class ExpiresInRenderTest < ActionController::TestCase
|
|
|
|
tests TestController
|
|
|
|
|
2016-01-26 20:06:31 -05:00
|
|
|
def setup
|
|
|
|
super
|
|
|
|
ActionController::Base.view_paths.paths.each(&:clear_cache)
|
|
|
|
end
|
|
|
|
|
2016-01-20 13:39:19 -05:00
|
|
|
def test_dynamic_render_with_file
|
2017-05-15 10:17:28 -04:00
|
|
|
assert File.exist?(File.expand_path("../../test/abstract_unit.rb", __dir__))
|
2019-04-01 19:35:07 -04:00
|
|
|
assert_deprecated do
|
|
|
|
assert_raises ActionView::MissingTemplate do
|
|
|
|
get :dynamic_render_with_file, params: { id: '../\\../test/abstract_unit.rb' }
|
|
|
|
end
|
|
|
|
end
|
2016-01-20 13:39:19 -05:00
|
|
|
end
|
|
|
|
|
2016-01-28 14:18:01 -05:00
|
|
|
def test_dynamic_render_with_absolute_path
|
2016-08-06 12:54:50 -04:00
|
|
|
file = Tempfile.new("name")
|
2016-01-28 14:18:01 -05:00
|
|
|
file.write "secrets!"
|
|
|
|
file.flush
|
|
|
|
assert_raises ActionView::MissingTemplate do
|
2016-01-29 23:40:12 -05:00
|
|
|
get :dynamic_render, params: { id: file.path }
|
2016-01-28 14:18:01 -05:00
|
|
|
end
|
|
|
|
ensure
|
2016-01-28 15:22:02 -05:00
|
|
|
file.close
|
2016-01-28 14:18:01 -05:00
|
|
|
file.unlink
|
|
|
|
end
|
|
|
|
|
2016-01-20 13:39:19 -05:00
|
|
|
def test_dynamic_render
|
2017-05-15 10:17:28 -04:00
|
|
|
assert File.exist?(File.expand_path("../../test/abstract_unit.rb", __dir__))
|
2016-01-20 13:39:19 -05:00
|
|
|
assert_raises ActionView::MissingTemplate do
|
2020-04-21 18:59:46 -04:00
|
|
|
get :dynamic_render, params: { id: '../\\../test/abstract_unit.rb' }
|
2016-01-20 13:39:19 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-01-26 21:00:05 -05:00
|
|
|
def test_permitted_dynamic_render_file_hash
|
2017-05-15 10:17:28 -04:00
|
|
|
assert File.exist?(File.expand_path("../../test/abstract_unit.rb", __dir__))
|
2019-04-01 19:35:07 -04:00
|
|
|
assert_deprecated do
|
|
|
|
assert_raises ActionView::MissingTemplate do
|
|
|
|
get :dynamic_render_permit, params: { id: { file: '../\\../test/abstract_unit.rb' } }
|
|
|
|
end
|
|
|
|
end
|
2016-01-26 21:00:05 -05:00
|
|
|
end
|
|
|
|
|
2016-01-20 13:39:19 -05:00
|
|
|
def test_dynamic_render_file_hash
|
|
|
|
assert_raises ArgumentError do
|
|
|
|
get :dynamic_render, params: { id: { file: '../\\../test/abstract_unit.rb' } }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-02-27 13:24:52 -05:00
|
|
|
def test_expires_in_header
|
|
|
|
get :conditional_hello_with_expires_in
|
|
|
|
assert_equal "max-age=60, private", @response.headers["Cache-Control"]
|
|
|
|
end
|
2009-12-08 17:52:26 -05:00
|
|
|
|
2009-03-06 04:17:20 -05:00
|
|
|
def test_expires_in_header_with_public
|
2009-02-27 13:24:52 -05:00
|
|
|
get :conditional_hello_with_expires_in_with_public
|
|
|
|
assert_equal "max-age=60, public", @response.headers["Cache-Control"]
|
|
|
|
end
|
2009-12-08 17:52:26 -05:00
|
|
|
|
2012-02-17 08:16:58 -05:00
|
|
|
def test_expires_in_header_with_must_revalidate
|
|
|
|
get :conditional_hello_with_expires_in_with_must_revalidate
|
|
|
|
assert_equal "max-age=60, private, must-revalidate", @response.headers["Cache-Control"]
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_expires_in_header_with_public_and_must_revalidate
|
|
|
|
get :conditional_hello_with_expires_in_with_public_and_must_revalidate
|
|
|
|
assert_equal "max-age=60, public, must-revalidate", @response.headers["Cache-Control"]
|
2018-06-13 12:08:24 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_expires_in_header_with_stale_while_revalidate
|
|
|
|
get :conditional_hello_with_expires_in_with_stale_while_revalidate
|
|
|
|
assert_equal "max-age=60, public, stale-while-revalidate=300", @response.headers["Cache-Control"]
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_expires_in_header_with_stale_if_error
|
|
|
|
get :conditional_hello_with_expires_in_with_stale_if_error
|
|
|
|
assert_equal "max-age=60, public, stale-if-error=300", @response.headers["Cache-Control"]
|
2012-02-17 08:16:58 -05:00
|
|
|
end
|
|
|
|
|
2009-02-27 13:24:52 -05:00
|
|
|
def test_expires_in_header_with_additional_headers
|
|
|
|
get :conditional_hello_with_expires_in_with_public_with_more_keys
|
2012-03-02 05:40:57 -05:00
|
|
|
assert_equal "max-age=60, public, s-maxage=18000", @response.headers["Cache-Control"]
|
2009-02-27 13:24:52 -05:00
|
|
|
end
|
2009-12-08 17:52:26 -05:00
|
|
|
|
2009-02-27 13:24:52 -05:00
|
|
|
def test_expires_in_old_syntax
|
|
|
|
get :conditional_hello_with_expires_in_with_public_with_more_keys_old_syntax
|
2012-03-02 05:40:57 -05:00
|
|
|
assert_equal "max-age=60, public, s-maxage=18000", @response.headers["Cache-Control"]
|
2009-02-27 13:24:52 -05:00
|
|
|
end
|
2009-10-26 20:32:42 -04:00
|
|
|
|
|
|
|
def test_expires_now
|
|
|
|
get :conditional_hello_with_expires_now
|
|
|
|
assert_equal "no-cache", @response.headers["Cache-Control"]
|
|
|
|
end
|
2011-10-31 05:24:03 -04:00
|
|
|
|
2012-06-21 07:30:19 -04:00
|
|
|
def test_expires_now_with_cache_control_headers
|
Ensure that cache-control headers are merged
There are several aspects to this commit, that don't well fit into broken down
commits, so they are detailed here:
* When a user uses response.headers['Cache-Control'] = some_value, then the
documented convention in ConditionalGet is not adhered to, in this case,
response.cache_control is ignored due to `return if
self[CACHE_CONTROL].present?`
* When a middleware sets cache-control headers that would clobber, they're
converted to symbols directly, without underscores. This would lead to bugs.
* Items that would live in :extras if set through expires_in, are placed
directly in the @cache_control hash, and not respected in many cases
(somewhat adhering to the aforementioned documentation).
* Although quite useless, any directive named 'extras' would be ignored.
The general convention applied is that expires_* take precedence, but no longer
overwrite everything and expires_* are ALWAYS applied, even if the header is
set.
I am still unhappy about the contents of this commit, and the code in general.
Ideally it should be refactored to no longer use :extras. I'd likely recommend
expanding @cache_control into a class, and giving it the power to handle the
merge in a more efficient fashion. Such a commit would be a larger change that
could have additional semantic changes for other libraries unless they utilize
expires_in in very standard ways.
2012-06-18 19:49:03 -04:00
|
|
|
get :conditional_hello_with_cache_control_headers
|
2012-06-21 07:30:19 -04:00
|
|
|
assert_match(/no-cache/, @response.headers["Cache-Control"])
|
|
|
|
assert_match(/no-transform/, @response.headers["Cache-Control"])
|
Ensure that cache-control headers are merged
There are several aspects to this commit, that don't well fit into broken down
commits, so they are detailed here:
* When a user uses response.headers['Cache-Control'] = some_value, then the
documented convention in ConditionalGet is not adhered to, in this case,
response.cache_control is ignored due to `return if
self[CACHE_CONTROL].present?`
* When a middleware sets cache-control headers that would clobber, they're
converted to symbols directly, without underscores. This would lead to bugs.
* Items that would live in :extras if set through expires_in, are placed
directly in the @cache_control hash, and not respected in many cases
(somewhat adhering to the aforementioned documentation).
* Although quite useless, any directive named 'extras' would be ignored.
The general convention applied is that expires_* take precedence, but no longer
overwrite everything and expires_* are ALWAYS applied, even if the header is
set.
I am still unhappy about the contents of this commit, and the code in general.
Ideally it should be refactored to no longer use :extras. I'd likely recommend
expanding @cache_control into a class, and giving it the power to handle the
merge in a more efficient fashion. Such a commit would be a larger change that
could have additional semantic changes for other libraries unless they utilize
expires_in in very standard ways.
2012-06-18 19:49:03 -04:00
|
|
|
end
|
|
|
|
|
2017-08-22 14:45:22 -04:00
|
|
|
def test_expires_now_with_conflicting_cache_control_headers
|
|
|
|
get :conditional_hello_with_expires_and_confliciting_cache_control_headers
|
2017-08-22 15:11:07 -04:00
|
|
|
assert_equal "no-cache", @response.headers["Cache-Control"]
|
2017-08-22 14:45:22 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_no_expires_now_with_conflicting_cache_control_headers
|
|
|
|
get :conditional_hello_without_expires_and_confliciting_cache_control_headers
|
2017-08-22 15:11:07 -04:00
|
|
|
assert_equal "no-cache", @response.headers["Cache-Control"]
|
2017-08-22 14:45:22 -04:00
|
|
|
end
|
|
|
|
|
2019-01-02 03:11:59 -05:00
|
|
|
def test_no_expires_now_with_public
|
|
|
|
get :conditional_hello_without_expires_and_public_header
|
|
|
|
assert_equal "public, no-cache", @response.headers["Cache-Control"]
|
|
|
|
end
|
|
|
|
|
2011-10-31 05:24:03 -04:00
|
|
|
def test_date_header_when_expires_in
|
2016-10-28 23:05:58 -04:00
|
|
|
time = Time.mktime(2011, 10, 30)
|
2015-08-21 16:33:50 -04:00
|
|
|
Time.stub :now, time do
|
|
|
|
get :conditional_hello_with_expires_in
|
|
|
|
assert_equal Time.now.httpdate, @response.headers["Date"]
|
|
|
|
end
|
2011-10-31 05:24:03 -04:00
|
|
|
end
|
2009-02-27 13:24:52 -05:00
|
|
|
end
|
|
|
|
|
2008-11-07 15:42:34 -05:00
|
|
|
class LastModifiedRenderTest < ActionController::TestCase
|
|
|
|
tests TestController
|
2007-04-24 13:52:03 -04:00
|
|
|
|
2008-11-07 15:42:34 -05:00
|
|
|
def setup
|
2009-04-08 20:33:06 -04:00
|
|
|
super
|
2008-07-16 07:32:15 -04:00
|
|
|
@last_modified = Time.now.utc.beginning_of_day.httpdate
|
2007-06-05 12:51:49 -04:00
|
|
|
end
|
|
|
|
|
2008-07-16 07:32:15 -04:00
|
|
|
def test_responds_with_last_modified
|
|
|
|
get :conditional_hello
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal @last_modified, @response.headers["Last-Modified"]
|
2007-05-14 23:15:36 -04:00
|
|
|
end
|
|
|
|
|
2008-07-16 07:32:15 -04:00
|
|
|
def test_request_not_modified
|
2008-08-08 05:31:12 -04:00
|
|
|
@request.if_modified_since = @last_modified
|
2008-07-16 07:32:15 -04:00
|
|
|
get :conditional_hello
|
2009-05-11 15:04:43 -04:00
|
|
|
assert_equal 304, @response.status.to_i
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @response.body, :blank?
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal @last_modified, @response.headers["Last-Modified"]
|
2007-10-25 02:38:01 -04:00
|
|
|
end
|
|
|
|
|
2008-10-20 20:30:13 -04:00
|
|
|
def test_request_not_modified_but_etag_differs
|
|
|
|
@request.if_modified_since = @last_modified
|
2016-03-31 20:47:00 -04:00
|
|
|
@request.if_none_match = '"234"'
|
2008-10-20 20:30:13 -04:00
|
|
|
get :conditional_hello
|
|
|
|
assert_response :success
|
|
|
|
end
|
|
|
|
|
2008-07-16 07:32:15 -04:00
|
|
|
def test_request_modified
|
2016-08-06 12:54:50 -04:00
|
|
|
@request.if_modified_since = "Thu, 16 Jul 2008 00:00:00 GMT"
|
2008-07-16 07:32:15 -04:00
|
|
|
get :conditional_hello
|
2009-05-11 15:04:43 -04:00
|
|
|
assert_equal 200, @response.status.to_i
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @response.body, :present?
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal @last_modified, @response.headers["Last-Modified"]
|
2007-12-09 17:11:37 -05:00
|
|
|
end
|
2008-11-17 23:09:22 -05:00
|
|
|
|
2011-12-01 13:09:22 -05:00
|
|
|
def test_responds_with_last_modified_with_record
|
|
|
|
get :conditional_hello_with_record
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal @last_modified, @response.headers["Last-Modified"]
|
2011-12-01 13:09:22 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_request_not_modified_with_record
|
|
|
|
@request.if_modified_since = @last_modified
|
|
|
|
get :conditional_hello_with_record
|
|
|
|
assert_equal 304, @response.status.to_i
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @response.body, :blank?
|
2015-02-10 20:02:24 -05:00
|
|
|
assert_not_nil @response.etag
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal @last_modified, @response.headers["Last-Modified"]
|
2011-12-01 13:09:22 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_request_not_modified_but_etag_differs_with_record
|
|
|
|
@request.if_modified_since = @last_modified
|
2016-03-31 20:47:00 -04:00
|
|
|
@request.if_none_match = '"234"'
|
2011-12-01 13:09:22 -05:00
|
|
|
get :conditional_hello_with_record
|
|
|
|
assert_response :success
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_request_modified_with_record
|
2016-08-06 12:54:50 -04:00
|
|
|
@request.if_modified_since = "Thu, 16 Jul 2008 00:00:00 GMT"
|
2011-12-01 13:09:22 -05:00
|
|
|
get :conditional_hello_with_record
|
|
|
|
assert_equal 200, @response.status.to_i
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @response.body, :present?
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal @last_modified, @response.headers["Last-Modified"]
|
2011-12-01 13:09:22 -05:00
|
|
|
end
|
|
|
|
|
2015-01-06 15:14:49 -05:00
|
|
|
def test_responds_with_last_modified_with_collection_of_records
|
|
|
|
get :conditional_hello_with_collection_of_records
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal @last_modified, @response.headers["Last-Modified"]
|
2015-01-06 15:14:49 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_request_not_modified_with_collection_of_records
|
|
|
|
@request.if_modified_since = @last_modified
|
|
|
|
get :conditional_hello_with_collection_of_records
|
|
|
|
assert_equal 304, @response.status.to_i
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @response.body, :blank?
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal @last_modified, @response.headers["Last-Modified"]
|
2015-01-06 15:14:49 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_request_not_modified_but_etag_differs_with_collection_of_records
|
|
|
|
@request.if_modified_since = @last_modified
|
2016-03-31 20:47:00 -04:00
|
|
|
@request.if_none_match = '"234"'
|
2015-01-06 15:14:49 -05:00
|
|
|
get :conditional_hello_with_collection_of_records
|
|
|
|
assert_response :success
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_request_modified_with_collection_of_records
|
2016-08-06 12:54:50 -04:00
|
|
|
@request.if_modified_since = "Thu, 16 Jul 2008 00:00:00 GMT"
|
2015-01-06 15:14:49 -05:00
|
|
|
get :conditional_hello_with_collection_of_records
|
|
|
|
assert_equal 200, @response.status.to_i
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @response.body, :present?
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal @last_modified, @response.headers["Last-Modified"]
|
2015-01-06 15:14:49 -05:00
|
|
|
end
|
|
|
|
|
2008-09-30 11:00:38 -04:00
|
|
|
def test_request_with_bang_gets_last_modified
|
|
|
|
get :conditional_hello_with_bangs
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal @last_modified, @response.headers["Last-Modified"]
|
2008-09-30 11:00:38 -04:00
|
|
|
assert_response :success
|
|
|
|
end
|
2008-11-17 23:09:22 -05:00
|
|
|
|
2008-09-30 11:00:38 -04:00
|
|
|
def test_request_with_bang_obeys_last_modified
|
|
|
|
@request.if_modified_since = @last_modified
|
|
|
|
get :conditional_hello_with_bangs
|
|
|
|
assert_response :not_modified
|
|
|
|
end
|
2008-10-07 15:09:07 -04:00
|
|
|
|
|
|
|
def test_last_modified_works_with_less_than_too
|
|
|
|
@request.if_modified_since = 5.years.ago.httpdate
|
|
|
|
get :conditional_hello_with_bangs
|
2008-10-20 20:30:13 -04:00
|
|
|
assert_response :success
|
2008-10-07 15:09:07 -04:00
|
|
|
end
|
2010-05-16 03:34:46 -04:00
|
|
|
end
|
2012-06-15 16:52:22 -04:00
|
|
|
|
2012-08-29 16:06:30 -04:00
|
|
|
class EtagRenderTest < ActionController::TestCase
|
|
|
|
tests TestControllerWithExtraEtags
|
2016-07-13 15:07:49 -04:00
|
|
|
include TemplateModificationHelper
|
2012-08-29 16:06:30 -04:00
|
|
|
|
2016-03-31 20:47:00 -04:00
|
|
|
def test_strong_etag
|
2016-08-06 12:54:50 -04:00
|
|
|
@request.if_none_match = strong_etag(["strong", "ab", :cde, [:f]])
|
2016-03-31 20:47:00 -04:00
|
|
|
get :strong
|
|
|
|
assert_response :not_modified
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
@request.if_none_match = "*"
|
2016-03-31 20:47:00 -04:00
|
|
|
get :strong
|
|
|
|
assert_response :not_modified
|
|
|
|
|
|
|
|
@request.if_none_match = '"strong"'
|
|
|
|
get :strong
|
|
|
|
assert_response :ok
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
@request.if_none_match = weak_etag(["strong", "ab", :cde, [:f]])
|
2016-03-31 20:47:00 -04:00
|
|
|
get :strong
|
|
|
|
assert_response :ok
|
|
|
|
end
|
|
|
|
|
2012-08-29 16:06:30 -04:00
|
|
|
def test_multiple_etags
|
2016-08-06 12:54:50 -04:00
|
|
|
@request.if_none_match = weak_etag(["123", "ab", :cde, [:f]])
|
2012-08-29 16:06:30 -04:00
|
|
|
get :fresh
|
|
|
|
assert_response :not_modified
|
|
|
|
|
|
|
|
@request.if_none_match = %("nomatch")
|
|
|
|
get :fresh
|
|
|
|
assert_response :success
|
|
|
|
end
|
2013-05-07 08:37:20 -04:00
|
|
|
|
|
|
|
def test_array
|
2016-08-06 12:54:50 -04:00
|
|
|
@request.if_none_match = weak_etag([%w(1 2 3), "ab", :cde, [:f]])
|
2013-05-07 08:37:20 -04:00
|
|
|
get :array
|
|
|
|
assert_response :not_modified
|
|
|
|
|
|
|
|
@request.if_none_match = %("nomatch")
|
|
|
|
get :array
|
|
|
|
assert_response :success
|
|
|
|
end
|
|
|
|
|
2014-08-16 18:06:20 -04:00
|
|
|
def test_etag_reflects_template_digest
|
|
|
|
get :with_template
|
|
|
|
assert_response :ok
|
|
|
|
assert_not_nil etag = @response.etag
|
|
|
|
|
|
|
|
request.if_none_match = etag
|
|
|
|
get :with_template
|
|
|
|
assert_response :not_modified
|
|
|
|
|
2016-07-13 15:07:49 -04:00
|
|
|
modify_template("test/hello_world") do
|
2016-06-27 16:59:49 -04:00
|
|
|
request.if_none_match = etag
|
|
|
|
get :with_template
|
|
|
|
assert_response :ok
|
|
|
|
assert_not_equal etag, @response.etag
|
|
|
|
end
|
|
|
|
end
|
2014-08-16 18:06:20 -04:00
|
|
|
|
2016-06-27 16:59:49 -04:00
|
|
|
def test_etag_reflects_implicit_template_digest
|
|
|
|
get :with_implicit_template
|
|
|
|
assert_response :ok
|
|
|
|
assert_not_nil etag = @response.etag
|
2014-08-16 18:06:20 -04:00
|
|
|
|
2016-06-27 16:59:49 -04:00
|
|
|
request.if_none_match = etag
|
|
|
|
get :with_implicit_template
|
|
|
|
assert_response :not_modified
|
|
|
|
|
2016-07-13 15:07:49 -04:00
|
|
|
modify_template("test/with_implicit_template") do
|
2014-08-16 18:06:20 -04:00
|
|
|
request.if_none_match = etag
|
2016-06-27 16:59:49 -04:00
|
|
|
get :with_implicit_template
|
2014-08-16 18:06:20 -04:00
|
|
|
assert_response :ok
|
|
|
|
assert_not_equal etag, @response.etag
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-03-31 20:47:00 -04:00
|
|
|
private
|
|
|
|
def weak_etag(record)
|
|
|
|
"W/#{strong_etag record}"
|
|
|
|
end
|
|
|
|
|
|
|
|
def strong_etag(record)
|
2017-11-29 19:27:27 -05:00
|
|
|
%("#{ActiveSupport::Digest.hexdigest(ActiveSupport::Cache.expand_cache_key(record))}")
|
2016-03-31 20:47:00 -04:00
|
|
|
end
|
2016-07-13 15:07:49 -04:00
|
|
|
end
|
2016-06-27 16:59:49 -04:00
|
|
|
|
2016-07-13 15:07:49 -04:00
|
|
|
class NamespacedEtagRenderTest < ActionController::TestCase
|
|
|
|
tests Namespaced::ImplicitRenderTestController
|
|
|
|
include TemplateModificationHelper
|
|
|
|
|
|
|
|
def test_etag_reflects_template_digest
|
|
|
|
get :hello_world
|
|
|
|
assert_response :ok
|
|
|
|
assert_not_nil etag = @response.etag
|
|
|
|
|
|
|
|
request.if_none_match = etag
|
|
|
|
get :hello_world
|
|
|
|
assert_response :not_modified
|
|
|
|
|
|
|
|
modify_template("namespaced/implicit_render_test/hello_world") do
|
|
|
|
request.if_none_match = etag
|
|
|
|
get :hello_world
|
|
|
|
assert_response :ok
|
|
|
|
assert_not_equal etag, @response.etag
|
2016-06-27 16:59:49 -04:00
|
|
|
end
|
2016-07-13 15:07:49 -04:00
|
|
|
end
|
2012-08-29 16:06:30 -04:00
|
|
|
end
|
|
|
|
|
2012-06-15 16:52:22 -04:00
|
|
|
class MetalRenderTest < ActionController::TestCase
|
|
|
|
tests MetalTestController
|
|
|
|
|
|
|
|
def test_access_to_logger_in_view
|
|
|
|
get :accessing_logger_in_template
|
|
|
|
assert_equal "NilClass", @response.body
|
|
|
|
end
|
|
|
|
end
|
2013-08-05 17:58:20 -04:00
|
|
|
|
2017-09-01 00:58:00 -04:00
|
|
|
class ActionControllerRenderTest < ActionController::TestCase
|
|
|
|
class MinimalController < ActionController::Metal
|
|
|
|
include AbstractController::Rendering
|
|
|
|
include ActionController::Rendering
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_direct_render_to_string_with_body
|
|
|
|
mc = MinimalController.new
|
|
|
|
assert_equal "Hello world!", mc.render_to_string(body: ["Hello world!"])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-06-09 09:36:07 -04:00
|
|
|
class ActionControllerBaseRenderTest < ActionController::TestCase
|
|
|
|
def test_direct_render_to_string
|
|
|
|
ac = ActionController::Base.new()
|
2016-08-06 12:54:50 -04:00
|
|
|
assert_equal "Hello world!", ac.render_to_string(template: "test/hello_world")
|
2016-06-09 09:36:07 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-06-02 16:08:53 -04:00
|
|
|
class ImplicitRenderTest < ActionController::TestCase
|
|
|
|
tests ImplicitRenderTestController
|
|
|
|
|
Lock down new `ImplicitRender` behavior for 5.0 RC
1. Conceptually revert #20276
The feature was implemented for the `responders` gem. In the end,
they did not need that feature, and have found a better fix (see
plataformatec/responders#131).
`ImplicitRender` is the place where Rails specifies our default
policies for the case where the user did not explicitly tell us
what to render, essentially describing a set of heuristics. If
the gem (or the user) knows exactly what they want, they could
just perform the correct `render` to avoid falling through to
here, as `responders` did (the user called `respond_with`).
Reverting the patch allows us to avoid exploding the complexity
and defining “the fallback for a fallback” policies.
2. `respond_to` and templates are considered exhaustive enumerations
If the user specified a list of formats/variants in a `respond_to`
block, anything that is not explicitly included should result
in an `UnknownFormat` error (which is then caught upstream to
mean “406 Not Acceptable” by default). This is already how it
works before this commit.
Same goes for templates – if the user defined a set of templates
(usually in the file system), that set is now considered exhaustive,
which means that “missing” templates are considered `UnknownFormat`
errors (406).
3. To keep API endpoints simple, the implicit render behavior for
actions with no templates defined at all (regardless of formats,
locales, variants, etc) are defaulted to “204 No Content”. This
is a strictly narrower version of the feature landed in #19036 and
#19377.
4. To avoid confusion when interacting in the browser, these actions
will raise an `UnknownFormat` error for “interactive” requests
instead. (The precise definition of “interactive” requests might
change – the spirit here is to give helpful messages and avoid
confusions.)
Closes #20666, #23062, #23077, #23564
[Godfrey Chan, Jon Moss, Kasper Timm Hansen, Mike Clark, Matthew Draper]
2016-02-23 12:41:26 -05:00
|
|
|
def test_implicit_no_content_response_as_browser
|
2017-05-30 10:12:34 -04:00
|
|
|
assert_raises(ActionController::MissingExactTemplate) do
|
Lock down new `ImplicitRender` behavior for 5.0 RC
1. Conceptually revert #20276
The feature was implemented for the `responders` gem. In the end,
they did not need that feature, and have found a better fix (see
plataformatec/responders#131).
`ImplicitRender` is the place where Rails specifies our default
policies for the case where the user did not explicitly tell us
what to render, essentially describing a set of heuristics. If
the gem (or the user) knows exactly what they want, they could
just perform the correct `render` to avoid falling through to
here, as `responders` did (the user called `respond_with`).
Reverting the patch allows us to avoid exploding the complexity
and defining “the fallback for a fallback” policies.
2. `respond_to` and templates are considered exhaustive enumerations
If the user specified a list of formats/variants in a `respond_to`
block, anything that is not explicitly included should result
in an `UnknownFormat` error (which is then caught upstream to
mean “406 Not Acceptable” by default). This is already how it
works before this commit.
Same goes for templates – if the user defined a set of templates
(usually in the file system), that set is now considered exhaustive,
which means that “missing” templates are considered `UnknownFormat`
errors (406).
3. To keep API endpoints simple, the implicit render behavior for
actions with no templates defined at all (regardless of formats,
locales, variants, etc) are defaulted to “204 No Content”. This
is a strictly narrower version of the feature landed in #19036 and
#19377.
4. To avoid confusion when interacting in the browser, these actions
will raise an `UnknownFormat` error for “interactive” requests
instead. (The precise definition of “interactive” requests might
change – the spirit here is to give helpful messages and avoid
confusions.)
Closes #20666, #23062, #23077, #23564
[Godfrey Chan, Jon Moss, Kasper Timm Hansen, Mike Clark, Matthew Draper]
2016-02-23 12:41:26 -05:00
|
|
|
get :empty_action
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_implicit_no_content_response_as_xhr
|
|
|
|
get :empty_action, xhr: true
|
2015-06-02 16:08:53 -04:00
|
|
|
assert_response :no_content
|
|
|
|
end
|
Lock down new `ImplicitRender` behavior for 5.0 RC
1. Conceptually revert #20276
The feature was implemented for the `responders` gem. In the end,
they did not need that feature, and have found a better fix (see
plataformatec/responders#131).
`ImplicitRender` is the place where Rails specifies our default
policies for the case where the user did not explicitly tell us
what to render, essentially describing a set of heuristics. If
the gem (or the user) knows exactly what they want, they could
just perform the correct `render` to avoid falling through to
here, as `responders` did (the user called `respond_with`).
Reverting the patch allows us to avoid exploding the complexity
and defining “the fallback for a fallback” policies.
2. `respond_to` and templates are considered exhaustive enumerations
If the user specified a list of formats/variants in a `respond_to`
block, anything that is not explicitly included should result
in an `UnknownFormat` error (which is then caught upstream to
mean “406 Not Acceptable” by default). This is already how it
works before this commit.
Same goes for templates – if the user defined a set of templates
(usually in the file system), that set is now considered exhaustive,
which means that “missing” templates are considered `UnknownFormat`
errors (406).
3. To keep API endpoints simple, the implicit render behavior for
actions with no templates defined at all (regardless of formats,
locales, variants, etc) are defaulted to “204 No Content”. This
is a strictly narrower version of the feature landed in #19036 and
#19377.
4. To avoid confusion when interacting in the browser, these actions
will raise an `UnknownFormat` error for “interactive” requests
instead. (The precise definition of “interactive” requests might
change – the spirit here is to give helpful messages and avoid
confusions.)
Closes #20666, #23062, #23077, #23564
[Godfrey Chan, Jon Moss, Kasper Timm Hansen, Mike Clark, Matthew Draper]
2016-02-23 12:41:26 -05:00
|
|
|
|
|
|
|
def test_implicit_success_response_with_right_format
|
|
|
|
get :empty_action_with_template
|
|
|
|
assert_equal "<h1>Empty action rendered this implicitly.</h1>\n", @response.body
|
|
|
|
assert_response :success
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_implicit_unknown_format_response
|
|
|
|
assert_raises(ActionController::UnknownFormat) do
|
2016-08-06 12:54:50 -04:00
|
|
|
get :empty_action_with_template, format: "json"
|
Lock down new `ImplicitRender` behavior for 5.0 RC
1. Conceptually revert #20276
The feature was implemented for the `responders` gem. In the end,
they did not need that feature, and have found a better fix (see
plataformatec/responders#131).
`ImplicitRender` is the place where Rails specifies our default
policies for the case where the user did not explicitly tell us
what to render, essentially describing a set of heuristics. If
the gem (or the user) knows exactly what they want, they could
just perform the correct `render` to avoid falling through to
here, as `responders` did (the user called `respond_with`).
Reverting the patch allows us to avoid exploding the complexity
and defining “the fallback for a fallback” policies.
2. `respond_to` and templates are considered exhaustive enumerations
If the user specified a list of formats/variants in a `respond_to`
block, anything that is not explicitly included should result
in an `UnknownFormat` error (which is then caught upstream to
mean “406 Not Acceptable” by default). This is already how it
works before this commit.
Same goes for templates – if the user defined a set of templates
(usually in the file system), that set is now considered exhaustive,
which means that “missing” templates are considered `UnknownFormat`
errors (406).
3. To keep API endpoints simple, the implicit render behavior for
actions with no templates defined at all (regardless of formats,
locales, variants, etc) are defaulted to “204 No Content”. This
is a strictly narrower version of the feature landed in #19036 and
#19377.
4. To avoid confusion when interacting in the browser, these actions
will raise an `UnknownFormat` error for “interactive” requests
instead. (The precise definition of “interactive” requests might
change – the spirit here is to give helpful messages and avoid
confusions.)
Closes #20666, #23062, #23077, #23564
[Godfrey Chan, Jon Moss, Kasper Timm Hansen, Mike Clark, Matthew Draper]
2016-02-23 12:41:26 -05:00
|
|
|
end
|
|
|
|
end
|
2015-06-02 16:08:53 -04:00
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
class HeadRenderTest < ActionController::TestCase
|
|
|
|
tests TestController
|
|
|
|
|
|
|
|
def setup
|
|
|
|
@request.host = "www.nextangle.com"
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_head_created
|
|
|
|
post :head_created
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @response.body, :blank?
|
2013-08-05 17:58:20 -04:00
|
|
|
assert_response :created
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_head_created_with_application_json_content_type
|
|
|
|
post :head_created_with_application_json_content_type
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @response.body, :blank?
|
2013-08-05 17:58:20 -04:00
|
|
|
assert_equal "application/json", @response.header["Content-Type"]
|
|
|
|
assert_response :created
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_head_ok_with_image_png_content_type
|
|
|
|
post :head_ok_with_image_png_content_type
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @response.body, :blank?
|
2013-08-05 17:58:20 -04:00
|
|
|
assert_equal "image/png", @response.header["Content-Type"]
|
|
|
|
assert_response :ok
|
|
|
|
end
|
|
|
|
|
2019-08-01 00:09:12 -04:00
|
|
|
def test_head_respect_string_content_type
|
|
|
|
get :head_ok_with_string_key_content_type
|
|
|
|
assert_equal "application/pdf", @response.header["Content-Type"]
|
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def test_head_with_location_header
|
|
|
|
get :head_with_location_header
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @response.body, :blank?
|
2013-08-05 17:58:20 -04:00
|
|
|
assert_equal "/foo", @response.headers["Location"]
|
|
|
|
assert_response :ok
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_head_with_location_object
|
|
|
|
with_routing do |set|
|
|
|
|
set.draw do
|
|
|
|
resources :customers
|
2016-03-01 03:48:53 -05:00
|
|
|
|
|
|
|
ActiveSupport::Deprecation.silence do
|
2016-08-06 12:54:50 -04:00
|
|
|
get ":controller/:action"
|
2016-03-01 03:48:53 -05:00
|
|
|
end
|
2013-08-05 17:58:20 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
get :head_with_location_object
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @response.body, :blank?
|
2013-08-05 17:58:20 -04:00
|
|
|
assert_equal "http://www.nextangle.com/customers/1", @response.headers["Location"]
|
|
|
|
assert_response :ok
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_head_with_custom_header
|
|
|
|
get :head_with_custom_header
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @response.body, :blank?
|
2013-08-05 17:58:20 -04:00
|
|
|
assert_equal "something", @response.headers["X-Custom-Header"]
|
|
|
|
assert_response :ok
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_head_with_www_authenticate_header
|
|
|
|
get :head_with_www_authenticate_header
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @response.body, :blank?
|
2013-08-05 17:58:20 -04:00
|
|
|
assert_equal "something", @response.headers["WWW-Authenticate"]
|
|
|
|
assert_response :ok
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_head_with_symbolic_status
|
2015-01-04 04:35:06 -05:00
|
|
|
get :head_with_symbolic_status, params: { status: "ok" }
|
2013-08-05 17:58:20 -04:00
|
|
|
assert_equal 200, @response.status
|
|
|
|
assert_response :ok
|
|
|
|
|
2015-01-04 04:35:06 -05:00
|
|
|
get :head_with_symbolic_status, params: { status: "not_found" }
|
2013-08-05 17:58:20 -04:00
|
|
|
assert_equal 404, @response.status
|
|
|
|
assert_response :not_found
|
|
|
|
|
2015-01-04 04:35:06 -05:00
|
|
|
get :head_with_symbolic_status, params: { status: "no_content" }
|
2013-08-05 17:58:20 -04:00
|
|
|
assert_equal 204, @response.status
|
2016-09-16 12:44:05 -04:00
|
|
|
assert_not_includes @response.headers, "Content-Length"
|
2013-08-05 17:58:20 -04:00
|
|
|
assert_response :no_content
|
|
|
|
|
|
|
|
Rack::Utils::SYMBOL_TO_STATUS_CODE.each do |status, code|
|
2015-01-04 04:35:06 -05:00
|
|
|
get :head_with_symbolic_status, params: { status: status.to_s }
|
2013-08-05 17:58:20 -04:00
|
|
|
assert_equal code, @response.response_code
|
|
|
|
assert_response status
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_head_with_integer_status
|
|
|
|
Rack::Utils::HTTP_STATUS_CODES.each do |code, message|
|
2015-01-04 04:35:06 -05:00
|
|
|
get :head_with_integer_status, params: { status: code.to_s }
|
2013-08-05 17:58:20 -04:00
|
|
|
assert_equal message, @response.message
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-12-31 06:21:55 -05:00
|
|
|
def test_head_with_no_content
|
|
|
|
get :head_with_no_content
|
|
|
|
|
|
|
|
assert_equal 204, @response.status
|
|
|
|
assert_nil @response.headers["Content-Type"]
|
|
|
|
assert_nil @response.headers["Content-Length"]
|
|
|
|
end
|
|
|
|
|
2013-08-05 17:58:20 -04:00
|
|
|
def test_head_with_string_status
|
2015-01-04 04:35:06 -05:00
|
|
|
get :head_with_string_status, params: { status: "404 Eat Dirt" }
|
2013-08-05 17:58:20 -04:00
|
|
|
assert_equal 404, @response.response_code
|
|
|
|
assert_equal "Not Found", @response.message
|
|
|
|
assert_response :not_found
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_head_with_status_code_first
|
|
|
|
get :head_with_status_code_first
|
|
|
|
assert_equal 403, @response.response_code
|
|
|
|
assert_equal "Forbidden", @response.message
|
|
|
|
assert_equal "something", @response.headers["X-Custom-Header"]
|
|
|
|
assert_response :forbidden
|
|
|
|
end
|
2015-03-11 14:31:14 -04:00
|
|
|
|
|
|
|
def test_head_returns_truthy_value
|
|
|
|
assert_nothing_raised do
|
|
|
|
get :head_and_return
|
|
|
|
end
|
|
|
|
end
|
2017-04-30 11:05:20 -04:00
|
|
|
|
|
|
|
def test_head_default_content_type
|
|
|
|
post :head_default_content_type
|
|
|
|
assert_equal "text/html", @response.header["Content-Type"]
|
|
|
|
end
|
2013-12-04 20:13:04 -05:00
|
|
|
end
|
2015-01-07 21:23:55 -05:00
|
|
|
|
2017-08-04 09:05:25 -04:00
|
|
|
class LiveTestController < ActionController::Base
|
|
|
|
include ActionController::Live
|
|
|
|
|
|
|
|
def test_action
|
|
|
|
head :ok
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class LiveHeadRenderTest < ActionController::TestCase
|
|
|
|
tests LiveTestController
|
|
|
|
|
|
|
|
def setup
|
|
|
|
super
|
|
|
|
|
|
|
|
def @controller.new_controller_thread
|
|
|
|
Thread.new { yield }
|
|
|
|
end
|
|
|
|
|
|
|
|
def @controller.response_body=(body)
|
|
|
|
super
|
|
|
|
sleep 0.1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_live_head_ok
|
|
|
|
get :test_action, format: "json"
|
|
|
|
|
|
|
|
@response.stream.on_error { flunk "action should not raise any errors" }
|
|
|
|
sleep 0.2
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-01-07 21:23:55 -05:00
|
|
|
class HttpCacheForeverTest < ActionController::TestCase
|
|
|
|
class HttpCacheForeverController < ActionController::Base
|
|
|
|
def cache_me_forever
|
2016-03-05 00:41:10 -05:00
|
|
|
http_cache_forever(public: params[:public]) do
|
2016-08-06 12:54:50 -04:00
|
|
|
render plain: "hello"
|
2015-01-07 21:23:55 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
tests HttpCacheForeverController
|
|
|
|
|
|
|
|
def test_cache_with_public
|
2016-08-16 03:30:11 -04:00
|
|
|
get :cache_me_forever, params: { public: true }
|
2016-03-31 20:47:00 -04:00
|
|
|
assert_response :ok
|
2015-10-22 06:43:41 -04:00
|
|
|
assert_equal "max-age=#{100.years}, public", @response.headers["Cache-Control"]
|
2015-01-07 21:23:55 -05:00
|
|
|
assert_not_nil @response.etag
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @response, :weak_etag?
|
2015-01-07 21:23:55 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_cache_with_private
|
|
|
|
get :cache_me_forever
|
2016-03-31 20:47:00 -04:00
|
|
|
assert_response :ok
|
2015-10-22 06:43:41 -04:00
|
|
|
assert_equal "max-age=#{100.years}, private", @response.headers["Cache-Control"]
|
2015-01-07 21:23:55 -05:00
|
|
|
assert_not_nil @response.etag
|
2018-01-25 18:14:09 -05:00
|
|
|
assert_predicate @response, :weak_etag?
|
2015-01-07 21:23:55 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_cache_response_code_with_if_modified_since
|
|
|
|
get :cache_me_forever
|
2016-03-31 20:47:00 -04:00
|
|
|
assert_response :ok
|
|
|
|
|
2016-08-06 12:54:50 -04:00
|
|
|
@request.if_modified_since = @response.headers["Last-Modified"]
|
2015-01-07 21:23:55 -05:00
|
|
|
get :cache_me_forever
|
|
|
|
assert_response :not_modified
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_cache_response_code_with_etag
|
|
|
|
get :cache_me_forever
|
2016-03-31 20:47:00 -04:00
|
|
|
assert_response :ok
|
2015-01-07 21:23:55 -05:00
|
|
|
|
2016-03-31 20:47:00 -04:00
|
|
|
@request.if_none_match = @response.etag
|
2015-01-07 21:23:55 -05:00
|
|
|
get :cache_me_forever
|
|
|
|
assert_response :not_modified
|
|
|
|
end
|
|
|
|
end
|