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