hiera 2.0.0-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +202 -0
  3. data/LICENSE +18 -0
  4. data/README.md +276 -0
  5. data/bin/hiera +248 -0
  6. data/lib/hiera/backend/json_backend.rb +58 -0
  7. data/lib/hiera/backend/yaml_backend.rb +63 -0
  8. data/lib/hiera/backend.rb +325 -0
  9. data/lib/hiera/config.rb +90 -0
  10. data/lib/hiera/console_logger.rb +13 -0
  11. data/lib/hiera/error.rb +4 -0
  12. data/lib/hiera/fallback_logger.rb +41 -0
  13. data/lib/hiera/filecache.rb +86 -0
  14. data/lib/hiera/interpolate.rb +98 -0
  15. data/lib/hiera/noop_logger.rb +8 -0
  16. data/lib/hiera/puppet_logger.rb +17 -0
  17. data/lib/hiera/recursive_guard.rb +20 -0
  18. data/lib/hiera/util.rb +47 -0
  19. data/lib/hiera/version.rb +89 -0
  20. data/lib/hiera.rb +115 -0
  21. data/spec/spec_helper.rb +78 -0
  22. data/spec/unit/backend/json_backend_spec.rb +85 -0
  23. data/spec/unit/backend/yaml_backend_spec.rb +138 -0
  24. data/spec/unit/backend_spec.rb +743 -0
  25. data/spec/unit/config_spec.rb +118 -0
  26. data/spec/unit/console_logger_spec.rb +19 -0
  27. data/spec/unit/fallback_logger_spec.rb +80 -0
  28. data/spec/unit/filecache_spec.rb +142 -0
  29. data/spec/unit/fixtures/interpolate/config/hiera.yaml +6 -0
  30. data/spec/unit/fixtures/interpolate/data/niltest.yaml +2 -0
  31. data/spec/unit/fixtures/interpolate/data/recursive.yaml +3 -0
  32. data/spec/unit/fixtures/override/config/hiera.yaml +5 -0
  33. data/spec/unit/fixtures/override/data/alternate.yaml +1 -0
  34. data/spec/unit/fixtures/override/data/common.yaml +2 -0
  35. data/spec/unit/hiera_spec.rb +81 -0
  36. data/spec/unit/interpolate_spec.rb +36 -0
  37. data/spec/unit/puppet_logger_spec.rb +31 -0
  38. data/spec/unit/util_spec.rb +49 -0
  39. data/spec/unit/version_spec.rb +44 -0
  40. metadata +128 -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