github.com/mikesimons/terraform@v0.6.13-0.20160304043642-f11448c69214/terraform/context_plan_test.go (about) 1 package terraform 2 3 import ( 4 "bytes" 5 "fmt" 6 "os" 7 "reflect" 8 "sort" 9 "strings" 10 "sync" 11 "testing" 12 ) 13 14 func TestContext2Plan(t *testing.T) { 15 m := testModule(t, "plan-good") 16 p := testProvider("aws") 17 p.DiffFn = testDiffFn 18 ctx := testContext2(t, &ContextOpts{ 19 Module: m, 20 Providers: map[string]ResourceProviderFactory{ 21 "aws": testProviderFuncFixed(p), 22 }, 23 }) 24 25 plan, err := ctx.Plan() 26 if err != nil { 27 t.Fatalf("err: %s", err) 28 } 29 30 if len(plan.Diff.RootModule().Resources) < 2 { 31 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 32 } 33 34 actual := strings.TrimSpace(plan.String()) 35 expected := strings.TrimSpace(testTerraformPlanStr) 36 if actual != expected { 37 t.Fatalf("bad:\n%s", actual) 38 } 39 } 40 41 func TestContext2Plan_createBefore_maintainRoot(t *testing.T) { 42 m := testModule(t, "plan-cbd-maintain-root") 43 p := testProvider("aws") 44 p.DiffFn = testDiffFn 45 ctx := testContext2(t, &ContextOpts{ 46 Module: m, 47 Providers: map[string]ResourceProviderFactory{ 48 "aws": testProviderFuncFixed(p), 49 }, 50 Variables: map[string]string{ 51 "in": "a,b,c", 52 }, 53 }) 54 55 plan, err := ctx.Plan() 56 if err != nil { 57 t.Fatalf("err: %s", err) 58 } 59 60 actual := strings.TrimSpace(plan.String()) 61 expected := strings.TrimSpace(` 62 DIFF: 63 64 CREATE: aws_instance.bar.0 65 CREATE: aws_instance.bar.1 66 CREATE: aws_instance.foo.0 67 CREATE: aws_instance.foo.1 68 69 STATE: 70 71 <no state> 72 `) 73 if actual != expected { 74 t.Fatalf("expected:\n%s, got:\n%s", expected, actual) 75 } 76 } 77 78 func TestContext2Plan_emptyDiff(t *testing.T) { 79 m := testModule(t, "plan-empty") 80 p := testProvider("aws") 81 p.DiffFn = func( 82 info *InstanceInfo, 83 s *InstanceState, 84 c *ResourceConfig) (*InstanceDiff, error) { 85 return nil, nil 86 } 87 88 ctx := testContext2(t, &ContextOpts{ 89 Module: m, 90 Providers: map[string]ResourceProviderFactory{ 91 "aws": testProviderFuncFixed(p), 92 }, 93 }) 94 95 plan, err := ctx.Plan() 96 if err != nil { 97 t.Fatalf("err: %s", err) 98 } 99 100 actual := strings.TrimSpace(plan.String()) 101 expected := strings.TrimSpace(testTerraformPlanEmptyStr) 102 if actual != expected { 103 t.Fatalf("bad:\n%s", actual) 104 } 105 } 106 107 func TestContext2Plan_escapedVar(t *testing.T) { 108 m := testModule(t, "plan-escaped-var") 109 p := testProvider("aws") 110 p.DiffFn = testDiffFn 111 ctx := testContext2(t, &ContextOpts{ 112 Module: m, 113 Providers: map[string]ResourceProviderFactory{ 114 "aws": testProviderFuncFixed(p), 115 }, 116 }) 117 118 plan, err := ctx.Plan() 119 if err != nil { 120 t.Fatalf("err: %s", err) 121 } 122 123 actual := strings.TrimSpace(plan.String()) 124 expected := strings.TrimSpace(testTerraformPlanEscapedVarStr) 125 if actual != expected { 126 t.Fatalf("bad:\n%s", actual) 127 } 128 } 129 130 func TestContext2Plan_minimal(t *testing.T) { 131 m := testModule(t, "plan-empty") 132 p := testProvider("aws") 133 p.DiffFn = testDiffFn 134 ctx := testContext2(t, &ContextOpts{ 135 Module: m, 136 Providers: map[string]ResourceProviderFactory{ 137 "aws": testProviderFuncFixed(p), 138 }, 139 }) 140 141 plan, err := ctx.Plan() 142 if err != nil { 143 t.Fatalf("err: %s", err) 144 } 145 146 actual := strings.TrimSpace(plan.String()) 147 expected := strings.TrimSpace(testTerraformPlanEmptyStr) 148 if actual != expected { 149 t.Fatalf("bad:\n%s", actual) 150 } 151 } 152 153 func TestContext2Plan_modules(t *testing.T) { 154 m := testModule(t, "plan-modules") 155 p := testProvider("aws") 156 p.DiffFn = testDiffFn 157 ctx := testContext2(t, &ContextOpts{ 158 Module: m, 159 Providers: map[string]ResourceProviderFactory{ 160 "aws": testProviderFuncFixed(p), 161 }, 162 }) 163 164 plan, err := ctx.Plan() 165 if err != nil { 166 t.Fatalf("err: %s", err) 167 } 168 169 actual := strings.TrimSpace(plan.String()) 170 expected := strings.TrimSpace(testTerraformPlanModulesStr) 171 if actual != expected { 172 t.Fatalf("bad:\n%s", actual) 173 } 174 } 175 176 // GH-1475 177 func TestContext2Plan_moduleCycle(t *testing.T) { 178 m := testModule(t, "plan-module-cycle") 179 p := testProvider("aws") 180 p.DiffFn = testDiffFn 181 ctx := testContext2(t, &ContextOpts{ 182 Module: m, 183 Providers: map[string]ResourceProviderFactory{ 184 "aws": testProviderFuncFixed(p), 185 }, 186 }) 187 188 plan, err := ctx.Plan() 189 if err != nil { 190 t.Fatalf("err: %s", err) 191 } 192 193 actual := strings.TrimSpace(plan.String()) 194 expected := strings.TrimSpace(testTerraformPlanModuleCycleStr) 195 if actual != expected { 196 t.Fatalf("bad:\n%s", actual) 197 } 198 } 199 200 func TestContext2Plan_moduleDeadlock(t *testing.T) { 201 testCheckDeadlock(t, func() { 202 m := testModule(t, "plan-module-deadlock") 203 p := testProvider("aws") 204 p.DiffFn = testDiffFn 205 206 ctx := testContext2(t, &ContextOpts{ 207 Module: m, 208 Providers: map[string]ResourceProviderFactory{ 209 "aws": testProviderFuncFixed(p), 210 }, 211 }) 212 213 plan, err := ctx.Plan() 214 if err != nil { 215 t.Fatalf("err: %s", err) 216 } 217 218 actual := strings.TrimSpace(plan.String()) 219 expected := strings.TrimSpace(` 220 DIFF: 221 222 module.child: 223 CREATE: aws_instance.foo.0 224 CREATE: aws_instance.foo.1 225 CREATE: aws_instance.foo.2 226 227 STATE: 228 229 <no state> 230 `) 231 if actual != expected { 232 t.Fatalf("expected:\n%sgot:\n%s", expected, actual) 233 } 234 }) 235 } 236 237 func TestContext2Plan_moduleInput(t *testing.T) { 238 m := testModule(t, "plan-module-input") 239 p := testProvider("aws") 240 p.DiffFn = testDiffFn 241 ctx := testContext2(t, &ContextOpts{ 242 Module: m, 243 Providers: map[string]ResourceProviderFactory{ 244 "aws": testProviderFuncFixed(p), 245 }, 246 }) 247 248 plan, err := ctx.Plan() 249 if err != nil { 250 t.Fatalf("err: %s", err) 251 } 252 253 actual := strings.TrimSpace(plan.String()) 254 expected := strings.TrimSpace(testTerraformPlanModuleInputStr) 255 if actual != expected { 256 t.Fatalf("bad:\n%s", actual) 257 } 258 } 259 260 func TestContext2Plan_moduleInputComputed(t *testing.T) { 261 m := testModule(t, "plan-module-input-computed") 262 p := testProvider("aws") 263 p.DiffFn = testDiffFn 264 ctx := testContext2(t, &ContextOpts{ 265 Module: m, 266 Providers: map[string]ResourceProviderFactory{ 267 "aws": testProviderFuncFixed(p), 268 }, 269 }) 270 271 plan, err := ctx.Plan() 272 if err != nil { 273 t.Fatalf("err: %s", err) 274 } 275 276 actual := strings.TrimSpace(plan.String()) 277 expected := strings.TrimSpace(testTerraformPlanModuleInputComputedStr) 278 if actual != expected { 279 t.Fatalf("bad:\n%s", actual) 280 } 281 } 282 283 func TestContext2Plan_moduleInputFromVar(t *testing.T) { 284 m := testModule(t, "plan-module-input-var") 285 p := testProvider("aws") 286 p.DiffFn = testDiffFn 287 ctx := testContext2(t, &ContextOpts{ 288 Module: m, 289 Providers: map[string]ResourceProviderFactory{ 290 "aws": testProviderFuncFixed(p), 291 }, 292 Variables: map[string]string{ 293 "foo": "52", 294 }, 295 }) 296 297 plan, err := ctx.Plan() 298 if err != nil { 299 t.Fatalf("err: %s", err) 300 } 301 302 actual := strings.TrimSpace(plan.String()) 303 expected := strings.TrimSpace(testTerraformPlanModuleInputVarStr) 304 if actual != expected { 305 t.Fatalf("bad:\n%s", actual) 306 } 307 } 308 309 func TestContext2Plan_moduleMultiVar(t *testing.T) { 310 m := testModule(t, "plan-module-multi-var") 311 p := testProvider("aws") 312 p.DiffFn = testDiffFn 313 ctx := testContext2(t, &ContextOpts{ 314 Module: m, 315 Providers: map[string]ResourceProviderFactory{ 316 "aws": testProviderFuncFixed(p), 317 }, 318 }) 319 320 plan, err := ctx.Plan() 321 if err != nil { 322 t.Fatalf("err: %s", err) 323 } 324 325 actual := strings.TrimSpace(plan.String()) 326 expected := strings.TrimSpace(testTerraformPlanModuleMultiVarStr) 327 if actual != expected { 328 t.Fatalf("bad:\n%s", actual) 329 } 330 } 331 332 func TestContext2Plan_moduleOrphans(t *testing.T) { 333 m := testModule(t, "plan-modules-remove") 334 p := testProvider("aws") 335 p.DiffFn = testDiffFn 336 s := &State{ 337 Modules: []*ModuleState{ 338 &ModuleState{ 339 Path: []string{"root", "child"}, 340 Resources: map[string]*ResourceState{ 341 "aws_instance.foo": &ResourceState{ 342 Type: "aws_instance", 343 Primary: &InstanceState{ 344 ID: "baz", 345 }, 346 }, 347 }, 348 }, 349 }, 350 } 351 ctx := testContext2(t, &ContextOpts{ 352 Module: m, 353 Providers: map[string]ResourceProviderFactory{ 354 "aws": testProviderFuncFixed(p), 355 }, 356 State: s, 357 }) 358 359 plan, err := ctx.Plan() 360 if err != nil { 361 t.Fatalf("err: %s", err) 362 } 363 364 actual := strings.TrimSpace(plan.String()) 365 expected := strings.TrimSpace(testTerraformPlanModuleOrphansStr) 366 if actual != expected { 367 t.Fatalf("bad:\n%s", actual) 368 } 369 } 370 371 // https://github.com/hashicorp/terraform/issues/3114 372 func TestContext2Plan_moduleOrphansWithProvisioner(t *testing.T) { 373 m := testModule(t, "plan-modules-remove-provisioners") 374 p := testProvider("aws") 375 pr := testProvisioner() 376 p.DiffFn = testDiffFn 377 s := &State{ 378 Modules: []*ModuleState{ 379 &ModuleState{ 380 Path: []string{"root"}, 381 Resources: map[string]*ResourceState{ 382 "aws_instance.top": &ResourceState{ 383 Type: "aws_instance", 384 Primary: &InstanceState{ 385 ID: "top", 386 }, 387 }, 388 }, 389 }, 390 &ModuleState{ 391 Path: []string{"root", "parent", "childone"}, 392 Resources: map[string]*ResourceState{ 393 "aws_instance.foo": &ResourceState{ 394 Type: "aws_instance", 395 Primary: &InstanceState{ 396 ID: "baz", 397 }, 398 }, 399 }, 400 }, 401 &ModuleState{ 402 Path: []string{"root", "parent", "childtwo"}, 403 Resources: map[string]*ResourceState{ 404 "aws_instance.foo": &ResourceState{ 405 Type: "aws_instance", 406 Primary: &InstanceState{ 407 ID: "baz", 408 }, 409 }, 410 }, 411 }, 412 }, 413 } 414 ctx := testContext2(t, &ContextOpts{ 415 Module: m, 416 Providers: map[string]ResourceProviderFactory{ 417 "aws": testProviderFuncFixed(p), 418 }, 419 Provisioners: map[string]ResourceProvisionerFactory{ 420 "shell": testProvisionerFuncFixed(pr), 421 }, 422 State: s, 423 }) 424 425 plan, err := ctx.Plan() 426 if err != nil { 427 t.Fatalf("err: %s", err) 428 } 429 430 actual := strings.TrimSpace(plan.String()) 431 expected := strings.TrimSpace(` 432 DIFF: 433 434 module.parent.childone: 435 DESTROY: aws_instance.foo 436 module.parent.childtwo: 437 DESTROY: aws_instance.foo 438 439 STATE: 440 441 aws_instance.top: 442 ID = top 443 444 module.parent.childone: 445 aws_instance.foo: 446 ID = baz 447 module.parent.childtwo: 448 aws_instance.foo: 449 ID = baz 450 `) 451 if actual != expected { 452 t.Fatalf("bad:\n%s", actual) 453 } 454 } 455 456 func TestContext2Plan_moduleProviderInherit(t *testing.T) { 457 var l sync.Mutex 458 var calls []string 459 460 m := testModule(t, "plan-module-provider-inherit") 461 ctx := testContext2(t, &ContextOpts{ 462 Module: m, 463 Providers: map[string]ResourceProviderFactory{ 464 "aws": func() (ResourceProvider, error) { 465 l.Lock() 466 defer l.Unlock() 467 468 p := testProvider("aws") 469 p.ConfigureFn = func(c *ResourceConfig) error { 470 if v, ok := c.Get("from"); !ok || v.(string) != "root" { 471 return fmt.Errorf("bad") 472 } 473 474 return nil 475 } 476 p.DiffFn = func( 477 info *InstanceInfo, 478 state *InstanceState, 479 c *ResourceConfig) (*InstanceDiff, error) { 480 v, _ := c.Get("from") 481 calls = append(calls, v.(string)) 482 return testDiffFn(info, state, c) 483 } 484 return p, nil 485 }, 486 }, 487 }) 488 489 _, err := ctx.Plan() 490 if err != nil { 491 t.Fatalf("err: %s", err) 492 } 493 494 actual := calls 495 sort.Strings(actual) 496 expected := []string{"child", "root"} 497 if !reflect.DeepEqual(actual, expected) { 498 t.Fatalf("bad: %#v", actual) 499 } 500 } 501 502 func TestContext2Plan_moduleProviderDefaults(t *testing.T) { 503 var l sync.Mutex 504 var calls []string 505 toCount := 0 506 507 m := testModule(t, "plan-module-provider-defaults") 508 ctx := testContext2(t, &ContextOpts{ 509 Module: m, 510 Providers: map[string]ResourceProviderFactory{ 511 "aws": func() (ResourceProvider, error) { 512 l.Lock() 513 defer l.Unlock() 514 515 p := testProvider("aws") 516 p.ConfigureFn = func(c *ResourceConfig) error { 517 if v, ok := c.Get("from"); !ok || v.(string) != "root" { 518 return fmt.Errorf("bad") 519 } 520 if v, ok := c.Get("to"); ok && v.(string) == "child" { 521 toCount++ 522 } 523 524 return nil 525 } 526 p.DiffFn = func( 527 info *InstanceInfo, 528 state *InstanceState, 529 c *ResourceConfig) (*InstanceDiff, error) { 530 v, _ := c.Get("from") 531 calls = append(calls, v.(string)) 532 return testDiffFn(info, state, c) 533 } 534 return p, nil 535 }, 536 }, 537 }) 538 539 _, err := ctx.Plan() 540 if err != nil { 541 t.Fatalf("err: %s", err) 542 } 543 544 if toCount != 1 { 545 t.Fatalf( 546 "provider in child didn't set proper config\n\n"+ 547 "toCount: %d", toCount) 548 } 549 550 actual := calls 551 sort.Strings(actual) 552 expected := []string{"child", "root"} 553 if !reflect.DeepEqual(actual, expected) { 554 t.Fatalf("bad: %#v", actual) 555 } 556 } 557 558 func TestContext2Plan_moduleProviderDefaultsVar(t *testing.T) { 559 var l sync.Mutex 560 var calls []string 561 562 m := testModule(t, "plan-module-provider-defaults-var") 563 ctx := testContext2(t, &ContextOpts{ 564 Module: m, 565 Providers: map[string]ResourceProviderFactory{ 566 "aws": func() (ResourceProvider, error) { 567 l.Lock() 568 defer l.Unlock() 569 570 p := testProvider("aws") 571 p.ConfigureFn = func(c *ResourceConfig) error { 572 var buf bytes.Buffer 573 if v, ok := c.Get("from"); ok { 574 buf.WriteString(v.(string) + "\n") 575 } 576 if v, ok := c.Get("to"); ok { 577 buf.WriteString(v.(string) + "\n") 578 } 579 580 calls = append(calls, buf.String()) 581 return nil 582 } 583 p.DiffFn = testDiffFn 584 return p, nil 585 }, 586 }, 587 Variables: map[string]string{ 588 "foo": "root", 589 }, 590 }) 591 592 _, err := ctx.Plan() 593 if err != nil { 594 t.Fatalf("err: %s", err) 595 } 596 597 expected := []string{ 598 "root\n", 599 "root\nchild\n", 600 } 601 if !reflect.DeepEqual(calls, expected) { 602 t.Fatalf("BAD: %#v", calls) 603 } 604 } 605 606 func TestContext2Plan_moduleVar(t *testing.T) { 607 m := testModule(t, "plan-module-var") 608 p := testProvider("aws") 609 p.DiffFn = testDiffFn 610 ctx := testContext2(t, &ContextOpts{ 611 Module: m, 612 Providers: map[string]ResourceProviderFactory{ 613 "aws": testProviderFuncFixed(p), 614 }, 615 }) 616 617 plan, err := ctx.Plan() 618 if err != nil { 619 t.Fatalf("err: %s", err) 620 } 621 622 actual := strings.TrimSpace(plan.String()) 623 expected := strings.TrimSpace(testTerraformPlanModuleVarStr) 624 if actual != expected { 625 t.Fatalf("bad:\n%s", actual) 626 } 627 } 628 629 func TestContext2Plan_moduleVarComputed(t *testing.T) { 630 m := testModule(t, "plan-module-var-computed") 631 p := testProvider("aws") 632 p.DiffFn = testDiffFn 633 ctx := testContext2(t, &ContextOpts{ 634 Module: m, 635 Providers: map[string]ResourceProviderFactory{ 636 "aws": testProviderFuncFixed(p), 637 }, 638 }) 639 640 plan, err := ctx.Plan() 641 if err != nil { 642 t.Fatalf("err: %s", err) 643 } 644 645 actual := strings.TrimSpace(plan.String()) 646 expected := strings.TrimSpace(testTerraformPlanModuleVarComputedStr) 647 if actual != expected { 648 t.Fatalf("bad:\n%s", actual) 649 } 650 } 651 652 func TestContext2Plan_nil(t *testing.T) { 653 m := testModule(t, "plan-nil") 654 p := testProvider("aws") 655 p.DiffFn = testDiffFn 656 ctx := testContext2(t, &ContextOpts{ 657 Module: m, 658 Providers: map[string]ResourceProviderFactory{ 659 "aws": testProviderFuncFixed(p), 660 }, 661 State: &State{ 662 Modules: []*ModuleState{ 663 &ModuleState{ 664 Path: rootModulePath, 665 Resources: map[string]*ResourceState{ 666 "aws_instance.foo": &ResourceState{ 667 Type: "aws_instance", 668 Primary: &InstanceState{ 669 ID: "bar", 670 }, 671 }, 672 }, 673 }, 674 }, 675 }, 676 }) 677 678 plan, err := ctx.Plan() 679 if err != nil { 680 t.Fatalf("err: %s", err) 681 } 682 if len(plan.Diff.RootModule().Resources) != 0 { 683 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 684 } 685 } 686 687 func TestContext2Plan_preventDestroy_bad(t *testing.T) { 688 m := testModule(t, "plan-prevent-destroy-bad") 689 p := testProvider("aws") 690 p.DiffFn = testDiffFn 691 ctx := testContext2(t, &ContextOpts{ 692 Module: m, 693 Providers: map[string]ResourceProviderFactory{ 694 "aws": testProviderFuncFixed(p), 695 }, 696 State: &State{ 697 Modules: []*ModuleState{ 698 &ModuleState{ 699 Path: rootModulePath, 700 Resources: map[string]*ResourceState{ 701 "aws_instance.foo": &ResourceState{ 702 Type: "aws_instance", 703 Primary: &InstanceState{ 704 ID: "i-abc123", 705 }, 706 }, 707 }, 708 }, 709 }, 710 }, 711 }) 712 713 plan, err := ctx.Plan() 714 715 expectedErr := "aws_instance.foo: the plan would destroy" 716 if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) { 717 t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s", 718 expectedErr, err, plan) 719 } 720 } 721 722 func TestContext2Plan_preventDestroy_good(t *testing.T) { 723 m := testModule(t, "plan-prevent-destroy-good") 724 p := testProvider("aws") 725 p.DiffFn = testDiffFn 726 ctx := testContext2(t, &ContextOpts{ 727 Module: m, 728 Providers: map[string]ResourceProviderFactory{ 729 "aws": testProviderFuncFixed(p), 730 }, 731 State: &State{ 732 Modules: []*ModuleState{ 733 &ModuleState{ 734 Path: rootModulePath, 735 Resources: map[string]*ResourceState{ 736 "aws_instance.foo": &ResourceState{ 737 Type: "aws_instance", 738 Primary: &InstanceState{ 739 ID: "i-abc123", 740 }, 741 }, 742 }, 743 }, 744 }, 745 }, 746 }) 747 748 plan, err := ctx.Plan() 749 if err != nil { 750 t.Fatalf("err: %s", err) 751 } 752 if !plan.Diff.Empty() { 753 t.Fatalf("Expected empty plan, got %s", plan.String()) 754 } 755 } 756 757 func TestContext2Plan_preventDestroy_destroyPlan(t *testing.T) { 758 m := testModule(t, "plan-prevent-destroy-good") 759 p := testProvider("aws") 760 p.DiffFn = testDiffFn 761 ctx := testContext2(t, &ContextOpts{ 762 Module: m, 763 Providers: map[string]ResourceProviderFactory{ 764 "aws": testProviderFuncFixed(p), 765 }, 766 State: &State{ 767 Modules: []*ModuleState{ 768 &ModuleState{ 769 Path: rootModulePath, 770 Resources: map[string]*ResourceState{ 771 "aws_instance.foo": &ResourceState{ 772 Type: "aws_instance", 773 Primary: &InstanceState{ 774 ID: "i-abc123", 775 }, 776 }, 777 }, 778 }, 779 }, 780 }, 781 Destroy: true, 782 }) 783 784 plan, err := ctx.Plan() 785 786 expectedErr := "aws_instance.foo: the plan would destroy" 787 if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) { 788 t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s", 789 expectedErr, err, plan) 790 } 791 } 792 793 func TestContext2Plan_computed(t *testing.T) { 794 m := testModule(t, "plan-computed") 795 p := testProvider("aws") 796 p.DiffFn = testDiffFn 797 ctx := testContext2(t, &ContextOpts{ 798 Module: m, 799 Providers: map[string]ResourceProviderFactory{ 800 "aws": testProviderFuncFixed(p), 801 }, 802 }) 803 804 plan, err := ctx.Plan() 805 if err != nil { 806 t.Fatalf("err: %s", err) 807 } 808 809 actual := strings.TrimSpace(plan.String()) 810 expected := strings.TrimSpace(testTerraformPlanComputedStr) 811 if actual != expected { 812 t.Fatalf("bad:\n%s", actual) 813 } 814 } 815 816 func TestContext2Plan_computedList(t *testing.T) { 817 m := testModule(t, "plan-computed-list") 818 p := testProvider("aws") 819 p.DiffFn = testDiffFn 820 ctx := testContext2(t, &ContextOpts{ 821 Module: m, 822 Providers: map[string]ResourceProviderFactory{ 823 "aws": testProviderFuncFixed(p), 824 }, 825 }) 826 827 plan, err := ctx.Plan() 828 if err != nil { 829 t.Fatalf("err: %s", err) 830 } 831 832 actual := strings.TrimSpace(plan.String()) 833 expected := strings.TrimSpace(testTerraformPlanComputedListStr) 834 if actual != expected { 835 t.Fatalf("bad:\n%s", actual) 836 } 837 } 838 839 func TestContext2Plan_count(t *testing.T) { 840 m := testModule(t, "plan-count") 841 p := testProvider("aws") 842 p.DiffFn = testDiffFn 843 ctx := testContext2(t, &ContextOpts{ 844 Module: m, 845 Providers: map[string]ResourceProviderFactory{ 846 "aws": testProviderFuncFixed(p), 847 }, 848 }) 849 850 plan, err := ctx.Plan() 851 if err != nil { 852 t.Fatalf("err: %s", err) 853 } 854 855 if len(plan.Diff.RootModule().Resources) < 6 { 856 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 857 } 858 859 actual := strings.TrimSpace(plan.String()) 860 expected := strings.TrimSpace(testTerraformPlanCountStr) 861 if actual != expected { 862 t.Fatalf("bad:\n%s", actual) 863 } 864 } 865 866 func TestContext2Plan_countComputed(t *testing.T) { 867 m := testModule(t, "plan-count-computed") 868 p := testProvider("aws") 869 p.DiffFn = testDiffFn 870 ctx := testContext2(t, &ContextOpts{ 871 Module: m, 872 Providers: map[string]ResourceProviderFactory{ 873 "aws": testProviderFuncFixed(p), 874 }, 875 }) 876 877 _, err := ctx.Plan() 878 if err == nil { 879 t.Fatal("should error") 880 } 881 } 882 883 func TestContext2Plan_countIndex(t *testing.T) { 884 m := testModule(t, "plan-count-index") 885 p := testProvider("aws") 886 p.DiffFn = testDiffFn 887 ctx := testContext2(t, &ContextOpts{ 888 Module: m, 889 Providers: map[string]ResourceProviderFactory{ 890 "aws": testProviderFuncFixed(p), 891 }, 892 }) 893 894 plan, err := ctx.Plan() 895 if err != nil { 896 t.Fatalf("err: %s", err) 897 } 898 899 actual := strings.TrimSpace(plan.String()) 900 expected := strings.TrimSpace(testTerraformPlanCountIndexStr) 901 if actual != expected { 902 t.Fatalf("bad:\n%s", actual) 903 } 904 } 905 906 func TestContext2Plan_countIndexZero(t *testing.T) { 907 m := testModule(t, "plan-count-index-zero") 908 p := testProvider("aws") 909 p.DiffFn = testDiffFn 910 ctx := testContext2(t, &ContextOpts{ 911 Module: m, 912 Providers: map[string]ResourceProviderFactory{ 913 "aws": testProviderFuncFixed(p), 914 }, 915 }) 916 917 plan, err := ctx.Plan() 918 if err != nil { 919 t.Fatalf("err: %s", err) 920 } 921 922 actual := strings.TrimSpace(plan.String()) 923 expected := strings.TrimSpace(testTerraformPlanCountIndexZeroStr) 924 if actual != expected { 925 t.Fatalf("bad:\n%s", actual) 926 } 927 } 928 929 func TestContext2Plan_countVar(t *testing.T) { 930 m := testModule(t, "plan-count-var") 931 p := testProvider("aws") 932 p.DiffFn = testDiffFn 933 ctx := testContext2(t, &ContextOpts{ 934 Module: m, 935 Providers: map[string]ResourceProviderFactory{ 936 "aws": testProviderFuncFixed(p), 937 }, 938 Variables: map[string]string{ 939 "count": "3", 940 }, 941 }) 942 943 plan, err := ctx.Plan() 944 if err != nil { 945 t.Fatalf("err: %s", err) 946 } 947 948 actual := strings.TrimSpace(plan.String()) 949 expected := strings.TrimSpace(testTerraformPlanCountVarStr) 950 if actual != expected { 951 t.Fatalf("bad:\n%s", actual) 952 } 953 } 954 955 func TestContext2Plan_countZero(t *testing.T) { 956 m := testModule(t, "plan-count-zero") 957 p := testProvider("aws") 958 p.DiffFn = testDiffFn 959 ctx := testContext2(t, &ContextOpts{ 960 Module: m, 961 Providers: map[string]ResourceProviderFactory{ 962 "aws": testProviderFuncFixed(p), 963 }, 964 }) 965 966 plan, err := ctx.Plan() 967 if err != nil { 968 t.Fatalf("err: %s", err) 969 } 970 971 actual := strings.TrimSpace(plan.String()) 972 expected := strings.TrimSpace(testTerraformPlanCountZeroStr) 973 if actual != expected { 974 t.Fatalf("bad:\n%s", actual) 975 } 976 } 977 978 func TestContext2Plan_countOneIndex(t *testing.T) { 979 m := testModule(t, "plan-count-one-index") 980 p := testProvider("aws") 981 p.DiffFn = testDiffFn 982 ctx := testContext2(t, &ContextOpts{ 983 Module: m, 984 Providers: map[string]ResourceProviderFactory{ 985 "aws": testProviderFuncFixed(p), 986 }, 987 }) 988 989 plan, err := ctx.Plan() 990 if err != nil { 991 t.Fatalf("err: %s", err) 992 } 993 994 actual := strings.TrimSpace(plan.String()) 995 expected := strings.TrimSpace(testTerraformPlanCountOneIndexStr) 996 if actual != expected { 997 t.Fatalf("bad:\n%s", actual) 998 } 999 } 1000 1001 func TestContext2Plan_countDecreaseToOne(t *testing.T) { 1002 m := testModule(t, "plan-count-dec") 1003 p := testProvider("aws") 1004 p.DiffFn = testDiffFn 1005 s := &State{ 1006 Modules: []*ModuleState{ 1007 &ModuleState{ 1008 Path: rootModulePath, 1009 Resources: map[string]*ResourceState{ 1010 "aws_instance.foo.0": &ResourceState{ 1011 Type: "aws_instance", 1012 Primary: &InstanceState{ 1013 ID: "bar", 1014 Attributes: map[string]string{ 1015 "foo": "foo", 1016 "type": "aws_instance", 1017 }, 1018 }, 1019 }, 1020 "aws_instance.foo.1": &ResourceState{ 1021 Type: "aws_instance", 1022 Primary: &InstanceState{ 1023 ID: "bar", 1024 }, 1025 }, 1026 "aws_instance.foo.2": &ResourceState{ 1027 Type: "aws_instance", 1028 Primary: &InstanceState{ 1029 ID: "bar", 1030 }, 1031 }, 1032 }, 1033 }, 1034 }, 1035 } 1036 ctx := testContext2(t, &ContextOpts{ 1037 Module: m, 1038 Providers: map[string]ResourceProviderFactory{ 1039 "aws": testProviderFuncFixed(p), 1040 }, 1041 State: s, 1042 }) 1043 1044 plan, err := ctx.Plan() 1045 if err != nil { 1046 t.Fatalf("err: %s", err) 1047 } 1048 1049 actual := strings.TrimSpace(plan.String()) 1050 expected := strings.TrimSpace(testTerraformPlanCountDecreaseStr) 1051 if actual != expected { 1052 t.Fatalf("bad:\n%s", actual) 1053 } 1054 } 1055 1056 func TestContext2Plan_countIncreaseFromNotSet(t *testing.T) { 1057 m := testModule(t, "plan-count-inc") 1058 p := testProvider("aws") 1059 p.DiffFn = testDiffFn 1060 s := &State{ 1061 Modules: []*ModuleState{ 1062 &ModuleState{ 1063 Path: rootModulePath, 1064 Resources: map[string]*ResourceState{ 1065 "aws_instance.foo": &ResourceState{ 1066 Type: "aws_instance", 1067 Primary: &InstanceState{ 1068 ID: "bar", 1069 Attributes: map[string]string{ 1070 "foo": "foo", 1071 "type": "aws_instance", 1072 }, 1073 }, 1074 }, 1075 }, 1076 }, 1077 }, 1078 } 1079 ctx := testContext2(t, &ContextOpts{ 1080 Module: m, 1081 Providers: map[string]ResourceProviderFactory{ 1082 "aws": testProviderFuncFixed(p), 1083 }, 1084 State: s, 1085 }) 1086 1087 plan, err := ctx.Plan() 1088 if err != nil { 1089 t.Fatalf("err: %s", err) 1090 } 1091 1092 actual := strings.TrimSpace(plan.String()) 1093 expected := strings.TrimSpace(testTerraformPlanCountIncreaseStr) 1094 if actual != expected { 1095 t.Fatalf("bad:\n%s", actual) 1096 } 1097 } 1098 1099 func TestContext2Plan_countIncreaseFromOne(t *testing.T) { 1100 m := testModule(t, "plan-count-inc") 1101 p := testProvider("aws") 1102 p.DiffFn = testDiffFn 1103 s := &State{ 1104 Modules: []*ModuleState{ 1105 &ModuleState{ 1106 Path: rootModulePath, 1107 Resources: map[string]*ResourceState{ 1108 "aws_instance.foo.0": &ResourceState{ 1109 Type: "aws_instance", 1110 Primary: &InstanceState{ 1111 ID: "bar", 1112 Attributes: map[string]string{ 1113 "foo": "foo", 1114 "type": "aws_instance", 1115 }, 1116 }, 1117 }, 1118 }, 1119 }, 1120 }, 1121 } 1122 ctx := testContext2(t, &ContextOpts{ 1123 Module: m, 1124 Providers: map[string]ResourceProviderFactory{ 1125 "aws": testProviderFuncFixed(p), 1126 }, 1127 State: s, 1128 }) 1129 1130 plan, err := ctx.Plan() 1131 if err != nil { 1132 t.Fatalf("err: %s", err) 1133 } 1134 1135 actual := strings.TrimSpace(plan.String()) 1136 expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneStr) 1137 if actual != expected { 1138 t.Fatalf("bad:\n%s", actual) 1139 } 1140 } 1141 1142 // https://github.com/PeoplePerHour/terraform/pull/11 1143 // 1144 // This tests a case where both a "resource" and "resource.0" are in 1145 // the state file, which apparently is a reasonable backwards compatibility 1146 // concern found in the above 3rd party repo. 1147 func TestContext2Plan_countIncreaseFromOneCorrupted(t *testing.T) { 1148 m := testModule(t, "plan-count-inc") 1149 p := testProvider("aws") 1150 p.DiffFn = testDiffFn 1151 s := &State{ 1152 Modules: []*ModuleState{ 1153 &ModuleState{ 1154 Path: rootModulePath, 1155 Resources: map[string]*ResourceState{ 1156 "aws_instance.foo": &ResourceState{ 1157 Type: "aws_instance", 1158 Primary: &InstanceState{ 1159 ID: "bar", 1160 Attributes: map[string]string{ 1161 "foo": "foo", 1162 "type": "aws_instance", 1163 }, 1164 }, 1165 }, 1166 "aws_instance.foo.0": &ResourceState{ 1167 Type: "aws_instance", 1168 Primary: &InstanceState{ 1169 ID: "bar", 1170 Attributes: map[string]string{ 1171 "foo": "foo", 1172 "type": "aws_instance", 1173 }, 1174 }, 1175 }, 1176 }, 1177 }, 1178 }, 1179 } 1180 ctx := testContext2(t, &ContextOpts{ 1181 Module: m, 1182 Providers: map[string]ResourceProviderFactory{ 1183 "aws": testProviderFuncFixed(p), 1184 }, 1185 State: s, 1186 }) 1187 1188 plan, err := ctx.Plan() 1189 if err != nil { 1190 t.Fatalf("err: %s", err) 1191 } 1192 1193 actual := strings.TrimSpace(plan.String()) 1194 expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneCorruptedStr) 1195 if actual != expected { 1196 t.Fatalf("bad:\n%s", actual) 1197 } 1198 } 1199 1200 func TestContext2Plan_destroy(t *testing.T) { 1201 m := testModule(t, "plan-destroy") 1202 p := testProvider("aws") 1203 p.DiffFn = testDiffFn 1204 s := &State{ 1205 Modules: []*ModuleState{ 1206 &ModuleState{ 1207 Path: rootModulePath, 1208 Resources: map[string]*ResourceState{ 1209 "aws_instance.one": &ResourceState{ 1210 Type: "aws_instance", 1211 Primary: &InstanceState{ 1212 ID: "bar", 1213 }, 1214 }, 1215 "aws_instance.two": &ResourceState{ 1216 Type: "aws_instance", 1217 Primary: &InstanceState{ 1218 ID: "baz", 1219 }, 1220 }, 1221 }, 1222 }, 1223 }, 1224 } 1225 ctx := testContext2(t, &ContextOpts{ 1226 Module: m, 1227 Providers: map[string]ResourceProviderFactory{ 1228 "aws": testProviderFuncFixed(p), 1229 }, 1230 State: s, 1231 Destroy: true, 1232 }) 1233 1234 plan, err := ctx.Plan() 1235 if err != nil { 1236 t.Fatalf("err: %s", err) 1237 } 1238 1239 if len(plan.Diff.RootModule().Resources) != 2 { 1240 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 1241 } 1242 1243 actual := strings.TrimSpace(plan.String()) 1244 expected := strings.TrimSpace(testTerraformPlanDestroyStr) 1245 if actual != expected { 1246 t.Fatalf("bad:\n%s", actual) 1247 } 1248 } 1249 1250 func TestContext2Plan_moduleDestroy(t *testing.T) { 1251 m := testModule(t, "plan-module-destroy") 1252 p := testProvider("aws") 1253 p.DiffFn = testDiffFn 1254 s := &State{ 1255 Modules: []*ModuleState{ 1256 &ModuleState{ 1257 Path: rootModulePath, 1258 Resources: map[string]*ResourceState{ 1259 "aws_instance.foo": &ResourceState{ 1260 Type: "aws_instance", 1261 Primary: &InstanceState{ 1262 ID: "bar", 1263 }, 1264 }, 1265 }, 1266 }, 1267 &ModuleState{ 1268 Path: []string{"root", "child"}, 1269 Resources: map[string]*ResourceState{ 1270 "aws_instance.foo": &ResourceState{ 1271 Type: "aws_instance", 1272 Primary: &InstanceState{ 1273 ID: "bar", 1274 }, 1275 }, 1276 }, 1277 }, 1278 }, 1279 } 1280 ctx := testContext2(t, &ContextOpts{ 1281 Module: m, 1282 Providers: map[string]ResourceProviderFactory{ 1283 "aws": testProviderFuncFixed(p), 1284 }, 1285 State: s, 1286 Destroy: true, 1287 }) 1288 1289 plan, err := ctx.Plan() 1290 if err != nil { 1291 t.Fatalf("err: %s", err) 1292 } 1293 1294 actual := strings.TrimSpace(plan.String()) 1295 expected := strings.TrimSpace(testTerraformPlanModuleDestroyStr) 1296 if actual != expected { 1297 t.Fatalf("bad:\n%s", actual) 1298 } 1299 } 1300 1301 // GH-1835 1302 func TestContext2Plan_moduleDestroyCycle(t *testing.T) { 1303 m := testModule(t, "plan-module-destroy-gh-1835") 1304 p := testProvider("aws") 1305 p.DiffFn = testDiffFn 1306 s := &State{ 1307 Modules: []*ModuleState{ 1308 &ModuleState{ 1309 Path: []string{"root", "a_module"}, 1310 Resources: map[string]*ResourceState{ 1311 "aws_instance.a": &ResourceState{ 1312 Type: "aws_instance", 1313 Primary: &InstanceState{ 1314 ID: "a", 1315 }, 1316 }, 1317 }, 1318 }, 1319 &ModuleState{ 1320 Path: []string{"root", "b_module"}, 1321 Resources: map[string]*ResourceState{ 1322 "aws_instance.b": &ResourceState{ 1323 Type: "aws_instance", 1324 Primary: &InstanceState{ 1325 ID: "b", 1326 }, 1327 }, 1328 }, 1329 }, 1330 }, 1331 } 1332 ctx := testContext2(t, &ContextOpts{ 1333 Module: m, 1334 Providers: map[string]ResourceProviderFactory{ 1335 "aws": testProviderFuncFixed(p), 1336 }, 1337 State: s, 1338 Destroy: true, 1339 }) 1340 1341 plan, err := ctx.Plan() 1342 if err != nil { 1343 t.Fatalf("err: %s", err) 1344 } 1345 1346 actual := strings.TrimSpace(plan.String()) 1347 expected := strings.TrimSpace(testTerraformPlanModuleDestroyCycleStr) 1348 if actual != expected { 1349 t.Fatalf("bad:\n%s", actual) 1350 } 1351 } 1352 1353 func TestContext2Plan_moduleDestroyMultivar(t *testing.T) { 1354 m := testModule(t, "plan-module-destroy-multivar") 1355 p := testProvider("aws") 1356 p.DiffFn = testDiffFn 1357 s := &State{ 1358 Modules: []*ModuleState{ 1359 &ModuleState{ 1360 Path: rootModulePath, 1361 Resources: map[string]*ResourceState{}, 1362 }, 1363 &ModuleState{ 1364 Path: []string{"root", "child"}, 1365 Resources: map[string]*ResourceState{ 1366 "aws_instance.foo.0": &ResourceState{ 1367 Type: "aws_instance", 1368 Primary: &InstanceState{ 1369 ID: "bar0", 1370 }, 1371 }, 1372 "aws_instance.foo.1": &ResourceState{ 1373 Type: "aws_instance", 1374 Primary: &InstanceState{ 1375 ID: "bar1", 1376 }, 1377 }, 1378 }, 1379 }, 1380 }, 1381 } 1382 ctx := testContext2(t, &ContextOpts{ 1383 Module: m, 1384 Providers: map[string]ResourceProviderFactory{ 1385 "aws": testProviderFuncFixed(p), 1386 }, 1387 State: s, 1388 Destroy: true, 1389 }) 1390 1391 plan, err := ctx.Plan() 1392 if err != nil { 1393 t.Fatalf("err: %s", err) 1394 } 1395 1396 actual := strings.TrimSpace(plan.String()) 1397 expected := strings.TrimSpace(testTerraformPlanModuleDestroyMultivarStr) 1398 if actual != expected { 1399 t.Fatalf("bad:\n%s", actual) 1400 } 1401 } 1402 1403 func TestContext2Plan_pathVar(t *testing.T) { 1404 cwd, err := os.Getwd() 1405 if err != nil { 1406 t.Fatalf("err: %s", err) 1407 } 1408 1409 m := testModule(t, "plan-path-var") 1410 p := testProvider("aws") 1411 p.DiffFn = testDiffFn 1412 ctx := testContext2(t, &ContextOpts{ 1413 Module: m, 1414 Providers: map[string]ResourceProviderFactory{ 1415 "aws": testProviderFuncFixed(p), 1416 }, 1417 }) 1418 1419 plan, err := ctx.Plan() 1420 if err != nil { 1421 t.Fatalf("err: %s", err) 1422 } 1423 1424 actual := strings.TrimSpace(plan.String()) 1425 expected := strings.TrimSpace(testTerraformPlanPathVarStr) 1426 1427 // Warning: this ordering REALLY matters for this test. The 1428 // order is: cwd, module, root. 1429 expected = fmt.Sprintf( 1430 expected, 1431 cwd, 1432 m.Config().Dir, 1433 m.Config().Dir) 1434 1435 if actual != expected { 1436 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 1437 } 1438 } 1439 1440 func TestContext2Plan_diffVar(t *testing.T) { 1441 m := testModule(t, "plan-diffvar") 1442 p := testProvider("aws") 1443 s := &State{ 1444 Modules: []*ModuleState{ 1445 &ModuleState{ 1446 Path: rootModulePath, 1447 Resources: map[string]*ResourceState{ 1448 "aws_instance.foo": &ResourceState{ 1449 Primary: &InstanceState{ 1450 ID: "bar", 1451 Attributes: map[string]string{ 1452 "num": "2", 1453 }, 1454 }, 1455 }, 1456 }, 1457 }, 1458 }, 1459 } 1460 ctx := testContext2(t, &ContextOpts{ 1461 Module: m, 1462 Providers: map[string]ResourceProviderFactory{ 1463 "aws": testProviderFuncFixed(p), 1464 }, 1465 State: s, 1466 }) 1467 1468 p.DiffFn = func( 1469 info *InstanceInfo, 1470 s *InstanceState, 1471 c *ResourceConfig) (*InstanceDiff, error) { 1472 if s.ID != "bar" { 1473 return testDiffFn(info, s, c) 1474 } 1475 1476 return &InstanceDiff{ 1477 Attributes: map[string]*ResourceAttrDiff{ 1478 "num": &ResourceAttrDiff{ 1479 Old: "2", 1480 New: "3", 1481 }, 1482 }, 1483 }, nil 1484 } 1485 1486 plan, err := ctx.Plan() 1487 if err != nil { 1488 t.Fatalf("err: %s", err) 1489 } 1490 1491 actual := strings.TrimSpace(plan.String()) 1492 expected := strings.TrimSpace(testTerraformPlanDiffVarStr) 1493 if actual != expected { 1494 t.Fatalf("actual:\n%s\n\nexpected:\n%s", actual, expected) 1495 } 1496 } 1497 1498 func TestContext2Plan_hook(t *testing.T) { 1499 m := testModule(t, "plan-good") 1500 h := new(MockHook) 1501 p := testProvider("aws") 1502 p.DiffFn = testDiffFn 1503 ctx := testContext2(t, &ContextOpts{ 1504 Module: m, 1505 Hooks: []Hook{h}, 1506 Providers: map[string]ResourceProviderFactory{ 1507 "aws": testProviderFuncFixed(p), 1508 }, 1509 }) 1510 1511 _, err := ctx.Plan() 1512 if err != nil { 1513 t.Fatalf("err: %s", err) 1514 } 1515 1516 if !h.PreDiffCalled { 1517 t.Fatal("should be called") 1518 } 1519 if !h.PostDiffCalled { 1520 t.Fatal("should be called") 1521 } 1522 } 1523 1524 func TestContext2Plan_orphan(t *testing.T) { 1525 m := testModule(t, "plan-orphan") 1526 p := testProvider("aws") 1527 p.DiffFn = testDiffFn 1528 s := &State{ 1529 Modules: []*ModuleState{ 1530 &ModuleState{ 1531 Path: rootModulePath, 1532 Resources: map[string]*ResourceState{ 1533 "aws_instance.baz": &ResourceState{ 1534 Type: "aws_instance", 1535 Primary: &InstanceState{ 1536 ID: "bar", 1537 }, 1538 }, 1539 }, 1540 }, 1541 }, 1542 } 1543 ctx := testContext2(t, &ContextOpts{ 1544 Module: m, 1545 Providers: map[string]ResourceProviderFactory{ 1546 "aws": testProviderFuncFixed(p), 1547 }, 1548 State: s, 1549 }) 1550 1551 plan, err := ctx.Plan() 1552 if err != nil { 1553 t.Fatalf("err: %s", err) 1554 } 1555 1556 actual := strings.TrimSpace(plan.String()) 1557 expected := strings.TrimSpace(testTerraformPlanOrphanStr) 1558 if actual != expected { 1559 t.Fatalf("bad:\n%s", actual) 1560 } 1561 } 1562 1563 func TestContext2Plan_state(t *testing.T) { 1564 m := testModule(t, "plan-good") 1565 p := testProvider("aws") 1566 p.DiffFn = testDiffFn 1567 s := &State{ 1568 Modules: []*ModuleState{ 1569 &ModuleState{ 1570 Path: rootModulePath, 1571 Resources: map[string]*ResourceState{ 1572 "aws_instance.foo": &ResourceState{ 1573 Primary: &InstanceState{ 1574 ID: "bar", 1575 }, 1576 }, 1577 }, 1578 }, 1579 }, 1580 } 1581 ctx := testContext2(t, &ContextOpts{ 1582 Module: m, 1583 Providers: map[string]ResourceProviderFactory{ 1584 "aws": testProviderFuncFixed(p), 1585 }, 1586 State: s, 1587 }) 1588 1589 plan, err := ctx.Plan() 1590 if err != nil { 1591 t.Fatalf("err: %s", err) 1592 } 1593 1594 if len(plan.Diff.RootModule().Resources) < 2 { 1595 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 1596 } 1597 1598 actual := strings.TrimSpace(plan.String()) 1599 expected := strings.TrimSpace(testTerraformPlanStateStr) 1600 if actual != expected { 1601 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 1602 } 1603 } 1604 1605 func TestContext2Plan_taint(t *testing.T) { 1606 m := testModule(t, "plan-taint") 1607 p := testProvider("aws") 1608 p.DiffFn = testDiffFn 1609 s := &State{ 1610 Modules: []*ModuleState{ 1611 &ModuleState{ 1612 Path: rootModulePath, 1613 Resources: map[string]*ResourceState{ 1614 "aws_instance.foo": &ResourceState{ 1615 Type: "aws_instance", 1616 Primary: &InstanceState{ 1617 ID: "bar", 1618 Attributes: map[string]string{"num": "2"}, 1619 }, 1620 }, 1621 "aws_instance.bar": &ResourceState{ 1622 Type: "aws_instance", 1623 Tainted: []*InstanceState{ 1624 &InstanceState{ 1625 ID: "baz", 1626 }, 1627 }, 1628 }, 1629 }, 1630 }, 1631 }, 1632 } 1633 ctx := testContext2(t, &ContextOpts{ 1634 Module: m, 1635 Providers: map[string]ResourceProviderFactory{ 1636 "aws": testProviderFuncFixed(p), 1637 }, 1638 State: s, 1639 }) 1640 1641 plan, err := ctx.Plan() 1642 if err != nil { 1643 t.Fatalf("err: %s", err) 1644 } 1645 1646 actual := strings.TrimSpace(plan.String()) 1647 expected := strings.TrimSpace(testTerraformPlanTaintStr) 1648 if actual != expected { 1649 t.Fatalf("bad:\n%s", actual) 1650 } 1651 } 1652 1653 func TestContext2Plan_multiple_taint(t *testing.T) { 1654 m := testModule(t, "plan-taint") 1655 p := testProvider("aws") 1656 p.DiffFn = testDiffFn 1657 s := &State{ 1658 Modules: []*ModuleState{ 1659 &ModuleState{ 1660 Path: rootModulePath, 1661 Resources: map[string]*ResourceState{ 1662 "aws_instance.foo": &ResourceState{ 1663 Type: "aws_instance", 1664 Primary: &InstanceState{ 1665 ID: "bar", 1666 Attributes: map[string]string{"num": "2"}, 1667 }, 1668 }, 1669 "aws_instance.bar": &ResourceState{ 1670 Type: "aws_instance", 1671 Tainted: []*InstanceState{ 1672 &InstanceState{ 1673 ID: "baz", 1674 }, 1675 &InstanceState{ 1676 ID: "zip", 1677 }, 1678 }, 1679 }, 1680 }, 1681 }, 1682 }, 1683 } 1684 ctx := testContext2(t, &ContextOpts{ 1685 Module: m, 1686 Providers: map[string]ResourceProviderFactory{ 1687 "aws": testProviderFuncFixed(p), 1688 }, 1689 State: s, 1690 }) 1691 1692 plan, err := ctx.Plan() 1693 if err != nil { 1694 t.Fatalf("err: %s", err) 1695 } 1696 1697 actual := strings.TrimSpace(plan.String()) 1698 expected := strings.TrimSpace(testTerraformPlanMultipleTaintStr) 1699 if actual != expected { 1700 t.Fatalf("bad:\n%s", actual) 1701 } 1702 } 1703 1704 // Fails about 50% of the time before the fix for GH-4982, covers the fix. 1705 func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) { 1706 m := testModule(t, "plan-taint-interpolated-count") 1707 p := testProvider("aws") 1708 p.DiffFn = testDiffFn 1709 s := &State{ 1710 Modules: []*ModuleState{ 1711 &ModuleState{ 1712 Path: rootModulePath, 1713 Resources: map[string]*ResourceState{ 1714 "aws_instance.foo.0": &ResourceState{ 1715 Type: "aws_instance", 1716 Tainted: []*InstanceState{ 1717 &InstanceState{ID: "bar"}, 1718 }, 1719 }, 1720 "aws_instance.foo.1": &ResourceState{ 1721 Type: "aws_instance", 1722 Primary: &InstanceState{ID: "bar"}, 1723 }, 1724 "aws_instance.foo.2": &ResourceState{ 1725 Type: "aws_instance", 1726 Primary: &InstanceState{ID: "bar"}, 1727 }, 1728 }, 1729 }, 1730 }, 1731 } 1732 ctx := testContext2(t, &ContextOpts{ 1733 Module: m, 1734 Providers: map[string]ResourceProviderFactory{ 1735 "aws": testProviderFuncFixed(p), 1736 }, 1737 State: s, 1738 }) 1739 1740 for i := 0; i < 100; i++ { 1741 plan, err := ctx.Plan() 1742 if err != nil { 1743 t.Fatalf("err: %s", err) 1744 } 1745 1746 actual := strings.TrimSpace(plan.String()) 1747 expected := strings.TrimSpace(` 1748 DIFF: 1749 1750 DESTROY/CREATE: aws_instance.foo.0 1751 1752 STATE: 1753 1754 aws_instance.foo.0: (1 tainted) 1755 ID = <not created> 1756 Tainted ID 1 = bar 1757 aws_instance.foo.1: 1758 ID = bar 1759 aws_instance.foo.2: 1760 ID = bar 1761 `) 1762 if actual != expected { 1763 t.Fatalf("bad:\n%s", actual) 1764 } 1765 } 1766 } 1767 1768 func TestContext2Plan_targeted(t *testing.T) { 1769 m := testModule(t, "plan-targeted") 1770 p := testProvider("aws") 1771 p.DiffFn = testDiffFn 1772 ctx := testContext2(t, &ContextOpts{ 1773 Module: m, 1774 Providers: map[string]ResourceProviderFactory{ 1775 "aws": testProviderFuncFixed(p), 1776 }, 1777 Targets: []string{"aws_instance.foo"}, 1778 }) 1779 1780 plan, err := ctx.Plan() 1781 if err != nil { 1782 t.Fatalf("err: %s", err) 1783 } 1784 1785 actual := strings.TrimSpace(plan.String()) 1786 expected := strings.TrimSpace(` 1787 DIFF: 1788 1789 CREATE: aws_instance.foo 1790 num: "" => "2" 1791 type: "" => "aws_instance" 1792 1793 STATE: 1794 1795 <no state> 1796 `) 1797 if actual != expected { 1798 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 1799 } 1800 } 1801 1802 func TestContext2Plan_targetedOrphan(t *testing.T) { 1803 m := testModule(t, "plan-targeted-orphan") 1804 p := testProvider("aws") 1805 p.DiffFn = testDiffFn 1806 ctx := testContext2(t, &ContextOpts{ 1807 Module: m, 1808 Providers: map[string]ResourceProviderFactory{ 1809 "aws": testProviderFuncFixed(p), 1810 }, 1811 State: &State{ 1812 Modules: []*ModuleState{ 1813 &ModuleState{ 1814 Path: rootModulePath, 1815 Resources: map[string]*ResourceState{ 1816 "aws_instance.orphan": &ResourceState{ 1817 Type: "aws_instance", 1818 Primary: &InstanceState{ 1819 ID: "i-789xyz", 1820 }, 1821 }, 1822 "aws_instance.nottargeted": &ResourceState{ 1823 Type: "aws_instance", 1824 Primary: &InstanceState{ 1825 ID: "i-abc123", 1826 }, 1827 }, 1828 }, 1829 }, 1830 }, 1831 }, 1832 Destroy: true, 1833 Targets: []string{"aws_instance.orphan"}, 1834 }) 1835 1836 plan, err := ctx.Plan() 1837 if err != nil { 1838 t.Fatalf("err: %s", err) 1839 } 1840 1841 actual := strings.TrimSpace(plan.String()) 1842 expected := strings.TrimSpace(`DIFF: 1843 1844 DESTROY: aws_instance.orphan 1845 1846 STATE: 1847 1848 aws_instance.nottargeted: 1849 ID = i-abc123 1850 aws_instance.orphan: 1851 ID = i-789xyz 1852 `) 1853 if actual != expected { 1854 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 1855 } 1856 } 1857 1858 // https://github.com/hashicorp/terraform/issues/2538 1859 func TestContext2Plan_targetedModuleOrphan(t *testing.T) { 1860 m := testModule(t, "plan-targeted-module-orphan") 1861 p := testProvider("aws") 1862 p.DiffFn = testDiffFn 1863 ctx := testContext2(t, &ContextOpts{ 1864 Module: m, 1865 Providers: map[string]ResourceProviderFactory{ 1866 "aws": testProviderFuncFixed(p), 1867 }, 1868 State: &State{ 1869 Modules: []*ModuleState{ 1870 &ModuleState{ 1871 Path: []string{"root", "child"}, 1872 Resources: map[string]*ResourceState{ 1873 "aws_instance.orphan": &ResourceState{ 1874 Type: "aws_instance", 1875 Primary: &InstanceState{ 1876 ID: "i-789xyz", 1877 }, 1878 }, 1879 "aws_instance.nottargeted": &ResourceState{ 1880 Type: "aws_instance", 1881 Primary: &InstanceState{ 1882 ID: "i-abc123", 1883 }, 1884 }, 1885 }, 1886 }, 1887 }, 1888 }, 1889 Destroy: true, 1890 Targets: []string{"module.child.aws_instance.orphan"}, 1891 }) 1892 1893 plan, err := ctx.Plan() 1894 if err != nil { 1895 t.Fatalf("err: %s", err) 1896 } 1897 1898 actual := strings.TrimSpace(plan.String()) 1899 expected := strings.TrimSpace(`DIFF: 1900 1901 module.child: 1902 DESTROY: aws_instance.orphan 1903 1904 STATE: 1905 1906 module.child: 1907 aws_instance.nottargeted: 1908 ID = i-abc123 1909 aws_instance.orphan: 1910 ID = i-789xyz 1911 `) 1912 if actual != expected { 1913 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 1914 } 1915 } 1916 1917 // https://github.com/hashicorp/terraform/issues/4515 1918 func TestContext2Plan_targetedOverTen(t *testing.T) { 1919 m := testModule(t, "plan-targeted-over-ten") 1920 p := testProvider("aws") 1921 p.DiffFn = testDiffFn 1922 1923 resources := make(map[string]*ResourceState) 1924 var expectedState []string 1925 for i := 0; i < 13; i++ { 1926 key := fmt.Sprintf("aws_instance.foo.%d", i) 1927 id := fmt.Sprintf("i-abc%d", i) 1928 resources[key] = &ResourceState{ 1929 Type: "aws_instance", 1930 Primary: &InstanceState{ID: id}, 1931 } 1932 expectedState = append(expectedState, 1933 fmt.Sprintf("%s:\n ID = %s\n", key, id)) 1934 } 1935 ctx := testContext2(t, &ContextOpts{ 1936 Module: m, 1937 Providers: map[string]ResourceProviderFactory{ 1938 "aws": testProviderFuncFixed(p), 1939 }, 1940 State: &State{ 1941 Modules: []*ModuleState{ 1942 &ModuleState{ 1943 Path: rootModulePath, 1944 Resources: resources, 1945 }, 1946 }, 1947 }, 1948 Targets: []string{"aws_instance.foo[1]"}, 1949 }) 1950 1951 plan, err := ctx.Plan() 1952 if err != nil { 1953 t.Fatalf("err: %s", err) 1954 } 1955 1956 actual := strings.TrimSpace(plan.String()) 1957 sort.Strings(expectedState) 1958 expected := strings.TrimSpace(` 1959 DIFF: 1960 1961 1962 1963 STATE: 1964 1965 aws_instance.foo.0: 1966 ID = i-abc0 1967 aws_instance.foo.1: 1968 ID = i-abc1 1969 aws_instance.foo.10: 1970 ID = i-abc10 1971 aws_instance.foo.11: 1972 ID = i-abc11 1973 aws_instance.foo.12: 1974 ID = i-abc12 1975 aws_instance.foo.2: 1976 ID = i-abc2 1977 aws_instance.foo.3: 1978 ID = i-abc3 1979 aws_instance.foo.4: 1980 ID = i-abc4 1981 aws_instance.foo.5: 1982 ID = i-abc5 1983 aws_instance.foo.6: 1984 ID = i-abc6 1985 aws_instance.foo.7: 1986 ID = i-abc7 1987 aws_instance.foo.8: 1988 ID = i-abc8 1989 aws_instance.foo.9: 1990 ID = i-abc9 1991 `) 1992 if actual != expected { 1993 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 1994 } 1995 } 1996 1997 func TestContext2Plan_provider(t *testing.T) { 1998 m := testModule(t, "plan-provider") 1999 p := testProvider("aws") 2000 p.DiffFn = testDiffFn 2001 2002 var value interface{} 2003 p.ConfigureFn = func(c *ResourceConfig) error { 2004 value, _ = c.Get("foo") 2005 return nil 2006 } 2007 2008 ctx := testContext2(t, &ContextOpts{ 2009 Module: m, 2010 Providers: map[string]ResourceProviderFactory{ 2011 "aws": testProviderFuncFixed(p), 2012 }, 2013 Variables: map[string]string{ 2014 "foo": "bar", 2015 }, 2016 }) 2017 2018 if _, err := ctx.Plan(); err != nil { 2019 t.Fatalf("err: %s", err) 2020 } 2021 2022 if value != "bar" { 2023 t.Fatalf("bad: %#v", value) 2024 } 2025 } 2026 2027 func TestContext2Plan_varListErr(t *testing.T) { 2028 m := testModule(t, "plan-var-list-err") 2029 p := testProvider("aws") 2030 ctx := testContext2(t, &ContextOpts{ 2031 Module: m, 2032 Providers: map[string]ResourceProviderFactory{ 2033 "aws": testProviderFuncFixed(p), 2034 }, 2035 }) 2036 2037 _, err := ctx.Plan() 2038 if err == nil { 2039 t.Fatal("should error") 2040 } 2041 } 2042 2043 func TestContext2Plan_ignoreChanges(t *testing.T) { 2044 m := testModule(t, "plan-ignore-changes") 2045 p := testProvider("aws") 2046 p.DiffFn = testDiffFn 2047 s := &State{ 2048 Modules: []*ModuleState{ 2049 &ModuleState{ 2050 Path: rootModulePath, 2051 Resources: map[string]*ResourceState{ 2052 "aws_instance.foo": &ResourceState{ 2053 Primary: &InstanceState{ 2054 ID: "bar", 2055 Attributes: map[string]string{"ami": "ami-abcd1234"}, 2056 }, 2057 }, 2058 }, 2059 }, 2060 }, 2061 } 2062 ctx := testContext2(t, &ContextOpts{ 2063 Module: m, 2064 Providers: map[string]ResourceProviderFactory{ 2065 "aws": testProviderFuncFixed(p), 2066 }, 2067 Variables: map[string]string{ 2068 "foo": "ami-1234abcd", 2069 }, 2070 State: s, 2071 }) 2072 2073 plan, err := ctx.Plan() 2074 if err != nil { 2075 t.Fatalf("err: %s", err) 2076 } 2077 2078 if len(plan.Diff.RootModule().Resources) < 1 { 2079 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 2080 } 2081 2082 actual := strings.TrimSpace(plan.String()) 2083 expected := strings.TrimSpace(testTerraformPlanIgnoreChangesStr) 2084 if actual != expected { 2085 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 2086 } 2087 }