aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_controller/test_case.rb94
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/routing.rb2
-rw-r--r--actionpack/lib/action_dispatch/testing/test_request.rb20
-rw-r--r--actionpack/test/controller/base_test.rb2
-rw-r--r--actionpack/test/controller/caching_test.rb12
-rw-r--r--actionpack/test/controller/filters_test.rb7
-rw-r--r--actionpack/test/controller/helper_test.rb19
-rw-r--r--actionpack/test/controller/request/test_request_test.rb6
-rw-r--r--actionpack/test/controller/request_forgery_protection_test.rb3
-rw-r--r--actionpack/test/controller/resources_test.rb4
-rw-r--r--actionpack/test/controller/send_file_test.rb2
-rw-r--r--actionpack/test/controller/test_case_test.rb49
-rw-r--r--actionpack/test/controller/url_rewriter_test.rb3
-rw-r--r--actionpack/test/dispatch/test_request_test.rb18
-rw-r--r--actionview/CHANGELOG.md5
-rw-r--r--actionview/lib/action_view/helpers/cache_helper.rb15
-rw-r--r--actionview/lib/action_view/template.rb17
-rw-r--r--actionview/lib/action_view/template/handlers/erb.rb11
-rw-r--r--actionview/lib/action_view/test_case.rb2
-rw-r--r--actionview/test/actionpack/controller/view_paths_test.rb2
-rw-r--r--actionview/test/template/template_test.rb8
-rw-r--r--activesupport/lib/active_support/testing/method_call_assertions.rb30
-rw-r--r--activesupport/test/testing/method_call_assertions_test.rb91
-rw-r--r--guides/source/active_job_basics.md7
24 files changed, 282 insertions, 147 deletions
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 9a7da54c95..329e321888 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -10,17 +10,42 @@ module ActionController
DEFAULT_ENV = ActionDispatch::TestRequest::DEFAULT_ENV.dup
DEFAULT_ENV.delete 'PATH_INFO'
- def initialize(env = {})
- super
+ def self.new_session
+ TestSession.new
+ end
+
+ # Create a new test request with default `env` values
+ def self.create
+ env = {}
+ env = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application
+ env["rack.request.cookie_hash"] = {}.with_indifferent_access
+ new(default_env.merge(env), new_session)
+ end
+
+ def self.default_env
+ DEFAULT_ENV
+ end
+ private_class_method :default_env
- self.session = TestSession.new
+ def initialize(env, session)
+ super(env)
+
+ self.session = session
self.session_options = TestSession::DEFAULT_OPTIONS
end
+ def query_string=(string)
+ @env[Rack::QUERY_STRING] = string
+ end
+
+ def request_parameters=(params)
+ @env["action_dispatch.request.request_parameters"] = params
+ end
+
def assign_parameters(routes, controller_path, action, parameters = {})
parameters = parameters.symbolize_keys
extra_keys = routes.extra_keys(parameters.merge(:controller => controller_path, :action => action))
- non_path_parameters = get? ? query_parameters : request_parameters
+ non_path_parameters = {}.with_indifferent_access
parameters.each do |key, value|
if value.is_a?(Array) && (value.frozen? || value.any?(&:frozen?))
@@ -44,6 +69,15 @@ module ActionController
end
end
+ if get?
+ if self.query_string.blank?
+ self.query_string = non_path_parameters.to_query
+ end
+ else
+ @env['action_dispatch.request.query_parameters'] = {}
+ self.request_parameters = non_path_parameters
+ end
+
path_parameters[:controller] = controller_path
path_parameters[:action] = action
@@ -57,35 +91,12 @@ module ActionController
@env['CONTENT_LENGTH'] = data.length.to_s
@env['rack.input'] = StringIO.new(data)
end
-
- def recycle!
- @formats = nil
- @env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
- @env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
- @method = @request_method = nil
- @fullpath = @ip = @remote_ip = @protocol = nil
- @env['action_dispatch.request.query_parameters'] = {}
- end
-
- private
-
- def default_env
- DEFAULT_ENV
- end
end
class TestResponse < ActionDispatch::TestResponse
- def recycle!
- initialize
- end
end
class LiveTestResponse < Live::Response
- def recycle!
- @body = nil
- initialize
- end
-
def body
@body ||= super
end
@@ -449,8 +460,9 @@ module ActionController
@request.env['HTTP_COOKIE'] = cookies.to_header
@request.env['action_dispatch.cookies'] = nil
- @request.recycle!
- @response.recycle!
+ @request = TestRequest.new scrub_env!(@request.env), @request.session
+ @response = build_response @response_klass
+ @response.request = @request
@controller.recycle!
@request.env['REQUEST_METHOD'] = http_method
@@ -497,6 +509,7 @@ module ActionController
@request.env.delete 'HTTP_X_REQUESTED_WITH'
@request.env.delete 'HTTP_ACCEPT'
end
+ @request.query_string = ''
@response
end
@@ -504,11 +517,11 @@ module ActionController
def setup_controller_request_and_response
@controller = nil unless defined? @controller
- response_klass = TestResponse
+ @response_klass = TestResponse
if klass = self.class.controller_class
if klass < ActionController::Live
- response_klass = LiveTestResponse
+ @response_klass = LiveTestResponse
end
unless @controller
begin
@@ -519,9 +532,8 @@ module ActionController
end
end
- @request = build_request
- @request.env["rack.request.cookie_hash"] = {}.with_indifferent_access
- @response = build_response response_klass
+ @request = TestRequest.create
+ @response = build_response @response_klass
@response.request = @request
if @controller
@@ -530,10 +542,6 @@ module ActionController
end
end
- def build_request
- TestRequest.new
- end
-
def build_response(klass)
klass.new
end
@@ -547,6 +555,13 @@ module ActionController
private
+ def scrub_env!(env)
+ env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
+ env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
+ env.delete 'action_dispatch.request.query_parameters'
+ env
+ end
+
def process_with_kwargs(http_method, action, *args)
if kwarg_request?(args)
args.first.merge!(method: http_method)
@@ -602,11 +617,10 @@ module ActionController
:relative_url_root => nil,
:_recall => @request.path_parameters)
- url, query_string = @routes.path_for(options).split("?", 2)
+ url, = @routes.path_for(options).split("?", 2)
@request.env["SCRIPT_NAME"] = @controller.config.relative_url_root
@request.env["PATH_INFO"] = url
- @request.env["QUERY_STRING"] = query_string || ""
end
end
diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
index c94eea9134..543c7b78a1 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -183,7 +183,7 @@ module ActionDispatch
end
# Assume given controller
- request = ActionController::TestRequest.new
+ request = ActionController::TestRequest.create
if path =~ %r{://}
fail_on(URI::InvalidURIError, msg) do
diff --git a/actionpack/lib/action_dispatch/testing/test_request.rb b/actionpack/lib/action_dispatch/testing/test_request.rb
index 06e9abdd62..ad1a7f7109 100644
--- a/actionpack/lib/action_dispatch/testing/test_request.rb
+++ b/actionpack/lib/action_dispatch/testing/test_request.rb
@@ -7,17 +7,19 @@ module ActionDispatch
'HTTP_HOST' => 'test.host',
'REMOTE_ADDR' => '0.0.0.0',
'HTTP_USER_AGENT' => 'Rails Testing',
- "rack.request.cookie_hash" => {}.with_indifferent_access
)
- def self.new(env = {})
- super
+ # Create a new test request with default `env` values
+ def self.create(env = {})
+ env = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application
+ env["rack.request.cookie_hash"] ||= {}.with_indifferent_access
+ new(default_env.merge(env))
end
- def initialize(env = {})
- env = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application
- super(default_env.merge(env))
+ def self.default_env
+ DEFAULT_ENV
end
+ private_class_method :default_env
def request_method=(method)
@env['REQUEST_METHOD'] = method.to_s.upcase
@@ -63,11 +65,5 @@ module ActionDispatch
@env.delete('action_dispatch.request.accepts')
@env['HTTP_ACCEPT'] = Array(mime_types).collect(&:to_s).join(",")
end
-
- private
-
- def default_env
- DEFAULT_ENV
- end
end
end
diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb
index 3240185414..b7fe253de7 100644
--- a/actionpack/test/controller/base_test.rb
+++ b/actionpack/test/controller/base_test.rb
@@ -127,8 +127,6 @@ class PerformActionTest < ActionController::TestCase
# a more accurate simulation of what happens in "real life".
@controller.logger = ActiveSupport::Logger.new(nil)
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
@request.host = "www.nextangle.com"
end
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index 4f5af85fea..5698159eba 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -22,8 +22,6 @@ class FragmentCachingMetalTest < ActionController::TestCase
@controller.perform_caching = true
@controller.cache_store = @store
@params = { controller: 'posts', action: 'index' }
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
@controller.params = @params
@controller.request = @request
@controller.response = @response
@@ -52,8 +50,6 @@ class FragmentCachingTest < ActionController::TestCase
@controller.perform_caching = true
@controller.cache_store = @store
@params = {:controller => 'posts', :action => 'index'}
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
@controller.params = @params
@controller.request = @request
@controller.response = @response
@@ -166,6 +162,8 @@ class FunctionalCachingController < CachingController
end
def formatted_fragment_cached_with_variant
+ request.variant = :phone if params[:v] == "phone"
+
respond_to do |format|
format.html.phone
format.html
@@ -183,8 +181,6 @@ class FunctionalFragmentCachingTest < ActionController::TestCase
@controller = FunctionalCachingController.new
@controller.perform_caching = true
@controller.cache_store = @store
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
end
def test_fragment_caching
@@ -268,9 +264,7 @@ CACHED
def test_fragment_caching_with_variant
- @request.variant = :phone
-
- get :formatted_fragment_cached_with_variant, format: "html"
+ get :formatted_fragment_cached_with_variant, format: "html", params: { v: :phone }
assert_response :success
expected_body = "<body>\n<p>PHONE</p>\n</body>\n"
diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb
index 9b0487841f..8a6a51c263 100644
--- a/actionpack/test/controller/filters_test.rb
+++ b/actionpack/test/controller/filters_test.rb
@@ -757,9 +757,8 @@ class FilterTest < ActionController::TestCase
def test_dynamic_dispatch
%w(foo bar baz).each do |action|
- request = ActionController::TestRequest.new
- request.query_parameters[:choose] = action
- response = DynamicDispatchController.action(action).call(request.env).last
+ @request.query_parameters[:choose] = action
+ response = DynamicDispatchController.action(action).call(@request.env).last
assert_equal action, response.body
end
end
@@ -839,8 +838,6 @@ class FilterTest < ActionController::TestCase
private
def test_process(controller, action = "show")
@controller = controller.is_a?(Class) ? controller.new : controller
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
process(action)
end
diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb
index e263ed341f..a96cfa3bf4 100644
--- a/actionpack/test/controller/helper_test.rb
+++ b/actionpack/test/controller/helper_test.rb
@@ -73,14 +73,8 @@ module LocalAbcHelper
end
class HelperPathsTest < ActiveSupport::TestCase
- def setup
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
- end
-
def test_helpers_paths_priority
- request = ActionController::TestRequest.new
- responses = HelpersPathsController.action(:index).call(request.env)
+ responses = HelpersPathsController.action(:index).call(ActionController::TestRequest::DEFAULT_ENV.dup)
# helpers1_pack was given as a second path, so pack1_helper should be
# included as the second one
@@ -141,8 +135,7 @@ class HelperTest < ActiveSupport::TestCase
end
def call_controller(klass, action)
- request = ActionController::TestRequest.new
- klass.action(action).call(request.env)
+ klass.action(action).call(ActionController::TestRequest::DEFAULT_ENV.dup)
end
def test_helper_for_nested_controller
@@ -249,7 +242,7 @@ class HelperTest < ActiveSupport::TestCase
end
-class IsolatedHelpersTest < ActiveSupport::TestCase
+class IsolatedHelpersTest < ActionController::TestCase
class A < ActionController::Base
def index
render :inline => '<%= shout %>'
@@ -273,13 +266,11 @@ class IsolatedHelpersTest < ActiveSupport::TestCase
end
def call_controller(klass, action)
- request = ActionController::TestRequest.new
- klass.action(action).call(request.env)
+ klass.action(action).call(@request.env)
end
def setup
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
+ super
@request.action = 'index'
end
diff --git a/actionpack/test/controller/request/test_request_test.rb b/actionpack/test/controller/request/test_request_test.rb
index 77a2f68b1c..e5d698d5c2 100644
--- a/actionpack/test/controller/request/test_request_test.rb
+++ b/actionpack/test/controller/request/test_request_test.rb
@@ -1,11 +1,7 @@
require 'abstract_unit'
require 'stringio'
-class ActionController::TestRequestTest < ActiveSupport::TestCase
-
- def setup
- @request = ActionController::TestRequest.new
- end
+class ActionController::TestRequestTest < ActionController::TestCase
def test_test_request_has_session_options_initialized
assert @request.session_options
diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb
index 82c808754c..7c17aed632 100644
--- a/actionpack/test/controller/request_forgery_protection_test.rb
+++ b/actionpack/test/controller/request_forgery_protection_test.rb
@@ -484,11 +484,10 @@ end
class FreeCookieControllerTest < ActionController::TestCase
def setup
@controller = FreeCookieController.new
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
@token = "cf50faa3fe97702ca1ae"
SecureRandom.stubs(:base64).returns(@token)
+ super
end
def test_should_not_render_form_with_token_tag
diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb
index f3da2df3ef..5a279639cc 100644
--- a/actionpack/test/controller/resources_test.rb
+++ b/actionpack/test/controller/resources_test.rb
@@ -1207,8 +1207,6 @@ class ResourcesTest < ActionController::TestCase
@controller = "#{options[:options][:controller].camelize}Controller".constantize.new
@controller.singleton_class.include(@routes.url_helpers)
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
get :index, params: options[:options]
options[:options].delete :action
@@ -1277,8 +1275,6 @@ class ResourcesTest < ActionController::TestCase
(options[:options] ||= {})[:controller] ||= singleton_name.to_s.pluralize
@controller = "#{options[:options][:controller].camelize}Controller".constantize.new
@controller.singleton_class.include(@routes.url_helpers)
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
get :show, params: options[:options]
options[:options].delete :action
diff --git a/actionpack/test/controller/send_file_test.rb b/actionpack/test/controller/send_file_test.rb
index 36c57ec9b2..c0ddcf7f50 100644
--- a/actionpack/test/controller/send_file_test.rb
+++ b/actionpack/test/controller/send_file_test.rb
@@ -34,8 +34,6 @@ class SendFileTest < ActionController::TestCase
def setup
@controller = SendFileController.new
- @request = ActionController::TestRequest.new
- @response = ActionController::TestResponse.new
end
def test_file_nostream
diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb
index 86ffb898ad..b991232a14 100644
--- a/actionpack/test/controller/test_case_test.rb
+++ b/actionpack/test/controller/test_case_test.rb
@@ -45,11 +45,11 @@ class TestCaseTest < ActionController::TestCase
end
def test_params
- render text: params.inspect
+ render text: ::JSON.dump(params)
end
def test_query_parameters
- render text: request.query_parameters.inspect
+ render text: ::JSON.dump(request.query_parameters)
end
def test_request_parameters
@@ -158,8 +158,6 @@ XML
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
@@ -229,7 +227,7 @@ XML
def test_document_body_and_params_with_post
post :test_params, params: { id: 1 }
- assert_equal(%({"id"=>"1", "controller"=>"test_case_test/test", "action"=>"test_params"}), @response.body)
+ assert_equal({"id"=>"1", "controller"=>"test_case_test/test", "action"=>"test_params"}, ::JSON.parse(@response.body))
end
def test_document_body_with_post
@@ -485,7 +483,7 @@ XML
assert_deprecated {
get :test_params, page: { name: "Page name", month: '4', year: '2004', day: '6' }
}
- parsed_params = eval(@response.body)
+ parsed_params = ::JSON.parse(@response.body)
assert_equal(
{
'controller' => 'test_case_test/test', 'action' => 'test_params',
@@ -504,7 +502,7 @@ XML
day: '6'
}
}
- parsed_params = eval(@response.body)
+ parsed_params = ::JSON.parse(@response.body)
assert_equal(
{
'controller' => 'test_case_test/test', 'action' => 'test_params',
@@ -516,8 +514,8 @@ XML
def test_query_param_named_action
get :test_query_parameters, params: {action: 'foobar'}
- parsed_params = eval(@response.body)
- assert_equal({action: 'foobar'}, parsed_params)
+ parsed_params = JSON.parse(@response.body)
+ assert_equal({'action' => 'foobar'}, parsed_params)
end
def test_request_param_named_action
@@ -536,7 +534,7 @@ XML
}
}, session: { 'foo' => 'bar' }, flash: { notice: 'created' }
- parsed_params = eval(@response.body)
+ parsed_params = ::JSON.parse(@response.body)
assert_equal(
{'controller' => 'test_case_test/test', 'action' => 'test_params',
'page' => {'name' => "Page name", 'month' => '4', 'year' => '2004', 'day' => '6'}},
@@ -551,7 +549,7 @@ XML
get :test_params, params: {
page: { name: "Page name", month: 4, year: 2004, day: 6 }
}
- parsed_params = eval(@response.body)
+ parsed_params = ::JSON.parse(@response.body)
assert_equal(
{'controller' => 'test_case_test/test', 'action' => 'test_params',
'page' => {'name' => "Page name", 'month' => '4', 'year' => '2004', 'day' => '6'}},
@@ -561,17 +559,17 @@ XML
def test_params_passing_with_fixnums_when_not_html_request
get :test_params, params: { format: 'json', count: 999 }
- parsed_params = eval(@response.body)
+ parsed_params = ::JSON.parse(@response.body)
assert_equal(
{'controller' => 'test_case_test/test', 'action' => 'test_params',
- 'format' => 'json', 'count' => 999 },
+ 'format' => 'json', 'count' => '999' },
parsed_params
)
end
def test_params_passing_path_parameter_is_string_when_not_html_request
get :test_params, params: { format: 'json', id: 1 }
- parsed_params = eval(@response.body)
+ parsed_params = ::JSON.parse(@response.body)
assert_equal(
{'controller' => 'test_case_test/test', 'action' => 'test_params',
'format' => 'json', 'id' => '1' },
@@ -581,7 +579,7 @@ XML
def test_deprecated_params_passing_path_parameter_is_string_when_not_html_request
assert_deprecated { get :test_params, format: 'json', id: 1 }
- parsed_params = eval(@response.body)
+ parsed_params = ::JSON.parse(@response.body)
assert_equal(
{'controller' => 'test_case_test/test', 'action' => 'test_params',
'format' => 'json', 'id' => '1' },
@@ -595,7 +593,7 @@ XML
frozen: 'icy'.freeze, frozens: ['icy'.freeze].freeze, deepfreeze: { frozen: 'icy'.freeze }.freeze
}
end
- parsed_params = eval(@response.body)
+ parsed_params = ::JSON.parse(@response.body)
assert_equal(
{'controller' => 'test_case_test/test', 'action' => 'test_params',
'frozen' => 'icy', 'frozens' => ['icy'], 'deepfreeze' => { 'frozen' => 'icy' }},
@@ -693,13 +691,13 @@ XML
def test_deprecated_xhr_with_params
assert_deprecated { xhr :get, :test_params, params: { id: 1 } }
- assert_equal(%({"id"=>"1", "controller"=>"test_case_test/test", "action"=>"test_params"}), @response.body)
+ assert_equal({"id"=>"1", "controller"=>"test_case_test/test", "action"=>"test_params"}, ::JSON.parse(@response.body))
end
def test_xhr_with_params
get :test_params, params: { id: 1 }, xhr: true
- assert_equal(%({"id"=>"1", "controller"=>"test_case_test/test", "action"=>"test_params"}), @response.body)
+ assert_equal({"id"=>"1", "controller"=>"test_case_test/test", "action"=>"test_params"}, ::JSON.parse(@response.body))
end
def test_xhr_with_session
@@ -720,12 +718,6 @@ XML
assert_equal 'it works', session[:symbol], "Test session hash should allow indifferent access"
end
- def test_header_properly_reset_after_get_request
- get :test_params
- @request.recycle!
- assert_nil @request.instance_variable_get("@request_method")
- end
-
def test_deprecated_params_reset_between_post_requests
assert_deprecated { post :no_op, foo: "bar" }
assert_equal "bar", @request.params[:foo]
@@ -916,7 +908,7 @@ XML
filename = 'mona_lisa.jpg'
path = "#{FILES_DIR}/#{filename}"
assert_deprecated {
- post :test_file_upload, file: ActionDispatch::Http::UploadedFile.new(filename: path, type: "image/jpg", tempfile: File.open(path))
+ post :test_file_upload, file: Rack::Test::UploadedFile.new(path, "image/jpg", true)
}
assert_equal '159528', @response.body
end
@@ -925,7 +917,7 @@ XML
filename = 'mona_lisa.jpg'
path = "#{FILES_DIR}/#{filename}"
post :test_file_upload, params: {
- file: ActionDispatch::Http::UploadedFile.new(filename: path, type: "image/jpg", tempfile: File.open(path))
+ file: Rack::Test::UploadedFile.new(path, "image/jpg", true)
}
assert_equal '159528', @response.body
end
@@ -957,10 +949,11 @@ class ResponseDefaultHeadersTest < ActionController::TestCase
end
end
- setup do
+ def before_setup
@original = ActionDispatch::Response.default_headers
@defaults = { 'A' => '1', 'B' => '2' }
ActionDispatch::Response.default_headers = @defaults
+ super
end
teardown do
@@ -970,8 +963,6 @@ class ResponseDefaultHeadersTest < ActionController::TestCase
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
diff --git a/actionpack/test/controller/url_rewriter_test.rb b/actionpack/test/controller/url_rewriter_test.rb
index d9a1ae7d4f..5f2abc9606 100644
--- a/actionpack/test/controller/url_rewriter_test.rb
+++ b/actionpack/test/controller/url_rewriter_test.rb
@@ -1,7 +1,7 @@
require 'abstract_unit'
require 'controller/fake_controllers'
-class UrlRewriterTests < ActiveSupport::TestCase
+class UrlRewriterTests < ActionController::TestCase
class Rewriter
def initialize(request)
@options = {
@@ -16,7 +16,6 @@ class UrlRewriterTests < ActiveSupport::TestCase
end
def setup
- @request = ActionController::TestRequest.new
@params = {}
@rewriter = Rewriter.new(@request) #.new(@request, @params)
@routes = ActionDispatch::Routing::RouteSet.new.tap do |r|
diff --git a/actionpack/test/dispatch/test_request_test.rb b/actionpack/test/dispatch/test_request_test.rb
index a4c124070a..ede1cec4e6 100644
--- a/actionpack/test/dispatch/test_request_test.rb
+++ b/actionpack/test/dispatch/test_request_test.rb
@@ -2,7 +2,7 @@ require 'abstract_unit'
class TestRequestTest < ActiveSupport::TestCase
test "sane defaults" do
- env = ActionDispatch::TestRequest.new.env
+ env = ActionDispatch::TestRequest.create.env
assert_equal "GET", env.delete("REQUEST_METHOD")
assert_equal "off", env.delete("HTTPS")
@@ -27,7 +27,7 @@ class TestRequestTest < ActiveSupport::TestCase
end
test "cookie jar" do
- req = ActionDispatch::TestRequest.new
+ req = ActionDispatch::TestRequest.create({})
assert_equal({}, req.cookies)
assert_equal nil, req.env["HTTP_COOKIE"]
@@ -55,38 +55,38 @@ class TestRequestTest < ActiveSupport::TestCase
test "does not complain when Rails.application is nil" do
Rails.stubs(:application).returns(nil)
- req = ActionDispatch::TestRequest.new
+ req = ActionDispatch::TestRequest.create({})
assert_equal false, req.env.empty?
end
test "default remote address is 0.0.0.0" do
- req = ActionDispatch::TestRequest.new
+ req = ActionDispatch::TestRequest.create({})
assert_equal '0.0.0.0', req.remote_addr
end
test "allows remote address to be overridden" do
- req = ActionDispatch::TestRequest.new('REMOTE_ADDR' => '127.0.0.1')
+ req = ActionDispatch::TestRequest.create('REMOTE_ADDR' => '127.0.0.1')
assert_equal '127.0.0.1', req.remote_addr
end
test "default host is test.host" do
- req = ActionDispatch::TestRequest.new
+ req = ActionDispatch::TestRequest.create({})
assert_equal 'test.host', req.host
end
test "allows host to be overridden" do
- req = ActionDispatch::TestRequest.new('HTTP_HOST' => 'www.example.com')
+ req = ActionDispatch::TestRequest.create('HTTP_HOST' => 'www.example.com')
assert_equal 'www.example.com', req.host
end
test "default user agent is 'Rails Testing'" do
- req = ActionDispatch::TestRequest.new
+ req = ActionDispatch::TestRequest.create({})
assert_equal 'Rails Testing', req.user_agent
end
test "allows user agent to be overridden" do
- req = ActionDispatch::TestRequest.new('HTTP_USER_AGENT' => 'GoogleBot')
+ req = ActionDispatch::TestRequest.create('HTTP_USER_AGENT' => 'GoogleBot')
assert_equal 'GoogleBot', req.user_agent
end
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index 069d181674..1f6bb31cd4 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,8 @@
+* Allow defining explicit collection caching using a `# Template Collection: ...`
+ directive inside templates.
+
+ *Dov Murik*
+
* Asset helpers raise `ArgumentError` when `nil` is passed as a source.
*Anton Kolomiychuk*
diff --git a/actionview/lib/action_view/helpers/cache_helper.rb b/actionview/lib/action_view/helpers/cache_helper.rb
index 8945575860..797d029317 100644
--- a/actionview/lib/action_view/helpers/cache_helper.rb
+++ b/actionview/lib/action_view/helpers/cache_helper.rb
@@ -137,6 +137,21 @@ module ActionView
# The automatic cache multi read can be turned off like so:
#
# <%= render @notifications, cache: false %>
+ #
+ # === Explicit Collection Caching
+ #
+ # If the partial template doesn't start with a clean cache call as
+ # mentioned above, you can still benefit from collection caching by
+ # adding a special comment format anywhere in the template, like:
+ #
+ # <%# Template Collection: notification %>
+ # <% my_helper_that_calls_cache(some_arg, notification) do %>
+ # <%= notification.name %>
+ # <% end %>
+ #
+ # The pattern used to match these is <tt>/# Template Collection: (\S+)/</tt>,
+ # so it's important that you type it out just so.
+ # You can only declare one collection in a partial template file.
def cache(name = {}, options = {}, &block)
if controller.respond_to?(:perform_caching) && controller.perform_caching
safe_concat(fragment_for(cache_fragment_name(name, options), options, &block))
diff --git a/actionview/lib/action_view/template.rb b/actionview/lib/action_view/template.rb
index 377ceb534a..d8585514d5 100644
--- a/actionview/lib/action_view/template.rb
+++ b/actionview/lib/action_view/template.rb
@@ -130,7 +130,7 @@ module ActionView
@source = source
@identifier = identifier
@handler = handler
- @cache_name = extract_resource_cache_call_name
+ @cache_name = extract_resource_cache_name
@compiled = false
@original_encoding = nil
@locals = details[:locals] || []
@@ -351,9 +351,18 @@ module ActionView
ActiveSupport::Notifications.instrument("#{action}.action_view", payload, &block)
end
- def extract_resource_cache_call_name
- $1 if @handler.respond_to?(:resource_cache_call_pattern) &&
- @source =~ @handler.resource_cache_call_pattern
+ EXPLICIT_COLLECTION = /# Template Collection: (?<resource_name>\w+)/
+
+ def extract_resource_cache_name
+ if match = @source.match(EXPLICIT_COLLECTION) || resource_cache_call_match
+ match[:resource_name]
+ end
+ end
+
+ def resource_cache_call_match
+ if @handler.respond_to?(:resource_cache_call_pattern)
+ @source.match(@handler.resource_cache_call_pattern)
+ end
end
def inferred_cache_name
diff --git a/actionview/lib/action_view/template/handlers/erb.rb b/actionview/lib/action_view/template/handlers/erb.rb
index da96347e4d..1f8459c24b 100644
--- a/actionview/lib/action_view/template/handlers/erb.rb
+++ b/actionview/lib/action_view/template/handlers/erb.rb
@@ -125,7 +125,7 @@ module ActionView
# Returns Regexp to extract a cached resource's name from a cache call at the
# first line of a template.
- # The extracted cache name is expected in $1.
+ # The extracted cache name is captured as :resource_name.
#
# <% cache notification do %> # => notification
#
@@ -138,7 +138,14 @@ module ActionView
#
# <% cache notification.event do %> # => nil
def resource_cache_call_pattern
- /\A(?:<%#.*%>)*\s*<%\s*cache\(?\s*(\w+)[\s\)]/m
+ /\A
+ (?:<%\#.*%>)* # optional initial comment
+ \s* # followed by optional spaces or newlines
+ <%\s*cache[\(\s] # followed by an ERB call to cache
+ \s* # followed by optional spaces or newlines
+ (?<resource_name>\w+) # capture the cache call argument as :resource_name
+ [\s\)] # followed by a space or close paren
+ /xm
end
private
diff --git a/actionview/lib/action_view/test_case.rb b/actionview/lib/action_view/test_case.rb
index 06810ad14d..b4f36c1f78 100644
--- a/actionview/lib/action_view/test_case.rb
+++ b/actionview/lib/action_view/test_case.rb
@@ -24,7 +24,7 @@ module ActionView
def initialize
super
self.class.controller_path = ""
- @request = ActionController::TestRequest.new
+ @request = ActionController::TestRequest.create
@response = ActionController::TestResponse.new
@request.env.delete('PATH_INFO')
diff --git a/actionview/test/actionpack/controller/view_paths_test.rb b/actionview/test/actionpack/controller/view_paths_test.rb
index 7fba9ff8ff..2dd27358f7 100644
--- a/actionview/test/actionpack/controller/view_paths_test.rb
+++ b/actionview/test/actionpack/controller/view_paths_test.rb
@@ -23,7 +23,7 @@ class ViewLoadPathsTest < ActionController::TestCase
end
def setup
- @request = ActionController::TestRequest.new
+ @request = ActionController::TestRequest.create
@response = ActionController::TestResponse.new
@controller = TestController.new
@paths = TestController.view_paths
diff --git a/actionview/test/template/template_test.rb b/actionview/test/template/template_test.rb
index d17034e88f..d3b51cd629 100644
--- a/actionview/test/template/template_test.rb
+++ b/actionview/test/template/template_test.rb
@@ -194,14 +194,15 @@ class TestERBTemplate < ActiveSupport::TestCase
[
"<%= 'Hello' %>",
"<% cache_customer = 42 %>",
- "<% cache customer.name do %><% end %>"
+ "<% cache customer.name do %><% end %>",
+ "<% my_cache customer do %><% end %>"
].each do |body|
template = new_template(body, virtual_path: "test/foo/_customer")
assert_not template.eligible_for_collection_caching?, "Template #{body.inspect} should not be eligible for collection caching"
end
end
- def test_eligible_for_collection_caching_with_cache_call
+ def test_eligible_for_collection_caching_with_cache_call_or_explicit
[
"<% cache customer do %><% end %>",
"<% cache(customer) do %><% end %>",
@@ -213,7 +214,8 @@ class TestERBTemplate < ActiveSupport::TestCase
"<%# comment %><% cache customer do %><% end %>",
"<%# comment %>\n<% cache customer do %><% end %>",
"<%# comment\n line 2\n line 3 %>\n<% cache customer do %><% end %>",
- "<%# comment 1 %>\n<%# comment 2 %>\n<% cache customer do %><% end %>"
+ "<%# comment 1 %>\n<%# comment 2 %>\n<% cache customer do %><% end %>",
+ "<%# comment 1 %>\n<%# Template Collection: customer %>\n<% my_cache customer do %><% end %>"
].each do |body|
template = new_template(body, virtual_path: "test/foo/_customer")
assert template.eligible_for_collection_caching?, "Template #{body.inspect} should be eligible for collection caching"
diff --git a/activesupport/lib/active_support/testing/method_call_assertions.rb b/activesupport/lib/active_support/testing/method_call_assertions.rb
new file mode 100644
index 0000000000..0d7d62341c
--- /dev/null
+++ b/activesupport/lib/active_support/testing/method_call_assertions.rb
@@ -0,0 +1,30 @@
+module ActiveSupport
+ module Testing
+ module MethodCallAssertions # :nodoc:
+ private
+ def assert_called(object, method_name, message = nil, times: 1)
+ times_called = 0
+
+ object.stub(method_name, -> { times_called += 1 }) { yield }
+
+ error = "Expected #{method_name} to be called #{times} times, " \
+ "but was called #{times_called} times"
+ error = "#{message}.\n#{error}" if message
+ assert_equal times, times_called, error
+ end
+
+ def assert_called_with(object, method_name, args = [], returns: nil)
+ mock = Minitest::Mock.new
+ mock.expect(:call, returns, args)
+
+ object.stub(method_name, mock) { yield }
+
+ mock.verify
+ end
+
+ def assert_not_called(object, method_name, message = nil, &block)
+ assert_called(object, method_name, message, times: 0, &block)
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/activesupport/test/testing/method_call_assertions_test.rb b/activesupport/test/testing/method_call_assertions_test.rb
new file mode 100644
index 0000000000..b327492b3b
--- /dev/null
+++ b/activesupport/test/testing/method_call_assertions_test.rb
@@ -0,0 +1,91 @@
+require 'abstract_unit'
+require 'active_support/testing/method_call_assertions'
+
+class MethodCallAssertionsTest < ActiveSupport::TestCase
+ include ActiveSupport::Testing::MethodCallAssertions
+
+ class Level
+ def increment; 1; end
+ def decrement; end
+ def <<(arg); end
+ end
+
+ setup do
+ @object = Level.new
+ end
+
+ def test_assert_called_with_defaults_to_expect_once
+ assert_called @object, :increment do
+ @object.increment
+ end
+ end
+
+ def test_assert_called_more_than_once
+ assert_called(@object, :increment, times: 2) do
+ @object.increment
+ @object.increment
+ end
+ end
+
+ def test_assert_called_failure
+ error = assert_raises(Minitest::Assertion) do
+ assert_called(@object, :increment) do
+ # Call nothing...
+ end
+ end
+
+ assert_equal "Expected increment to be called 1 times, but was called 0 times.\nExpected: 1\n Actual: 0", error.message
+ end
+
+ def test_assert_called_with_message
+ error = assert_raises(Minitest::Assertion) do
+ assert_called(@object, :increment, 'dang it') do
+ # Call nothing...
+ end
+ end
+
+ assert_match(/dang it.\nExpected increment/, error.message)
+ end
+
+ def test_assert_called_with
+ assert_called_with(@object, :increment) do
+ @object.increment
+ end
+ end
+
+ def test_assert_called_with_arguments
+ assert_called_with(@object, :<<, [ 2 ]) do
+ @object << 2
+ end
+ end
+
+ def test_assert_called_with_failure
+ assert_raises(MockExpectationError) do
+ assert_called_with(@object, :<<, [ 4567 ]) do
+ @object << 2
+ end
+ end
+ end
+
+ def test_assert_called_with_returns
+ assert_called_with(@object, :increment, returns: 1) do
+ @object.increment
+ end
+ end
+
+ def test_assert_not_called
+ assert_not_called(@object, :decrement) do
+ @object.increment
+ end
+ end
+
+ def test_assert_not_called_failure
+ error = assert_raises(Minitest::Assertion) do
+ assert_not_called(@object, :increment) do
+ @object.increment
+ end
+ end
+
+ assert_equal "Expected increment to be called 0 times, but was called 1 times.\nExpected: 0\n Actual: 1", error.message
+ end
+end
diff --git a/guides/source/active_job_basics.md b/guides/source/active_job_basics.md
index 22f3c0146a..dd545b56f5 100644
--- a/guides/source/active_job_basics.md
+++ b/guides/source/active_job_basics.md
@@ -330,6 +330,13 @@ class GuestsCleanupJob < ActiveJob::Base
end
```
+### Deserialization
+
+GlobalID allows serializing full Active Record objects passed to `#perform`.
+
+If a passed record is deleted after the job is enqueued but before the `#perform`
+method is called Active Job will raise an `ActiveJob::DeserializationError`
+exception.
Job Testing
--------------