Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions examples/liquid_ruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,19 @@
end

LiquidSpec.render do |ctx, assigns, render_options|
resource_limits = if render_options[:resource_limits]
limits = Liquid::ResourceLimits.new({})
render_options[:resource_limits].each do |key, value|
limits.send(:"#{key}=", value)
end
limits
end

context = Liquid::Context.build(
static_environments: assigns,
registers: Liquid::Registers.new(render_options[:registers] || {}),
rethrow_errors: render_options[:strict_errors],
resource_limits: resource_limits,
)
context.exception_renderer = render_options[:exception_renderer] if render_options[:exception_renderer]

Expand Down
1 change: 1 addition & 0 deletions lib/liquid/spec/cli/runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1399,6 +1399,7 @@ def run_single_spec(spec, _config)
render_options = {
registers: build_registers(spec, filesystem),
strict_errors: !render_errors,
resource_limits: spec.raw_resource_limits.empty? ? nil : spec.raw_resource_limits,
}.compact

begin
Expand Down
4 changes: 3 additions & 1 deletion lib/liquid/spec/lazy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class LazySpec
attr_reader :name, :template, :template_name, :expected, :expected_pattern, :errors, :hint, :doc, :complexity
attr_reader :error_mode, :render_errors, :required_features
attr_reader :source_file, :line_number
attr_reader :raw_environment, :raw_filesystem, :raw_template_factory
attr_reader :raw_environment, :raw_filesystem, :raw_template_factory, :raw_resource_limits

def initialize(
name:,
Expand All @@ -50,6 +50,7 @@ def initialize(
raw_environment: {},
raw_filesystem: {},
raw_template_factory: nil,
raw_resource_limits: {},
source_hint: nil,
source_required_options: {}
)
Expand All @@ -70,6 +71,7 @@ def initialize(
@raw_environment = raw_environment || {}
@raw_filesystem = raw_filesystem || {}
@raw_template_factory = raw_template_factory
@raw_resource_limits = raw_resource_limits || {}
@source_hint = source_hint
@source_required_options = source_required_options || {}

Expand Down
3 changes: 2 additions & 1 deletion lib/liquid/spec/spec_loader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ module SpecLoader
VALID_METADATA_KEYS = %w[hint doc required_options render_errors minimum_complexity complexity required_features data_files].freeze
VALID_SPEC_KEYS = %w[
name template expected expected_pattern environment filesystem complexity hint doc
error_mode render_errors required_features errors template_name
error_mode render_errors required_features errors template_name resource_limits
].freeze

class << self
Expand Down Expand Up @@ -259,6 +259,7 @@ def load_yaml_file(path, suite: nil)
raw_environment: raw_env,
raw_filesystem: spec_data["filesystem"] || {},
raw_template_factory: spec_data["template_factory"],
raw_resource_limits: spec_data["resource_limits"],
source_hint: source_hint,
source_required_options: source_required_options,
)
Expand Down
49 changes: 49 additions & 0 deletions specs/basics/resource-limits.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
_metadata:
hint: |
Tests for resource limit enforcement during rendering.
Cumulative scores survive reset() across partial renders,
preventing unbounded work via many small partials.
complexity: 300
required_features:
- core

specs:
- name: cumulative_render_score_across_partials
template: "{% render 'a' %}{% render 'b' %}{% render 'c' %}"
filesystem:
a: "{% for i in (1..10) %}x{% endfor %}"
b: "{% for i in (1..10) %}x{% endfor %}"
c: "{% for i in (1..10) %}x{% endfor %}"
resource_limits:
render_score_limit: 100
cumulative_render_score_limit: 25
errors:
render_error:
- Liquid error
hint: |
Each partial renders a for-loop scoring ~10 points. Per-template limit (100)
is fine, but cumulative limit (25) is exceeded after the second partial.

- name: cumulative_limits_not_triggered_when_unset
template: "{% render 'a' %}{% render 'b' %}"
filesystem:
a: "{% for i in (1..5) %}x{% endfor %}"
b: "{% for i in (1..5) %}y{% endfor %}"
resource_limits:
render_score_limit: 100
expected: "xxxxxyyyyy"
hint: |
Without cumulative limits set, partials render normally even though
cumulative score grows. Only per-template limits are checked.

- name: per_template_limit_still_works_with_cumulative
template: "{% for i in (1..100) %}x{% endfor %}"
resource_limits:
render_score_limit: 10
cumulative_render_score_limit: 1000
errors:
render_error:
- Liquid error
hint: |
Per-template render_score_limit (10) fires even when
cumulative_render_score_limit (1000) is generous.
Loading