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