Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to get the content of a rendered .erb template as a string? #778

Open
enricovianello opened this issue Dec 12, 2019 · 4 comments
Open

Comments

@enricovianello
Copy link

I have a resource which creates an XML file via an erb template and I'd like to test its content via XPath. I found Nokogiri library and it works but I need to access the content of the rendered file as a string.

I tried:

content = catalogue.resource('file', '/path/to/file.xml').send(:parameters)[:content]

but I get:

undefined method `parameters' for nil:NilClass

My puppet version is 5.5.17.
Is there an alternative way to access the content of a rendered .erb template as a string?

@ekohl
Copy link
Contributor

ekohl commented Dec 19, 2019

Why can't you use contain_file('/path/to/file.xml').with_content()?

@enricovianello
Copy link
Author

@ekohl Because I'd like to query the content of my XML file with XPath, in order to improve the maintainability of my tests but, for all I know, only a regex is supported with .with_content () method. Or am I wrong?

@ekohl
Copy link
Contributor

ekohl commented Jan 2, 2020

This happens when the resource is not found in the catalog. We have similar helpers and they start with is_expected.to contain_file(title) to ensure the resource is actually in the catalog. Currently in our modules we have a helper:

def get_content(subject, title)
  is_expected.to contain_file(title)
  content = subject.resource('file', title).send(:parameters)[:content]
  content.split(/\n/).reject { |line| line =~ /(^#|^$|^\s+#)/ }
end

While looking at this issue, I checked the source and the alternative is to use a proc:

it { is_expected.to contain_concat__fragment(title).with_content(Proc.new { |content| content.split("\n") & expected_lines == expected_lines}) }

The downside of this is that the error reporting is not great: the to_s of a Proc is not useful. This leads to failures (cut down for readability):

expected that the catalogue would contain Concat::Fragment[foreman_settings+01-header.yaml] with content set to #<Proc:0x0000564ec832c950@/home/ekohl/dev/puppet-foreman/spec/spec_helper.rb:61> but it is set to "---\n### File managed with puppet ###\n## Module:
Diff:
@@ -1,2 +1,62 @@
-#<Proc:0x0000564ec832c950@/home/ekohl/dev/puppet-foreman/spec/spec_helper.rb:61>
+---
+### File managed with puppet ###
+## Module:           'foreman'

A more advanced example would be to use a class:

class ValidateConcatFragmentContent
  def initialize(expected_lines)
    @expected_lines = expected_lines
  end

  def call(content)
    content.split("\n") & @expected_lines == @expected_lines
  end

  def to_s
    @expected_lines.join("\n")
  end
end

it { is_expected.to contain_concat__fragment(title).with_content(ValidateConcatFragmentContent.new(expected_lines)) }

Now the error reporting is better:

expected that the catalogue would contain Concat::Fragment[foreman_settings+01-header.yaml] with content set to #<ValidateConcatFragmentContent:0x0000557a165390b8 @expected_lines=[":lgging:", "  :level: info", "  :production:", "    :type: journald", "    :layout: pattern"]> but it is set to "---\n### File managed with puppet ###\n## Module:           'foreman'
Diff:

@@ -1,6 +1,62 @@
-:lgging:
+---
+### File managed with puppet ###
+## Module:           'foreman'
+:logging:
   :level: info
   :production:
     :type: journald
     :layout: pattern

Perhaps the code should be extended to allow raising an error to allow customizing the message. See

def check_proc(expected, actual)
expected_return = @should_match
actual_return = expected.call(actual)
actual_return == expected_return
end

@ekohl
Copy link
Contributor

ekohl commented Jan 2, 2020

Looking closer it appears the call was not actually called since it's now a class and not a proc. It just matched the to_s representation. It may be better to write a custom matcher or use the workaround of first checking if the catalog really contains the desired resource.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants