github.com/magodo/terraform@v0.11.12-beta1/config/config_test.go (about) 1 package config 2 3 import ( 4 "flag" 5 "fmt" 6 "io/ioutil" 7 "log" 8 "os" 9 "path/filepath" 10 "reflect" 11 "strings" 12 "testing" 13 14 "github.com/hashicorp/hil/ast" 15 "github.com/hashicorp/terraform/helper/logging" 16 ) 17 18 // This is the directory where our test fixtures are. 19 const fixtureDir = "./test-fixtures" 20 21 func TestMain(m *testing.M) { 22 flag.Parse() 23 if testing.Verbose() { 24 // if we're verbose, use the logging requested by TF_LOG 25 logging.SetOutput() 26 } else { 27 // otherwise silence all logs 28 log.SetOutput(ioutil.Discard) 29 } 30 31 os.Exit(m.Run()) 32 } 33 34 func TestConfigCopy(t *testing.T) { 35 c := testConfig(t, "copy-basic") 36 rOrig := c.Resources[0] 37 rCopy := rOrig.Copy() 38 39 if rCopy.Name != rOrig.Name { 40 t.Fatalf("Expected names to equal: %q <=> %q", rCopy.Name, rOrig.Name) 41 } 42 43 if rCopy.Type != rOrig.Type { 44 t.Fatalf("Expected types to equal: %q <=> %q", rCopy.Type, rOrig.Type) 45 } 46 47 origCount := rOrig.RawCount.Config()["count"] 48 rCopy.RawCount.Config()["count"] = "5" 49 if rOrig.RawCount.Config()["count"] != origCount { 50 t.Fatalf("Expected RawCount to be copied, but it behaves like a ref!") 51 } 52 53 rCopy.RawConfig.Config()["newfield"] = "hello" 54 if rOrig.RawConfig.Config()["newfield"] == "hello" { 55 t.Fatalf("Expected RawConfig to be copied, but it behaves like a ref!") 56 } 57 58 rCopy.Provisioners = append(rCopy.Provisioners, &Provisioner{}) 59 if len(rOrig.Provisioners) == len(rCopy.Provisioners) { 60 t.Fatalf("Expected Provisioners to be copied, but it behaves like a ref!") 61 } 62 63 if rCopy.Provider != rOrig.Provider { 64 t.Fatalf("Expected providers to equal: %q <=> %q", 65 rCopy.Provider, rOrig.Provider) 66 } 67 68 rCopy.DependsOn[0] = "gotchya" 69 if rOrig.DependsOn[0] == rCopy.DependsOn[0] { 70 t.Fatalf("Expected DependsOn to be copied, but it behaves like a ref!") 71 } 72 73 rCopy.Lifecycle.IgnoreChanges[0] = "gotchya" 74 if rOrig.Lifecycle.IgnoreChanges[0] == rCopy.Lifecycle.IgnoreChanges[0] { 75 t.Fatalf("Expected Lifecycle to be copied, but it behaves like a ref!") 76 } 77 78 } 79 80 func TestConfigCount(t *testing.T) { 81 c := testConfig(t, "count-int") 82 actual, err := c.Resources[0].Count() 83 if err != nil { 84 t.Fatalf("err: %s", err) 85 } 86 if actual != 5 { 87 t.Fatalf("bad: %#v", actual) 88 } 89 } 90 91 func TestConfigCount_string(t *testing.T) { 92 c := testConfig(t, "count-string") 93 actual, err := c.Resources[0].Count() 94 if err != nil { 95 t.Fatalf("err: %s", err) 96 } 97 if actual != 5 { 98 t.Fatalf("bad: %#v", actual) 99 } 100 } 101 102 // Terraform GH-11800 103 func TestConfigCount_list(t *testing.T) { 104 c := testConfig(t, "count-list") 105 106 // The key is to interpolate so it doesn't fail parsing 107 c.Resources[0].RawCount.Interpolate(map[string]ast.Variable{ 108 "var.list": ast.Variable{ 109 Value: []ast.Variable{}, 110 Type: ast.TypeList, 111 }, 112 }) 113 114 _, err := c.Resources[0].Count() 115 if err == nil { 116 t.Fatal("should error") 117 } 118 } 119 120 func TestConfigCount_var(t *testing.T) { 121 c := testConfig(t, "count-var") 122 _, err := c.Resources[0].Count() 123 if err == nil { 124 t.Fatalf("should error") 125 } 126 } 127 128 func TestConfig_emptyCollections(t *testing.T) { 129 c := testConfig(t, "empty-collections") 130 if len(c.Variables) != 3 { 131 t.Fatalf("bad: expected 3 variables, got %d", len(c.Variables)) 132 } 133 for _, variable := range c.Variables { 134 switch variable.Name { 135 case "empty_string": 136 if variable.Default != "" { 137 t.Fatalf("bad: wrong default %q for variable empty_string", variable.Default) 138 } 139 case "empty_map": 140 if !reflect.DeepEqual(variable.Default, map[string]interface{}{}) { 141 t.Fatalf("bad: wrong default %#v for variable empty_map", variable.Default) 142 } 143 case "empty_list": 144 if !reflect.DeepEqual(variable.Default, []interface{}{}) { 145 t.Fatalf("bad: wrong default %#v for variable empty_list", variable.Default) 146 } 147 default: 148 t.Fatalf("Unexpected variable: %s", variable.Name) 149 } 150 } 151 } 152 153 // This table test is the preferred way to test validation of configuration. 154 // There are dozens of functions below which do not follow this that are 155 // there mostly historically. They should be converted at some point. 156 func TestConfigValidate_table(t *testing.T) { 157 cases := []struct { 158 Name string 159 Fixture string 160 Err bool 161 ErrString string 162 }{ 163 { 164 "basic good", 165 "validate-good", 166 false, 167 "", 168 }, 169 170 { 171 "depends on module", 172 "validate-depends-on-module", 173 false, 174 "", 175 }, 176 177 { 178 "depends on non-existent module", 179 "validate-depends-on-bad-module", 180 true, 181 "non-existent module 'foo'", 182 }, 183 184 { 185 "data source with provisioners", 186 "validate-data-provisioner", 187 true, 188 "data sources cannot have", 189 }, 190 191 { 192 "basic provisioners", 193 "validate-basic-provisioners", 194 false, 195 "", 196 }, 197 198 { 199 "backend config with interpolations", 200 "validate-backend-interpolate", 201 true, 202 "cannot contain interp", 203 }, 204 { 205 "nested types in variable default", 206 "validate-var-nested", 207 false, 208 "", 209 }, 210 { 211 "provider with valid version constraint", 212 "provider-version", 213 false, 214 "", 215 }, 216 { 217 "provider with invalid version constraint", 218 "provider-version-invalid", 219 true, 220 "not a valid version constraint", 221 }, 222 { 223 "invalid provider name in module block", 224 "validate-missing-provider", 225 true, 226 "cannot pass non-existent provider", 227 }, 228 } 229 230 for i, tc := range cases { 231 t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) { 232 c := testConfig(t, tc.Fixture) 233 diags := c.Validate() 234 if diags.HasErrors() != tc.Err { 235 t.Fatalf("err: %s", diags.Err().Error()) 236 } 237 if diags.HasErrors() { 238 gotErr := diags.Err().Error() 239 if tc.ErrString != "" && !strings.Contains(gotErr, tc.ErrString) { 240 t.Fatalf("expected err to contain: %s\n\ngot: %s", tc.ErrString, gotErr) 241 } 242 243 return 244 } 245 }) 246 } 247 248 } 249 250 func TestConfigValidate_tfVersion(t *testing.T) { 251 c := testConfig(t, "validate-tf-version") 252 if err := c.Validate(); err != nil { 253 t.Fatalf("err: %s", err) 254 } 255 } 256 257 func TestConfigValidate_tfVersionBad(t *testing.T) { 258 c := testConfig(t, "validate-bad-tf-version") 259 if err := c.Validate(); err == nil { 260 t.Fatal("should not be valid") 261 } 262 } 263 264 func TestConfigValidate_tfVersionInterpolations(t *testing.T) { 265 c := testConfig(t, "validate-tf-version-interp") 266 if err := c.Validate(); err == nil { 267 t.Fatal("should not be valid") 268 } 269 } 270 271 func TestConfigValidate_badDependsOn(t *testing.T) { 272 c := testConfig(t, "validate-bad-depends-on") 273 if err := c.Validate(); err == nil { 274 t.Fatal("should not be valid") 275 } 276 } 277 278 func TestConfigValidate_countInt(t *testing.T) { 279 c := testConfig(t, "validate-count-int") 280 if err := c.Validate(); err != nil { 281 t.Fatalf("err: %s", err) 282 } 283 } 284 285 func TestConfigValidate_countInt_HCL2(t *testing.T) { 286 c := testConfigHCL2(t, "validate-count-int") 287 if err := c.Validate(); err != nil { 288 t.Fatalf("unexpected error: %s", err) 289 } 290 } 291 292 func TestConfigValidate_countBadContext(t *testing.T) { 293 c := testConfig(t, "validate-count-bad-context") 294 295 diags := c.Validate() 296 297 expected := []string{ 298 "output \"no_count_in_output\": count variables are only valid within resources", 299 "module \"no_count_in_module\": count variables are only valid within resources", 300 } 301 for _, exp := range expected { 302 errStr := diags.Err().Error() 303 if !strings.Contains(errStr, exp) { 304 t.Errorf("expected: %q,\nto contain: %q", errStr, exp) 305 } 306 } 307 } 308 309 func TestConfigValidate_countCountVar(t *testing.T) { 310 c := testConfig(t, "validate-count-count-var") 311 if err := c.Validate(); err == nil { 312 t.Fatal("should not be valid") 313 } 314 } 315 316 func TestConfigValidate_countNotInt(t *testing.T) { 317 c := testConfig(t, "validate-count-not-int") 318 if err := c.Validate(); err == nil { 319 t.Fatal("should not be valid") 320 } 321 } 322 323 func TestConfigValidate_countNotInt_HCL2(t *testing.T) { 324 c := testConfigHCL2(t, "validate-count-not-int-const") 325 if err := c.Validate(); err == nil { 326 t.Fatal("should not be valid") 327 } 328 } 329 330 func TestConfigValidate_countNotIntUnknown_HCL2(t *testing.T) { 331 c := testConfigHCL2(t, "validate-count-not-int") 332 // In HCL2 this is not an error because the unknown variable interpolates 333 // to produce an unknown string, which we assume (incorrectly, it turns out) 334 // will become a string containing only digits. This is okay because 335 // the config validation is only a "best effort" and we'll get a definitive 336 // result during the validation graph walk. 337 if err := c.Validate(); err != nil { 338 t.Fatalf("unexpected error: %s", err) 339 } 340 } 341 342 func TestConfigValidate_countUserVar(t *testing.T) { 343 c := testConfig(t, "validate-count-user-var") 344 if err := c.Validate(); err != nil { 345 t.Fatalf("err: %s", err) 346 } 347 } 348 349 func TestConfigValidate_countUserVar_HCL2(t *testing.T) { 350 c := testConfigHCL2(t, "validate-count-user-var") 351 if err := c.Validate(); err != nil { 352 t.Fatalf("err: %s", err) 353 } 354 } 355 356 func TestConfigValidate_countLocalValue(t *testing.T) { 357 c := testConfig(t, "validate-local-value-count") 358 if err := c.Validate(); err != nil { 359 t.Fatalf("err: %s", err) 360 } 361 } 362 363 func TestConfigValidate_countVar(t *testing.T) { 364 c := testConfig(t, "validate-count-var") 365 if err := c.Validate(); err != nil { 366 t.Fatalf("err: %s", err) 367 } 368 } 369 370 func TestConfigValidate_countVarInvalid(t *testing.T) { 371 c := testConfig(t, "validate-count-var-invalid") 372 if err := c.Validate(); err == nil { 373 t.Fatal("should not be valid") 374 } 375 } 376 377 func TestConfigValidate_countVarUnknown(t *testing.T) { 378 c := testConfig(t, "validate-count-var-unknown") 379 if err := c.Validate(); err == nil { 380 t.Fatal("should not be valid") 381 } 382 } 383 384 func TestConfigValidate_dependsOnVar(t *testing.T) { 385 c := testConfig(t, "validate-depends-on-var") 386 if err := c.Validate(); err == nil { 387 t.Fatal("should not be valid") 388 } 389 } 390 391 func TestConfigValidate_dupModule(t *testing.T) { 392 c := testConfig(t, "validate-dup-module") 393 if err := c.Validate(); err == nil { 394 t.Fatal("should not be valid") 395 } 396 } 397 398 func TestConfigValidate_dupResource(t *testing.T) { 399 c := testConfig(t, "validate-dup-resource") 400 if err := c.Validate(); err == nil { 401 t.Fatal("should not be valid") 402 } 403 } 404 405 func TestConfigValidate_ignoreChanges(t *testing.T) { 406 c := testConfig(t, "validate-ignore-changes") 407 if err := c.Validate(); err != nil { 408 t.Fatalf("err: %s", err) 409 } 410 } 411 412 func TestConfigValidate_ignoreChangesBad(t *testing.T) { 413 c := testConfig(t, "validate-ignore-changes-bad") 414 if err := c.Validate(); err == nil { 415 t.Fatal("should not be valid") 416 } 417 } 418 419 func TestConfigValidate_ignoreChangesInterpolate(t *testing.T) { 420 c := testConfig(t, "validate-ignore-changes-interpolate") 421 if err := c.Validate(); err == nil { 422 t.Fatal("should not be valid") 423 } 424 } 425 426 func TestConfigValidate_moduleNameBad(t *testing.T) { 427 c := testConfig(t, "validate-module-name-bad") 428 if err := c.Validate(); err == nil { 429 t.Fatal("should not be valid") 430 } 431 } 432 433 func TestConfigValidate_moduleSourceVar(t *testing.T) { 434 c := testConfig(t, "validate-module-source-var") 435 if err := c.Validate(); err == nil { 436 t.Fatal("should not be valid") 437 } 438 } 439 440 func TestConfigValidate_moduleVarInt(t *testing.T) { 441 c := testConfig(t, "validate-module-var-int") 442 if err := c.Validate(); err != nil { 443 t.Fatalf("should be valid: %s", err) 444 } 445 } 446 447 func TestConfigValidate_moduleVarMap(t *testing.T) { 448 c := testConfig(t, "validate-module-var-map") 449 if err := c.Validate(); err != nil { 450 t.Fatalf("should be valid: %s", err) 451 } 452 } 453 454 func TestConfigValidate_moduleVarList(t *testing.T) { 455 c := testConfig(t, "validate-module-var-list") 456 if err := c.Validate(); err != nil { 457 t.Fatalf("should be valid: %s", err) 458 } 459 } 460 461 func TestConfigValidate_moduleVarSelf(t *testing.T) { 462 c := testConfig(t, "validate-module-var-self") 463 if err := c.Validate(); err == nil { 464 t.Fatal("should be invalid") 465 } 466 } 467 468 func TestConfigValidate_nil(t *testing.T) { 469 var c Config 470 if err := c.Validate(); err != nil { 471 t.Fatalf("err: %s", err) 472 } 473 } 474 475 func TestConfigValidate_outputBadField(t *testing.T) { 476 c := testConfig(t, "validate-output-bad-field") 477 if err := c.Validate(); err == nil { 478 t.Fatal("should not be valid") 479 } 480 } 481 482 func TestConfigValidate_outputDescription(t *testing.T) { 483 c := testConfig(t, "validate-output-description") 484 if err := c.Validate(); err != nil { 485 t.Fatalf("err: %s", err) 486 } 487 if len(c.Outputs) != 1 { 488 t.Fatalf("got %d outputs; want 1", len(c.Outputs)) 489 } 490 if got, want := "Number 5", c.Outputs[0].Description; got != want { 491 t.Fatalf("got description %q; want %q", got, want) 492 } 493 } 494 495 func TestConfigValidate_outputDuplicate(t *testing.T) { 496 c := testConfig(t, "validate-output-dup") 497 if err := c.Validate(); err == nil { 498 t.Fatal("should not be valid") 499 } 500 } 501 502 func TestConfigValidate_pathVar(t *testing.T) { 503 c := testConfig(t, "validate-path-var") 504 if err := c.Validate(); err != nil { 505 t.Fatalf("err: %s", err) 506 } 507 } 508 509 func TestConfigValidate_pathVarInvalid(t *testing.T) { 510 c := testConfig(t, "validate-path-var-invalid") 511 if err := c.Validate(); err == nil { 512 t.Fatal("should not be valid") 513 } 514 } 515 516 func TestConfigValidate_providerMulti(t *testing.T) { 517 c := testConfig(t, "validate-provider-multi") 518 if err := c.Validate(); err == nil { 519 t.Fatal("should not be valid") 520 } 521 } 522 523 func TestConfigValidate_providerMultiGood(t *testing.T) { 524 c := testConfig(t, "validate-provider-multi-good") 525 if err := c.Validate(); err != nil { 526 t.Fatalf("should be valid: %s", err) 527 } 528 } 529 530 func TestConfigValidate_providerMultiRefGood(t *testing.T) { 531 c := testConfig(t, "validate-provider-multi-ref-good") 532 if err := c.Validate(); err != nil { 533 t.Fatalf("should be valid: %s", err) 534 } 535 } 536 537 func TestConfigValidate_provConnSplatOther(t *testing.T) { 538 c := testConfig(t, "validate-prov-conn-splat-other") 539 if err := c.Validate(); err != nil { 540 t.Fatalf("should be valid: %s", err) 541 } 542 } 543 544 func TestConfigValidate_provConnSplatSelf(t *testing.T) { 545 c := testConfig(t, "validate-prov-conn-splat-self") 546 if err := c.Validate(); err == nil { 547 t.Fatal("should not be valid") 548 } 549 } 550 551 func TestConfigValidate_provSplatOther(t *testing.T) { 552 c := testConfig(t, "validate-prov-splat-other") 553 if err := c.Validate(); err != nil { 554 t.Fatalf("should be valid: %s", err) 555 } 556 } 557 558 func TestConfigValidate_provSplatSelf(t *testing.T) { 559 c := testConfig(t, "validate-prov-splat-self") 560 if err := c.Validate(); err == nil { 561 t.Fatal("should not be valid") 562 } 563 } 564 565 func TestConfigValidate_resourceProvVarSelf(t *testing.T) { 566 c := testConfig(t, "validate-resource-prov-self") 567 if err := c.Validate(); err != nil { 568 t.Fatalf("should be valid: %s", err) 569 } 570 } 571 572 func TestConfigValidate_resourceVarSelf(t *testing.T) { 573 c := testConfig(t, "validate-resource-self") 574 if err := c.Validate(); err == nil { 575 t.Fatal("should not be valid") 576 } 577 } 578 579 func TestConfigValidate_unknownThing(t *testing.T) { 580 c := testConfig(t, "validate-unknownthing") 581 if err := c.Validate(); err == nil { 582 t.Fatal("should not be valid") 583 } 584 } 585 586 func TestConfigValidate_unknownResourceVar(t *testing.T) { 587 c := testConfig(t, "validate-unknown-resource-var") 588 if err := c.Validate(); err == nil { 589 t.Fatal("should not be valid") 590 } 591 } 592 593 func TestConfigValidate_unknownResourceVar_output(t *testing.T) { 594 c := testConfig(t, "validate-unknown-resource-var-output") 595 if err := c.Validate(); err == nil { 596 t.Fatal("should not be valid") 597 } 598 } 599 600 func TestConfigValidate_unknownVar(t *testing.T) { 601 c := testConfig(t, "validate-unknownvar") 602 if err := c.Validate(); err == nil { 603 t.Fatal("should not be valid") 604 } 605 } 606 607 func TestConfigValidate_unknownVarCount(t *testing.T) { 608 c := testConfig(t, "validate-unknownvar-count") 609 if err := c.Validate(); err == nil { 610 t.Fatal("should not be valid") 611 } 612 } 613 614 func TestConfigValidate_varDefault(t *testing.T) { 615 c := testConfig(t, "validate-var-default") 616 if err := c.Validate(); err != nil { 617 t.Fatalf("should be valid: %s", err) 618 } 619 } 620 621 func TestConfigValidate_varDefaultListType(t *testing.T) { 622 c := testConfig(t, "validate-var-default-list-type") 623 if err := c.Validate(); err != nil { 624 t.Fatalf("should be valid: %s", err) 625 } 626 } 627 628 func TestConfigValidate_varDefaultInterpolate(t *testing.T) { 629 c := testConfig(t, "validate-var-default-interpolate") 630 if err := c.Validate(); err == nil { 631 t.Fatal("should not be valid") 632 } 633 } 634 635 func TestConfigValidate_varDefaultInterpolateEscaped(t *testing.T) { 636 c := testConfig(t, "validate-var-default-interpolate-escaped") 637 if err := c.Validate(); err != nil { 638 t.Fatalf("should be valid, but got err: %s", err) 639 } 640 } 641 642 func TestConfigValidate_varDup(t *testing.T) { 643 c := testConfig(t, "validate-var-dup") 644 if err := c.Validate(); err == nil { 645 t.Fatal("should not be valid") 646 } 647 } 648 649 func TestConfigValidate_varMultiExactNonSlice(t *testing.T) { 650 c := testConfig(t, "validate-var-multi-exact-non-slice") 651 if err := c.Validate(); err != nil { 652 t.Fatalf("should be valid: %s", err) 653 } 654 } 655 656 func TestConfigValidate_varMultiFunctionCall(t *testing.T) { 657 c := testConfig(t, "validate-var-multi-func") 658 if err := c.Validate(); err != nil { 659 t.Fatalf("should be valid: %s", err) 660 } 661 } 662 663 func TestConfigValidate_varModule(t *testing.T) { 664 c := testConfig(t, "validate-var-module") 665 if err := c.Validate(); err != nil { 666 t.Fatalf("err: %s", err) 667 } 668 } 669 670 func TestConfigValidate_varModuleInvalid(t *testing.T) { 671 c := testConfig(t, "validate-var-module-invalid") 672 if err := c.Validate(); err == nil { 673 t.Fatal("should not be valid") 674 } 675 } 676 677 func TestConfigValidate_varProviderVersionInvalid(t *testing.T) { 678 c := testConfig(t, "validate-provider-version-invalid") 679 if err := c.Validate(); err == nil { 680 t.Fatal("should not be valid") 681 } 682 } 683 684 func TestNameRegexp(t *testing.T) { 685 cases := []struct { 686 Input string 687 Match bool 688 }{ 689 {"hello", true}, 690 {"foo-bar", true}, 691 {"foo_bar", true}, 692 {"_hello", true}, 693 {"foo bar", false}, 694 {"foo.bar", false}, 695 } 696 697 for _, tc := range cases { 698 if NameRegexp.Match([]byte(tc.Input)) != tc.Match { 699 t.Fatalf("Input: %s\n\nExpected: %#v", tc.Input, tc.Match) 700 } 701 } 702 } 703 704 func TestConfigValidate_localValuesMultiFile(t *testing.T) { 705 c, err := LoadDir(filepath.Join(fixtureDir, "validate-local-multi-file")) 706 if err != nil { 707 t.Fatalf("unexpected error during load: %s", err) 708 } 709 if err := c.Validate(); err != nil { 710 t.Fatalf("unexpected error from validate: %s", err) 711 } 712 if len(c.Locals) != 1 { 713 t.Fatalf("got 0 locals; want 1") 714 } 715 if got, want := c.Locals[0].Name, "test"; got != want { 716 t.Errorf("wrong local name\ngot: %#v\nwant: %#v", got, want) 717 } 718 } 719 720 func TestProviderConfigName(t *testing.T) { 721 pcs := []*ProviderConfig{ 722 &ProviderConfig{Name: "aw"}, 723 &ProviderConfig{Name: "aws"}, 724 &ProviderConfig{Name: "a"}, 725 &ProviderConfig{Name: "gce_"}, 726 } 727 728 n := ProviderConfigName("aws_instance", pcs) 729 if n != "aws" { 730 t.Fatalf("bad: %s", n) 731 } 732 } 733 734 func testConfig(t *testing.T, name string) *Config { 735 c, err := LoadFile(filepath.Join(fixtureDir, name, "main.tf")) 736 if err != nil { 737 t.Fatalf("file: %s\n\nerr: %s", name, err) 738 } 739 740 return c 741 } 742 743 // testConfigHCL loads a config, forcing it to be processed with the HCL2 744 // loader even if it doesn't explicitly opt in to the HCL2 experiment. 745 func testConfigHCL2(t *testing.T, name string) *Config { 746 t.Helper() 747 cer, _, err := globalHCL2Loader.loadFile(filepath.Join(fixtureDir, name, "main.tf")) 748 if err != nil { 749 t.Fatalf("failed to load %s: %s", name, err) 750 } 751 752 cfg, err := cer.Config() 753 if err != nil { 754 t.Fatalf("failed to decode %s: %s", name, err) 755 } 756 757 return cfg 758 } 759 760 func TestConfigDataCount(t *testing.T) { 761 c := testConfig(t, "data-count") 762 actual, err := c.Resources[0].Count() 763 if err != nil { 764 t.Fatalf("err: %s", err) 765 } 766 if actual != 5 { 767 t.Fatalf("bad: %#v", actual) 768 } 769 770 // we need to make sure "count" has been removed from the RawConfig, since 771 // it's not a real key and won't validate. 772 if _, ok := c.Resources[0].RawConfig.Raw["count"]; ok { 773 t.Fatal("count key still exists in RawConfig") 774 } 775 } 776 777 func TestConfigProviderVersion(t *testing.T) { 778 c := testConfig(t, "provider-version") 779 780 if len(c.ProviderConfigs) != 1 { 781 t.Fatal("expected 1 provider") 782 } 783 784 p := c.ProviderConfigs[0] 785 if p.Name != "aws" { 786 t.Fatalf("expected provider name 'aws', got %q", p.Name) 787 } 788 789 if p.Version != "0.0.1" { 790 t.Fatalf("expected providers version '0.0.1', got %q", p.Version) 791 } 792 793 if _, ok := p.RawConfig.Raw["version"]; ok { 794 t.Fatal("'version' should not exist in raw config") 795 } 796 } 797 798 func TestResourceProviderFullName(t *testing.T) { 799 type testCase struct { 800 ResourceName string 801 Alias string 802 Expected string 803 } 804 805 tests := []testCase{ 806 { 807 // If no alias is provided, the first underscore-separated segment 808 // is assumed to be the provider name. 809 ResourceName: "aws_thing", 810 Alias: "", 811 Expected: "aws", 812 }, 813 { 814 // If we have more than one underscore then it's the first one that we'll use. 815 ResourceName: "aws_thingy_thing", 816 Alias: "", 817 Expected: "aws", 818 }, 819 { 820 // A provider can export a resource whose name is just the bare provider name, 821 // e.g. because the provider only has one resource and so any additional 822 // parts would be redundant. 823 ResourceName: "external", 824 Alias: "", 825 Expected: "external", 826 }, 827 { 828 // Alias always overrides the default extraction of the name 829 ResourceName: "aws_thing", 830 Alias: "tls.baz", 831 Expected: "tls.baz", 832 }, 833 } 834 835 for _, test := range tests { 836 got := ResourceProviderFullName(test.ResourceName, test.Alias) 837 if got != test.Expected { 838 t.Errorf( 839 "(%q, %q) produced %q; want %q", 840 test.ResourceName, test.Alias, 841 got, 842 test.Expected, 843 ) 844 } 845 } 846 } 847 848 func TestConfigModuleProviders(t *testing.T) { 849 c := testConfig(t, "module-providers") 850 851 if len(c.Modules) != 1 { 852 t.Fatalf("expected 1 module, got %d", len(c.Modules)) 853 } 854 855 expected := map[string]string{ 856 "aws": "aws.foo", 857 } 858 859 got := c.Modules[0].Providers 860 861 if !reflect.DeepEqual(expected, got) { 862 t.Fatalf("exptected providers %#v, got providers %#v", expected, got) 863 } 864 } 865 866 func TestValidateOutputErrorWarnings(t *testing.T) { 867 // TODO: remove this in 0.12 868 c := testConfig(t, "output-warnings") 869 870 diags := c.Validate() 871 if diags.HasErrors() { 872 t.Fatal("config should not have errors:", diags) 873 } 874 if len(diags) != 2 { 875 t.Fatalf("should have 2 warnings, got %d:\n%s", len(diags), diags) 876 } 877 878 // this fixture has no explicit count, and should have no warning 879 c = testConfig(t, "output-no-warnings") 880 if err := c.Validate(); err != nil { 881 t.Fatal("config should have no warnings or errors") 882 } 883 }