Files
liquid/test/integration/render_profiling_test.rb
Jason Roelofs 173a58d36a Profile liquid rendering
Add a simple profiling system to liquid rendering. Each
liquid tag ({{ }} and {% %}) is processed through this profiling,
keeping track of the partial name (in the case of {% include %}), line
number, and the time it took to render the tag. In the case of {%
include %}, the profiler keeps track of the name of the partial and
properly links back tag rendering to the partial and line number for
easy lookup and dive down. With this, it's now possible to track down
exactly how long each tag takes to render.

These hooks get installed and uninstalled on an as-need basis so by
default there is no impact on the overall liquid execution speed.
2014-08-12 15:37:21 -04:00

143 lines
4.0 KiB
Ruby

require 'test_helper'
class RenderProfilingTest < Minitest::Test
include Liquid
class ProfilingFileSystem
def read_template_file(template_path, context)
"Rendering template {% assign template_name = '#{template_path}'%}\n{{ template_name }}"
end
end
def setup
Liquid::Template.file_system = ProfilingFileSystem.new
end
def test_template_allows_flagging_profiling
t = Template.parse("{{ 'a string' | upcase }}")
t.render!
assert_nil t.profiler
end
def test_parse_makes_available_simple_profiling
t = Template.parse("{{ 'a string' | upcase }}", :profile => true)
t.render!
assert_equal 1, t.profiler.length
node = t.profiler[0]
assert_equal " 'a string' | upcase ", node.code
end
def test_render_ignores_raw_strings_when_profiling
t = Template.parse("This is raw string\nstuff\nNewline", :profile => true)
t.render!
assert_equal 0, t.profiler.length
end
def test_profiling_includes_line_numbers_of_liquid_nodes
t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", :profile => true)
t.render!
assert_equal 2, t.profiler.length
# {{ 'a string' | upcase }}
assert_equal 1, t.profiler[0].line_number
# {{ increment test }}
assert_equal 2, t.profiler[1].line_number
end
def test_profiling_times_the_rendering_of_tokens
t = Template.parse("{% include 'a_template' %}", :profile => true)
t.render!
node = t.profiler[0]
refute_nil node.render_time
end
def test_profiling_times_the_entire_render
t = Template.parse("{% include 'a_template' %}", :profile => true)
t.render!
assert t.profiler.total_render_time > 0, "Total render time was not calculated"
end
def test_profiling_uses_include_to_mark_children
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}", :profile => true)
t.render!
include_node = t.profiler[1]
assert_equal 2, include_node.children.length
end
def test_profiling_marks_children_with_the_name_of_included_partial
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}", :profile => true)
t.render!
include_node = t.profiler[1]
include_node.children.each do |child|
assert_equal "'a_template'", child.partial
end
end
def test_profiling_supports_multiple_templates
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}\n{% include 'b_template' %}", :profile => true)
t.render!
a_template = t.profiler[1]
a_template.children.each do |child|
assert_equal "'a_template'", child.partial
end
b_template = t.profiler[2]
b_template.children.each do |child|
assert_equal "'b_template'", child.partial
end
end
def test_profiling_supports_rendering_the_same_partial_multiple_times
t = Template.parse("{{ 'a string' | upcase }}\n{% include 'a_template' %}\n{% include 'a_template' %}", :profile => true)
t.render!
a_template1 = t.profiler[1]
a_template1.children.each do |child|
assert_equal "'a_template'", child.partial
end
a_template2 = t.profiler[2]
a_template2.children.each do |child|
assert_equal "'a_template'", child.partial
end
end
def test_can_iterate_over_each_profiling_entry
t = Template.parse("{{ 'a string' | upcase }}\n{% increment test %}", :profile => true)
t.render!
timing_count = 0
t.profiler.each do |timing|
timing_count += 1
end
assert_equal 2, timing_count
end
def test_profiling_marks_children_of_if_blocks
t = Template.parse("{% if true %} {% increment test %} {{ test }} {% endif %}", :profile => true)
t.render!
assert_equal 1, t.profiler.length
assert_equal 2, t.profiler[0].children.length
end
def test_profiling_marks_children_of_for_blocks
t = Template.parse("{% for item in collection %} {{ item }} {% endfor %}", :profile => true)
t.render!({"collection" => ["one", "two"]})
assert_equal 1, t.profiler.length
# Will profile each invocation of the for block
assert_equal 2, t.profiler[0].children.length
end
end