hiera 1.3.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,28 +1,71 @@
1
1
  require 'hiera/backend'
2
+ require 'hiera/recursive_guard'
3
+
4
+
5
+ class Hiera::InterpolationInvalidValue < StandardError; end
2
6
 
3
7
  class Hiera::Interpolate
4
8
  class << self
5
9
  INTERPOLATION = /%\{([^\}]*)\}/
6
- METHOD_INTERPOLATION = /%\{(scope|hiera)\(['"]([^"']*)["']\)\}/
10
+ METHOD_INTERPOLATION = /%\{(scope|hiera|literal|alias)\(['"]([^"']*)["']\)\}/
11
+
12
+ def interpolate(data, scope, extra_data, context)
13
+ if data.is_a?(String)
14
+ # Wrapping do_interpolation in a gsub block ensures we process
15
+ # each interpolation site in isolation using separate recursion guards.
16
+ context ||= {}
17
+ new_context = context.clone
18
+ new_context[:recurse_guard] ||= Hiera::RecursiveGuard.new
19
+ data.gsub(INTERPOLATION) do |match|
20
+ interp_val = do_interpolation(match, scope, extra_data, new_context)
7
21
 
8
- def interpolate(data, recurse_guard, scope, extra_data)
22
+ # Get interp method in case we are aliasing
23
+ if data.is_a?(String) && (match = data.match(INTERPOLATION))
24
+ interpolate_method, key = get_interpolation_method_and_key(data)
25
+ else
26
+ interpolate_method = nil
27
+ end
28
+
29
+ if ( (interpolate_method == :alias_interpolate) and (!interp_val.is_a?(String)) )
30
+ if data.match("^#{INTERPOLATION}$")
31
+ return interp_val
32
+ else
33
+ raise Hiera::InterpolationInvalidValue, "Cannot call alias in the string context"
34
+ end
35
+ else
36
+ interp_val
37
+ end
38
+ end
39
+ else
40
+ data
41
+ end
42
+ end
43
+
44
+ def do_interpolation(data, scope, extra_data, context)
9
45
  if data.is_a?(String) && (match = data.match(INTERPOLATION))
10
46
  interpolation_variable = match[1]
11
- recurse_guard.check(interpolation_variable) do
47
+ context[:recurse_guard].check(interpolation_variable) do
12
48
  interpolate_method, key = get_interpolation_method_and_key(data)
13
- interpolated_data = send(interpolate_method, data, key, scope, extra_data)
14
- interpolate(interpolated_data, recurse_guard, scope, extra_data)
49
+ interpolated_data = send(interpolate_method, data, key, scope, extra_data, context)
50
+
51
+ # Halt recursion if we encounter a literal.
52
+ return interpolated_data if interpolate_method == :literal_interpolate
53
+
54
+ do_interpolation(interpolated_data, scope, extra_data, context)
15
55
  end
16
56
  else
17
57
  data
18
58
  end
19
59
  end
60
+ private :do_interpolation
20
61
 
21
62
  def get_interpolation_method_and_key(data)
22
63
  if (match = data.match(METHOD_INTERPOLATION))
23
64
  case match[1]
24
65
  when 'hiera' then [:hiera_interpolate, match[2]]
25
66
  when 'scope' then [:scope_interpolate, match[2]]
67
+ when 'literal' then [:literal_interpolate, match[2]]
68
+ when 'alias' then [:alias_interpolate, match[2]]
26
69
  end
27
70
  elsif (match = data.match(INTERPOLATION))
28
71
  [:scope_interpolate, match[1]]
@@ -30,19 +73,26 @@ class Hiera::Interpolate
30
73
  end
31
74
  private :get_interpolation_method_and_key
32
75
 
33
- def scope_interpolate(data, key, scope, extra_data)
34
- value = scope[key]
35
- if value.nil? || value == :undefined
36
- value = extra_data[key]
37
- end
38
- data.sub(INTERPOLATION, value.to_s)
76
+ def scope_interpolate(data, key, scope, extra_data, context)
77
+ segments = key.split('.')
78
+ catch(:no_such_key) { return Hiera::Backend.qualified_lookup(segments, scope) }
79
+ catch(:no_such_key) { Hiera::Backend.qualified_lookup(segments, extra_data) }
39
80
  end
40
81
  private :scope_interpolate
41
82
 
42
- def hiera_interpolate(data, key, scope, extra_data)
43
- value = Hiera::Backend.lookup(key, nil, scope, nil, :priority)
44
- data.sub(METHOD_INTERPOLATION, value)
83
+ def hiera_interpolate(data, key, scope, extra_data, context)
84
+ Hiera::Backend.lookup(key, nil, scope, context[:order_override], :priority, context)
45
85
  end
46
86
  private :hiera_interpolate
87
+
88
+ def literal_interpolate(data, key, scope, extra_data, context)
89
+ key
90
+ end
91
+ private :literal_interpolate
92
+
93
+ def alias_interpolate(data, key, scope, extra_data, context)
94
+ Hiera::Backend.lookup(key, nil, scope, context[:order_override], :priority, context)
95
+ end
96
+ private :alias_interpolate
47
97
  end
48
98
  end
data/lib/hiera/util.rb CHANGED
@@ -9,7 +9,7 @@ class Hiera
9
9
 
10
10
  def microsoft_windows?
11
11
  return false unless file_alt_separator
12
-
12
+
13
13
  begin
14
14
  require 'win32/dir'
15
15
  true
@@ -21,17 +21,17 @@ class Hiera
21
21
 
22
22
  def config_dir
23
23
  if microsoft_windows?
24
- File.join(common_appdata, 'PuppetLabs', 'hiera', 'etc')
24
+ File.join(common_appdata, 'PuppetLabs', 'code')
25
25
  else
26
- '/etc'
26
+ '/etc/puppetlabs/code'
27
27
  end
28
28
  end
29
29
 
30
30
  def var_dir
31
31
  if microsoft_windows?
32
- File.join(common_appdata, 'PuppetLabs', 'hiera', 'var')
32
+ File.join(common_appdata, 'PuppetLabs', 'code', 'hieradata')
33
33
  else
34
- '/var/lib/hiera'
34
+ '/etc/puppetlabs/code/hieradata'
35
35
  end
36
36
  end
37
37
 
data/lib/hiera/version.rb CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
 
9
9
  class Hiera
10
- VERSION = "1.3.0"
10
+ VERSION = "2.0.0"
11
11
 
12
12
  ##
13
13
  # version is a public API method intended to always provide a fast and
data/lib/hiera.rb CHANGED
@@ -49,15 +49,67 @@ class Hiera
49
49
 
50
50
  # Calls the backends to do the actual lookup.
51
51
  #
52
- # The scope can be anything that responds to [], if you have input
52
+ # The _scope_ can be anything that responds to `[]`, if you have input
53
53
  # data like a Puppet Scope that does not you can wrap that data in a
54
- # class that has a [] method that fetches the data from your source.
54
+ # class that has a `[]` method that fetches the data from your source.
55
55
  # See hiera-puppet for an example of this.
56
56
  #
57
57
  # The order-override will insert as first in the hierarchy a data source
58
58
  # of your choice.
59
+ #
60
+ # Possible values for the _resolution_type_ parameter:
61
+ #
62
+ # - _:priority_ - This is the default. First found value is returned and no merge is performed
63
+ # - _:array_ - An array merge lookup assembles a value from every matching level of the hierarchy. It retrieves all
64
+ # of the (string or array) values for a given key, then flattens them into a single array of unique values.
65
+ # If _priority_ lookup can be thought of as a “default with overrides” pattern, _array_ merge lookup can be though
66
+ # of as “default with additions.”
67
+ # - _:hash_ - A hash merge lookup assembles a value from every matching level of the hierarchy. It retrieves all of
68
+ # the (hash) values for a given key, then merges the hashes into a single hash. Hash merge lookups will fail with
69
+ # an error if any of the values found in the data sources are strings or arrays. It only works when every value
70
+ # found is a hash. The actual merge behavior is determined by looking up the keys `:merge_behavior` and
71
+ # `:deep_merge_options` in the Hiera config. `:merge_behavior` can be set to `:deep`, :deeper` or `:native`
72
+ # (explained in detail below).
73
+ # - _{ deep merge options }_ - Configured values for `:merge_behavior` and `:deep_merge_options`will be completely
74
+ # ignored. Instead the _resolution_type_ will be a `:hash` merge where the `:merge_behavior` will be the value
75
+ # keyed by `:behavior` in the given hash and the `:deep_merge_options` will be the remaining top level entries of
76
+ # that same hash.
77
+ #
78
+ # Valid behaviors for the _:hash_ resolution type:
79
+ #
80
+ # - _native_ - Performs a simple hash-merge by overwriting keys of lower lookup priority.
81
+ # - _deeper_ - In a deeper hash merge, Hiera recursively merges keys and values in each source hash. For each key,
82
+ # if the value is:
83
+ # - only present in one source hash, it goes into the final hash.
84
+ # - a string/number/boolean and exists in two or more source hashes, the highest priority value goes into
85
+ # the final hash.
86
+ # - an array and exists in two or more source hashes, the values from each source are merged into a single
87
+ # array and de-duplicated (but not automatically flattened, as in an array merge lookup).
88
+ # - a hash and exists in two or more source hashes, the values from each source are recursively merged, as
89
+ # though they were source hashes.
90
+ # - mismatched between two or more source hashes, we haven’t validated the behavior. It should act as
91
+ # described in the deep_merge gem documentation.
92
+ # - _deep_ - In a deep hash merge, Hiera behaves the same as for _deeper_, except that when a string/number/boolean
93
+ # exists in two or more source hashes, the lowest priority value goes into the final hash. This is considered
94
+ # largely useless and should be avoided. Use _deeper_ instead.
95
+ #
96
+ # The _merge_ can be given as a hash with the mandatory key `:strategy` to denote the actual strategy. This
97
+ # is useful for the `:deeper` and `:deep` strategy since they can use additional options to control the behavior.
98
+ # The options can be passed as top level keys in the `merge` parameter when it is a given as a hash. Recognized
99
+ # options are:
100
+ #
101
+ # - 'knockout_prefix' Set to string value to signify prefix which deletes elements from existing element. Defaults is _undef_
102
+ # - 'sort_merged_arrays' Set to _true_ to sort all arrays that are merged together. Default is _false_
103
+ # - 'unpack_arrays' Set to string value used as a deliminator to join all array values and then split them again. Default is _undef_
104
+ # - 'merge_hash_arrays' Set to _true_ to merge hashes within arrays. Default is _false_
105
+ #
106
+ # @param key [String] The key to lookup
107
+ # @param default [Object,nil] The value to return when there is no match for _key_
108
+ # @param scope [#[],nil] The scope to use for the lookup
109
+ # @param order_override [#[]] An override that will considered the first source of lookup
110
+ # @param resolution_type [String,Hash<Symbol,String>] Symbolic resolution type or deep merge configuration
111
+ # @return [Object] The found value or the given _default_ value
59
112
  def lookup(key, default, scope, order_override=nil, resolution_type=:priority)
60
113
  Backend.lookup(key, default, scope, order_override, resolution_type)
61
114
  end
62
115
  end
63
-
data/spec/spec_helper.rb CHANGED
@@ -8,6 +8,29 @@ require 'tmpdir'
8
8
 
9
9
  RSpec.configure do |config|
10
10
  config.mock_with :mocha
11
+
12
+ if Hiera::Util.microsoft_windows? && RUBY_VERSION =~ /^1\./
13
+ require 'win32console'
14
+ config.output_stream = $stdout
15
+ config.error_stream = $stderr
16
+ config.formatters.each { |f| f.instance_variable_set(:@output, $stdout) }
17
+ end
18
+
19
+ config.after :suite do
20
+ # Log the spec order to a file, but only if the LOG_SPEC_ORDER environment variable is
21
+ # set. This should be enabled on Jenkins runs, as it can be used with Nick L.'s bisect
22
+ # script to help identify and debug order-dependent spec failures.
23
+ if ENV['LOG_SPEC_ORDER']
24
+ File.open("./spec_order.txt", "w") do |logfile|
25
+ config.instance_variable_get(:@files_to_run).each { |f| logfile.puts f }
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ # So everyone else doesn't have to include this base constant.
32
+ module HieraSpec
33
+ FIXTURE_DIR = File.join(dir = File.expand_path(File.dirname(__FILE__)), 'unit', 'fixtures') unless defined?(FIXTURE_DIR)
11
34
  end
12
35
 
13
36
  # In ruby 1.8.5 Dir does not have mktmpdir defined, so this monkey patches
@@ -25,7 +25,7 @@ class Hiera
25
25
  Backend.expects(:datafile).with(:json, {}, "one", "json").returns(nil)
26
26
  Backend.expects(:datafile).with(:json, {}, "two", "json").returns(nil)
27
27
 
28
- @backend.lookup("key", {}, nil, :priority)
28
+ expect { @backend.lookup("key", {}, nil, :priority, nil) }.to throw_symbol(:no_such_key)
29
29
  end
30
30
 
31
31
  it "should retain the data types found in data files" do
@@ -35,9 +35,9 @@ class Hiera
35
35
 
36
36
  @cache.expects(:read_file).with("/nonexisting/one.json", Hash).returns({"stringval" => "string", "boolval" => true, "numericval" => 1}).times(3)
37
37
 
38
- @backend.lookup("stringval", {}, nil, :priority).should == "string"
39
- @backend.lookup("boolval", {}, nil, :priority).should == true
40
- @backend.lookup("numericval", {}, nil, :priority).should == 1
38
+ @backend.lookup("stringval", {}, nil, :priority, nil).should == "string"
39
+ @backend.lookup("boolval", {}, nil, :priority, nil).should == true
40
+ @backend.lookup("numericval", {}, nil, :priority, nil).should == 1
41
41
  end
42
42
 
43
43
  it "should pick data earliest source that has it for priority searches" do
@@ -49,12 +49,12 @@ class Hiera
49
49
  File.stubs(:exist?).with("/nonexisting/one.json").returns(true)
50
50
  @cache.expects(:read_file).with("/nonexisting/one.json", Hash).returns({"key" => "test_%{rspec}"})
51
51
 
52
- @backend.lookup("key", scope, nil, :priority).should == "test_test"
52
+ @backend.lookup("key", scope, nil, :priority, nil).should == "test_test"
53
53
  end
54
54
 
55
55
  it "should build an array of all data sources for array searches" do
56
56
  Hiera::Backend.stubs(:empty_answer).returns([])
57
- Backend.stubs(:parse_answer).with('answer', {}).returns("answer")
57
+ Backend.stubs(:parse_answer).with('answer', {}, {}, anything).returns("answer")
58
58
  Backend.expects(:datafile).with(:json, {}, "one", "json").returns("/nonexisting/one.json")
59
59
  Backend.expects(:datafile).with(:json, {}, "two", "json").returns("/nonexisting/two.json")
60
60
 
@@ -66,18 +66,18 @@ class Hiera
66
66
  @cache.expects(:read_file).with("/nonexisting/one.json", Hash).returns({"key" => "answer"})
67
67
  @cache.expects(:read_file).with("/nonexisting/two.json", Hash).returns({"key" => "answer"})
68
68
 
69
- @backend.lookup("key", {}, nil, :array).should == ["answer", "answer"]
69
+ @backend.lookup("key", {}, nil, :array, nil).should == ["answer", "answer"]
70
70
  end
71
71
 
72
72
  it "should parse the answer for scope variables" do
73
- Backend.stubs(:parse_answer).with('test_%{rspec}', {'rspec' => 'test'}).returns("test_test")
73
+ Backend.stubs(:parse_answer).with('test_%{rspec}', {'rspec' => 'test'}, {}, anything).returns("test_test")
74
74
  Backend.expects(:datasources).yields("one")
75
75
  Backend.expects(:datafile).with(:json, {"rspec" => "test"}, "one", "json").returns("/nonexisting/one.json")
76
76
 
77
77
  File.expects(:exist?).with("/nonexisting/one.json").returns(true)
78
78
  @cache.expects(:read_file).with("/nonexisting/one.json", Hash).returns({"key" => "test_%{rspec}"})
79
79
 
80
- @backend.lookup("key", {"rspec" => "test"}, nil, :priority).should == "test_test"
80
+ @backend.lookup("key", {"rspec" => "test"}, nil, :priority, nil).should == "test_test"
81
81
  end
82
82
  end
83
83
  end
@@ -3,12 +3,29 @@ require 'hiera/backend/yaml_backend'
3
3
 
4
4
  class Hiera
5
5
  module Backend
6
+ class FakeCache
7
+ attr_accessor :value
8
+ def read(path, expected_type, default, &block)
9
+ read_file(path, expected_type, &block)
10
+ rescue => e
11
+ default
12
+ end
13
+
14
+ def read_file(path, expected_type, &block)
15
+ output = block.call(@value)
16
+ if !output.is_a? expected_type
17
+ raise TypeError
18
+ end
19
+ output
20
+ end
21
+ end
22
+
6
23
  describe Yaml_backend do
7
24
  before do
8
25
  Config.load({})
9
26
  Hiera.stubs(:debug)
10
27
  Hiera.stubs(:warn)
11
- @cache = mock
28
+ @cache = FakeCache.new
12
29
  @backend = Yaml_backend.new(@cache)
13
30
  end
14
31
 
@@ -20,128 +37,100 @@ class Hiera
20
37
  end
21
38
 
22
39
  describe "#lookup" do
23
- it "should look for data in all sources" do
24
- Backend.expects(:datasources).multiple_yields(["one"], ["two"])
25
- Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns(nil)
26
- Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns(nil)
27
-
28
- @backend.lookup("key", {}, nil, :priority)
29
- end
30
-
31
40
  it "should pick data earliest source that has it for priority searches" do
32
- Backend.expects(:datasources).multiple_yields(["one"], ["two"])
33
- Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml")
34
- Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns(nil).never
35
- @cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({"key"=>"answer"})
36
- File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
37
-
38
- @backend.lookup("key", {}, nil, :priority).should == "answer"
39
- end
41
+ Backend.expects(:datasourcefiles).with(:yaml, {}, "yaml", nil).yields(["one", "/nonexisting/one.yaml"])
42
+ @cache.value = "---\nkey: answer"
40
43
 
41
- it "should not look up missing data files" do
42
- Backend.expects(:datasources).multiple_yields(["one"])
43
- Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns(nil)
44
- YAML.expects(:load_file).never
45
-
46
- @backend.lookup("key", {}, nil, :priority)
44
+ @backend.lookup("key", {}, nil, :priority, nil).should == "answer"
47
45
  end
48
46
 
49
- it "should return nil for empty data files" do
50
- Backend.expects(:datasources).multiple_yields(["one"])
51
- Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml")
52
- File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
53
- @cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({})
54
-
55
- @backend.lookup("key", {}, nil, :priority).should be_nil
47
+ describe "handling unexpected YAML values" do
48
+ before do
49
+ Backend.expects(:datasourcefiles).with(:yaml, {}, "yaml", nil).yields(["one", "/nonexisting/one.yaml"])
50
+ end
51
+
52
+ it "throws :no_such_key when key is missing in YAML" do
53
+ @cache.value = "---\n"
54
+ expect { @backend.lookup("key", {}, nil, :priority, nil) }.to throw_symbol(:no_such_key)
55
+ end
56
+
57
+ it "returns nil when the YAML value is nil" do
58
+ @cache.value = "key: ~\n"
59
+ @backend.lookup("key", {}, nil, :priority, nil).should be_nil
60
+ end
61
+
62
+ it "throws :no_such_key when the YAML file is false" do
63
+ @cache.value = ""
64
+ expect { @backend.lookup("key", {}, nil, :priority, nil) }.to throw_symbol(:no_such_key)
65
+ end
66
+
67
+ it "raises a TypeError when the YAML value is not a hash" do
68
+ @cache.value = "---\n[one, two, three]"
69
+ expect { @backend.lookup("key", {}, nil, :priority, nil) }.to raise_error(TypeError)
70
+ end
56
71
  end
57
72
 
58
73
  it "should build an array of all data sources for array searches" do
59
- Backend.expects(:datasources).multiple_yields(["one"], ["two"])
60
- Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml")
61
- Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns("/nonexisting/two.yaml")
62
- File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
63
- File.stubs(:exist?).with("/nonexisting/two.yaml").returns(true)
64
-
74
+ Backend.expects(:datasourcefiles).with(:yaml, {}, "yaml", nil).multiple_yields(["one", "/nonexisting/one.yaml"], ["two", "/nonexisting/two.yaml"])
65
75
  @cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({"key"=>"answer"})
66
76
  @cache.expects(:read_file).with("/nonexisting/two.yaml", Hash).returns({"key"=>"answer"})
67
77
 
68
- @backend.lookup("key", {}, nil, :array).should == ["answer", "answer"]
78
+ @backend.lookup("key", {}, nil, :array, nil).should == ["answer", "answer"]
69
79
  end
70
80
 
71
81
  it "should ignore empty hash of data sources for hash searches" do
72
- Backend.expects(:datasources).multiple_yields(["one"], ["two"])
73
- Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml")
74
- Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns("/nonexisting/two.yaml")
75
- File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
76
- File.stubs(:exist?).with("/nonexisting/two.yaml").returns(true)
82
+ Backend.expects(:datasourcefiles).with(:yaml, {}, "yaml", nil).multiple_yields(["one", "/nonexisting/one.yaml"], ["two", "/nonexisting/two.yaml"])
77
83
 
78
84
  @cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({})
79
85
  @cache.expects(:read_file).with("/nonexisting/two.yaml", Hash).returns({"key"=>{"a"=>"answer"}})
80
86
 
81
- @backend.lookup("key", {}, nil, :hash).should == {"a" => "answer"}
87
+ @backend.lookup("key", {}, nil, :hash, nil).should == {"a" => "answer"}
82
88
  end
83
89
 
84
90
  it "should build a merged hash of data sources for hash searches" do
85
- Backend.expects(:datasources).multiple_yields(["one"], ["two"])
86
- Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml")
87
- Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns("/nonexisting/two.yaml")
88
- File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
89
- File.stubs(:exist?).with("/nonexisting/two.yaml").returns(true)
91
+ Backend.expects(:datasourcefiles).with(:yaml, {}, "yaml", nil).multiple_yields(["one", "/nonexisting/one.yaml"], ["two", "/nonexisting/two.yaml"])
90
92
 
91
93
  @cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({"key"=>{"a"=>"answer"}})
92
94
  @cache.expects(:read_file).with("/nonexisting/two.yaml", Hash).returns({"key"=>{"b"=>"answer", "a"=>"wrong"}})
93
95
 
94
- @backend.lookup("key", {}, nil, :hash).should == {"a" => "answer", "b" => "answer"}
96
+ @backend.lookup("key", {}, nil, :hash, nil).should == {"a" => "answer", "b" => "answer"}
95
97
  end
96
98
 
97
99
  it "should fail when trying to << a Hash" do
98
- Backend.expects(:datasources).multiple_yields(["one"], ["two"])
99
- Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml")
100
- Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns("/nonexisting/two.yaml")
101
- File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
102
- File.stubs(:exist?).with("/nonexisting/two.yaml").returns(true)
100
+ Backend.expects(:datasourcefiles).with(:yaml, {}, "yaml", nil).multiple_yields(["one", "/nonexisting/one.yaml"], ["two", "/nonexisting/two.yaml"])
103
101
 
104
102
  @cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({"key"=>["a", "answer"]})
105
103
  @cache.expects(:read_file).with("/nonexisting/two.yaml", Hash).returns({"key"=>{"a"=>"answer"}})
106
104
 
107
- expect {@backend.lookup("key", {}, nil, :array)}.to raise_error(Exception, "Hiera type mismatch: expected Array and got Hash")
105
+ expect {@backend.lookup("key", {}, nil, :array, nil)}.to raise_error(Exception, "Hiera type mismatch for key 'key': expected Array and got Hash")
108
106
  end
109
107
 
110
108
  it "should fail when trying to merge an Array" do
111
- Backend.expects(:datasources).multiple_yields(["one"], ["two"])
112
- Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml")
113
- Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns("/nonexisting/two.yaml")
114
- File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
115
- File.stubs(:exist?).with("/nonexisting/two.yaml").returns(true)
109
+ Backend.expects(:datasourcefiles).with(:yaml, {}, "yaml", nil).multiple_yields(["one", "/nonexisting/one.yaml"], ["two", "/nonexisting/two.yaml"])
116
110
 
117
111
  @cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({"key"=>{"a"=>"answer"}})
118
112
  @cache.expects(:read_file).with("/nonexisting/two.yaml", Hash).returns({"key"=>["a", "wrong"]})
119
113
 
120
- expect { @backend.lookup("key", {}, nil, :hash) }.to raise_error(Exception, "Hiera type mismatch: expected Hash and got Array")
114
+ expect { @backend.lookup("key", {}, nil, :hash, nil) }.to raise_error(Exception, "Hiera type mismatch for key 'key': expected Hash and got Array")
121
115
  end
122
116
 
123
117
  it "should parse the answer for scope variables" do
124
- Backend.expects(:datasources).yields("one")
125
- Backend.expects(:datafile).with(:yaml, {"rspec" => "test"}, "one", "yaml").returns("/nonexisting/one.yaml")
126
- File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
118
+ Backend.expects(:datasourcefiles).with(:yaml, {"rspec" => "test"}, "yaml", nil).multiple_yields(["one", "/nonexisting/one.yaml"])
127
119
 
128
120
  @cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).returns({"key"=>"test_%{rspec}"})
129
121
 
130
- @backend.lookup("key", {"rspec" => "test"}, nil, :priority).should == "test_test"
122
+ @backend.lookup("key", {"rspec" => "test"}, nil, :priority, nil).should == "test_test"
131
123
  end
132
124
 
133
125
  it "should retain datatypes found in yaml files" do
134
- Backend.expects(:datasources).yields("one").times(3)
135
- Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml").times(3)
136
- File.stubs(:exist?).with("/nonexisting/one.yaml").returns(true)
126
+ Backend.expects(:datasourcefiles).with(:yaml, {}, "yaml", nil).multiple_yields(["one", "/nonexisting/one.yaml"]).times(3)
137
127
 
138
- yaml = "---\nstringval: 'string'\nboolval: true\nnumericval: 1"
139
128
 
140
- @cache.expects(:read_file).with("/nonexisting/one.yaml", Hash).times(3).returns({"boolval"=>true, "numericval"=>1, "stringval"=>"string"})
129
+ @cache.value = "---\nstringval: 'string'\nboolval: true\nnumericval: 1"
141
130
 
142
- @backend.lookup("stringval", {}, nil, :priority).should == "string"
143
- @backend.lookup("boolval", {}, nil, :priority).should == true
144
- @backend.lookup("numericval", {}, nil, :priority).should == 1
131
+ @backend.lookup("stringval", {}, nil, :priority, nil).should == "string"
132
+ @backend.lookup("boolval", {}, nil, :priority, nil).should == true
133
+ @backend.lookup("numericval", {}, nil, :priority, nil).should == 1
145
134
  end
146
135
  end
147
136
  end