github.com/lyraproj/hiera@v1.0.0-rc4/lookup/lookup_test.go (about) 1 package main_test 2 3 import ( 4 "context" 5 "io" 6 "os" 7 "os/exec" 8 "path/filepath" 9 "runtime" 10 "strings" 11 "sync" 12 "testing" 13 14 "github.com/lyraproj/dgo/dgo" 15 "github.com/lyraproj/dgo/vf" 16 "github.com/lyraproj/hiera/api" 17 "github.com/lyraproj/hiera/cli" 18 "github.com/lyraproj/hiera/hiera" 19 "github.com/lyraproj/hiera/provider" 20 "github.com/stretchr/testify/assert" 21 "github.com/stretchr/testify/require" 22 ) 23 24 func TestLookup_defaultInt(t *testing.T) { 25 result, err := cli.ExecuteLookup(`--default`, `23`, `--dialect`, `dgo`, `--type`, `int`, `foo`) 26 require.NoError(t, err) 27 require.Equal(t, "23\n", string(result)) 28 } 29 30 func TestLookup_defaultString(t *testing.T) { 31 result, err := cli.ExecuteLookup(`--default`, `23`, `--type`, `String`, `foo`) 32 require.NoError(t, err) 33 require.Equal(t, "\"23\"\n", string(result)) 34 } 35 36 func TestLookup_notFound(t *testing.T) { 37 result, err := cli.ExecuteLookup(`foo`) 38 require.NoError(t, err) 39 require.Equal(t, "", string(result)) 40 } 41 42 func TestLookup_defaultEmptyString(t *testing.T) { 43 result, err := cli.ExecuteLookup(`--default`, ``, `foo`) 44 require.NoError(t, err) 45 require.Equal(t, "\"\"\n", string(result)) 46 } 47 48 func TestLookup_defaultHash(t *testing.T) { 49 result, err := cli.ExecuteLookup(`--default`, `{ x: "a", y: 9 }`, `--dialect`, `dgo`, `--type`, `map[string](string|int)`, `foo`) 50 require.NoError(t, err) 51 require.Equal(t, "x: a\ny: 9\n", string(result)) 52 } 53 54 func TestLookup_defaultHash_json(t *testing.T) { 55 result, err := cli.ExecuteLookup(`--default`, `{ x: "a", y: 9 }`, `--dialect`, `dgo`, `--type`, `map[string](string|int)`, `--render-as`, `json`, `foo`) 56 require.NoError(t, err) 57 require.Equal(t, "{\"x\":\"a\",\"y\":9}\n", string(result)) 58 } 59 60 func TestLookup_defaultString_s(t *testing.T) { 61 result, err := cli.ExecuteLookup(`--default`, `xyz`, `--render-as`, `s`, `foo`) 62 require.NoError(t, err) 63 require.Equal(t, "xyz\n", string(result)) 64 } 65 66 func TestLookup_defaultString_binary(t *testing.T) { 67 result, err := cli.ExecuteLookup(`--default`, `YWJjMTIzIT8kKiYoKSctPUB+`, `--render-as`, `binary`, `foo`) 68 require.NoError(t, err) 69 require.Equal(t, "abc123!?$*&()'-=@~", string(result)) 70 } 71 72 func TestLookup_defaultArray_binary(t *testing.T) { 73 result, err := cli.ExecuteLookup(`--default`, `{12, 28, 37, 15}`, `--dialect`, `dgo`, `--type`, `[]int`, `--render-as`, `binary`, `foo`) 74 require.NoError(t, err) 75 require.Equal(t, []byte{12, 28, 37, 15}, result) 76 } 77 78 func TestLookup_facts(t *testing.T) { 79 inTestdata(func() { 80 result, err := cli.ExecuteLookup(`--facts`, `facts.yaml`, `interpolate_a`) 81 require.NoError(t, err) 82 require.Equal(t, "This is value of a\n", string(result)) 83 }) 84 } 85 86 func TestLookup_fact_interpolated_config(t *testing.T) { 87 inTestdata(func() { 88 result, err := cli.ExecuteLookup(`--facts`, `facts.yaml`, `interpolate_ca`) 89 require.NoError(t, err) 90 require.Equal(t, "This is value of c.a\n", string(result)) 91 }) 92 } 93 94 func TestLookup_vars_interpolated_config(t *testing.T) { 95 inTestdata(func() { 96 result, err := cli.ExecuteLookup(`--vars`, `facts.yaml`, `interpolate_ca`) 97 require.NoError(t, err) 98 require.Equal(t, "This is value of c.a\n", string(result)) 99 }) 100 } 101 102 func TestLookup_var_interpolated_config(t *testing.T) { 103 inTestdata(func() { 104 result, err := cli.ExecuteLookup(`--dialect`, `dgo`, `--var`, `c={a:"the option value"}`, `--var`, `data_file: by_fact`, `interpolate_ca`) 105 require.NoError(t, err) 106 require.Equal(t, "This is the option value\n", string(result)) 107 }) 108 } 109 110 func TestLookup_fact_directly(t *testing.T) { 111 inTestdata(func() { 112 result, err := cli.ExecuteLookup(`--facts`, `facts.yaml`, `--config`, `fact_directly_hiera.yaml`, `the_fact`) 113 require.NoError(t, err) 114 require.Equal(t, "value of the_fact\n", string(result)) 115 }) 116 } 117 118 func TestLookup_nullentry(t *testing.T) { 119 inTestdata(func() { 120 result, err := cli.ExecuteLookup(`nullentry`) 121 require.NoError(t, err) 122 require.Equal(t, "nv: null\n", string(result)) 123 }) 124 } 125 126 func TestLookup_emptyMap(t *testing.T) { 127 inTestdata(func() { 128 result, err := cli.ExecuteLookup(`--config`, `empty_map_hiera.yaml`, `--render-as`, `json`, `empty_map`) 129 require.NoError(t, err) 130 require.Equal(t, "{}\n", string(result)) 131 }) 132 } 133 134 func TestLookup_emptySubMap(t *testing.T) { 135 inTestdata(func() { 136 result, err := cli.ExecuteLookup(`--config`, `empty_map_hiera.yaml`, `--render-as`, `json`, `empty_sub_map`) 137 require.NoError(t, err) 138 require.Equal(t, "{\"x\":\"the x\",\"empty\":{}}\n", string(result)) 139 }) 140 } 141 142 func TestLookup_emptySubMapInArray(t *testing.T) { 143 inTestdata(func() { 144 result, err := cli.ExecuteLookup(`--config`, `empty_map_hiera.yaml`, `--render-as`, `json`, `empty_sub_map_in_array`) 145 require.NoError(t, err) 146 require.Equal(t, "[{}]\n", string(result)) 147 }) 148 } 149 150 func TestLookup_sensitive(t *testing.T) { 151 inTestdata(func() { 152 result, err := cli.ExecuteLookup(`sense`, `--render-as`, `s`) 153 require.NoError(t, err) 154 require.Equal(t, "sensitive [value redacted]\n", string(result)) 155 156 // Default rendering is yaml and the output is rich data. 157 result, err = cli.ExecuteLookup(`sense`) 158 require.NoError(t, err) 159 require.Equal(t, "__type: sensitive\n__value: Don't reveal this\n", string(result)) 160 }) 161 } 162 163 func TestLookup_renderJSON_NoDedup(t *testing.T) { 164 inTestdata(func() { 165 result, err := cli.ExecuteLookup(`non-existent`, `--dialect`, `dgo`, `--default`, 166 `{ x: "a string longer than 20 characters in length", y: "a string longer than 20 characters in length" }`, 167 `--render-as`, `json`) 168 169 require.NoError(t, err) 170 require.Equal(t, 171 `{"x":"a string longer than 20 characters in length","y":"a string longer than 20 characters in length"} 172 `, 173 string(result)) 174 }) 175 } 176 177 func TestLookup_renderYAML_NoDedup(t *testing.T) { 178 inTestdata(func() { 179 result, err := cli.ExecuteLookup(`non-existent`, `--dialect`, `dgo`, `--default`, 180 `{ x: "a string longer than 20 characters in length", y: "a string longer than 20 characters in length" }`, 181 `--render-as`, `yaml`) 182 183 require.NoError(t, err) 184 require.Equal(t, `x: a string longer than 20 characters in length 185 y: a string longer than 20 characters in length 186 `, 187 string(result)) 188 }) 189 } 190 191 func TestLookup_lookup(t *testing.T) { 192 inTestdata(func() { 193 result, err := cli.ExecuteLookup(`lookup_array`) 194 require.NoError(t, err) 195 require.Equal(t, "'{\"one\",\"two\",\"three\"}'\n", string(result)) 196 }) 197 } 198 199 func TestLookup_alias(t *testing.T) { 200 inTestdata(func() { 201 result, err := cli.ExecuteLookup(`alias_array`) 202 require.NoError(t, err) 203 require.Equal(t, "- one\n- two\n- three\n", string(result)) 204 }) 205 } 206 207 func TestLookup_strictAlias(t *testing.T) { 208 inTestdata(func() { 209 result, err := cli.ExecuteLookup(`strict_alias_array`) 210 require.NoError(t, err) 211 require.Equal(t, "- one\n- two\n- three\n", string(result)) 212 }) 213 } 214 215 func TestLookup_lookupNothing(t *testing.T) { 216 inTestdata(func() { 217 result, err := cli.ExecuteLookup(`lookup_nothing`) 218 require.NoError(t, err) 219 require.Equal(t, "\"\"\n", string(result)) 220 }) 221 } 222 223 func TestLookup_aliasNothing(t *testing.T) { 224 inTestdata(func() { 225 result, err := cli.ExecuteLookup(`alias_nothing`) 226 require.NoError(t, err) 227 require.Equal(t, "\"\"\n", string(result)) 228 }) 229 } 230 231 func cmdLookup(cmdOpts *hiera.CommandOptions, opts dgo.Keyed, args []string, out io.Writer) error { 232 return hiera.TryWithParent(context.Background(), provider.ConfigLookupKey, opts, func(c api.Session) error { 233 hiera.LookupAndRender(c, cmdOpts, args, out) 234 return nil 235 }) 236 } 237 238 // TestLookup_aliasNewInvocation tests that an alias uses a new invocation where the 239 // lookup_options map is not inherited 240 func TestLookup_aliasNewInvocation(t *testing.T) { 241 cmdOpts := &hiera.CommandOptions{} 242 cfgOpts := vf.MutableMap() 243 cfgOpts.Put(api.HieraConfig, "interpolate_fresh.yaml") 244 inTestdata(func() { 245 bs := &strings.Builder{} 246 err := cmdLookup(cmdOpts, cfgOpts, []string{"hash_with_alias"}, bs) 247 require.NoError(t, err) 248 require.Equal(t, "y: Y\neh: {}\nea: []\nx: X\n", bs.String()) 249 }) 250 } 251 252 func TestLookup_strictAliasNothing(t *testing.T) { 253 inTestdata(func() { 254 result, err := cli.ExecuteLookup(`strict_alias_nothing`) 255 require.NoError(t, err) 256 require.Equal(t, ``, string(result)) 257 }) 258 } 259 260 func TestLookup_explain(t *testing.T) { 261 inTestdata(func() { 262 result, err := cli.ExecuteLookup(`--explain`, `--facts`, `facts.yaml`, `interpolate_ca`) 263 require.NoError(t, err) 264 require.Regexp(t, 265 `\ASearching for "interpolate_ca" 266 data_hash function 'yaml_data' 267 Path "[^"]*/testdata/hiera/common\.yaml" 268 Original path: "common\.yaml" 269 No such key: "interpolate_ca" 270 data_hash function 'yaml_data' 271 Path "[^"]*/testdata/hiera/named_by_fact\.yaml" 272 Original path: "named_%\{data_file\}.yaml" 273 Interpolation on "This is %\{c\.a\}" 274 Sub key: "a" 275 Found key: "a" value: "value of c.a" 276 Found key: "interpolate_ca" value: "This is value of c\.a" 277 \z`, filepath.ToSlash(string(result))) 278 }) 279 } 280 281 func TestLookup_explain_yaml(t *testing.T) { 282 inTestdata(func() { 283 result, err := cli.ExecuteLookup(`--explain`, `--facts`, `facts.yaml`, `--render-as`, `yaml`, `interpolate_ca`) 284 require.NoError(t, err) 285 require.Regexp(t, 286 `\A__type: hiera\.explainer 287 branches: 288 - __type: hiera\.explainLookup 289 branches: 290 - __type: hiera\.explainDataProvider 291 branches: 292 - __type: hiera\.explainLocation 293 event: not_found 294 key: interpolate_ca 295 location: 296 __type: hiera\.path 297 original: common\.yaml 298 resolved: .*/testdata/hiera/common\.yaml 299 exists: true 300 providerName: data_hash function 'yaml_data' 301 - __type: hiera\.explainDataProvider 302 branches: 303 - __type: hiera\.explainLocation 304 branches: 305 - __type: hiera\.explainInterpolate 306 branches: 307 - __type: hiera\.explainSubLookup 308 branches: 309 - __type: hiera\.explainKeySegment 310 event: found 311 key: a 312 value: value of c\.a 313 segment: a 314 subKey: c\.a 315 expression: This is %\{c\.a\} 316 event: found 317 key: interpolate_ca 318 value: This is value of c\.a 319 location: 320 __type: hiera\.path 321 original: named_%\{data_file\}\.yaml 322 resolved: .*/testdata/hiera/named_by_fact\.yaml 323 exists: true 324 providerName: data_hash function 'yaml_data' 325 event: result 326 key: interpolate_ca 327 value: This is value of c\.a 328 \z`, filepath.ToSlash(string(result))) 329 }) 330 } 331 332 func TestLookup_explain_options(t *testing.T) { 333 inTestdata(func() { 334 result, err := cli.ExecuteLookup(`--explain-options`, `--facts`, `facts.yaml`, `hash`) 335 require.NoError(t, err) 336 require.Regexp(t, 337 `\ASearching for "lookup_options" 338 Merge strategy "deep merge strategy" 339 data_hash function 'yaml_data' 340 Path "[^"]*/testdata/hiera/common\.yaml" 341 Original path: "common\.yaml" 342 Found key: "lookup_options" value: \{ 343 "hash": \{ 344 "merge": "deep" 345 \}, 346 "sense": \{ 347 "convert_to": "Sensitive" 348 \} 349 \} 350 data_hash function 'yaml_data' 351 Path "[^"]*/testdata/hiera/named_by_fact\.yaml" 352 Original path: "named_%\{data_file\}\.yaml" 353 No such key: "lookup_options" 354 Merged result: \{ 355 "hash": \{ 356 "merge": "deep" 357 \}, 358 "sense": \{ 359 "convert_to": "Sensitive" 360 \} 361 \} 362 \z`, filepath.ToSlash(string(result))) 363 }) 364 } 365 366 func TestLookup_explain_explain_options(t *testing.T) { 367 inTestdata(func() { 368 result, err := cli.ExecuteLookup(`--explain`, `--explain-options`, `--facts`, `facts.yaml`, `hash`) 369 require.NoError(t, err) 370 require.Regexp(t, 371 `\ASearching for "lookup_options" 372 Merge strategy "deep merge strategy" 373 data_hash function 'yaml_data' 374 Path "[^"]*/testdata/hiera/common\.yaml" 375 Original path: "common\.yaml" 376 Found key: "lookup_options" value: \{ 377 "hash": \{ 378 "merge": "deep" 379 \}, 380 "sense": \{ 381 "convert_to": "Sensitive" 382 \} 383 \} 384 data_hash function 'yaml_data' 385 Path "[^"]*/testdata/hiera/named_by_fact\.yaml" 386 Original path: "named_%\{data_file\}\.yaml" 387 No such key: "lookup_options" 388 Merged result: \{ 389 "hash": \{ 390 "merge": "deep" 391 \}, 392 "sense": \{ 393 "convert_to": "Sensitive" 394 \} 395 \} 396 Searching for "hash" 397 Using merge options from "lookup_options" hash 398 Merge strategy "deep merge strategy" 399 data_hash function 'yaml_data' 400 Path "[^"]*/testdata/hiera/common\.yaml" 401 Original path: "common\.yaml" 402 Found key: "hash" value: \{ 403 "one": 1, 404 "two": "two", 405 "three": \{ 406 "a": "A", 407 "c": "C" 408 \} 409 \} 410 data_hash function 'yaml_data' 411 Path "[^"]*/testdata/hiera/named_by_fact\.yaml" 412 Original path: "named_%\{data_file\}\.yaml" 413 Found key: "hash" value: \{ 414 "one": "overwritten one", 415 "three": \{ 416 "a": "overwritten A", 417 "b": "B", 418 "c": "overwritten C" 419 \} 420 \} 421 Merged result: \{ 422 "one": 1, 423 "two": "two", 424 "three": \{ 425 "a": "A", 426 "c": "C", 427 "b": "B" 428 \} 429 \} 430 \z`, filepath.ToSlash(string(result))) 431 }) 432 } 433 434 func TestLookupKey_plugin(t *testing.T) { 435 ensureTestPlugin(t) 436 inTestdata(func() { 437 result, err := cli.ExecuteLookup(`--config`, `lookup_key_plugin_hiera.yaml`, `a`) 438 require.NoError(t, err) 439 require.Equal(t, "option a\n", string(result)) 440 }) 441 } 442 443 func TestDataHash_plugin(t *testing.T) { 444 ensureTestPlugin(t) 445 inTestdata(func() { 446 result, err := cli.ExecuteLookup(`--config`, `data_hash_plugin_hiera.yaml`, `d`) 447 require.NoError(t, err) 448 require.Equal(t, "interpolate c is value c\n", string(result)) 449 }) 450 } 451 452 func TestLookup_issue75(t *testing.T) { 453 ensureTestPlugin(t) 454 for i := 0; i < 100; i++ { 455 inTestdata(func() { 456 result, err := cli.ExecuteLookup(`dns_resource_group_name`, `--config`, `dedup_hiera.yaml`, `--dialect`, `dgo`, 457 `--render-as`, `yaml`) 458 459 require.NoError(t, err) 460 require.Equal(t, `cbuk-shared-sharedproduction-dns-uksouth 461 `, 462 string(result)) 463 }) 464 } 465 } 466 467 /* 468 func TestDataHash_refuseToDie(t *testing.T) { 469 ensureTestPlugin(t) 470 inTestdata(func() { 471 _, err := cli.ExecuteLookup(`--config`, `refuse_to_die_plugin_hiera.yaml`, `a`) 472 if assert.Error(t, err) { 473 require.Regexp(t, `net/http: request canceled`, err.Error()) 474 } 475 }) 476 } 477 */ 478 479 func TestDataHash_panic(t *testing.T) { 480 ensureTestPlugin(t) 481 inTestdata(func() { 482 _, err := cli.ExecuteLookup(`--config`, `panic_plugin_hiera.yaml`, `a`) 483 if assert.Error(t, err) { 484 require.Regexp(t, `500 Internal Server Error: dit dit dit daah daah daah dit dit dit`, err.Error()) 485 } 486 }) 487 } 488 489 // Mimics: 490 // docker run --rm --hostname puppet -v $(pwd)/testdata/:/etc/puppetlabs/puppet/ -v $(pwd)/testdata/glob_hiera.yaml:/etc/puppetlabs/puppet/hiera.yaml --entrypoint puppet puppet/puppetserver lookup --facts /etc/puppetlabs/puppet/glob_facts.yaml a --explain 491 func TestLookupKey_globExpansionExistant(t *testing.T) { 492 inTestdata(func() { 493 result, err := cli.ExecuteLookup(`--config`, `glob_hiera.yaml`, `--facts`, `glob_facts.yaml`, `a`) 494 require.NoError(t, err) 495 require.Equal(t, "fragment a\n", string(result)) 496 }) 497 } 498 499 // Mimics: 500 // docker run --rm --hostname puppet -v $(pwd)/testdata/:/etc/puppetlabs/puppet/ -v $(pwd)/testdata/glob_hiera.yaml:/etc/puppetlabs/puppet/hiera.yaml --entrypoint puppet puppet/puppetserver lookup a --explain 501 func TestLookupKey_globExpansionNonExistant(t *testing.T) { 502 inTestdata(func() { 503 result, err := cli.ExecuteLookup(`--config`, `glob_hiera.yaml`, `a`) 504 require.NoError(t, err) 505 require.Equal(t, "common a\n", string(result)) 506 }) 507 } 508 509 func TestLookup_fourElementSlice(t *testing.T) { 510 inTestdata(func() { 511 result, err := cli.ExecuteLookup(`--config`, `hiera.yaml`, `--render-as`, `json`, `myList`) 512 require.NoError(t, err) 513 require.Equal(t, `[{"typeA":"a"},{"typeB":"b"},{"typeC":"c"},{"tupeD":"d"}]`, strings.TrimSpace(string(result))) 514 }) 515 } 516 517 var once = sync.Once{} 518 519 func ensureTestPlugin(t *testing.T) { 520 once.Do(func() { 521 t.Helper() 522 cw, err := os.Getwd() 523 if err != nil { 524 t.Fatal(err) 525 } 526 527 if err = os.Chdir(filepath.Join(`testdata`, `hieratestplugin`)); err != nil { 528 t.Fatal(err) 529 } 530 531 defer func() { 532 _ = os.Chdir(cw) 533 }() 534 535 pe := `hieratestplugin` 536 ps := pe + `.go` 537 if runtime.GOOS == `windows` { 538 pe += `.exe` 539 } 540 541 cmd := exec.Command(`go`, `build`, `-o`, filepath.Join(`..`, `plugin`, pe), ps) 542 cmd.Stderr = os.Stderr 543 cmd.Stdout = os.Stdout 544 if err = cmd.Run(); err != nil { 545 t.Fatal(err) 546 } 547 }) 548 } 549 550 func inTestdata(f func()) { 551 cw, err := os.Getwd() 552 if err == nil { 553 err = os.Chdir(`testdata`) 554 if err == nil { 555 defer func() { 556 _ = os.Chdir(cw) 557 }() 558 f() 559 } 560 } 561 if err != nil { 562 panic(err) 563 } 564 }