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