hiera 2.0.0-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- 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
|