diff --git a/lib/rspec-puppet.rb b/lib/rspec-puppet.rb index 2588da4a..502e4348 100644 --- a/lib/rspec-puppet.rb +++ b/lib/rspec-puppet.rb @@ -57,6 +57,7 @@ def self.current_example c.add_setting :fixture_hiera_configs, default: {} c.add_setting :use_fixture_spec_hiera, default: false c.add_setting :fallback_to_default_hiera, default: true + c.add_setting :strict_catalog_encoding, default: false c.before(:all) do RSpec::Puppet::Setup.safe_setup_directories(nil, false) if RSpec.configuration.setup_fixtures? diff --git a/lib/rspec-puppet/adapters.rb b/lib/rspec-puppet/adapters.rb index ca66255e..a81203f2 100644 --- a/lib/rspec-puppet/adapters.rb +++ b/lib/rspec-puppet/adapters.rb @@ -128,6 +128,8 @@ def catalog(node, exported) Puppet::Pops::Evaluator::DeferredResolver.resolve_and_replace(node.facts, catalog) + check_encoding(catalog) + catalog end @@ -179,6 +181,42 @@ def set_facter_impl(impl) impl = impl.call if impl.is_a?(Proc) Object.send(:const_set, :FacterImpl, impl) end + + # Puppet expects source code to be UTF-8, but other inputs to the + # compilation process can cause binary data to be added, which cause + # problems later when serializing the catalog as JSON. Warn or raise if + # there are any ASCII_8BIT strings or the byte representation does not + # match its encoding. + # + def check_encoding(obj, path = '') + case obj + when Puppet::Resource::Catalog + obj.resources.each do |r| + check_encoding(r) + end + when Puppet::Resource + obj.to_hash.each do |param, value| + check_encoding(value, "#{obj.type}[#{obj.title}]/#{param}") + end + when Array + obj.each_with_index do |elem, idx| + check_encoding(elem, "#{path}[#{idx}]") + end + when Hash + obj.each do |k, v| + check_encoding(k, "#{path}/key") + check_encoding(v, "#{path}/value") + end + when String + meth = RSpec.configuration.strict_catalog_encoding ? :raise : :warn + if obj.encoding == Encoding::ASCII_8BIT + send(meth, "#{path} must be wrapped in a Binary data type, not encoded as #{obj.encoding}") + elsif !obj.valid_encoding? + send(meth, "#{path} is not a valid #{obj.encoding} encoded String") + end + end + end + private :check_encoding end def self.get