hiera 1.3.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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