diff --git a/lib/hiera/puppet_function.rb b/lib/hiera/puppet_function.rb index a42821c2d..6eddfbe13 100644 --- a/lib/hiera/puppet_function.rb +++ b/lib/hiera/puppet_function.rb @@ -1,71 +1,82 @@ require 'hiera_puppet' # Provides the base class for the puppet functions hiera, hiera_array, hiera_hash, and hiera_include. # The actual function definitions will call init_dispatch and override the merge_type and post_lookup methods. # # @see hiera_array.rb, hiera_include.rb under lib/puppet/functions for sample usage # class Hiera::PuppetFunction < Puppet::Functions::InternalFunction def self.init_dispatch dispatch :hiera_splat do scope_param param 'Tuple[String, Any, Any, 1, 3]', :args end - dispatch :hiera do + dispatch :hiera_no_default do scope_param param 'String',:key - optional_param 'Any', :default + end + + dispatch :hiera_with_default do + scope_param + param 'String',:key + param 'Any', :default optional_param 'Any', :override end dispatch :hiera_block1 do scope_param param 'String', :key block_param 'Callable[1,1]', :default_block end dispatch :hiera_block2 do scope_param param 'String', :key param 'Any', :override block_param 'Callable[1,1]', :default_block end end def hiera_splat(scope, args) hiera(scope, *args) end - def hiera(scope, key, default = nil, override = nil) - post_lookup(key, lookup(scope, key, default, override)) + def hiera_no_default(scope, key) + post_lookup(key, lookup(scope, key, nil, nil)) + end + + def hiera_with_default(scope, key, default, override = nil) + undefined = (@@undefined_value ||= Object.new) + result = lookup(scope, key, undefined, override) + post_lookup(key, result.equal?(undefined) ? default : result) end def hiera_block1(scope, key, &default_block) common(scope, key, nil, default_block) end def hiera_block2(scope, key, override, &default_block) common(scope, key, override, default_block) end def common(scope, key, override, default_block) undefined = (@@undefined_value ||= Object.new) result = lookup(scope, key, undefined, override) post_lookup(key, result.equal?(undefined) ? default_block.call(key) : result) end private :common def lookup(scope, key, default, override) HieraPuppet.lookup(key, default,scope, override, merge_type) end def merge_type :priority end def post_lookup(key, result) result end end diff --git a/spec/unit/functions/hiera_spec.rb b/spec/unit/functions/hiera_spec.rb index b9b7b2206..fb0468673 100755 --- a/spec/unit/functions/hiera_spec.rb +++ b/spec/unit/functions/hiera_spec.rb @@ -1,127 +1,129 @@ require 'spec_helper' require 'puppet_spec/scope' require 'puppet/pops' require 'puppet/loaders' describe 'when calling' do include PuppetSpec::Scope let(:scope) { create_test_scope_for_node('foo') } let(:loaders) { Puppet::Pops::Loaders.new(Puppet::Node::Environment.create(:testing, [])) } let(:loader) { loaders.puppet_system_loader } context 'hiera' do let(:hiera) { loader.load(:function, 'hiera') } it 'should require a key argument' do expect { hiera.call(scope, []) }.to raise_error(ArgumentError) end it 'should raise a useful error when nil is returned' do expect { hiera.call(scope, 'badkey') }.to raise_error(Puppet::ParseError, /Could not find data item badkey/) end it 'should use the priority resolution_type' do Hiera.any_instance.expects(:lookup).with { |*args| args[4].should be(:priority) }.returns('foo_result') expect(hiera.call(scope, 'key')).to eql('foo_result') end - it 'should propagate optional default' do - dflt = 'the_default' - Hiera.any_instance.expects(:lookup).with { |*args| args[1].should be(dflt) }.returns('foo_result') - expect(hiera.call(scope, 'key', dflt)).to eql('foo_result') - end - it 'should propagate optional override' do ovr = 'the_override' Hiera.any_instance.expects(:lookup).with { |*args| args[3].should be(ovr) }.returns('foo_result') expect(hiera.call(scope, 'key', nil, ovr)).to eql('foo_result') end + it 'should return default value nil when key is not found' do + expect(hiera.call(scope, 'foo', nil)).to be_nil + end + + it "should return default value '' when key is not found" do + expect(hiera.call(scope, 'foo', '')).to eq('') + end + it 'should use default block' do #expect(hiera.call(scope, 'foo', lambda_1(scope, loader) { |k| "default for key '#{k}'" })).to eql("default for key 'foo'") expect(hiera.call(scope, 'foo') { |k| "default for key '#{k}'" }).to eql("default for key 'foo'") end # Test disabled since it assumes that Yaml_backend returns nil when a key is not found and that this # triggers use of default. This changes in Hiera 2.0 so that the backend throws a :no_such_key exception. # Changing that here will invalidate tests using hiera stable. # # it 'should propagate optional override when combined with default block' do # ovr = 'the_override' # Hiera::Backend::Yaml_backend.any_instance.expects(:lookup).with { |*args| args[2].should be(ovr) } # expect(hiera.call(scope, 'foo', ovr) { |k| "default for key '#{k}'" }).to eql("default for key 'foo'") # end end context 'hiera_array' do # noinspection RubyResolve let(:hiera_array) { loader.load(:function, 'hiera_array') } it 'should require a key argument' do expect { hiera_array.call(scope, []) }.to raise_error(ArgumentError) end it 'should raise a useful error when nil is returned' do expect { hiera_array.call(scope, 'badkey') }.to raise_error(Puppet::ParseError, /Could not find data item badkey/) end it 'should use the array resolution_type' do Hiera.any_instance.expects(:lookup).with { |*args| args[4].should be(:array) }.returns(%w[foo bar baz]) expect(hiera_array.call(scope, 'key', {'key' => 'foo_result'})).to eql(%w[foo bar baz]) end it 'should use default block' do expect(hiera_array.call(scope, 'foo') { |k| ['key', k] }).to eql(%w[key foo]) end end context 'hiera_hash' do let(:hiera_hash) { loader.load(:function, 'hiera_hash') } it 'should require a key argument' do expect { hiera_hash.call(scope, []) }.to raise_error(ArgumentError) end it 'should raise a useful error when nil is returned' do expect { hiera_hash.call(scope, 'badkey') }.to raise_error(Puppet::ParseError, /Could not find data item badkey/) end it 'should use the hash resolution_type' do Hiera.any_instance.expects(:lookup).with { |*args| args[4].should be(:hash) }.returns({'foo' => 'result'}) expect(hiera_hash.call(scope, 'key', {'key' => 'foo_result'})).to eql({'foo' => 'result'}) end it 'should use default block' do expect(hiera_hash.call(scope, 'foo') { |k| {'key' => k} }).to eql({'key' => 'foo'}) end end context 'hiera_include' do let(:hiera_include) { loader.load(:function, 'hiera_include') } it 'should require a key argument' do expect { hiera_include.call(scope, []) }.to raise_error(ArgumentError) end it 'should raise a useful error when nil is returned' do expect { hiera_include.call(scope, 'badkey') }.to raise_error(Puppet::ParseError, /Could not find data item badkey/) end it 'should use the array resolution_type' do Hiera.any_instance.expects(:lookup).with { |*args| args[4].should be(:array) }.returns(%w[foo bar baz]) hiera_include.expects(:call_function).with('include', %w[foo bar baz]) hiera_include.call(scope, 'key', {'key' => 'foo_result'}) end it 'should not raise an error if the resulting hiera lookup returns an empty array' do Hiera.any_instance.expects(:lookup).returns [] expect { hiera_include.call(scope, 'key') }.to_not raise_error end it 'should use default block' do hiera_include.expects(:call_function).with('include', %w[key foo]) hiera_include.call(scope, 'foo') { |k| ['key', k] } end end end