github.com/gettyimages/terraform@v0.7.6-0.20161219132226-dc052c5707a3/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 TestLoadJSONBasic(t *testing.T) { 338 raw, err := ioutil.ReadFile(filepath.Join(fixtureDir, "basic.tf.json")) 339 if err != nil { 340 t.Fatalf("err: %s", err) 341 } 342 343 c, err := LoadJSON(raw) 344 if err != nil { 345 t.Fatalf("err: %s", err) 346 } 347 348 if c == nil { 349 t.Fatal("config should not be nil") 350 } 351 352 if c.Dir != "" { 353 t.Fatalf("bad: %#v", c.Dir) 354 } 355 356 expectedAtlas := &AtlasConfig{Name: "mitchellh/foo"} 357 if !reflect.DeepEqual(c.Atlas, expectedAtlas) { 358 t.Fatalf("bad: %#v", c.Atlas) 359 } 360 361 actual := variablesStr(c.Variables) 362 if actual != strings.TrimSpace(basicVariablesStr) { 363 t.Fatalf("bad:\n%s", actual) 364 } 365 366 actual = providerConfigsStr(c.ProviderConfigs) 367 if actual != strings.TrimSpace(basicProvidersStr) { 368 t.Fatalf("bad:\n%s", actual) 369 } 370 371 actual = resourcesStr(c.Resources) 372 if actual != strings.TrimSpace(basicResourcesStr) { 373 t.Fatalf("bad:\n%s", actual) 374 } 375 376 actual = outputsStr(c.Outputs) 377 if actual != strings.TrimSpace(basicOutputsStr) { 378 t.Fatalf("bad:\n%s", actual) 379 } 380 } 381 382 func TestLoadJSONAmbiguous(t *testing.T) { 383 js := ` 384 { 385 "variable": { 386 "first": { 387 "default": { 388 "key": "val" 389 } 390 }, 391 "second": { 392 "description": "Described", 393 "default": { 394 "key": "val" 395 } 396 } 397 } 398 } 399 ` 400 401 c, err := LoadJSON([]byte(js)) 402 if err != nil { 403 t.Fatalf("err: %s", err) 404 } 405 406 if len(c.Variables) != 2 { 407 t.Fatal("config should have 2 variables, found", len(c.Variables)) 408 } 409 410 first := &Variable{ 411 Name: "first", 412 Default: map[string]interface{}{"key": "val"}, 413 } 414 second := &Variable{ 415 Name: "second", 416 Description: "Described", 417 Default: map[string]interface{}{"key": "val"}, 418 } 419 420 if !reflect.DeepEqual(first, c.Variables[0]) { 421 t.Fatalf("\nexpected: %#v\ngot: %#v", first, c.Variables[0]) 422 } 423 424 if !reflect.DeepEqual(second, c.Variables[1]) { 425 t.Fatalf("\nexpected: %#v\ngot: %#v", second, c.Variables[1]) 426 } 427 } 428 429 func TestLoadFileBasic_jsonNoName(t *testing.T) { 430 c, err := LoadFile(filepath.Join(fixtureDir, "resource-no-name.tf.json")) 431 if err != nil { 432 t.Fatalf("err: %s", err) 433 } 434 435 if c == nil { 436 t.Fatal("config should not be nil") 437 } 438 439 actual := resourcesStr(c.Resources) 440 if actual != strings.TrimSpace(basicJsonNoNameResourcesStr) { 441 t.Fatalf("bad:\n%s", actual) 442 } 443 } 444 445 func TestLoadFile_variables(t *testing.T) { 446 c, err := LoadFile(filepath.Join(fixtureDir, "variables.tf")) 447 if err != nil { 448 t.Fatalf("err: %s", err) 449 } 450 if c == nil { 451 t.Fatal("config should not be nil") 452 } 453 454 if c.Dir != "" { 455 t.Fatalf("bad: %#v", c.Dir) 456 } 457 458 actual := variablesStr(c.Variables) 459 if actual != strings.TrimSpace(variablesVariablesStr) { 460 t.Fatalf("bad:\n%s", actual) 461 } 462 } 463 464 func TestLoadDir_basic(t *testing.T) { 465 dir := filepath.Join(fixtureDir, "dir-basic") 466 c, err := LoadDir(dir) 467 if err != nil { 468 t.Fatalf("err: %s", err) 469 } 470 471 if c == nil { 472 t.Fatal("config should not be nil") 473 } 474 475 dirAbs, err := filepath.Abs(dir) 476 if err != nil { 477 t.Fatalf("err: %s", err) 478 } 479 if c.Dir != dirAbs { 480 t.Fatalf("bad: %#v", c.Dir) 481 } 482 483 actual := variablesStr(c.Variables) 484 if actual != strings.TrimSpace(dirBasicVariablesStr) { 485 t.Fatalf("bad:\n%s", actual) 486 } 487 488 actual = providerConfigsStr(c.ProviderConfigs) 489 if actual != strings.TrimSpace(dirBasicProvidersStr) { 490 t.Fatalf("bad:\n%s", actual) 491 } 492 493 actual = resourcesStr(c.Resources) 494 if actual != strings.TrimSpace(dirBasicResourcesStr) { 495 t.Fatalf("bad:\n%s", actual) 496 } 497 498 actual = outputsStr(c.Outputs) 499 if actual != strings.TrimSpace(dirBasicOutputsStr) { 500 t.Fatalf("bad:\n%s", actual) 501 } 502 } 503 504 func TestLoadDir_file(t *testing.T) { 505 _, err := LoadDir(filepath.Join(fixtureDir, "variables.tf")) 506 if err == nil { 507 t.Fatal("should error") 508 } 509 } 510 511 func TestLoadDir_noConfigs(t *testing.T) { 512 _, err := LoadDir(filepath.Join(fixtureDir, "dir-empty")) 513 if err == nil { 514 t.Fatal("should error") 515 } 516 } 517 518 func TestLoadDir_noMerge(t *testing.T) { 519 c, err := LoadDir(filepath.Join(fixtureDir, "dir-merge")) 520 if err != nil { 521 t.Fatalf("err: %s", err) 522 } 523 524 if c == nil { 525 t.Fatal("config should not be nil") 526 } 527 528 if err := c.Validate(); err == nil { 529 t.Fatal("should not be valid") 530 } 531 } 532 533 func TestLoadDir_override(t *testing.T) { 534 c, err := LoadDir(filepath.Join(fixtureDir, "dir-override")) 535 if err != nil { 536 t.Fatalf("err: %s", err) 537 } 538 539 if c == nil { 540 t.Fatal("config should not be nil") 541 } 542 543 actual := variablesStr(c.Variables) 544 if actual != strings.TrimSpace(dirOverrideVariablesStr) { 545 t.Fatalf("bad:\n%s", actual) 546 } 547 548 actual = providerConfigsStr(c.ProviderConfigs) 549 if actual != strings.TrimSpace(dirOverrideProvidersStr) { 550 t.Fatalf("bad:\n%s", actual) 551 } 552 553 actual = resourcesStr(c.Resources) 554 if actual != strings.TrimSpace(dirOverrideResourcesStr) { 555 t.Fatalf("bad:\n%s", actual) 556 } 557 558 actual = outputsStr(c.Outputs) 559 if actual != strings.TrimSpace(dirOverrideOutputsStr) { 560 t.Fatalf("bad:\n%s", actual) 561 } 562 } 563 564 func TestLoadDir_overrideVar(t *testing.T) { 565 c, err := LoadDir(filepath.Join(fixtureDir, "dir-override-var")) 566 if err != nil { 567 t.Fatalf("err: %s", err) 568 } 569 570 if c == nil { 571 t.Fatal("config should not be nil") 572 } 573 574 actual := variablesStr(c.Variables) 575 if actual != strings.TrimSpace(dirOverrideVarsVariablesStr) { 576 t.Fatalf("bad:\n%s", actual) 577 } 578 } 579 580 func TestLoadFile_mismatchedVariableTypes(t *testing.T) { 581 _, err := LoadFile(filepath.Join(fixtureDir, "variable-mismatched-type.tf")) 582 if err == nil { 583 t.Fatalf("bad: expected error") 584 } 585 586 errorStr := err.Error() 587 if !strings.Contains(errorStr, "'not_a_map' has a default value which is not of type 'string'") { 588 t.Fatalf("bad: expected error has wrong text: %s", errorStr) 589 } 590 } 591 592 func TestLoadFile_badVariableTypes(t *testing.T) { 593 _, err := LoadFile(filepath.Join(fixtureDir, "bad-variable-type.tf")) 594 if err == nil { 595 t.Fatalf("bad: expected error") 596 } 597 598 errorStr := err.Error() 599 if !strings.Contains(errorStr, "'bad_type' must be of type string") { 600 t.Fatalf("bad: expected error has wrong text: %s", errorStr) 601 } 602 } 603 604 func TestLoadFile_variableNoName(t *testing.T) { 605 _, err := LoadFile(filepath.Join(fixtureDir, "variable-no-name.tf")) 606 if err == nil { 607 t.Fatalf("bad: expected error") 608 } 609 610 errorStr := err.Error() 611 if !strings.Contains(errorStr, "'variable' must be followed") { 612 t.Fatalf("bad: expected error has wrong text: %s", errorStr) 613 } 614 } 615 616 func TestLoadFile_provisioners(t *testing.T) { 617 c, err := LoadFile(filepath.Join(fixtureDir, "provisioners.tf")) 618 if err != nil { 619 t.Fatalf("err: %s", err) 620 } 621 622 if c == nil { 623 t.Fatal("config should not be nil") 624 } 625 626 actual := resourcesStr(c.Resources) 627 if actual != strings.TrimSpace(provisionerResourcesStr) { 628 t.Fatalf("bad:\n%s", actual) 629 } 630 } 631 632 func TestLoadFile_unnamedOutput(t *testing.T) { 633 _, err := LoadFile(filepath.Join(fixtureDir, "output-unnamed.tf")) 634 if err == nil { 635 t.Fatalf("bad: expected error") 636 } 637 638 errorStr := err.Error() 639 if !strings.Contains(errorStr, "'output' must be followed") { 640 t.Fatalf("bad: expected error has wrong text: %s", errorStr) 641 } 642 } 643 644 func TestLoadFile_connections(t *testing.T) { 645 c, err := LoadFile(filepath.Join(fixtureDir, "connection.tf")) 646 if err != nil { 647 t.Fatalf("err: %s", err) 648 } 649 650 if c == nil { 651 t.Fatal("config should not be nil") 652 } 653 654 actual := resourcesStr(c.Resources) 655 if actual != strings.TrimSpace(connectionResourcesStr) { 656 t.Fatalf("bad:\n%s", actual) 657 } 658 659 // Check for the connection info 660 r := c.Resources[0] 661 if r.Name != "web" && r.Type != "aws_instance" { 662 t.Fatalf("Bad: %#v", r) 663 } 664 665 p1 := r.Provisioners[0] 666 if p1.ConnInfo == nil || len(p1.ConnInfo.Raw) != 2 { 667 t.Fatalf("Bad: %#v", p1.ConnInfo) 668 } 669 if p1.ConnInfo.Raw["user"] != "nobody" { 670 t.Fatalf("Bad: %#v", p1.ConnInfo) 671 } 672 673 p2 := r.Provisioners[1] 674 if p2.ConnInfo == nil || len(p2.ConnInfo.Raw) != 2 { 675 t.Fatalf("Bad: %#v", p2.ConnInfo) 676 } 677 if p2.ConnInfo.Raw["user"] != "root" { 678 t.Fatalf("Bad: %#v", p2.ConnInfo) 679 } 680 } 681 682 func TestLoadFile_createBeforeDestroy(t *testing.T) { 683 c, err := LoadFile(filepath.Join(fixtureDir, "create-before-destroy.tf")) 684 if err != nil { 685 t.Fatalf("err: %s", err) 686 } 687 688 if c == nil { 689 t.Fatal("config should not be nil") 690 } 691 692 actual := resourcesStr(c.Resources) 693 if actual != strings.TrimSpace(createBeforeDestroyResourcesStr) { 694 t.Fatalf("bad:\n%s", actual) 695 } 696 697 // Check for the flag value 698 r := c.Resources[0] 699 if r.Name != "web" && r.Type != "aws_instance" { 700 t.Fatalf("Bad: %#v", r) 701 } 702 703 // Should enable create before destroy 704 if !r.Lifecycle.CreateBeforeDestroy { 705 t.Fatalf("Bad: %#v", r) 706 } 707 708 r = c.Resources[1] 709 if r.Name != "bar" && r.Type != "aws_instance" { 710 t.Fatalf("Bad: %#v", r) 711 } 712 713 // Should not enable create before destroy 714 if r.Lifecycle.CreateBeforeDestroy { 715 t.Fatalf("Bad: %#v", r) 716 } 717 } 718 719 func TestLoadFile_ignoreChanges(t *testing.T) { 720 c, err := LoadFile(filepath.Join(fixtureDir, "ignore-changes.tf")) 721 if err != nil { 722 t.Fatalf("err: %s", err) 723 } 724 725 if c == nil { 726 t.Fatal("config should not be nil") 727 } 728 729 actual := resourcesStr(c.Resources) 730 print(actual) 731 if actual != strings.TrimSpace(ignoreChangesResourcesStr) { 732 t.Fatalf("bad:\n%s", actual) 733 } 734 735 // Check for the flag value 736 r := c.Resources[0] 737 if r.Name != "web" && r.Type != "aws_instance" { 738 t.Fatalf("Bad: %#v", r) 739 } 740 741 // Should populate ignore changes 742 if len(r.Lifecycle.IgnoreChanges) == 0 { 743 t.Fatalf("Bad: %#v", r) 744 } 745 746 r = c.Resources[1] 747 if r.Name != "bar" && r.Type != "aws_instance" { 748 t.Fatalf("Bad: %#v", r) 749 } 750 751 // Should not populate ignore changes 752 if len(r.Lifecycle.IgnoreChanges) > 0 { 753 t.Fatalf("Bad: %#v", r) 754 } 755 756 r = c.Resources[2] 757 if r.Name != "baz" && r.Type != "aws_instance" { 758 t.Fatalf("Bad: %#v", r) 759 } 760 761 // Should not populate ignore changes 762 if len(r.Lifecycle.IgnoreChanges) > 0 { 763 t.Fatalf("Bad: %#v", r) 764 } 765 } 766 767 func TestLoad_preventDestroyString(t *testing.T) { 768 c, err := LoadFile(filepath.Join(fixtureDir, "prevent-destroy-string.tf")) 769 if err != nil { 770 t.Fatalf("err: %s", err) 771 } 772 773 if c == nil { 774 t.Fatal("config should not be nil") 775 } 776 777 actual := resourcesStr(c.Resources) 778 if actual != strings.TrimSpace(createBeforeDestroyResourcesStr) { 779 t.Fatalf("bad:\n%s", actual) 780 } 781 782 // Check for the flag value 783 r := c.Resources[0] 784 if r.Name != "web" && r.Type != "aws_instance" { 785 t.Fatalf("Bad: %#v", r) 786 } 787 788 // Should enable create before destroy 789 if !r.Lifecycle.PreventDestroy { 790 t.Fatalf("Bad: %#v", r) 791 } 792 793 r = c.Resources[1] 794 if r.Name != "bar" && r.Type != "aws_instance" { 795 t.Fatalf("Bad: %#v", r) 796 } 797 798 // Should not enable create before destroy 799 if r.Lifecycle.PreventDestroy { 800 t.Fatalf("Bad: %#v", r) 801 } 802 } 803 804 func TestLoad_temporary_files(t *testing.T) { 805 _, err := LoadDir(filepath.Join(fixtureDir, "dir-temporary-files")) 806 if err == nil { 807 t.Fatalf("Expected to see an error stating no config files found") 808 } 809 } 810 811 func TestLoad_hclAttributes(t *testing.T) { 812 c, err := LoadFile(filepath.Join(fixtureDir, "attributes.tf")) 813 if err != nil { 814 t.Fatalf("Bad: %s", err) 815 } 816 817 if c == nil { 818 t.Fatal("config should not be nil") 819 } 820 821 actual := resourcesStr(c.Resources) 822 print(actual) 823 if actual != strings.TrimSpace(jsonAttributeStr) { 824 t.Fatalf("bad:\n%s", actual) 825 } 826 827 r := c.Resources[0] 828 if r.Name != "test" && r.Type != "cloudstack_firewall" { 829 t.Fatalf("Bad: %#v", r) 830 } 831 832 raw := r.RawConfig 833 if raw.Raw["ipaddress"] != "192.168.0.1" { 834 t.Fatalf("Bad: %s", raw.Raw["ipAddress"]) 835 } 836 837 rule := raw.Raw["rule"].([]map[string]interface{})[0] 838 if rule["protocol"] != "tcp" { 839 t.Fatalf("Bad: %s", rule["protocol"]) 840 } 841 842 if rule["source_cidr"] != "10.0.0.0/8" { 843 t.Fatalf("Bad: %s", rule["source_cidr"]) 844 } 845 846 ports := rule["ports"].([]interface{}) 847 848 if ports[0] != "80" { 849 t.Fatalf("Bad ports: %s", ports[0]) 850 } 851 if ports[1] != "1000-2000" { 852 t.Fatalf("Bad ports: %s", ports[1]) 853 } 854 } 855 856 func TestLoad_jsonAttributes(t *testing.T) { 857 c, err := LoadFile(filepath.Join(fixtureDir, "attributes.tf.json")) 858 if err != nil { 859 t.Fatalf("Bad: %s", err) 860 } 861 862 if c == nil { 863 t.Fatal("config should not be nil") 864 } 865 866 actual := resourcesStr(c.Resources) 867 print(actual) 868 if actual != strings.TrimSpace(jsonAttributeStr) { 869 t.Fatalf("bad:\n%s", actual) 870 } 871 872 r := c.Resources[0] 873 if r.Name != "test" && r.Type != "cloudstack_firewall" { 874 t.Fatalf("Bad: %#v", r) 875 } 876 877 raw := r.RawConfig 878 if raw.Raw["ipaddress"] != "192.168.0.1" { 879 t.Fatalf("Bad: %s", raw.Raw["ipAddress"]) 880 } 881 882 rule := raw.Raw["rule"].([]map[string]interface{})[0] 883 if rule["protocol"] != "tcp" { 884 t.Fatalf("Bad: %s", rule["protocol"]) 885 } 886 887 if rule["source_cidr"] != "10.0.0.0/8" { 888 t.Fatalf("Bad: %s", rule["source_cidr"]) 889 } 890 891 ports := rule["ports"].([]interface{}) 892 893 if ports[0] != "80" { 894 t.Fatalf("Bad ports: %s", ports[0]) 895 } 896 if ports[1] != "1000-2000" { 897 t.Fatalf("Bad ports: %s", ports[1]) 898 } 899 } 900 901 const jsonAttributeStr = ` 902 cloudstack_firewall.test (x1) 903 ipaddress 904 rule 905 ` 906 907 const windowsHeredocResourcesStr = ` 908 aws_instance.test (x1) 909 user_data 910 ` 911 912 const heredocProvidersStr = ` 913 aws 914 access_key 915 secret_key 916 ` 917 918 const heredocResourcesStr = ` 919 aws_iam_policy.policy (x1) 920 description 921 name 922 path 923 policy 924 aws_instance.heredocwithnumbers (x1) 925 ami 926 provisioners 927 local-exec 928 command 929 aws_instance.test (x1) 930 ami 931 provisioners 932 remote-exec 933 inline 934 ` 935 936 const basicOutputsStr = ` 937 web_ip 938 vars 939 resource: aws_instance.web.private_ip 940 ` 941 942 const basicProvidersStr = ` 943 aws 944 access_key 945 secret_key 946 do 947 api_key 948 vars 949 user: var.foo 950 ` 951 952 const basicResourcesStr = ` 953 aws_instance.db (x1) 954 VPC 955 security_groups 956 provisioners 957 file 958 destination 959 source 960 dependsOn 961 aws_instance.web 962 vars 963 resource: aws_security_group.firewall.*.id 964 aws_instance.web (x1) 965 ami 966 network_interface 967 security_groups 968 provisioners 969 file 970 destination 971 source 972 vars 973 resource: aws_security_group.firewall.foo 974 user: var.foo 975 aws_security_group.firewall (x5) 976 data.do.depends (x1) 977 dependsOn 978 data.do.simple 979 data.do.simple (x1) 980 foo 981 ` 982 983 const basicVariablesStr = ` 984 bar (required) (string) 985 <> 986 <> 987 baz (map) 988 map[key:value] 989 <> 990 foo 991 bar 992 bar 993 ` 994 995 const basicJsonNoNameResourcesStr = ` 996 aws_security_group.allow_external_http_https (x1) 997 tags 998 ` 999 1000 const dirBasicOutputsStr = ` 1001 web_ip 1002 vars 1003 resource: aws_instance.web.private_ip 1004 ` 1005 1006 const dirBasicProvidersStr = ` 1007 aws 1008 access_key 1009 secret_key 1010 do 1011 api_key 1012 vars 1013 user: var.foo 1014 ` 1015 1016 const dirBasicResourcesStr = ` 1017 aws_instance.db (x1) 1018 security_groups 1019 vars 1020 resource: aws_security_group.firewall.*.id 1021 aws_instance.web (x1) 1022 ami 1023 network_interface 1024 security_groups 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 dirBasicVariablesStr = ` 1037 foo 1038 bar 1039 bar 1040 ` 1041 1042 const dirOverrideOutputsStr = ` 1043 web_ip 1044 vars 1045 resource: aws_instance.web.private_ip 1046 ` 1047 1048 const dirOverrideProvidersStr = ` 1049 aws 1050 access_key 1051 secret_key 1052 do 1053 api_key 1054 vars 1055 user: var.foo 1056 ` 1057 1058 const dirOverrideResourcesStr = ` 1059 aws_instance.db (x1) 1060 ami 1061 security_groups 1062 aws_instance.web (x1) 1063 ami 1064 foo 1065 network_interface 1066 security_groups 1067 vars 1068 resource: aws_security_group.firewall.foo 1069 user: var.foo 1070 aws_security_group.firewall (x5) 1071 data.do.depends (x1) 1072 hello 1073 dependsOn 1074 data.do.simple 1075 data.do.simple (x1) 1076 foo 1077 ` 1078 1079 const dirOverrideVariablesStr = ` 1080 foo 1081 bar 1082 bar 1083 ` 1084 1085 const dirOverrideVarsVariablesStr = ` 1086 foo 1087 baz 1088 bar 1089 ` 1090 1091 const importProvidersStr = ` 1092 aws 1093 bar 1094 foo 1095 ` 1096 1097 const importResourcesStr = ` 1098 aws_security_group.db (x1) 1099 aws_security_group.web (x1) 1100 ` 1101 1102 const importVariablesStr = ` 1103 bar (required) 1104 <> 1105 <> 1106 foo 1107 bar 1108 bar 1109 ` 1110 1111 const modulesModulesStr = ` 1112 bar 1113 source = baz 1114 memory 1115 ` 1116 1117 const provisionerResourcesStr = ` 1118 aws_instance.web (x1) 1119 ami 1120 security_groups 1121 provisioners 1122 shell 1123 path 1124 vars 1125 resource: aws_security_group.firewall.foo 1126 user: var.foo 1127 ` 1128 1129 const connectionResourcesStr = ` 1130 aws_instance.web (x1) 1131 ami 1132 security_groups 1133 provisioners 1134 shell 1135 path 1136 shell 1137 path 1138 vars 1139 resource: aws_security_group.firewall.foo 1140 user: var.foo 1141 ` 1142 1143 const outputDependsOnStr = ` 1144 value 1145 dependsOn 1146 foo 1147 ` 1148 1149 const variablesVariablesStr = ` 1150 bar 1151 <> 1152 <> 1153 baz 1154 foo 1155 <> 1156 foo (required) 1157 <> 1158 <> 1159 ` 1160 1161 const createBeforeDestroyResourcesStr = ` 1162 aws_instance.bar (x1) 1163 ami 1164 aws_instance.web (x1) 1165 ami 1166 ` 1167 1168 const ignoreChangesResourcesStr = ` 1169 aws_instance.bar (x1) 1170 ami 1171 aws_instance.baz (x1) 1172 ami 1173 aws_instance.web (x1) 1174 ami 1175 `