github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/config/loader_test.go (about) 1 package config 2 3 import ( 4 "io/ioutil" 5 "path/filepath" 6 "reflect" 7 "strings" 8 "testing" 9 ) 10 11 func TestErrNoConfigsFound_impl(t *testing.T) { 12 var _ error = new(ErrNoConfigsFound) 13 } 14 15 func TestIsEmptyDir(t *testing.T) { 16 val, err := IsEmptyDir(fixtureDir) 17 if err != nil { 18 t.Fatalf("err: %s", err) 19 } 20 if val { 21 t.Fatal("should not be empty") 22 } 23 } 24 25 func TestIsEmptyDir_noExist(t *testing.T) { 26 val, err := IsEmptyDir(filepath.Join(fixtureDir, "nopenopenope")) 27 if err != nil { 28 t.Fatalf("err: %s", err) 29 } 30 if !val { 31 t.Fatal("should be empty") 32 } 33 } 34 35 func TestIsEmptyDir_noConfigs(t *testing.T) { 36 val, err := IsEmptyDir(filepath.Join(fixtureDir, "dir-empty")) 37 if err != nil { 38 t.Fatalf("err: %s", err) 39 } 40 if !val { 41 t.Fatal("should be empty") 42 } 43 } 44 45 func TestLoadFile_badType(t *testing.T) { 46 _, err := LoadFile(filepath.Join(fixtureDir, "bad_type.tf.nope")) 47 if err == nil { 48 t.Fatal("should have error") 49 } 50 } 51 52 func TestLoadFile_gitCrypt(t *testing.T) { 53 _, err := LoadFile(filepath.Join(fixtureDir, "git-crypt.tf")) 54 if err == nil { 55 t.Fatal("should have error") 56 } 57 58 t.Logf("err: %s", err) 59 } 60 61 func TestLoadFile_lifecycleKeyCheck(t *testing.T) { 62 _, err := LoadFile(filepath.Join(fixtureDir, "lifecycle_cbd_typo.tf")) 63 if err == nil { 64 t.Fatal("should have error") 65 } 66 67 t.Logf("err: %s", err) 68 } 69 70 func TestLoadFile_varInvalidKey(t *testing.T) { 71 _, err := LoadFile(filepath.Join(fixtureDir, "var-invalid-key.tf")) 72 if err == nil { 73 t.Fatal("should have error") 74 } 75 } 76 77 func TestLoadFile_resourceArityMistake(t *testing.T) { 78 _, err := LoadFile(filepath.Join(fixtureDir, "resource-arity-mistake.tf")) 79 if err == nil { 80 t.Fatal("should have error") 81 } 82 expected := "Error loading test-fixtures/resource-arity-mistake.tf: position 2:10: resource must be followed by exactly two strings, a type and a name" 83 if err.Error() != expected { 84 t.Fatalf("expected:\n%s\ngot:\n%s", expected, err) 85 } 86 } 87 88 func TestLoadFile_resourceMultiLifecycle(t *testing.T) { 89 _, err := LoadFile(filepath.Join(fixtureDir, "resource-multi-lifecycle.tf")) 90 if err == nil { 91 t.Fatal("should have error") 92 } 93 } 94 95 func TestLoadFile_dataSourceArityMistake(t *testing.T) { 96 _, err := LoadFile(filepath.Join(fixtureDir, "data-source-arity-mistake.tf")) 97 if err == nil { 98 t.Fatal("should have error") 99 } 100 expected := "Error loading test-fixtures/data-source-arity-mistake.tf: position 2:6: 'data' must be followed by exactly two strings: a type and a name" 101 if err.Error() != expected { 102 t.Fatalf("expected:\n%s\ngot:\n%s", expected, err) 103 } 104 } 105 106 func TestLoadFileWindowsLineEndings(t *testing.T) { 107 testFile := filepath.Join(fixtureDir, "windows-line-endings.tf") 108 109 contents, err := ioutil.ReadFile(testFile) 110 if err != nil { 111 t.Fatalf("err: %s", err) 112 } 113 if !strings.Contains(string(contents), "\r\n") { 114 t.Fatalf("Windows line endings test file %s contains no windows line endings - this may be an autocrlf related issue.", testFile) 115 } 116 117 c, err := LoadFile(testFile) 118 if err != nil { 119 t.Fatalf("err: %s", err) 120 } 121 122 if c == nil { 123 t.Fatal("config should not be nil") 124 } 125 126 if c.Dir != "" { 127 t.Fatalf("bad: %#v", c.Dir) 128 } 129 130 actual := resourcesStr(c.Resources) 131 if actual != strings.TrimSpace(windowsHeredocResourcesStr) { 132 t.Fatalf("bad:\n%s", actual) 133 } 134 } 135 136 func TestLoadFileHeredoc(t *testing.T) { 137 c, err := LoadFile(filepath.Join(fixtureDir, "heredoc.tf")) 138 if err != nil { 139 t.Fatalf("err: %s", err) 140 } 141 142 if c == nil { 143 t.Fatal("config should not be nil") 144 } 145 146 if c.Dir != "" { 147 t.Fatalf("bad: %#v", c.Dir) 148 } 149 150 actual := providerConfigsStr(c.ProviderConfigs) 151 if actual != strings.TrimSpace(heredocProvidersStr) { 152 t.Fatalf("bad:\n%s", actual) 153 } 154 155 actual = resourcesStr(c.Resources) 156 if actual != strings.TrimSpace(heredocResourcesStr) { 157 t.Fatalf("bad:\n%s", actual) 158 } 159 } 160 161 func TestLoadFileEscapedQuotes(t *testing.T) { 162 _, err := LoadFile(filepath.Join(fixtureDir, "escapedquotes.tf")) 163 if err == nil { 164 t.Fatalf("expected syntax error as escaped quotes are no longer supported") 165 } 166 167 if !strings.Contains(err.Error(), "parse error") { 168 t.Fatalf("expected \"syntax error\", got: %s", err) 169 } 170 } 171 172 func TestLoadFileBasic(t *testing.T) { 173 c, err := LoadFile(filepath.Join(fixtureDir, "basic.tf")) 174 if err != nil { 175 t.Fatalf("err: %s", err) 176 } 177 178 if c == nil { 179 t.Fatal("config should not be nil") 180 } 181 182 if c.Dir != "" { 183 t.Fatalf("bad: %#v", c.Dir) 184 } 185 186 expectedTF := &Terraform{RequiredVersion: "foo"} 187 if !reflect.DeepEqual(c.Terraform, expectedTF) { 188 t.Fatalf("bad: %#v", c.Terraform) 189 } 190 191 expectedAtlas := &AtlasConfig{Name: "mitchellh/foo"} 192 if !reflect.DeepEqual(c.Atlas, expectedAtlas) { 193 t.Fatalf("bad: %#v", c.Atlas) 194 } 195 196 actual := variablesStr(c.Variables) 197 if actual != strings.TrimSpace(basicVariablesStr) { 198 t.Fatalf("bad:\n%s", actual) 199 } 200 201 actual = providerConfigsStr(c.ProviderConfigs) 202 if actual != strings.TrimSpace(basicProvidersStr) { 203 t.Fatalf("bad:\n%s", actual) 204 } 205 206 actual = resourcesStr(c.Resources) 207 if actual != strings.TrimSpace(basicResourcesStr) { 208 t.Fatalf("bad:\n%s", actual) 209 } 210 211 actual = outputsStr(c.Outputs) 212 if actual != strings.TrimSpace(basicOutputsStr) { 213 t.Fatalf("bad:\n%s", actual) 214 } 215 } 216 217 func TestLoadFileBasic_empty(t *testing.T) { 218 c, err := LoadFile(filepath.Join(fixtureDir, "empty.tf")) 219 if err != nil { 220 t.Fatalf("err: %s", err) 221 } 222 223 if c == nil { 224 t.Fatal("config should not be nil") 225 } 226 } 227 228 func TestLoadFileBasic_import(t *testing.T) { 229 // Skip because we disabled importing 230 t.Skip() 231 232 c, err := LoadFile(filepath.Join(fixtureDir, "import.tf")) 233 if err != nil { 234 t.Fatalf("err: %s", err) 235 } 236 237 if c == nil { 238 t.Fatal("config should not be nil") 239 } 240 241 actual := variablesStr(c.Variables) 242 if actual != strings.TrimSpace(importVariablesStr) { 243 t.Fatalf("bad:\n%s", actual) 244 } 245 246 actual = providerConfigsStr(c.ProviderConfigs) 247 if actual != strings.TrimSpace(importProvidersStr) { 248 t.Fatalf("bad:\n%s", actual) 249 } 250 251 actual = resourcesStr(c.Resources) 252 if actual != strings.TrimSpace(importResourcesStr) { 253 t.Fatalf("bad:\n%s", actual) 254 } 255 } 256 257 func TestLoadFileBasic_json(t *testing.T) { 258 c, err := LoadFile(filepath.Join(fixtureDir, "basic.tf.json")) 259 if err != nil { 260 t.Fatalf("err: %s", err) 261 } 262 263 if c == nil { 264 t.Fatal("config should not be nil") 265 } 266 267 if c.Dir != "" { 268 t.Fatalf("bad: %#v", c.Dir) 269 } 270 271 expectedAtlas := &AtlasConfig{Name: "mitchellh/foo"} 272 if !reflect.DeepEqual(c.Atlas, expectedAtlas) { 273 t.Fatalf("bad: %#v", c.Atlas) 274 } 275 276 actual := variablesStr(c.Variables) 277 if actual != strings.TrimSpace(basicVariablesStr) { 278 t.Fatalf("bad:\n%s", actual) 279 } 280 281 actual = providerConfigsStr(c.ProviderConfigs) 282 if actual != strings.TrimSpace(basicProvidersStr) { 283 t.Fatalf("bad:\n%s", actual) 284 } 285 286 actual = resourcesStr(c.Resources) 287 if actual != strings.TrimSpace(basicResourcesStr) { 288 t.Fatalf("bad:\n%s", actual) 289 } 290 291 actual = outputsStr(c.Outputs) 292 if actual != strings.TrimSpace(basicOutputsStr) { 293 t.Fatalf("bad:\n%s", actual) 294 } 295 } 296 297 func TestLoadFileBasic_modules(t *testing.T) { 298 c, err := LoadFile(filepath.Join(fixtureDir, "modules.tf")) 299 if err != nil { 300 t.Fatalf("err: %s", err) 301 } 302 303 if c == nil { 304 t.Fatal("config should not be nil") 305 } 306 307 if c.Dir != "" { 308 t.Fatalf("bad: %#v", c.Dir) 309 } 310 311 actual := modulesStr(c.Modules) 312 if actual != strings.TrimSpace(modulesModulesStr) { 313 t.Fatalf("bad:\n%s", actual) 314 } 315 } 316 317 func TestLoadFile_outputDependsOn(t *testing.T) { 318 c, err := LoadFile(filepath.Join(fixtureDir, "output-depends-on.tf")) 319 if err != nil { 320 t.Fatalf("err: %s", err) 321 } 322 323 if c == nil { 324 t.Fatal("config should not be nil") 325 } 326 327 if c.Dir != "" { 328 t.Fatalf("bad: %#v", c.Dir) 329 } 330 331 actual := outputsStr(c.Outputs) 332 if actual != strings.TrimSpace(outputDependsOnStr) { 333 t.Fatalf("bad:\n%s", actual) 334 } 335 } 336 337 func TestLoadFile_terraformBackend(t *testing.T) { 338 c, err := LoadFile(filepath.Join(fixtureDir, "terraform-backend.tf")) 339 if err != nil { 340 t.Fatalf("err: %s", err) 341 } 342 343 if c == nil { 344 t.Fatal("config should not be nil") 345 } 346 347 if c.Dir != "" { 348 t.Fatalf("bad: %#v", c.Dir) 349 } 350 351 { 352 actual := terraformStr(c.Terraform) 353 expected := strings.TrimSpace(` 354 backend (s3) 355 foo`) 356 if actual != expected { 357 t.Fatalf("bad:\n%s", actual) 358 } 359 } 360 } 361 362 func TestLoadFile_terraformBackendMulti(t *testing.T) { 363 _, err := LoadFile(filepath.Join(fixtureDir, "terraform-backend-multi.tf")) 364 if err == nil { 365 t.Fatal("expected error") 366 } 367 368 errorStr := err.Error() 369 if !strings.Contains(errorStr, "only one 'backend'") { 370 t.Fatalf("bad: expected error has wrong text: %s", errorStr) 371 } 372 } 373 374 func TestLoadJSONBasic(t *testing.T) { 375 raw, err := ioutil.ReadFile(filepath.Join(fixtureDir, "basic.tf.json")) 376 if err != nil { 377 t.Fatalf("err: %s", err) 378 } 379 380 c, err := LoadJSON(raw) 381 if err != nil { 382 t.Fatalf("err: %s", err) 383 } 384 385 if c == nil { 386 t.Fatal("config should not be nil") 387 } 388 389 if c.Dir != "" { 390 t.Fatalf("bad: %#v", c.Dir) 391 } 392 393 expectedAtlas := &AtlasConfig{Name: "mitchellh/foo"} 394 if !reflect.DeepEqual(c.Atlas, expectedAtlas) { 395 t.Fatalf("bad: %#v", c.Atlas) 396 } 397 398 actual := variablesStr(c.Variables) 399 if actual != strings.TrimSpace(basicVariablesStr) { 400 t.Fatalf("bad:\n%s", actual) 401 } 402 403 actual = providerConfigsStr(c.ProviderConfigs) 404 if actual != strings.TrimSpace(basicProvidersStr) { 405 t.Fatalf("bad:\n%s", actual) 406 } 407 408 actual = resourcesStr(c.Resources) 409 if actual != strings.TrimSpace(basicResourcesStr) { 410 t.Fatalf("bad:\n%s", actual) 411 } 412 413 actual = outputsStr(c.Outputs) 414 if actual != strings.TrimSpace(basicOutputsStr) { 415 t.Fatalf("bad:\n%s", actual) 416 } 417 } 418 419 func TestLoadJSONAmbiguous(t *testing.T) { 420 js := ` 421 { 422 "variable": { 423 "first": { 424 "default": { 425 "key": "val" 426 } 427 }, 428 "second": { 429 "description": "Described", 430 "default": { 431 "key": "val" 432 } 433 } 434 } 435 } 436 ` 437 438 c, err := LoadJSON([]byte(js)) 439 if err != nil { 440 t.Fatalf("err: %s", err) 441 } 442 443 if len(c.Variables) != 2 { 444 t.Fatal("config should have 2 variables, found", len(c.Variables)) 445 } 446 447 first := &Variable{ 448 Name: "first", 449 Default: map[string]interface{}{"key": "val"}, 450 } 451 second := &Variable{ 452 Name: "second", 453 Description: "Described", 454 Default: map[string]interface{}{"key": "val"}, 455 } 456 457 if !reflect.DeepEqual(first, c.Variables[0]) { 458 t.Fatalf("\nexpected: %#v\ngot: %#v", first, c.Variables[0]) 459 } 460 461 if !reflect.DeepEqual(second, c.Variables[1]) { 462 t.Fatalf("\nexpected: %#v\ngot: %#v", second, c.Variables[1]) 463 } 464 } 465 466 func TestLoadFileBasic_jsonNoName(t *testing.T) { 467 c, err := LoadFile(filepath.Join(fixtureDir, "resource-no-name.tf.json")) 468 if err != nil { 469 t.Fatalf("err: %s", err) 470 } 471 472 if c == nil { 473 t.Fatal("config should not be nil") 474 } 475 476 actual := resourcesStr(c.Resources) 477 if actual != strings.TrimSpace(basicJsonNoNameResourcesStr) { 478 t.Fatalf("bad:\n%s", actual) 479 } 480 } 481 482 func TestLoadFile_variables(t *testing.T) { 483 c, err := LoadFile(filepath.Join(fixtureDir, "variables.tf")) 484 if err != nil { 485 t.Fatalf("err: %s", err) 486 } 487 if c == nil { 488 t.Fatal("config should not be nil") 489 } 490 491 if c.Dir != "" { 492 t.Fatalf("bad: %#v", c.Dir) 493 } 494 495 actual := variablesStr(c.Variables) 496 if actual != strings.TrimSpace(variablesVariablesStr) { 497 t.Fatalf("bad:\n%s", actual) 498 } 499 } 500 501 func TestLoadDir_basic(t *testing.T) { 502 dir := filepath.Join(fixtureDir, "dir-basic") 503 c, err := LoadDir(dir) 504 if err != nil { 505 t.Fatalf("err: %s", err) 506 } 507 508 if c == nil { 509 t.Fatal("config should not be nil") 510 } 511 512 dirAbs, err := filepath.Abs(dir) 513 if err != nil { 514 t.Fatalf("err: %s", err) 515 } 516 if c.Dir != dirAbs { 517 t.Fatalf("bad: %#v", c.Dir) 518 } 519 520 actual := variablesStr(c.Variables) 521 if actual != strings.TrimSpace(dirBasicVariablesStr) { 522 t.Fatalf("bad:\n%s", actual) 523 } 524 525 actual = providerConfigsStr(c.ProviderConfigs) 526 if actual != strings.TrimSpace(dirBasicProvidersStr) { 527 t.Fatalf("bad:\n%s", actual) 528 } 529 530 actual = resourcesStr(c.Resources) 531 if actual != strings.TrimSpace(dirBasicResourcesStr) { 532 t.Fatalf("bad:\n%s", actual) 533 } 534 535 actual = outputsStr(c.Outputs) 536 if actual != strings.TrimSpace(dirBasicOutputsStr) { 537 t.Fatalf("bad:\n%s", actual) 538 } 539 } 540 541 func TestLoadDir_file(t *testing.T) { 542 _, err := LoadDir(filepath.Join(fixtureDir, "variables.tf")) 543 if err == nil { 544 t.Fatal("should error") 545 } 546 } 547 548 func TestLoadDir_noConfigs(t *testing.T) { 549 _, err := LoadDir(filepath.Join(fixtureDir, "dir-empty")) 550 if err == nil { 551 t.Fatal("should error") 552 } 553 } 554 555 func TestLoadDir_noMerge(t *testing.T) { 556 c, err := LoadDir(filepath.Join(fixtureDir, "dir-merge")) 557 if err != nil { 558 t.Fatalf("err: %s", err) 559 } 560 561 if c == nil { 562 t.Fatal("config should not be nil") 563 } 564 565 if err := c.Validate(); err == nil { 566 t.Fatal("should not be valid") 567 } 568 } 569 570 func TestLoadDir_override(t *testing.T) { 571 c, err := LoadDir(filepath.Join(fixtureDir, "dir-override")) 572 if err != nil { 573 t.Fatalf("err: %s", err) 574 } 575 576 if c == nil { 577 t.Fatal("config should not be nil") 578 } 579 580 actual := variablesStr(c.Variables) 581 if actual != strings.TrimSpace(dirOverrideVariablesStr) { 582 t.Fatalf("bad:\n%s", actual) 583 } 584 585 actual = providerConfigsStr(c.ProviderConfigs) 586 if actual != strings.TrimSpace(dirOverrideProvidersStr) { 587 t.Fatalf("bad:\n%s", actual) 588 } 589 590 actual = resourcesStr(c.Resources) 591 if actual != strings.TrimSpace(dirOverrideResourcesStr) { 592 t.Fatalf("bad:\n%s", actual) 593 } 594 595 actual = outputsStr(c.Outputs) 596 if actual != strings.TrimSpace(dirOverrideOutputsStr) { 597 t.Fatalf("bad:\n%s", actual) 598 } 599 } 600 601 func TestLoadDir_overrideVar(t *testing.T) { 602 c, err := LoadDir(filepath.Join(fixtureDir, "dir-override-var")) 603 if err != nil { 604 t.Fatalf("err: %s", err) 605 } 606 607 if c == nil { 608 t.Fatal("config should not be nil") 609 } 610 611 actual := variablesStr(c.Variables) 612 if actual != strings.TrimSpace(dirOverrideVarsVariablesStr) { 613 t.Fatalf("bad:\n%s", actual) 614 } 615 } 616 617 func TestLoadFile_mismatchedVariableTypes(t *testing.T) { 618 _, err := LoadFile(filepath.Join(fixtureDir, "variable-mismatched-type.tf")) 619 if err == nil { 620 t.Fatalf("bad: expected error") 621 } 622 623 errorStr := err.Error() 624 if !strings.Contains(errorStr, "'not_a_map' has a default value which is not of type 'string'") { 625 t.Fatalf("bad: expected error has wrong text: %s", errorStr) 626 } 627 } 628 629 func TestLoadFile_badVariableTypes(t *testing.T) { 630 _, err := LoadFile(filepath.Join(fixtureDir, "bad-variable-type.tf")) 631 if err == nil { 632 t.Fatalf("bad: expected error") 633 } 634 635 errorStr := err.Error() 636 if !strings.Contains(errorStr, "'bad_type' must be of type string") { 637 t.Fatalf("bad: expected error has wrong text: %s", errorStr) 638 } 639 } 640 641 func TestLoadFile_variableNoName(t *testing.T) { 642 _, err := LoadFile(filepath.Join(fixtureDir, "variable-no-name.tf")) 643 if err == nil { 644 t.Fatalf("bad: expected error") 645 } 646 647 errorStr := err.Error() 648 if !strings.Contains(errorStr, "'variable' must be followed") { 649 t.Fatalf("bad: expected error has wrong text: %s", errorStr) 650 } 651 } 652 653 func TestLoadFile_provisioners(t *testing.T) { 654 c, err := LoadFile(filepath.Join(fixtureDir, "provisioners.tf")) 655 if err != nil { 656 t.Fatalf("err: %s", err) 657 } 658 659 if c == nil { 660 t.Fatal("config should not be nil") 661 } 662 663 actual := resourcesStr(c.Resources) 664 if actual != strings.TrimSpace(provisionerResourcesStr) { 665 t.Fatalf("bad:\n%s", actual) 666 } 667 } 668 669 func TestLoadFile_provisionersDestroy(t *testing.T) { 670 c, err := LoadFile(filepath.Join(fixtureDir, "provisioners-destroy.tf")) 671 if err != nil { 672 t.Fatalf("err: %s", err) 673 } 674 675 if c == nil { 676 t.Fatal("config should not be nil") 677 } 678 679 actual := resourcesStr(c.Resources) 680 if actual != strings.TrimSpace(provisionerDestroyResourcesStr) { 681 t.Fatalf("bad:\n%s", actual) 682 } 683 } 684 685 func TestLoadFile_unnamedOutput(t *testing.T) { 686 _, err := LoadFile(filepath.Join(fixtureDir, "output-unnamed.tf")) 687 if err == nil { 688 t.Fatalf("bad: expected error") 689 } 690 691 errorStr := err.Error() 692 if !strings.Contains(errorStr, "'output' must be followed") { 693 t.Fatalf("bad: expected error has wrong text: %s", errorStr) 694 } 695 } 696 697 func TestLoadFile_connections(t *testing.T) { 698 c, err := LoadFile(filepath.Join(fixtureDir, "connection.tf")) 699 if err != nil { 700 t.Fatalf("err: %s", err) 701 } 702 703 if c == nil { 704 t.Fatal("config should not be nil") 705 } 706 707 actual := resourcesStr(c.Resources) 708 if actual != strings.TrimSpace(connectionResourcesStr) { 709 t.Fatalf("bad:\n%s", actual) 710 } 711 712 // Check for the connection info 713 r := c.Resources[0] 714 if r.Name != "web" && r.Type != "aws_instance" { 715 t.Fatalf("Bad: %#v", r) 716 } 717 718 p1 := r.Provisioners[0] 719 if p1.ConnInfo == nil || len(p1.ConnInfo.Raw) != 2 { 720 t.Fatalf("Bad: %#v", p1.ConnInfo) 721 } 722 if p1.ConnInfo.Raw["user"] != "nobody" { 723 t.Fatalf("Bad: %#v", p1.ConnInfo) 724 } 725 726 p2 := r.Provisioners[1] 727 if p2.ConnInfo == nil || len(p2.ConnInfo.Raw) != 2 { 728 t.Fatalf("Bad: %#v", p2.ConnInfo) 729 } 730 if p2.ConnInfo.Raw["user"] != "root" { 731 t.Fatalf("Bad: %#v", p2.ConnInfo) 732 } 733 } 734 735 func TestLoadFile_createBeforeDestroy(t *testing.T) { 736 c, err := LoadFile(filepath.Join(fixtureDir, "create-before-destroy.tf")) 737 if err != nil { 738 t.Fatalf("err: %s", err) 739 } 740 741 if c == nil { 742 t.Fatal("config should not be nil") 743 } 744 745 actual := resourcesStr(c.Resources) 746 if actual != strings.TrimSpace(createBeforeDestroyResourcesStr) { 747 t.Fatalf("bad:\n%s", actual) 748 } 749 750 // Check for the flag value 751 r := c.Resources[0] 752 if r.Name != "web" && r.Type != "aws_instance" { 753 t.Fatalf("Bad: %#v", r) 754 } 755 756 // Should enable create before destroy 757 if !r.Lifecycle.CreateBeforeDestroy { 758 t.Fatalf("Bad: %#v", r) 759 } 760 761 r = c.Resources[1] 762 if r.Name != "bar" && r.Type != "aws_instance" { 763 t.Fatalf("Bad: %#v", r) 764 } 765 766 // Should not enable create before destroy 767 if r.Lifecycle.CreateBeforeDestroy { 768 t.Fatalf("Bad: %#v", r) 769 } 770 } 771 772 func TestLoadFile_ignoreChanges(t *testing.T) { 773 c, err := LoadFile(filepath.Join(fixtureDir, "ignore-changes.tf")) 774 if err != nil { 775 t.Fatalf("err: %s", err) 776 } 777 778 if c == nil { 779 t.Fatal("config should not be nil") 780 } 781 782 actual := resourcesStr(c.Resources) 783 print(actual) 784 if actual != strings.TrimSpace(ignoreChangesResourcesStr) { 785 t.Fatalf("bad:\n%s", actual) 786 } 787 788 // Check for the flag value 789 r := c.Resources[0] 790 if r.Name != "web" && r.Type != "aws_instance" { 791 t.Fatalf("Bad: %#v", r) 792 } 793 794 // Should populate ignore changes 795 if len(r.Lifecycle.IgnoreChanges) == 0 { 796 t.Fatalf("Bad: %#v", r) 797 } 798 799 r = c.Resources[1] 800 if r.Name != "bar" && r.Type != "aws_instance" { 801 t.Fatalf("Bad: %#v", r) 802 } 803 804 // Should not populate ignore changes 805 if len(r.Lifecycle.IgnoreChanges) > 0 { 806 t.Fatalf("Bad: %#v", r) 807 } 808 809 r = c.Resources[2] 810 if r.Name != "baz" && r.Type != "aws_instance" { 811 t.Fatalf("Bad: %#v", r) 812 } 813 814 // Should not populate ignore changes 815 if len(r.Lifecycle.IgnoreChanges) > 0 { 816 t.Fatalf("Bad: %#v", r) 817 } 818 } 819 820 func TestLoad_preventDestroyString(t *testing.T) { 821 c, err := LoadFile(filepath.Join(fixtureDir, "prevent-destroy-string.tf")) 822 if err != nil { 823 t.Fatalf("err: %s", err) 824 } 825 826 if c == nil { 827 t.Fatal("config should not be nil") 828 } 829 830 actual := resourcesStr(c.Resources) 831 if actual != strings.TrimSpace(createBeforeDestroyResourcesStr) { 832 t.Fatalf("bad:\n%s", actual) 833 } 834 835 // Check for the flag value 836 r := c.Resources[0] 837 if r.Name != "web" && r.Type != "aws_instance" { 838 t.Fatalf("Bad: %#v", r) 839 } 840 841 // Should enable create before destroy 842 if !r.Lifecycle.PreventDestroy { 843 t.Fatalf("Bad: %#v", r) 844 } 845 846 r = c.Resources[1] 847 if r.Name != "bar" && r.Type != "aws_instance" { 848 t.Fatalf("Bad: %#v", r) 849 } 850 851 // Should not enable create before destroy 852 if r.Lifecycle.PreventDestroy { 853 t.Fatalf("Bad: %#v", r) 854 } 855 } 856 857 func TestLoad_temporary_files(t *testing.T) { 858 _, err := LoadDir(filepath.Join(fixtureDir, "dir-temporary-files")) 859 if err == nil { 860 t.Fatalf("Expected to see an error stating no config files found") 861 } 862 } 863 864 func TestLoad_hclAttributes(t *testing.T) { 865 c, err := LoadFile(filepath.Join(fixtureDir, "attributes.tf")) 866 if err != nil { 867 t.Fatalf("Bad: %s", err) 868 } 869 870 if c == nil { 871 t.Fatal("config should not be nil") 872 } 873 874 actual := resourcesStr(c.Resources) 875 print(actual) 876 if actual != strings.TrimSpace(jsonAttributeStr) { 877 t.Fatalf("bad:\n%s", actual) 878 } 879 880 r := c.Resources[0] 881 if r.Name != "test" && r.Type != "cloudstack_firewall" { 882 t.Fatalf("Bad: %#v", r) 883 } 884 885 raw := r.RawConfig 886 if raw.Raw["ipaddress"] != "192.168.0.1" { 887 t.Fatalf("Bad: %s", raw.Raw["ipAddress"]) 888 } 889 890 rule := raw.Raw["rule"].([]map[string]interface{})[0] 891 if rule["protocol"] != "tcp" { 892 t.Fatalf("Bad: %s", rule["protocol"]) 893 } 894 895 if rule["source_cidr"] != "10.0.0.0/8" { 896 t.Fatalf("Bad: %s", rule["source_cidr"]) 897 } 898 899 ports := rule["ports"].([]interface{}) 900 901 if ports[0] != "80" { 902 t.Fatalf("Bad ports: %s", ports[0]) 903 } 904 if ports[1] != "1000-2000" { 905 t.Fatalf("Bad ports: %s", ports[1]) 906 } 907 } 908 909 func TestLoad_jsonAttributes(t *testing.T) { 910 c, err := LoadFile(filepath.Join(fixtureDir, "attributes.tf.json")) 911 if err != nil { 912 t.Fatalf("Bad: %s", err) 913 } 914 915 if c == nil { 916 t.Fatal("config should not be nil") 917 } 918 919 actual := resourcesStr(c.Resources) 920 print(actual) 921 if actual != strings.TrimSpace(jsonAttributeStr) { 922 t.Fatalf("bad:\n%s", actual) 923 } 924 925 r := c.Resources[0] 926 if r.Name != "test" && r.Type != "cloudstack_firewall" { 927 t.Fatalf("Bad: %#v", r) 928 } 929 930 raw := r.RawConfig 931 if raw.Raw["ipaddress"] != "192.168.0.1" { 932 t.Fatalf("Bad: %s", raw.Raw["ipAddress"]) 933 } 934 935 rule := raw.Raw["rule"].([]map[string]interface{})[0] 936 if rule["protocol"] != "tcp" { 937 t.Fatalf("Bad: %s", rule["protocol"]) 938 } 939 940 if rule["source_cidr"] != "10.0.0.0/8" { 941 t.Fatalf("Bad: %s", rule["source_cidr"]) 942 } 943 944 ports := rule["ports"].([]interface{}) 945 946 if ports[0] != "80" { 947 t.Fatalf("Bad ports: %s", ports[0]) 948 } 949 if ports[1] != "1000-2000" { 950 t.Fatalf("Bad ports: %s", ports[1]) 951 } 952 } 953 954 const jsonAttributeStr = ` 955 cloudstack_firewall.test (x1) 956 ipaddress 957 rule 958 ` 959 960 const windowsHeredocResourcesStr = ` 961 aws_instance.test (x1) 962 user_data 963 ` 964 965 const heredocProvidersStr = ` 966 aws 967 access_key 968 secret_key 969 ` 970 971 const heredocResourcesStr = ` 972 aws_iam_policy.policy (x1) 973 description 974 name 975 path 976 policy 977 aws_instance.heredocwithnumbers (x1) 978 ami 979 provisioners 980 local-exec 981 command 982 aws_instance.test (x1) 983 ami 984 provisioners 985 remote-exec 986 inline 987 ` 988 989 const basicOutputsStr = ` 990 web_ip 991 vars 992 resource: aws_instance.web.private_ip 993 ` 994 995 const basicProvidersStr = ` 996 aws 997 access_key 998 secret_key 999 do 1000 api_key 1001 vars 1002 user: var.foo 1003 ` 1004 1005 const basicResourcesStr = ` 1006 aws_instance.db (x1) 1007 VPC 1008 security_groups 1009 provisioners 1010 file 1011 destination 1012 source 1013 dependsOn 1014 aws_instance.web 1015 vars 1016 resource: aws_security_group.firewall.*.id 1017 aws_instance.web (x1) 1018 ami 1019 network_interface 1020 security_groups 1021 provisioners 1022 file 1023 destination 1024 source 1025 vars 1026 resource: aws_security_group.firewall.foo 1027 user: var.foo 1028 aws_security_group.firewall (x5) 1029 data.do.depends (x1) 1030 dependsOn 1031 data.do.simple 1032 data.do.simple (x1) 1033 foo 1034 ` 1035 1036 const basicVariablesStr = ` 1037 bar (required) (string) 1038 <> 1039 <> 1040 baz (map) 1041 map[key:value] 1042 <> 1043 foo 1044 bar 1045 bar 1046 ` 1047 1048 const basicJsonNoNameResourcesStr = ` 1049 aws_security_group.allow_external_http_https (x1) 1050 tags 1051 ` 1052 1053 const dirBasicOutputsStr = ` 1054 web_ip 1055 vars 1056 resource: aws_instance.web.private_ip 1057 ` 1058 1059 const dirBasicProvidersStr = ` 1060 aws 1061 access_key 1062 secret_key 1063 do 1064 api_key 1065 vars 1066 user: var.foo 1067 ` 1068 1069 const dirBasicResourcesStr = ` 1070 aws_instance.db (x1) 1071 security_groups 1072 vars 1073 resource: aws_security_group.firewall.*.id 1074 aws_instance.web (x1) 1075 ami 1076 network_interface 1077 security_groups 1078 vars 1079 resource: aws_security_group.firewall.foo 1080 user: var.foo 1081 aws_security_group.firewall (x5) 1082 data.do.depends (x1) 1083 dependsOn 1084 data.do.simple 1085 data.do.simple (x1) 1086 foo 1087 ` 1088 1089 const dirBasicVariablesStr = ` 1090 foo 1091 bar 1092 bar 1093 ` 1094 1095 const dirOverrideOutputsStr = ` 1096 web_ip 1097 vars 1098 resource: aws_instance.web.private_ip 1099 ` 1100 1101 const dirOverrideProvidersStr = ` 1102 aws 1103 access_key 1104 secret_key 1105 do 1106 api_key 1107 vars 1108 user: var.foo 1109 ` 1110 1111 const dirOverrideResourcesStr = ` 1112 aws_instance.db (x1) 1113 ami 1114 security_groups 1115 aws_instance.web (x1) 1116 ami 1117 foo 1118 network_interface 1119 security_groups 1120 vars 1121 resource: aws_security_group.firewall.foo 1122 user: var.foo 1123 aws_security_group.firewall (x5) 1124 data.do.depends (x1) 1125 hello 1126 dependsOn 1127 data.do.simple 1128 data.do.simple (x1) 1129 foo 1130 ` 1131 1132 const dirOverrideVariablesStr = ` 1133 foo 1134 bar 1135 bar 1136 ` 1137 1138 const dirOverrideVarsVariablesStr = ` 1139 foo 1140 baz 1141 bar 1142 ` 1143 1144 const importProvidersStr = ` 1145 aws 1146 bar 1147 foo 1148 ` 1149 1150 const importResourcesStr = ` 1151 aws_security_group.db (x1) 1152 aws_security_group.web (x1) 1153 ` 1154 1155 const importVariablesStr = ` 1156 bar (required) 1157 <> 1158 <> 1159 foo 1160 bar 1161 bar 1162 ` 1163 1164 const modulesModulesStr = ` 1165 bar 1166 source = baz 1167 memory 1168 ` 1169 1170 const provisionerResourcesStr = ` 1171 aws_instance.web (x1) 1172 ami 1173 security_groups 1174 provisioners 1175 shell 1176 path 1177 vars 1178 resource: aws_security_group.firewall.foo 1179 user: var.foo 1180 ` 1181 1182 const provisionerDestroyResourcesStr = ` 1183 aws_instance.web (x1) 1184 provisioners 1185 shell 1186 shell (destroy) 1187 path 1188 shell (destroy) 1189 on_failure = continue 1190 path 1191 ` 1192 1193 const connectionResourcesStr = ` 1194 aws_instance.web (x1) 1195 ami 1196 security_groups 1197 provisioners 1198 shell 1199 path 1200 shell 1201 path 1202 vars 1203 resource: aws_security_group.firewall.foo 1204 user: var.foo 1205 ` 1206 1207 const outputDependsOnStr = ` 1208 value 1209 dependsOn 1210 foo 1211 ` 1212 1213 const variablesVariablesStr = ` 1214 bar 1215 <> 1216 <> 1217 baz 1218 foo 1219 <> 1220 foo (required) 1221 <> 1222 <> 1223 ` 1224 1225 const createBeforeDestroyResourcesStr = ` 1226 aws_instance.bar (x1) 1227 ami 1228 aws_instance.web (x1) 1229 ami 1230 ` 1231 1232 const ignoreChangesResourcesStr = ` 1233 aws_instance.bar (x1) 1234 ami 1235 aws_instance.baz (x1) 1236 ami 1237 aws_instance.web (x1) 1238 ami 1239 `