github.com/paybyphone/terraform@v0.9.5-0.20170613192930-9706042ddd51/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 "invalid version constraint", 221 }, 222 } 223 224 for i, tc := range cases { 225 t.Run(fmt.Sprintf("%d-%s", i, tc.Name), func(t *testing.T) { 226 c := testConfig(t, tc.Fixture) 227 err := c.Validate() 228 if (err != nil) != tc.Err { 229 t.Fatalf("err: %s", err) 230 } 231 if err != nil { 232 if tc.ErrString != "" && !strings.Contains(err.Error(), tc.ErrString) { 233 t.Fatalf("expected err to contain: %s\n\ngot: %s", tc.ErrString, err) 234 } 235 236 return 237 } 238 }) 239 } 240 241 } 242 243 func TestConfigValidate_tfVersion(t *testing.T) { 244 c := testConfig(t, "validate-tf-version") 245 if err := c.Validate(); err != nil { 246 t.Fatalf("err: %s", err) 247 } 248 } 249 250 func TestConfigValidate_tfVersionBad(t *testing.T) { 251 c := testConfig(t, "validate-bad-tf-version") 252 if err := c.Validate(); err == nil { 253 t.Fatal("should not be valid") 254 } 255 } 256 257 func TestConfigValidate_tfVersionInterpolations(t *testing.T) { 258 c := testConfig(t, "validate-tf-version-interp") 259 if err := c.Validate(); err == nil { 260 t.Fatal("should not be valid") 261 } 262 } 263 264 func TestConfigValidate_badDependsOn(t *testing.T) { 265 c := testConfig(t, "validate-bad-depends-on") 266 if err := c.Validate(); err == nil { 267 t.Fatal("should not be valid") 268 } 269 } 270 271 func TestConfigValidate_countInt(t *testing.T) { 272 c := testConfig(t, "validate-count-int") 273 if err := c.Validate(); err != nil { 274 t.Fatalf("err: %s", err) 275 } 276 } 277 278 func TestConfigValidate_countBadContext(t *testing.T) { 279 c := testConfig(t, "validate-count-bad-context") 280 281 err := c.Validate() 282 283 expected := []string{ 284 "no_count_in_output: count variables are only valid within resources", 285 "no_count_in_module: count variables are only valid within resources", 286 } 287 for _, exp := range expected { 288 if !strings.Contains(err.Error(), exp) { 289 t.Fatalf("expected: %q,\nto contain: %q", err, exp) 290 } 291 } 292 } 293 294 func TestConfigValidate_countCountVar(t *testing.T) { 295 c := testConfig(t, "validate-count-count-var") 296 if err := c.Validate(); err == nil { 297 t.Fatal("should not be valid") 298 } 299 } 300 301 func TestConfigValidate_countNotInt(t *testing.T) { 302 c := testConfig(t, "validate-count-not-int") 303 if err := c.Validate(); err == nil { 304 t.Fatal("should not be valid") 305 } 306 } 307 308 func TestConfigValidate_countUserVar(t *testing.T) { 309 c := testConfig(t, "validate-count-user-var") 310 if err := c.Validate(); err != nil { 311 t.Fatalf("err: %s", err) 312 } 313 } 314 315 func TestConfigValidate_countVar(t *testing.T) { 316 c := testConfig(t, "validate-count-var") 317 if err := c.Validate(); err != nil { 318 t.Fatalf("err: %s", err) 319 } 320 } 321 322 func TestConfigValidate_countVarInvalid(t *testing.T) { 323 c := testConfig(t, "validate-count-var-invalid") 324 if err := c.Validate(); err == nil { 325 t.Fatal("should not be valid") 326 } 327 } 328 329 func TestConfigValidate_countVarUnknown(t *testing.T) { 330 c := testConfig(t, "validate-count-var-unknown") 331 if err := c.Validate(); err == nil { 332 t.Fatal("should not be valid") 333 } 334 } 335 336 func TestConfigValidate_dependsOnVar(t *testing.T) { 337 c := testConfig(t, "validate-depends-on-var") 338 if err := c.Validate(); err == nil { 339 t.Fatal("should not be valid") 340 } 341 } 342 343 func TestConfigValidate_dupModule(t *testing.T) { 344 c := testConfig(t, "validate-dup-module") 345 if err := c.Validate(); err == nil { 346 t.Fatal("should not be valid") 347 } 348 } 349 350 func TestConfigValidate_dupResource(t *testing.T) { 351 c := testConfig(t, "validate-dup-resource") 352 if err := c.Validate(); err == nil { 353 t.Fatal("should not be valid") 354 } 355 } 356 357 func TestConfigValidate_ignoreChanges(t *testing.T) { 358 c := testConfig(t, "validate-ignore-changes") 359 if err := c.Validate(); err != nil { 360 t.Fatalf("err: %s", err) 361 } 362 } 363 364 func TestConfigValidate_ignoreChangesBad(t *testing.T) { 365 c := testConfig(t, "validate-ignore-changes-bad") 366 if err := c.Validate(); err == nil { 367 t.Fatal("should not be valid") 368 } 369 } 370 371 func TestConfigValidate_ignoreChangesInterpolate(t *testing.T) { 372 c := testConfig(t, "validate-ignore-changes-interpolate") 373 if err := c.Validate(); err == nil { 374 t.Fatal("should not be valid") 375 } 376 } 377 378 func TestConfigValidate_moduleNameBad(t *testing.T) { 379 c := testConfig(t, "validate-module-name-bad") 380 if err := c.Validate(); err == nil { 381 t.Fatal("should not be valid") 382 } 383 } 384 385 func TestConfigValidate_moduleSourceVar(t *testing.T) { 386 c := testConfig(t, "validate-module-source-var") 387 if err := c.Validate(); err == nil { 388 t.Fatal("should not be valid") 389 } 390 } 391 392 func TestConfigValidate_moduleVarInt(t *testing.T) { 393 c := testConfig(t, "validate-module-var-int") 394 if err := c.Validate(); err != nil { 395 t.Fatalf("should be valid: %s", err) 396 } 397 } 398 399 func TestConfigValidate_moduleVarMap(t *testing.T) { 400 c := testConfig(t, "validate-module-var-map") 401 if err := c.Validate(); err != nil { 402 t.Fatalf("should be valid: %s", err) 403 } 404 } 405 406 func TestConfigValidate_moduleVarList(t *testing.T) { 407 c := testConfig(t, "validate-module-var-list") 408 if err := c.Validate(); err != nil { 409 t.Fatalf("should be valid: %s", err) 410 } 411 } 412 413 func TestConfigValidate_moduleVarSelf(t *testing.T) { 414 c := testConfig(t, "validate-module-var-self") 415 if err := c.Validate(); err == nil { 416 t.Fatal("should be invalid") 417 } 418 } 419 420 func TestConfigValidate_nil(t *testing.T) { 421 var c Config 422 if err := c.Validate(); err != nil { 423 t.Fatalf("err: %s", err) 424 } 425 } 426 427 func TestConfigValidate_outputBadField(t *testing.T) { 428 c := testConfig(t, "validate-output-bad-field") 429 if err := c.Validate(); err == nil { 430 t.Fatal("should not be valid") 431 } 432 } 433 434 func TestConfigValidate_outputDescription(t *testing.T) { 435 c := testConfig(t, "validate-output-description") 436 if err := c.Validate(); err != nil { 437 t.Fatalf("err: %s", err) 438 } 439 if len(c.Outputs) != 1 { 440 t.Fatalf("got %d outputs; want 1", len(c.Outputs)) 441 } 442 if got, want := "Number 5", c.Outputs[0].Description; got != want { 443 t.Fatalf("got description %q; want %q", got, want) 444 } 445 } 446 447 func TestConfigValidate_outputDuplicate(t *testing.T) { 448 c := testConfig(t, "validate-output-dup") 449 if err := c.Validate(); err == nil { 450 t.Fatal("should not be valid") 451 } 452 } 453 454 func TestConfigValidate_pathVar(t *testing.T) { 455 c := testConfig(t, "validate-path-var") 456 if err := c.Validate(); err != nil { 457 t.Fatalf("err: %s", err) 458 } 459 } 460 461 func TestConfigValidate_pathVarInvalid(t *testing.T) { 462 c := testConfig(t, "validate-path-var-invalid") 463 if err := c.Validate(); err == nil { 464 t.Fatal("should not be valid") 465 } 466 } 467 468 func TestConfigValidate_providerMulti(t *testing.T) { 469 c := testConfig(t, "validate-provider-multi") 470 if err := c.Validate(); err == nil { 471 t.Fatal("should not be valid") 472 } 473 } 474 475 func TestConfigValidate_providerMultiGood(t *testing.T) { 476 c := testConfig(t, "validate-provider-multi-good") 477 if err := c.Validate(); err != nil { 478 t.Fatalf("should be valid: %s", err) 479 } 480 } 481 482 func TestConfigValidate_providerMultiRefGood(t *testing.T) { 483 c := testConfig(t, "validate-provider-multi-ref-good") 484 if err := c.Validate(); err != nil { 485 t.Fatalf("should be valid: %s", err) 486 } 487 } 488 489 func TestConfigValidate_provConnSplatOther(t *testing.T) { 490 c := testConfig(t, "validate-prov-conn-splat-other") 491 if err := c.Validate(); err != nil { 492 t.Fatalf("should be valid: %s", err) 493 } 494 } 495 496 func TestConfigValidate_provConnSplatSelf(t *testing.T) { 497 c := testConfig(t, "validate-prov-conn-splat-self") 498 if err := c.Validate(); err == nil { 499 t.Fatal("should not be valid") 500 } 501 } 502 503 func TestConfigValidate_provSplatOther(t *testing.T) { 504 c := testConfig(t, "validate-prov-splat-other") 505 if err := c.Validate(); err != nil { 506 t.Fatalf("should be valid: %s", err) 507 } 508 } 509 510 func TestConfigValidate_provSplatSelf(t *testing.T) { 511 c := testConfig(t, "validate-prov-splat-self") 512 if err := c.Validate(); err == nil { 513 t.Fatal("should not be valid") 514 } 515 } 516 517 func TestConfigValidate_resourceProvVarSelf(t *testing.T) { 518 c := testConfig(t, "validate-resource-prov-self") 519 if err := c.Validate(); err != nil { 520 t.Fatalf("should be valid: %s", err) 521 } 522 } 523 524 func TestConfigValidate_resourceVarSelf(t *testing.T) { 525 c := testConfig(t, "validate-resource-self") 526 if err := c.Validate(); err == nil { 527 t.Fatal("should not be valid") 528 } 529 } 530 531 func TestConfigValidate_unknownThing(t *testing.T) { 532 c := testConfig(t, "validate-unknownthing") 533 if err := c.Validate(); err == nil { 534 t.Fatal("should not be valid") 535 } 536 } 537 538 func TestConfigValidate_unknownResourceVar(t *testing.T) { 539 c := testConfig(t, "validate-unknown-resource-var") 540 if err := c.Validate(); err == nil { 541 t.Fatal("should not be valid") 542 } 543 } 544 545 func TestConfigValidate_unknownResourceVar_output(t *testing.T) { 546 c := testConfig(t, "validate-unknown-resource-var-output") 547 if err := c.Validate(); err == nil { 548 t.Fatal("should not be valid") 549 } 550 } 551 552 func TestConfigValidate_unknownVar(t *testing.T) { 553 c := testConfig(t, "validate-unknownvar") 554 if err := c.Validate(); err == nil { 555 t.Fatal("should not be valid") 556 } 557 } 558 559 func TestConfigValidate_unknownVarCount(t *testing.T) { 560 c := testConfig(t, "validate-unknownvar-count") 561 if err := c.Validate(); err == nil { 562 t.Fatal("should not be valid") 563 } 564 } 565 566 func TestConfigValidate_varDefault(t *testing.T) { 567 c := testConfig(t, "validate-var-default") 568 if err := c.Validate(); err != nil { 569 t.Fatalf("should be valid: %s", err) 570 } 571 } 572 573 func TestConfigValidate_varDefaultListType(t *testing.T) { 574 c := testConfig(t, "validate-var-default-list-type") 575 if err := c.Validate(); err != nil { 576 t.Fatalf("should be valid: %s", err) 577 } 578 } 579 580 func TestConfigValidate_varDefaultInterpolate(t *testing.T) { 581 c := testConfig(t, "validate-var-default-interpolate") 582 if err := c.Validate(); err == nil { 583 t.Fatal("should not be valid") 584 } 585 } 586 587 func TestConfigValidate_varDefaultInterpolateEscaped(t *testing.T) { 588 c := testConfig(t, "validate-var-default-interpolate-escaped") 589 if err := c.Validate(); err != nil { 590 t.Fatalf("should be valid, but got err: %s", err) 591 } 592 } 593 594 func TestConfigValidate_varDup(t *testing.T) { 595 c := testConfig(t, "validate-var-dup") 596 if err := c.Validate(); err == nil { 597 t.Fatal("should not be valid") 598 } 599 } 600 601 func TestConfigValidate_varMultiExactNonSlice(t *testing.T) { 602 c := testConfig(t, "validate-var-multi-exact-non-slice") 603 if err := c.Validate(); err != nil { 604 t.Fatalf("should be valid: %s", err) 605 } 606 } 607 608 func TestConfigValidate_varMultiFunctionCall(t *testing.T) { 609 c := testConfig(t, "validate-var-multi-func") 610 if err := c.Validate(); err != nil { 611 t.Fatalf("should be valid: %s", err) 612 } 613 } 614 615 func TestConfigValidate_varModule(t *testing.T) { 616 c := testConfig(t, "validate-var-module") 617 if err := c.Validate(); err != nil { 618 t.Fatalf("err: %s", err) 619 } 620 } 621 622 func TestConfigValidate_varModuleInvalid(t *testing.T) { 623 c := testConfig(t, "validate-var-module-invalid") 624 if err := c.Validate(); err == nil { 625 t.Fatal("should not be valid") 626 } 627 } 628 629 func TestConfigValidate_varProviderVersionInvalid(t *testing.T) { 630 c := testConfig(t, "validate-provider-version-invalid") 631 if err := c.Validate(); err == nil { 632 t.Fatal("should not be valid") 633 } 634 } 635 636 func TestNameRegexp(t *testing.T) { 637 cases := []struct { 638 Input string 639 Match bool 640 }{ 641 {"hello", true}, 642 {"foo-bar", true}, 643 {"foo_bar", true}, 644 {"_hello", true}, 645 {"foo bar", false}, 646 {"foo.bar", false}, 647 } 648 649 for _, tc := range cases { 650 if NameRegexp.Match([]byte(tc.Input)) != tc.Match { 651 t.Fatalf("Input: %s\n\nExpected: %#v", tc.Input, tc.Match) 652 } 653 } 654 } 655 656 func TestProviderConfigName(t *testing.T) { 657 pcs := []*ProviderConfig{ 658 &ProviderConfig{Name: "aw"}, 659 &ProviderConfig{Name: "aws"}, 660 &ProviderConfig{Name: "a"}, 661 &ProviderConfig{Name: "gce_"}, 662 } 663 664 n := ProviderConfigName("aws_instance", pcs) 665 if n != "aws" { 666 t.Fatalf("bad: %s", n) 667 } 668 } 669 670 func testConfig(t *testing.T, name string) *Config { 671 c, err := LoadFile(filepath.Join(fixtureDir, name, "main.tf")) 672 if err != nil { 673 t.Fatalf("file: %s\n\nerr: %s", name, err) 674 } 675 676 return c 677 } 678 679 func TestConfigDataCount(t *testing.T) { 680 c := testConfig(t, "data-count") 681 actual, err := c.Resources[0].Count() 682 if err != nil { 683 t.Fatalf("err: %s", err) 684 } 685 if actual != 5 { 686 t.Fatalf("bad: %#v", actual) 687 } 688 689 // we need to make sure "count" has been removed from the RawConfig, since 690 // it's not a real key and won't validate. 691 if _, ok := c.Resources[0].RawConfig.Raw["count"]; ok { 692 t.Fatal("count key still exists in RawConfig") 693 } 694 } 695 696 func TestConfigProviderVersion(t *testing.T) { 697 c := testConfig(t, "provider-version") 698 699 if len(c.ProviderConfigs) != 1 { 700 t.Fatal("expected 1 provider") 701 } 702 703 p := c.ProviderConfigs[0] 704 if p.Name != "aws" { 705 t.Fatalf("expected provider name 'aws', got %q", p.Name) 706 } 707 708 if p.Version != "0.0.1" { 709 t.Fatalf("expected providers version '0.0.1', got %q", p.Version) 710 } 711 712 if _, ok := p.RawConfig.Raw["version"]; ok { 713 t.Fatal("'version' should not exist in raw config") 714 } 715 } 716 717 func TestResourceProviderFullName(t *testing.T) { 718 type testCase struct { 719 ResourceName string 720 Alias string 721 Expected string 722 } 723 724 tests := []testCase{ 725 { 726 // If no alias is provided, the first underscore-separated segment 727 // is assumed to be the provider name. 728 ResourceName: "aws_thing", 729 Alias: "", 730 Expected: "aws", 731 }, 732 { 733 // If we have more than one underscore then it's the first one that we'll use. 734 ResourceName: "aws_thingy_thing", 735 Alias: "", 736 Expected: "aws", 737 }, 738 { 739 // A provider can export a resource whose name is just the bare provider name, 740 // e.g. because the provider only has one resource and so any additional 741 // parts would be redundant. 742 ResourceName: "external", 743 Alias: "", 744 Expected: "external", 745 }, 746 { 747 // Alias always overrides the default extraction of the name 748 ResourceName: "aws_thing", 749 Alias: "tls.baz", 750 Expected: "tls.baz", 751 }, 752 } 753 754 for _, test := range tests { 755 got := ResourceProviderFullName(test.ResourceName, test.Alias) 756 if got != test.Expected { 757 t.Errorf( 758 "(%q, %q) produced %q; want %q", 759 test.ResourceName, test.Alias, 760 got, 761 test.Expected, 762 ) 763 } 764 } 765 }