Skip to content

Commit

Permalink
Add support for evaluating lazy attributes in templates
Browse files Browse the repository at this point in the history
Previously if you had a template with `variables` that used the `lazy`
keyword, previously it was not possible to validate that the blocks
were evaluated in the template. The rendered string would contain an
`<Chef::DelayedEvaluator>` string.

This commit renders the variables to ensure the template renderer
displays the lazily-evaluated values.
  • Loading branch information
stanhu committed Jan 23, 2023
1 parent df9ca04 commit ae77ba2
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 4 deletions.
19 changes: 18 additions & 1 deletion lib/chefspec/renderer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,11 @@ def content_from_template(chef_run, template)

if Chef::Mixin::Template.const_defined?(:TemplateContext) # Chef 11+
template_context = Chef::Mixin::Template::TemplateContext.new([])
variables = template_variables(template)
template_context.update({
node: chef_run.node,
template_finder: template_finder(chef_run, cookbook_name),
}.merge(template.variables))
}.merge(variables))
if template.respond_to?(:helper_modules) # Chef 11.4+
template_context._extend_modules(template.helper_modules)
end
Expand Down Expand Up @@ -141,5 +142,21 @@ def template_finder(chef_run, cookbook_name)
nil
end
end

# Return a hash of template variables. Evaulates any lazy variables.
#
# @param [Chef::Provider::Template] template
# the template resource
#
# @return [Hash]
def template_variables(template)
vars = template.variables.dup

vars.each do |key, value|
vars[key] = value.call if value.is_a?(Proc)
end

vars
end
end
end
42 changes: 39 additions & 3 deletions spec/unit/renderer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
end

let(:chef_run) { double("chef_run", { node: "node" }) }
let(:resource) { double("resource", { cookbook: "cookbook", source: "source", variables: {} }) }
let(:variables) { {} }
let(:resource) { double("resource", { cookbook: "cookbook", source: "source", variables: variables }) }
subject { described_class.new(chef_run, resource) }

describe "#content" do
Expand Down Expand Up @@ -50,20 +51,55 @@
end

describe "content_from_template" do
it "renders the template by extending modules for rendering paritals within the template" do
before do
cookbook_collection = {}
cookbook_collection["cookbook"] = double("", { preferred_filename_on_disk_location: "/template/location" } )
allow(subject).to receive(:cookbook_collection).with("node").and_return(cookbook_collection)
allow(subject).to receive(:template_finder)

allow(resource).to receive(:helper_modules).and_return([Module.new])
allow(resource).to receive(:resource_name).and_return("template")
end

chef_template_context = double("context", { render_template: "rendered template content", update: nil })
it "renders the template by extending modules for rendering paritals within the template" do
chef_template_context = double("context", { render_template: 'rendered template content', update: nil })
allow(Chef::Mixin::Template::TemplateContext).to receive(:new).and_return(chef_template_context)

expect(chef_template_context).to receive(:_extend_modules).with(resource.helper_modules)

expect(subject.content).to eq("rendered template content")
end

context 'with lazy variables' do
let(:variables) { { 'a' => 1, 'b' => Chef::DelayedEvaluator.new { 2 } } }

let(:template_context) do
Class.new do
def render_template(template)
@attributes.to_json
end

def update(attributes)
@attributes = attributes
end

def _extend_modules(module_names)
end
end
end

let(:chef_template_context) { template_context.new }

before do
allow(Chef::Mixin::Template::TemplateContext).to receive(:new).and_return(chef_template_context)
end

it 'renders the template by evaulating the lazy variables' do
data = JSON.load(subject.content)

expect(data['a']).to eq(1)
expect(data['b']).to eq(2)
end
end
end
end

0 comments on commit ae77ba2

Please sign in to comment.