hiera 2.0.0-x86-mingw32
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.
- checksums.yaml +7 -0
- data/COPYING +202 -0
- data/LICENSE +18 -0
- data/README.md +276 -0
- data/bin/hiera +248 -0
- data/lib/hiera.rb +115 -0
- data/lib/hiera/backend.rb +325 -0
- data/lib/hiera/backend/json_backend.rb +58 -0
- data/lib/hiera/backend/yaml_backend.rb +63 -0
- data/lib/hiera/config.rb +90 -0
- data/lib/hiera/console_logger.rb +13 -0
- data/lib/hiera/error.rb +4 -0
- data/lib/hiera/fallback_logger.rb +41 -0
- data/lib/hiera/filecache.rb +86 -0
- data/lib/hiera/interpolate.rb +98 -0
- data/lib/hiera/noop_logger.rb +8 -0
- data/lib/hiera/puppet_logger.rb +17 -0
- data/lib/hiera/recursive_guard.rb +20 -0
- data/lib/hiera/util.rb +47 -0
- data/lib/hiera/version.rb +89 -0
- data/spec/spec_helper.rb +78 -0
- data/spec/unit/backend/json_backend_spec.rb +85 -0
- data/spec/unit/backend/yaml_backend_spec.rb +138 -0
- data/spec/unit/backend_spec.rb +743 -0
- data/spec/unit/config_spec.rb +118 -0
- data/spec/unit/console_logger_spec.rb +19 -0
- data/spec/unit/fallback_logger_spec.rb +80 -0
- data/spec/unit/filecache_spec.rb +142 -0
- data/spec/unit/fixtures/interpolate/config/hiera.yaml +6 -0
- data/spec/unit/fixtures/interpolate/data/niltest.yaml +2 -0
- data/spec/unit/fixtures/interpolate/data/recursive.yaml +3 -0
- data/spec/unit/fixtures/override/config/hiera.yaml +5 -0
- data/spec/unit/fixtures/override/data/alternate.yaml +1 -0
- data/spec/unit/fixtures/override/data/common.yaml +2 -0
- data/spec/unit/hiera_spec.rb +81 -0
- data/spec/unit/interpolate_spec.rb +36 -0
- data/spec/unit/puppet_logger_spec.rb +31 -0
- data/spec/unit/util_spec.rb +49 -0
- data/spec/unit/version_spec.rb +44 -0
- metadata +142 -0
@@ -0,0 +1,743 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'hiera/util'
|
3
|
+
|
4
|
+
class Hiera
|
5
|
+
module Backend
|
6
|
+
class Backend1x_backend
|
7
|
+
def lookup(key, scope, order_override, resolution_type)
|
8
|
+
["a", "b"]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe Backend do
|
14
|
+
describe "#datadir" do
|
15
|
+
it "interpolates any values in the configured value" do
|
16
|
+
Config.load({:rspec => {:datadir => "/tmp/%{interpolate}"}})
|
17
|
+
|
18
|
+
dir = Backend.datadir(:rspec, { "interpolate" => "my_data" })
|
19
|
+
|
20
|
+
dir.should == "/tmp/my_data"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "defaults to a directory in var" do
|
24
|
+
Config.load({})
|
25
|
+
Backend.datadir(:rspec, {}).should == Hiera::Util.var_dir
|
26
|
+
|
27
|
+
Config.load({:rspec => nil})
|
28
|
+
Backend.datadir(:rspec, {}).should == Hiera::Util.var_dir
|
29
|
+
|
30
|
+
Config.load({:rspec => {}})
|
31
|
+
Backend.datadir(:rspec, {}).should == Hiera::Util.var_dir
|
32
|
+
end
|
33
|
+
|
34
|
+
it "fails when the datadir is an array" do
|
35
|
+
Config.load({:rspec => {:datadir => []}})
|
36
|
+
|
37
|
+
expect do
|
38
|
+
Backend.datadir(:rspec, {})
|
39
|
+
end.to raise_error(Hiera::InvalidConfigurationError, /datadir for rspec cannot be an array/)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#datafile" do
|
44
|
+
it "translates a non-existant datafile into nil" do
|
45
|
+
Hiera.expects(:debug).with("Cannot find datafile /nonexisting/test.yaml, skipping")
|
46
|
+
Backend.expects(:datadir).returns("/nonexisting")
|
47
|
+
Backend.datafile(:yaml, {}, "test", "yaml").should == nil
|
48
|
+
end
|
49
|
+
|
50
|
+
it "concatenates the datadir and datafile and format to produce the full datafile filename" do
|
51
|
+
Backend.expects(:datadir).returns("/nonexisting")
|
52
|
+
File.expects(:exist?).with("/nonexisting/test.yaml").returns(true)
|
53
|
+
Backend.datafile(:yaml, {}, "test", "yaml").should == "/nonexisting/test.yaml"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#datasources" do
|
58
|
+
it "iterates over the datasources in the order of the given hierarchy" do
|
59
|
+
expected = ["one", "two"]
|
60
|
+
Backend.datasources({}, nil, ["one", "two"]) do |backend|
|
61
|
+
backend.should == expected.delete_at(0)
|
62
|
+
end
|
63
|
+
|
64
|
+
expected.empty?.should == true
|
65
|
+
end
|
66
|
+
|
67
|
+
it "uses the configured hierarchy no specific hierarchy is given" do
|
68
|
+
Config.load(:hierarchy => "test")
|
69
|
+
|
70
|
+
Backend.datasources({}) do |backend|
|
71
|
+
backend.should == "test"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
it "defaults to a hierarchy of only 'common' if not configured or given" do
|
76
|
+
Config.load({})
|
77
|
+
|
78
|
+
Backend.datasources({}) do |backend|
|
79
|
+
backend.should == "common"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it "prefixes the hierarchy with the override if an override is provided" do
|
84
|
+
Config.load({})
|
85
|
+
|
86
|
+
expected = ["override", "common"]
|
87
|
+
Backend.datasources({}, "override") do |backend|
|
88
|
+
backend.should == expected.delete_at(0)
|
89
|
+
end
|
90
|
+
|
91
|
+
expected.empty?.should == true
|
92
|
+
end
|
93
|
+
|
94
|
+
it "parses the names of the hierarchy levels using the given scope" do
|
95
|
+
Backend.expects(:parse_string).with("common", {:rspec => :tests}, {}, {:order_override => nil})
|
96
|
+
Backend.datasources({:rspec => :tests}) { }
|
97
|
+
end
|
98
|
+
|
99
|
+
it "defaults to 'common' if the hierarchy contains no hierarchies with non-empty names" do
|
100
|
+
Config.load({})
|
101
|
+
|
102
|
+
expected = ["common"]
|
103
|
+
Backend.datasources({}, "%{rspec}") do |backend|
|
104
|
+
backend.should == expected.delete_at(0)
|
105
|
+
end
|
106
|
+
|
107
|
+
expected.empty?.should == true
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "#parse_string" do
|
112
|
+
it "passes nil through untouched" do
|
113
|
+
Backend.parse_string(nil, {}).should == nil
|
114
|
+
end
|
115
|
+
|
116
|
+
it "does not modify the input data" do
|
117
|
+
data = "%{value}"
|
118
|
+
Backend.parse_string(data, { "value" => "replacement" })
|
119
|
+
|
120
|
+
data.should == "%{value}"
|
121
|
+
end
|
122
|
+
|
123
|
+
it "passes non-string data through untouched" do
|
124
|
+
input = { "not a" => "string" }
|
125
|
+
|
126
|
+
Backend.parse_string(input, {}).should == input
|
127
|
+
end
|
128
|
+
|
129
|
+
@scope_interpolation_tests = {
|
130
|
+
"replace %{part1} and %{part2}" =>
|
131
|
+
"replace value of part1 and value of part2",
|
132
|
+
"replace %{scope('part1')} and %{scope('part2')}" =>
|
133
|
+
"replace value of part1 and value of part2"
|
134
|
+
}
|
135
|
+
|
136
|
+
@scope_interpolation_tests.each do |input, expected|
|
137
|
+
it "replaces interpolations with data looked up in the scope" do
|
138
|
+
scope = {"part1" => "value of part1", "part2" => "value of part2"}
|
139
|
+
|
140
|
+
Backend.parse_string(input, scope).should == expected
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
it "replaces interpolations with data looked up in extra_data when scope does not contain the value" do
|
145
|
+
input = "test_%{rspec}_test"
|
146
|
+
Backend.parse_string(input, {}, {"rspec" => "extra"}).should == "test_extra_test"
|
147
|
+
end
|
148
|
+
|
149
|
+
it "prefers data from scope over data from extra_data" do
|
150
|
+
input = "test_%{rspec}_test"
|
151
|
+
Backend.parse_string(input, {"rspec" => "test"}, {"rspec" => "fail"}).should == "test_test_test"
|
152
|
+
end
|
153
|
+
|
154
|
+
@interprets_nil_in_scope_tests = {
|
155
|
+
"test_%{rspec}_test" => "test__test",
|
156
|
+
"test_%{scope('rspec')}_test" => "test__test"
|
157
|
+
}
|
158
|
+
|
159
|
+
@interprets_nil_in_scope_tests.each do |input, expected|
|
160
|
+
it "interprets nil in scope as a non-value" do
|
161
|
+
Backend.parse_string(input, {"rspec" => nil}).should == expected
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
@interprets_false_in_scope_tests = {
|
166
|
+
"test_%{rspec}_test" => "test_false_test",
|
167
|
+
"test_%{scope('rspec')}_test" => "test_false_test"
|
168
|
+
}
|
169
|
+
|
170
|
+
@interprets_false_in_scope_tests.each do |input, expected|
|
171
|
+
it "interprets false in scope as a real value" do
|
172
|
+
input = "test_%{scope('rspec')}_test"
|
173
|
+
Backend.parse_string(input, {"rspec" => false}).should == expected
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
it "interprets false in extra_data as a real value" do
|
178
|
+
input = "test_%{rspec}_test"
|
179
|
+
Backend.parse_string(input, {}, {"rspec" => false}).should == "test_false_test"
|
180
|
+
end
|
181
|
+
|
182
|
+
it "interprets nil in extra_data as a non-value" do
|
183
|
+
input = "test_%{rspec}_test"
|
184
|
+
Backend.parse_string(input, {}, {"rspec" => nil}).should == "test__test"
|
185
|
+
end
|
186
|
+
|
187
|
+
@interprets_undefined_in_scope_tests = {
|
188
|
+
"test_%{rspec}_test" => "test__test",
|
189
|
+
"test_%{scope('rspec')}_test" => "test__test"
|
190
|
+
}
|
191
|
+
|
192
|
+
@exact_lookup_tests = {
|
193
|
+
"test_%{::rspec::data}_test" => "test_value_test",
|
194
|
+
"test_%{scope('::rspec::data')}_test" => "test_value_test"
|
195
|
+
}
|
196
|
+
|
197
|
+
@exact_lookup_tests.each do |input, expected|
|
198
|
+
it "looks up the interpolated value exactly as it appears in the input" do
|
199
|
+
Backend.parse_string(input, {"::rspec::data" => "value"}).should == expected
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
@surrounding_whitespace_tests = {
|
204
|
+
"test_%{\trspec::data }_test" => "test_value_test",
|
205
|
+
"test_%{scope('\trspec::data ')}_test" => "test_value_test"
|
206
|
+
}
|
207
|
+
@surrounding_whitespace_tests.each do |input, expected|
|
208
|
+
it "does not remove any surrounding whitespace when parsing the key to lookup" do
|
209
|
+
Backend.parse_string(input, {"\trspec::data " => "value"}).should == expected
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
@leading_double_colon_tests = {
|
214
|
+
"test_%{::rspec::data}_test" => "test__test",
|
215
|
+
"test_%{scope('::rspec::data')}_test" => "test__test"
|
216
|
+
}
|
217
|
+
|
218
|
+
@leading_double_colon_tests.each do |input, expected|
|
219
|
+
it "does not try removing leading :: when a full lookup fails (#17434)" do
|
220
|
+
Backend.parse_string(input, {"rspec::data" => "value"}).should == expected
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
@double_colon_key_tests = {
|
225
|
+
"test_%{::rspec::data}_test" => "test__test",
|
226
|
+
"test_%{scope('::rspec::data')}_test" => "test__test"
|
227
|
+
}
|
228
|
+
@double_colon_key_tests.each do |input, expected|
|
229
|
+
it "does not try removing leading sections separated by :: when a full lookup fails (#17434)" do
|
230
|
+
Backend.parse_string(input, {"data" => "value"}).should == expected
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
it "does not try removing unknown, preceeding characters when looking up values" do
|
235
|
+
input = "test_%{$var}_test"
|
236
|
+
Backend.parse_string(input, {"$var" => "value"}).should == "test_value_test"
|
237
|
+
end
|
238
|
+
|
239
|
+
it "looks up recursively" do
|
240
|
+
scope = {"rspec" => "%{first}", "first" => "%{last}", "last" => "final"}
|
241
|
+
input = "test_%{rspec}_test"
|
242
|
+
Backend.parse_string(input, scope).should == "test_final_test"
|
243
|
+
end
|
244
|
+
|
245
|
+
it "raises an error if the recursive lookup results in an infinite loop" do
|
246
|
+
scope = {"first" => "%{second}", "second" => "%{first}"}
|
247
|
+
input = "test_%{first}_test"
|
248
|
+
expect do
|
249
|
+
Backend.parse_string(input, scope)
|
250
|
+
end.to raise_error Hiera::InterpolationLoop, "Detected in [first, second]"
|
251
|
+
end
|
252
|
+
|
253
|
+
it "replaces repeated occurances of the same lookup" do
|
254
|
+
scope = {"rspec" => "value"}
|
255
|
+
input = "it replaces %{rspec} and %{rspec}"
|
256
|
+
Backend.parse_string(input, scope).should == "it replaces value and value"
|
257
|
+
end
|
258
|
+
|
259
|
+
it "replaces hiera interpolations with data looked up in hiera" do
|
260
|
+
input = "%{hiera('key1')}"
|
261
|
+
scope = {}
|
262
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
263
|
+
Config.load_backends
|
264
|
+
Backend::Yaml_backend.any_instance.stubs(:lookup).with("key1", scope, nil, :priority, instance_of(Hash)).returns("answer")
|
265
|
+
|
266
|
+
Backend.parse_string(input, scope).should == "answer"
|
267
|
+
end
|
268
|
+
|
269
|
+
it "interpolation passes the order_override back into the backend" do
|
270
|
+
Backend.expects(:lookup).with("lookup::key", nil, {}, "order_override_datasource", :priority, instance_of(Hash))
|
271
|
+
Backend.parse_string("%{hiera('lookup::key')}", {}, {}, {:order_override => "order_override_datasource"})
|
272
|
+
end
|
273
|
+
|
274
|
+
it "replaces literal interpolations with their argument" do
|
275
|
+
scope = {}
|
276
|
+
input = "%{literal('%')}{rspec::data}"
|
277
|
+
Backend.parse_string(input, scope).should == "%{rspec::data}"
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
describe "#parse_answer" do
|
282
|
+
it "interpolates values in strings" do
|
283
|
+
input = "test_%{rspec}_test"
|
284
|
+
Backend.parse_answer(input, {"rspec" => "test"}).should == "test_test_test"
|
285
|
+
end
|
286
|
+
|
287
|
+
it "interpolates each string in an array" do
|
288
|
+
input = ["test_%{rspec}_test", "test_%{rspec}_test", ["test_%{rspec}_test"]]
|
289
|
+
Backend.parse_answer(input, {"rspec" => "test"}).should == ["test_test_test", "test_test_test", ["test_test_test"]]
|
290
|
+
end
|
291
|
+
|
292
|
+
it "interpolates each string in a hash" do
|
293
|
+
input = {"foo" => "test_%{rspec}_test", "bar" => "test_%{rspec}_test"}
|
294
|
+
Backend.parse_answer(input, {"rspec" => "test"}).should == {"foo"=>"test_test_test", "bar"=>"test_test_test"}
|
295
|
+
end
|
296
|
+
|
297
|
+
it "interpolates string in hash keys" do
|
298
|
+
input = {"%{rspec}" => "test"}
|
299
|
+
Backend.parse_answer(input, {"rspec" => "foo"}).should == {"foo"=>"test"}
|
300
|
+
end
|
301
|
+
|
302
|
+
it "interpolates strings in nested hash keys" do
|
303
|
+
input = {"topkey" => {"%{rspec}" => "test"}}
|
304
|
+
Backend.parse_answer(input, {"rspec" => "foo"}).should == {"topkey"=>{"foo" => "test"}}
|
305
|
+
end
|
306
|
+
|
307
|
+
it "interpolates strings in a mixed structure of arrays and hashes" do
|
308
|
+
input = {"foo" => "test_%{rspec}_test", "bar" => ["test_%{rspec}_test", "test_%{rspec}_test"]}
|
309
|
+
Backend.parse_answer(input, {"rspec" => "test"}).should == {"foo"=>"test_test_test", "bar"=>["test_test_test", "test_test_test"]}
|
310
|
+
end
|
311
|
+
|
312
|
+
it "interpolates hiera lookups values in strings" do
|
313
|
+
input = "test_%{hiera('rspec')}_test"
|
314
|
+
scope = {}
|
315
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
316
|
+
Config.load_backends
|
317
|
+
Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority, instance_of(Hash)).returns("test")
|
318
|
+
Backend.parse_answer(input, scope).should == "test_test_test"
|
319
|
+
end
|
320
|
+
|
321
|
+
it "interpolates alias lookups with non-string types" do
|
322
|
+
input = "%{alias('rspec')}"
|
323
|
+
scope = {}
|
324
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
325
|
+
Config.load_backends
|
326
|
+
Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority, instance_of(Hash)).returns(['test', 'test'])
|
327
|
+
Backend.parse_answer(input, scope).should == ['test', 'test']
|
328
|
+
end
|
329
|
+
|
330
|
+
it 'fails if alias interpolation is attempted in a string context with a prefix' do
|
331
|
+
input = "stuff_before%{alias('rspec')}"
|
332
|
+
scope = {}
|
333
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
334
|
+
Config.load_backends
|
335
|
+
Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority, instance_of(Hash)).returns(['test', 'test'])
|
336
|
+
expect do
|
337
|
+
Backend.parse_answer(input, scope).should == ['test', 'test']
|
338
|
+
end.to raise_error(Hiera::InterpolationInvalidValue, 'Cannot call alias in the string context')
|
339
|
+
end
|
340
|
+
|
341
|
+
it 'fails if alias interpolation is attempted in a string context with a postfix' do
|
342
|
+
input = "%{alias('rspec')}_stiff after"
|
343
|
+
scope = {}
|
344
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
345
|
+
Config.load_backends
|
346
|
+
Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority, instance_of(Hash)).returns(['test', 'test'])
|
347
|
+
expect do
|
348
|
+
Backend.parse_answer(input, scope).should == ['test', 'test']
|
349
|
+
end.to raise_error(Hiera::InterpolationInvalidValue, 'Cannot call alias in the string context')
|
350
|
+
end
|
351
|
+
|
352
|
+
it "interpolates hiera lookups in each string in an array" do
|
353
|
+
input = ["test_%{hiera('rspec')}_test", "test_%{hiera('rspec')}_test", ["test_%{hiera('rspec')}_test"]]
|
354
|
+
scope = {}
|
355
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
356
|
+
Config.load_backends
|
357
|
+
Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority, instance_of(Hash)).returns("test")
|
358
|
+
Backend.parse_answer(input, scope).should == ["test_test_test", "test_test_test", ["test_test_test"]]
|
359
|
+
end
|
360
|
+
|
361
|
+
it "interpolates hiera lookups in each string in a hash" do
|
362
|
+
input = {"foo" => "test_%{hiera('rspec')}_test", "bar" => "test_%{hiera('rspec')}_test"}
|
363
|
+
scope = {}
|
364
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
365
|
+
Config.load_backends
|
366
|
+
Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority, instance_of(Hash)).returns("test")
|
367
|
+
Backend.parse_answer(input, scope).should == {"foo"=>"test_test_test", "bar"=>"test_test_test"}
|
368
|
+
end
|
369
|
+
|
370
|
+
it "interpolates hiera lookups in string in hash keys" do
|
371
|
+
input = {"%{hiera('rspec')}" => "test"}
|
372
|
+
scope = {}
|
373
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
374
|
+
Config.load_backends
|
375
|
+
Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority, instance_of(Hash)).returns("foo")
|
376
|
+
Backend.parse_answer(input, scope).should == {"foo"=>"test"}
|
377
|
+
end
|
378
|
+
|
379
|
+
it "interpolates hiera lookups in strings in nested hash keys" do
|
380
|
+
input = {"topkey" => {"%{hiera('rspec')}" => "test"}}
|
381
|
+
scope = {}
|
382
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
383
|
+
Config.load_backends
|
384
|
+
Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority, instance_of(Hash)).returns("foo")
|
385
|
+
Backend.parse_answer(input, scope).should == {"topkey"=>{"foo" => "test"}}
|
386
|
+
end
|
387
|
+
|
388
|
+
it "interpolates hiera lookups in strings in a mixed structure of arrays and hashes" do
|
389
|
+
input = {"foo" => "test_%{hiera('rspec')}_test", "bar" => ["test_%{hiera('rspec')}_test", "test_%{hiera('rspec')}_test"]}
|
390
|
+
scope = {}
|
391
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
392
|
+
Config.load_backends
|
393
|
+
Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority, instance_of(Hash)).returns("test")
|
394
|
+
Backend.parse_answer(input, scope).should == {"foo"=>"test_test_test", "bar"=>["test_test_test", "test_test_test"]}
|
395
|
+
end
|
396
|
+
|
397
|
+
it "interpolates hiera lookups and scope lookups in the same string" do
|
398
|
+
input = {"foo" => "test_%{hiera('rspec')}_test", "bar" => "test_%{rspec2}_test"}
|
399
|
+
scope = {"rspec2" => "scope_rspec"}
|
400
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
401
|
+
Config.load_backends
|
402
|
+
Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority, instance_of(Hash)).returns("hiera_rspec")
|
403
|
+
Backend.parse_answer(input, scope).should == {"foo"=>"test_hiera_rspec_test", "bar"=>"test_scope_rspec_test"}
|
404
|
+
end
|
405
|
+
|
406
|
+
it "interpolates hiera and scope lookups with the same lookup query in a single string" do
|
407
|
+
input = "test_%{hiera('rspec')}_test_%{rspec}"
|
408
|
+
scope = {"rspec" => "scope_rspec"}
|
409
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
410
|
+
Config.load_backends
|
411
|
+
Backend::Yaml_backend.any_instance.stubs(:lookup).with("rspec", scope, nil, :priority, instance_of(Hash)).returns("hiera_rspec")
|
412
|
+
Backend.parse_answer(input, scope).should == "test_hiera_rspec_test_scope_rspec"
|
413
|
+
end
|
414
|
+
|
415
|
+
it "passes integers unchanged" do
|
416
|
+
input = 1
|
417
|
+
Backend.parse_answer(input, {"rspec" => "test"}).should == 1
|
418
|
+
end
|
419
|
+
|
420
|
+
it "passes floats unchanged" do
|
421
|
+
input = 0.233
|
422
|
+
Backend.parse_answer(input, {"rspec" => "test"}).should == 0.233
|
423
|
+
end
|
424
|
+
|
425
|
+
it "passes the boolean true unchanged" do
|
426
|
+
input = true
|
427
|
+
Backend.parse_answer(input, {"rspec" => "test"}).should == true
|
428
|
+
end
|
429
|
+
|
430
|
+
it "passes the boolean false unchanged" do
|
431
|
+
input = false
|
432
|
+
Backend.parse_answer(input, {"rspec" => "test"}).should == false
|
433
|
+
end
|
434
|
+
|
435
|
+
it "interpolates lookups using single or double quotes" do
|
436
|
+
input = "test_%{scope(\"rspec\")}_test_%{scope('rspec')}"
|
437
|
+
scope = {"rspec" => "scope_rspec"}
|
438
|
+
Backend.parse_answer(input, scope).should == "test_scope_rspec_test_scope_rspec"
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
describe "#resolve_answer" do
|
443
|
+
it "flattens and removes duplicate values from arrays during an array lookup" do
|
444
|
+
Backend.resolve_answer(["foo", ["foo", "foo"], "bar"], :array).should == ["foo", "bar"]
|
445
|
+
end
|
446
|
+
|
447
|
+
it "returns the data unchanged during a priority lookup" do
|
448
|
+
Backend.resolve_answer(["foo", ["foo", "foo"], "bar"], :priority).should == ["foo", ["foo", "foo"], "bar"]
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
describe "#lookup" do
|
453
|
+
before do
|
454
|
+
Hiera.stubs(:debug)
|
455
|
+
Hiera.stubs(:warn)
|
456
|
+
end
|
457
|
+
|
458
|
+
it "caches loaded backends" do
|
459
|
+
Backend.clear!
|
460
|
+
Hiera.expects(:debug).with(regexp_matches(/Hiera YAML backend starting/)).once
|
461
|
+
|
462
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
463
|
+
Config.load_backends
|
464
|
+
|
465
|
+
Backend.lookup("key", "default", {}, nil, nil)
|
466
|
+
Backend.lookup("key", "default", {}, nil, nil)
|
467
|
+
end
|
468
|
+
|
469
|
+
it "returns the answer from the backend" do
|
470
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
471
|
+
Config.load_backends
|
472
|
+
|
473
|
+
Backend::Yaml_backend.any_instance.expects(:lookup).with("key", {}, nil, nil, instance_of(Hash)).returns("answer")
|
474
|
+
|
475
|
+
Backend.lookup("key", "default", {}, nil, nil).should == "answer"
|
476
|
+
end
|
477
|
+
|
478
|
+
it "retains the datatypes as returned by the backend" do
|
479
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
480
|
+
Config.load_backends
|
481
|
+
|
482
|
+
Backend::Yaml_backend.any_instance.expects(:lookup).with("stringval", {}, nil, nil, instance_of(Hash)).returns("string")
|
483
|
+
Backend::Yaml_backend.any_instance.expects(:lookup).with("boolval", {}, nil, nil, instance_of(Hash)).returns(false)
|
484
|
+
Backend::Yaml_backend.any_instance.expects(:lookup).with("numericval", {}, nil, nil, instance_of(Hash)).returns(1)
|
485
|
+
|
486
|
+
Backend.lookup("stringval", "default", {}, nil, nil).should == "string"
|
487
|
+
Backend.lookup("boolval", "default", {}, nil, nil).should == false
|
488
|
+
Backend.lookup("numericval", "default", {}, nil, nil).should == 1
|
489
|
+
end
|
490
|
+
|
491
|
+
it "calls to all backends till an answer is found" do
|
492
|
+
backend = mock
|
493
|
+
backend.expects(:lookup).returns("answer")
|
494
|
+
Config.load({})
|
495
|
+
Config.instance_variable_set("@config", {:backends => ["yaml", "rspec"]})
|
496
|
+
Backend.instance_variable_set("@backends", {"rspec" => backend})
|
497
|
+
#Backend::Yaml_backend.any_instance.expects(:lookup).with("key", {"rspec" => "test"}, nil, nil)
|
498
|
+
Backend.expects(:constants).returns(["Yaml_backend", "Rspec_backend"]).twice
|
499
|
+
|
500
|
+
Backend.lookup("key", "test_%{rspec}", {"rspec" => "test"}, nil, nil).should == "answer"
|
501
|
+
end
|
502
|
+
|
503
|
+
it "calls to all backends till an answer is found when doing array lookups" do
|
504
|
+
backend = mock
|
505
|
+
backend.expects(:lookup).returns(["answer"])
|
506
|
+
Config.load({})
|
507
|
+
Config.instance_variable_set("@config", {:backends => ["yaml", "rspec"]})
|
508
|
+
Backend.instance_variable_set("@backends", {"rspec" => backend})
|
509
|
+
Backend.expects(:constants).returns(["Yaml_backend", "Rspec_backend"]).twice
|
510
|
+
|
511
|
+
Backend.lookup("key", "notfound", {"rspec" => "test"}, nil, :array).should == ["answer"]
|
512
|
+
end
|
513
|
+
|
514
|
+
it "calls to all backends till an answer is found when doing hash lookups" do
|
515
|
+
thehash = {:answer => "value"}
|
516
|
+
backend = mock
|
517
|
+
backend.expects(:lookup).returns(thehash)
|
518
|
+
Config.load({})
|
519
|
+
Config.instance_variable_set("@config", {:backends => ["yaml", "rspec"]})
|
520
|
+
Backend.instance_variable_set("@backends", {"rspec" => backend})
|
521
|
+
Backend.expects(:constants).returns(["Yaml_backend", "Rspec_backend"]).twice
|
522
|
+
|
523
|
+
Backend.lookup("key", "notfound", {"rspec" => "test"}, nil, :hash).should == thehash
|
524
|
+
end
|
525
|
+
|
526
|
+
it "builds a merged hash from all backends for hash searches" do
|
527
|
+
backend1 = mock :lookup => {"a" => "answer"}
|
528
|
+
backend2 = mock :lookup => {"b" => "bnswer"}
|
529
|
+
Config.load({})
|
530
|
+
Config.instance_variable_set("@config", {:backends => ["first", "second"]})
|
531
|
+
Backend.instance_variable_set("@backends", {"first" => backend1, "second" => backend2})
|
532
|
+
Backend.stubs(:constants).returns(["First_backend", "Second_backend"])
|
533
|
+
|
534
|
+
Backend.lookup("key", {}, {"rspec" => "test"}, nil, :hash).should == {"a" => "answer", "b" => "bnswer"}
|
535
|
+
end
|
536
|
+
|
537
|
+
it "builds an array from all backends for array searches" do
|
538
|
+
backend1 = mock :lookup => ["a", "b"]
|
539
|
+
backend2 = mock :lookup => ["c", "d"]
|
540
|
+
Config.load({})
|
541
|
+
Config.instance_variable_set("@config", {:backends => ["first", "second"]})
|
542
|
+
Backend.instance_variable_set("@backends", {"first" => backend1, "second" => backend2})
|
543
|
+
Backend.stubs(:constants).returns(["First_backend", "Second_backend"])
|
544
|
+
|
545
|
+
Backend.lookup("key", {}, {"rspec" => "test"}, nil, :array).should == ["a", "b", "c", "d"]
|
546
|
+
end
|
547
|
+
|
548
|
+
it "uses the earliest backend result for priority searches" do
|
549
|
+
backend1 = mock
|
550
|
+
backend1.stubs(:lookup).returns(["a", "b"])
|
551
|
+
backend2 = mock
|
552
|
+
backend2.stubs(:lookup).returns(["c", "d"])
|
553
|
+
Config.load({})
|
554
|
+
Config.instance_variable_set("@config", {:backends => ["first", "second"]})
|
555
|
+
Backend.instance_variable_set("@backends", {"first" => backend1, "second" => backend2})
|
556
|
+
Backend.stubs(:constants).returns(["First_backend", "Second_backend"])
|
557
|
+
|
558
|
+
Backend.lookup("key", {}, {"rspec" => "test"}, nil, :priority).should == ["a", "b"]
|
559
|
+
end
|
560
|
+
|
561
|
+
it "parses the answers based on resolution_type" do
|
562
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
563
|
+
Config.load_backends
|
564
|
+
|
565
|
+
Backend.expects(:resolve_answer).with("test_test", :priority).returns("parsed")
|
566
|
+
Backend::Yaml_backend.any_instance.expects(:lookup).with("key", {"rspec" => "test"}, nil, :priority, instance_of(Hash)).returns("test_test")
|
567
|
+
|
568
|
+
Backend.lookup("key", "test_%{rspec}", {"rspec" => "test"}, nil, :priority).should == "parsed"
|
569
|
+
end
|
570
|
+
|
571
|
+
it "returns the default with variables parsed if nothing is found" do
|
572
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
573
|
+
Config.load_backends
|
574
|
+
|
575
|
+
Backend::Yaml_backend.any_instance.expects(:lookup).with("key", {"rspec" => "test"}, nil, nil, instance_of(Hash)).throws(:no_such_key)
|
576
|
+
|
577
|
+
Backend.lookup("key", "test_%{rspec}", {"rspec" => "test"}, nil, nil).should == "test_test"
|
578
|
+
end
|
579
|
+
|
580
|
+
it "returns nil instead of the default when key is found with a nil value" do
|
581
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
582
|
+
Config.load_backends
|
583
|
+
|
584
|
+
Backend::Yaml_backend.any_instance.expects(:lookup).with("key", {"rspec" => "test"}, nil, nil, instance_of(Hash)).returns(nil)
|
585
|
+
|
586
|
+
Backend.lookup("key", "test_%{rspec}", {"rspec" => "test"}, nil, nil).should == nil
|
587
|
+
end
|
588
|
+
|
589
|
+
it "keeps string default data as a string" do
|
590
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
591
|
+
Config.load_backends
|
592
|
+
Backend::Yaml_backend.any_instance.expects(:lookup).with("key", {}, nil, nil, instance_of(Hash)).throws(:no_such_key)
|
593
|
+
Backend.lookup("key", "test", {}, nil, nil).should == "test"
|
594
|
+
end
|
595
|
+
|
596
|
+
it "keeps array default data as an array" do
|
597
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
598
|
+
Config.load_backends
|
599
|
+
Backend::Yaml_backend.any_instance.expects(:lookup).with("key", {}, nil, :array, instance_of(Hash)).throws(:no_such_key)
|
600
|
+
Backend.lookup("key", ["test"], {}, nil, :array).should == ["test"]
|
601
|
+
end
|
602
|
+
|
603
|
+
it "keeps hash default data as a hash" do
|
604
|
+
Config.load({:yaml => {:datadir => "/tmp"}})
|
605
|
+
Config.load_backends
|
606
|
+
Backend::Yaml_backend.any_instance.expects(:lookup).with("key", {}, nil, :hash, instance_of(Hash)).throws(:no_such_key)
|
607
|
+
Backend.lookup("key", {"test" => "value"}, {}, nil, :hash).should == {"test" => "value"}
|
608
|
+
end
|
609
|
+
|
610
|
+
it 'can use qualified key to lookup value in hash' do
|
611
|
+
Config.load({:yaml => {:datadir => '/tmp'}})
|
612
|
+
Config.load_backends
|
613
|
+
Backend::Yaml_backend.any_instance.expects(:lookup).with('key', {}, nil, nil, instance_of(Hash)).returns({ 'test' => 'value'})
|
614
|
+
Backend.lookup('key.test', 'dflt', {}, nil, nil).should == 'value'
|
615
|
+
end
|
616
|
+
|
617
|
+
it 'can use qualified key to lookup value in array' do
|
618
|
+
Config.load({:yaml => {:datadir => '/tmp'}})
|
619
|
+
Config.load_backends
|
620
|
+
Backend::Yaml_backend.any_instance.expects(:lookup).with('key', {}, nil, nil, instance_of(Hash)).returns([ 'first', 'second'])
|
621
|
+
Backend.lookup('key.1', 'dflt', {}, nil, nil).should == 'second'
|
622
|
+
end
|
623
|
+
|
624
|
+
it 'will fail when qualified key is partially found but not expected hash' do
|
625
|
+
Config.load({:yaml => {:datadir => '/tmp'}})
|
626
|
+
Config.load_backends
|
627
|
+
Backend::Yaml_backend.any_instance.expects(:lookup).with('key', {}, nil, nil, instance_of(Hash)).returns(['value 1', 'value 2'])
|
628
|
+
expect do
|
629
|
+
Backend.lookup('key.test', 'dflt', {}, nil, nil)
|
630
|
+
end.to raise_error(Exception, /^Hiera type mismatch:/)
|
631
|
+
end
|
632
|
+
|
633
|
+
it 'will fail when qualified key used with resolution_type :hash' do
|
634
|
+
expect do
|
635
|
+
Backend.lookup('key.test', 'dflt', {}, nil, :hash)
|
636
|
+
end.to raise_error(ArgumentError, /^Resolution type :hash is illegal/)
|
637
|
+
end
|
638
|
+
|
639
|
+
it 'will fail when qualified key used with resolution_type :array' do
|
640
|
+
expect do
|
641
|
+
Backend.lookup('key.test', 'dflt', {}, nil, :array)
|
642
|
+
end.to raise_error(ArgumentError, /^Resolution type :array is illegal/)
|
643
|
+
end
|
644
|
+
|
645
|
+
it 'will succeed when qualified key used with resolution_type :priority' do
|
646
|
+
Config.load({:yaml => {:datadir => '/tmp'}})
|
647
|
+
Config.load_backends
|
648
|
+
Backend::Yaml_backend.any_instance.expects(:lookup).with('key', {}, nil, :priority, instance_of(Hash)).returns({ 'test' => 'value'})
|
649
|
+
Backend.lookup('key.test', 'dflt', {}, nil, :priority).should == 'value'
|
650
|
+
end
|
651
|
+
|
652
|
+
it 'will fail when qualified key is partially found but not expected array' do
|
653
|
+
Config.load({:yaml => {:datadir => '/tmp'}})
|
654
|
+
Config.load_backends
|
655
|
+
Backend::Yaml_backend.any_instance.expects(:lookup).with('key', {}, nil, nil, instance_of(Hash)).returns({ 'test' => 'value'})
|
656
|
+
expect do
|
657
|
+
Backend.lookup('key.2', 'dflt', {}, nil, nil)
|
658
|
+
end.to raise_error(Exception, /^Hiera type mismatch:/)
|
659
|
+
end
|
660
|
+
|
661
|
+
it 'will not fail when qualified key is partially not found' do
|
662
|
+
Config.load({:yaml => {:datadir => '/tmp'}})
|
663
|
+
Config.load_backends
|
664
|
+
Backend::Yaml_backend.any_instance.expects(:lookup).with('key', {}, nil, nil, instance_of(Hash)).returns(nil)
|
665
|
+
Backend.lookup('key.test', 'dflt', {}, nil, nil).should == 'dflt'
|
666
|
+
end
|
667
|
+
|
668
|
+
it 'will not fail when qualified key is array index out of bounds' do
|
669
|
+
Config.load({:yaml => {:datadir => '/tmp'}})
|
670
|
+
Config.load_backends
|
671
|
+
Backend::Yaml_backend.any_instance.expects(:lookup).with('key', {}, nil, nil, instance_of(Hash)).returns(['value 1', 'value 2'])
|
672
|
+
Backend.lookup('key.33', 'dflt', {}, nil, nil).should == 'dflt'
|
673
|
+
end
|
674
|
+
|
675
|
+
it 'can use qualified key in interpolation to lookup value in hash' do
|
676
|
+
Config.load({:yaml => {:datadir => '/tmp'}})
|
677
|
+
Config.load_backends
|
678
|
+
Hiera::Backend.stubs(:datasourcefiles).yields('foo', 'bar')
|
679
|
+
Hiera::Filecache.any_instance.expects(:read_file).at_most(2).returns({'key' => '%{hiera(\'some.subkey\')}', 'some' => { 'subkey' => 'value' }})
|
680
|
+
Backend.lookup('key', 'dflt', {}, nil, nil).should == 'value'
|
681
|
+
end
|
682
|
+
|
683
|
+
it 'can use qualified key in interpolated default and scope' do
|
684
|
+
Config.load({:yaml => {:datadir => '/tmp'}})
|
685
|
+
Config.load_backends
|
686
|
+
scope = { 'some' => { 'test' => 'value'}}
|
687
|
+
Backend::Yaml_backend.any_instance.expects(:lookup).with('key', scope, nil, nil, instance_of(Hash))
|
688
|
+
Backend.lookup('key.notfound', '%{some.test}', scope, nil, nil).should == 'value'
|
689
|
+
end
|
690
|
+
|
691
|
+
it "handles older backend with 4 argument lookup" do
|
692
|
+
Config.load({})
|
693
|
+
Config.instance_variable_set("@config", {:backends => ["Backend1x"]})
|
694
|
+
|
695
|
+
Hiera.expects(:debug).at_least_once.with(regexp_matches /Using Hiera 1.x backend/)
|
696
|
+
Backend.lookup("key", {}, {"rspec" => "test"}, nil, :priority).should == ["a", "b"]
|
697
|
+
end
|
698
|
+
end
|
699
|
+
|
700
|
+
describe '#merge_answer' do
|
701
|
+
before do
|
702
|
+
Hiera.stubs(:debug)
|
703
|
+
Hiera.stubs(:warn)
|
704
|
+
Config.stubs(:validate!)
|
705
|
+
end
|
706
|
+
|
707
|
+
it "uses Hash.merge when configured with :merge_behavior => :native" do
|
708
|
+
Config.load({:merge_behavior => :native})
|
709
|
+
Hash.any_instance.expects(:merge).with({"b" => "bnswer"}).returns({"a" => "answer", "b" => "bnswer"})
|
710
|
+
Backend.merge_answer({"a" => "answer"},{"b" => "bnswer"}).should == {"a" => "answer", "b" => "bnswer"}
|
711
|
+
end
|
712
|
+
|
713
|
+
it "uses deep_merge! when configured with :merge_behavior => :deeper" do
|
714
|
+
Config.load({:merge_behavior => :deeper})
|
715
|
+
Hash.any_instance.expects('deep_merge!').with({"b" => "bnswer"}, {}).returns({"a" => "answer", "b" => "bnswer"})
|
716
|
+
Backend.merge_answer({"a" => "answer"},{"b" => "bnswer"}).should == {"a" => "answer", "b" => "bnswer"}
|
717
|
+
end
|
718
|
+
|
719
|
+
it "uses deep_merge when configured with :merge_behavior => :deep" do
|
720
|
+
Config.load({:merge_behavior => :deep})
|
721
|
+
Hash.any_instance.expects('deep_merge').with({"b" => "bnswer"}, {}).returns({"a" => "answer", "b" => "bnswer"})
|
722
|
+
Backend.merge_answer({"a" => "answer"},{"b" => "bnswer"}).should == {"a" => "answer", "b" => "bnswer"}
|
723
|
+
end
|
724
|
+
|
725
|
+
it "disregards configuration when 'merge' parameter is given as a Hash" do
|
726
|
+
Config.load({:merge_behavior => :deep})
|
727
|
+
Hash.any_instance.expects('deep_merge!').with({"b" => "bnswer"}, {}).returns({"a" => "answer", "b" => "bnswer"})
|
728
|
+
Backend.merge_answer({"a" => "answer"},{"b" => "bnswer"}, {:behavior => 'deeper' }).should == {"a" => "answer", "b" => "bnswer"}
|
729
|
+
end
|
730
|
+
|
731
|
+
it "propagates deep merge options when given Hash 'merge' parameter" do
|
732
|
+
Hash.any_instance.expects('deep_merge!').with({"b" => "bnswer"}, { :knockout_prefix => '-' }).returns({"a" => "answer", "b" => "bnswer"})
|
733
|
+
Backend.merge_answer({"a" => "answer"},{"b" => "bnswer"}, {:behavior => 'deeper', :knockout_prefix => '-'}).should == {"a" => "answer", "b" => "bnswer"}
|
734
|
+
end
|
735
|
+
|
736
|
+
it "passes Config[:deep_merge_options] into calls to deep_merge" do
|
737
|
+
Config.load({:merge_behavior => :deep, :deep_merge_options => { :knockout_prefix => '-' } })
|
738
|
+
Hash.any_instance.expects('deep_merge').with({"b" => "bnswer"}, {:knockout_prefix => '-'}).returns({"a" => "answer", "b" => "bnswer"})
|
739
|
+
Backend.merge_answer({"a" => "answer"},{"b" => "bnswer"}).should == {"a" => "answer", "b" => "bnswer"}
|
740
|
+
end
|
741
|
+
end
|
742
|
+
end
|
743
|
+
end
|