mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
a5776ed2b2
* master: (113 commits) remove useless method Updated file documentation [ci skip] changes caching guide to add note on weak etags Don't put config.action_mailer.perform_caching entry twice in development.rb Fix wording and wrong reference Add Ruby formatting to CHANGELOG entry Fix ActionView's cache section reference Do not define methods in the included block Add caching guide in ActionMailer basics Add ActionMailer configuration options Preparing for 5.0.0.beta3 release Update 5.0 release notes Enable tmp_restart plugin for puma Prep release for Rails 5 beta3 [ci skip] Move collection caching changelog entry. Ensure `drop_table` even if tests failure or interrupted 💣 run the test @rafaelfranca 😠 Remove changelog entry for reverted commit Add CHANGELOG for https://github.com/rails/rails/pull/23734 [ci skip] No need CHANGELOG entry for #23849. ...
350 lines
10 KiB
Ruby
350 lines
10 KiB
Ruby
require 'abstract_unit'
|
|
require 'fileutils'
|
|
require 'action_view/dependency_tracker'
|
|
|
|
class FixtureTemplate
|
|
attr_reader :source, :handler
|
|
|
|
def initialize(template_path)
|
|
@source = File.read(template_path)
|
|
@handler = ActionView::Template.handler_for_extension(:erb)
|
|
rescue Errno::ENOENT
|
|
raise ActionView::MissingTemplate.new([], "", [], true, [])
|
|
end
|
|
end
|
|
|
|
class FixtureFinder < ActionView::LookupContext
|
|
FIXTURES_DIR = "#{File.dirname(__FILE__)}/../fixtures/digestor"
|
|
|
|
def initialize(details = {})
|
|
super(ActionView::PathSet.new(['digestor']), details, [])
|
|
end
|
|
end
|
|
|
|
class TemplateDigestorTest < ActionView::TestCase
|
|
def setup
|
|
@cwd = Dir.pwd
|
|
@tmp_dir = Dir.mktmpdir
|
|
|
|
ActionView::LookupContext::DetailsKey.clear
|
|
FileUtils.cp_r FixtureFinder::FIXTURES_DIR, @tmp_dir
|
|
Dir.chdir @tmp_dir
|
|
end
|
|
|
|
def teardown
|
|
Dir.chdir @cwd
|
|
FileUtils.rm_r @tmp_dir
|
|
end
|
|
|
|
def test_top_level_change_reflected
|
|
assert_digest_difference("messages/show") do
|
|
change_template("messages/show")
|
|
end
|
|
end
|
|
|
|
def test_explicit_dependency
|
|
assert_digest_difference("messages/show") do
|
|
change_template("messages/_message")
|
|
end
|
|
end
|
|
|
|
def test_explicit_dependency_in_multiline_erb_tag
|
|
assert_digest_difference("messages/show") do
|
|
change_template("messages/_form")
|
|
end
|
|
end
|
|
|
|
def test_explicit_dependency_wildcard
|
|
assert_digest_difference("events/index") do
|
|
change_template("events/_completed")
|
|
end
|
|
end
|
|
|
|
def test_explicit_dependency_wildcard_picks_up_added_file
|
|
old_caching, ActionView::Resolver.caching = ActionView::Resolver.caching, false
|
|
|
|
assert_digest_difference("events/index") do
|
|
add_template("events/_uncompleted")
|
|
end
|
|
ensure
|
|
remove_template("events/_uncompleted")
|
|
ActionView::Resolver.caching = old_caching
|
|
end
|
|
|
|
def test_explicit_dependency_wildcard_picks_up_removed_file
|
|
old_caching, ActionView::Resolver.caching = ActionView::Resolver.caching, false
|
|
add_template("events/_subscribers_changed")
|
|
|
|
assert_digest_difference("events/index") do
|
|
remove_template("events/_subscribers_changed")
|
|
end
|
|
ensure
|
|
ActionView::Resolver.caching = old_caching
|
|
end
|
|
|
|
def test_second_level_dependency
|
|
assert_digest_difference("messages/show") do
|
|
change_template("comments/_comments")
|
|
end
|
|
end
|
|
|
|
def test_second_level_dependency_within_same_directory
|
|
assert_digest_difference("messages/show") do
|
|
change_template("messages/_header")
|
|
end
|
|
end
|
|
|
|
def test_third_level_dependency
|
|
assert_digest_difference("messages/show") do
|
|
change_template("comments/_comment")
|
|
end
|
|
end
|
|
|
|
def test_directory_depth_dependency
|
|
assert_digest_difference("level/below/index") do
|
|
change_template("level/below/_header")
|
|
end
|
|
end
|
|
|
|
def test_logging_of_missing_template
|
|
assert_logged "Couldn't find template for digesting: messages/something_missing" do
|
|
digest("messages/show")
|
|
end
|
|
end
|
|
|
|
def test_logging_of_missing_template_ending_with_number
|
|
assert_logged "Couldn't find template for digesting: messages/something_missing_1" do
|
|
digest("messages/show")
|
|
end
|
|
end
|
|
|
|
def test_logging_of_missing_template_for_dependencies
|
|
assert_logged "'messages/something_missing' file doesn't exist, so no dependencies" do
|
|
dependencies("messages/something_missing")
|
|
end
|
|
end
|
|
|
|
def test_logging_of_missing_template_for_nested_dependencies
|
|
assert_logged "'messages/something_missing' file doesn't exist, so no dependencies" do
|
|
nested_dependencies("messages/something_missing")
|
|
end
|
|
end
|
|
|
|
def test_getting_of_singly_nested_dependencies
|
|
singly_nested_dependencies = ["messages/header", "messages/form", "messages/message", "events/event", "comments/comment"]
|
|
assert_equal singly_nested_dependencies, nested_dependencies('messages/edit')
|
|
end
|
|
|
|
def test_getting_of_doubly_nested_dependencies
|
|
doubly_nested = [{"comments/comments"=>["comments/comment"]}, "messages/message"]
|
|
assert_equal doubly_nested, nested_dependencies('messages/peek')
|
|
end
|
|
|
|
def test_nested_template_directory
|
|
assert_digest_difference("messages/show") do
|
|
change_template("messages/actions/_move")
|
|
end
|
|
end
|
|
|
|
def test_nested_template_deps
|
|
nested_deps = ["messages/header", {"comments/comments"=>["comments/comment"]}, "messages/actions/move", "events/event", "messages/something_missing", "messages/something_missing_1", "messages/message", "messages/form"]
|
|
assert_equal nested_deps, nested_dependencies("messages/show")
|
|
end
|
|
|
|
def test_recursion_in_renders
|
|
assert digest("level/recursion") # assert recursion is possible
|
|
assert_not_nil digest("level/recursion") # assert digest is stored
|
|
end
|
|
|
|
def test_chaining_the_top_template_on_recursion
|
|
assert digest("level/recursion") # assert recursion is possible
|
|
|
|
assert_digest_difference("level/recursion") do
|
|
change_template("level/recursion")
|
|
end
|
|
|
|
assert_not_nil digest("level/recursion") # assert digest is stored
|
|
end
|
|
|
|
def test_chaining_the_partial_template_on_recursion
|
|
assert digest("level/recursion") # assert recursion is possible
|
|
|
|
assert_digest_difference("level/recursion") do
|
|
change_template("level/_recursion")
|
|
end
|
|
|
|
assert_not_nil digest("level/recursion") # assert digest is stored
|
|
end
|
|
|
|
def test_dont_generate_a_digest_for_missing_templates
|
|
assert_equal '', digest("nothing/there")
|
|
end
|
|
|
|
def test_collection_dependency
|
|
assert_digest_difference("messages/index") do
|
|
change_template("messages/_message")
|
|
end
|
|
|
|
assert_digest_difference("messages/index") do
|
|
change_template("events/_event")
|
|
end
|
|
end
|
|
|
|
def test_collection_derived_from_record_dependency
|
|
assert_digest_difference("messages/show") do
|
|
change_template("events/_event")
|
|
end
|
|
end
|
|
|
|
def test_details_are_included_in_cache_key
|
|
# Cache the template digest.
|
|
@finder = FixtureFinder.new({:formats => [:html]})
|
|
old_digest = digest("events/_event")
|
|
|
|
# Change the template; the cached digest remains unchanged.
|
|
change_template("events/_event")
|
|
|
|
# The details are changed, so a new cache key is generated.
|
|
@finder = FixtureFinder.new
|
|
|
|
# The cache is busted.
|
|
assert_not_equal old_digest, digest("events/_event")
|
|
end
|
|
|
|
def test_extra_whitespace_in_render_partial
|
|
assert_digest_difference("messages/edit") do
|
|
change_template("messages/_form")
|
|
end
|
|
end
|
|
|
|
def test_extra_whitespace_in_render_named_partial
|
|
assert_digest_difference("messages/edit") do
|
|
change_template("messages/_header")
|
|
end
|
|
end
|
|
|
|
def test_extra_whitespace_in_render_record
|
|
assert_digest_difference("messages/edit") do
|
|
change_template("messages/_message")
|
|
end
|
|
end
|
|
|
|
def test_extra_whitespace_in_render_with_parenthesis
|
|
assert_digest_difference("messages/edit") do
|
|
change_template("events/_event")
|
|
end
|
|
end
|
|
|
|
def test_old_style_hash_in_render_invocation
|
|
assert_digest_difference("messages/edit") do
|
|
change_template("comments/_comment")
|
|
end
|
|
end
|
|
|
|
def test_variants
|
|
assert_digest_difference("messages/new", variants: [:iphone]) do
|
|
change_template("messages/new", :iphone)
|
|
change_template("messages/_header", :iphone)
|
|
end
|
|
end
|
|
|
|
def test_dependencies_via_options_results_in_different_digest
|
|
digest_plain = digest("comments/_comment")
|
|
digest_fridge = digest("comments/_comment", dependencies: ["fridge"])
|
|
digest_phone = digest("comments/_comment", dependencies: ["phone"])
|
|
digest_fridge_phone = digest("comments/_comment", dependencies: ["fridge", "phone"])
|
|
|
|
assert_not_equal digest_plain, digest_fridge
|
|
assert_not_equal digest_plain, digest_phone
|
|
assert_not_equal digest_plain, digest_fridge_phone
|
|
assert_not_equal digest_fridge, digest_phone
|
|
assert_not_equal digest_fridge, digest_fridge_phone
|
|
assert_not_equal digest_phone, digest_fridge_phone
|
|
end
|
|
|
|
def test_digest_cache_cleanup_with_recursion
|
|
first_digest = digest("level/_recursion")
|
|
second_digest = digest("level/_recursion")
|
|
|
|
assert first_digest
|
|
|
|
# If the cache is cleaned up correctly, subsequent digests should return the same
|
|
assert_equal first_digest, second_digest
|
|
end
|
|
|
|
def test_digest_cache_cleanup_with_recursion_and_template_caching_off
|
|
resolver_before = ActionView::Resolver.caching
|
|
ActionView::Resolver.caching = false
|
|
|
|
first_digest = digest("level/_recursion")
|
|
second_digest = digest("level/_recursion")
|
|
|
|
assert first_digest
|
|
|
|
# If the cache is cleaned up correctly, subsequent digests should return the same
|
|
assert_equal first_digest, second_digest
|
|
ensure
|
|
ActionView::Resolver.caching = resolver_before
|
|
end
|
|
|
|
|
|
private
|
|
def assert_logged(message)
|
|
old_logger = ActionView::Base.logger
|
|
log = StringIO.new
|
|
ActionView::Base.logger = Logger.new(log)
|
|
|
|
begin
|
|
yield
|
|
|
|
log.rewind
|
|
assert_match message, log.read
|
|
ensure
|
|
ActionView::Base.logger = old_logger
|
|
end
|
|
end
|
|
|
|
def assert_digest_difference(template_name, options = {})
|
|
previous_digest = digest(template_name, options)
|
|
finder.digest_cache.clear
|
|
|
|
yield
|
|
|
|
assert_not_equal previous_digest, digest(template_name, options), "digest didn't change"
|
|
finder.digest_cache.clear
|
|
end
|
|
|
|
def digest(template_name, options = {})
|
|
options = options.dup
|
|
|
|
finder.variants = options.delete(:variants) || []
|
|
ActionView::Digestor.digest(name: template_name, finder: finder, dependencies: (options[:dependencies] || []))
|
|
end
|
|
|
|
def dependencies(template_name)
|
|
tree = ActionView::Digestor.tree(template_name, finder)
|
|
tree.children.map(&:name)
|
|
end
|
|
|
|
def nested_dependencies(template_name)
|
|
tree = ActionView::Digestor.tree(template_name, finder)
|
|
tree.children.map(&:to_dep_map)
|
|
end
|
|
|
|
def finder
|
|
@finder ||= FixtureFinder.new
|
|
end
|
|
|
|
def change_template(template_name, variant = nil)
|
|
variant = "+#{variant}" if variant.present?
|
|
|
|
File.open("digestor/#{template_name}.html#{variant}.erb", "w") do |f|
|
|
f.write "\nTHIS WAS CHANGED!"
|
|
end
|
|
end
|
|
alias_method :add_template, :change_template
|
|
|
|
def remove_template(template_name)
|
|
File.delete("digestor/#{template_name}.html.erb")
|
|
end
|
|
end
|