github.com/jrasell/terraform@v0.6.17-0.20160523115548-2652f5232949/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_moduleVarWrongType(t *testing.T) { 630 m := testModule(t, "plan-module-wrong-var-type") 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 _, err := ctx.Plan() 641 if err == nil { 642 t.Fatalf("should error") 643 } 644 } 645 646 func TestContext2Plan_moduleVarWrongTypeNested(t *testing.T) { 647 m := testModule(t, "plan-module-wrong-var-type-nested") 648 p := testProvider("aws") 649 p.DiffFn = testDiffFn 650 ctx := testContext2(t, &ContextOpts{ 651 Module: m, 652 Providers: map[string]ResourceProviderFactory{ 653 "aws": testProviderFuncFixed(p), 654 }, 655 }) 656 657 _, err := ctx.Plan() 658 if err == nil { 659 t.Fatalf("should error") 660 } 661 } 662 663 func TestContext2Plan_moduleVarWithDefaultValue(t *testing.T) { 664 m := testModule(t, "plan-module-var-with-default-value") 665 p := testProvider("null") 666 p.DiffFn = testDiffFn 667 ctx := testContext2(t, &ContextOpts{ 668 Module: m, 669 Providers: map[string]ResourceProviderFactory{ 670 "null": testProviderFuncFixed(p), 671 }, 672 }) 673 674 _, err := ctx.Plan() 675 if err != nil { 676 t.Fatalf("bad: %s", err) 677 } 678 } 679 680 func TestContext2Plan_moduleVarComputed(t *testing.T) { 681 m := testModule(t, "plan-module-var-computed") 682 p := testProvider("aws") 683 p.DiffFn = testDiffFn 684 ctx := testContext2(t, &ContextOpts{ 685 Module: m, 686 Providers: map[string]ResourceProviderFactory{ 687 "aws": testProviderFuncFixed(p), 688 }, 689 }) 690 691 plan, err := ctx.Plan() 692 if err != nil { 693 t.Fatalf("err: %s", err) 694 } 695 696 actual := strings.TrimSpace(plan.String()) 697 expected := strings.TrimSpace(testTerraformPlanModuleVarComputedStr) 698 if actual != expected { 699 t.Fatalf("bad:\n%s", actual) 700 } 701 } 702 703 func TestContext2Plan_nil(t *testing.T) { 704 m := testModule(t, "plan-nil") 705 p := testProvider("aws") 706 p.DiffFn = testDiffFn 707 ctx := testContext2(t, &ContextOpts{ 708 Module: m, 709 Providers: map[string]ResourceProviderFactory{ 710 "aws": testProviderFuncFixed(p), 711 }, 712 State: &State{ 713 Modules: []*ModuleState{ 714 &ModuleState{ 715 Path: rootModulePath, 716 Resources: map[string]*ResourceState{ 717 "aws_instance.foo": &ResourceState{ 718 Type: "aws_instance", 719 Primary: &InstanceState{ 720 ID: "bar", 721 }, 722 }, 723 }, 724 }, 725 }, 726 }, 727 }) 728 729 plan, err := ctx.Plan() 730 if err != nil { 731 t.Fatalf("err: %s", err) 732 } 733 if len(plan.Diff.RootModule().Resources) != 0 { 734 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 735 } 736 } 737 738 func TestContext2Plan_preventDestroy_bad(t *testing.T) { 739 m := testModule(t, "plan-prevent-destroy-bad") 740 p := testProvider("aws") 741 p.DiffFn = testDiffFn 742 ctx := testContext2(t, &ContextOpts{ 743 Module: m, 744 Providers: map[string]ResourceProviderFactory{ 745 "aws": testProviderFuncFixed(p), 746 }, 747 State: &State{ 748 Modules: []*ModuleState{ 749 &ModuleState{ 750 Path: rootModulePath, 751 Resources: map[string]*ResourceState{ 752 "aws_instance.foo": &ResourceState{ 753 Type: "aws_instance", 754 Primary: &InstanceState{ 755 ID: "i-abc123", 756 }, 757 }, 758 }, 759 }, 760 }, 761 }, 762 }) 763 764 plan, err := ctx.Plan() 765 766 expectedErr := "aws_instance.foo: the plan would destroy" 767 if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) { 768 t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s", 769 expectedErr, err, plan) 770 } 771 } 772 773 func TestContext2Plan_preventDestroy_good(t *testing.T) { 774 m := testModule(t, "plan-prevent-destroy-good") 775 p := testProvider("aws") 776 p.DiffFn = testDiffFn 777 ctx := testContext2(t, &ContextOpts{ 778 Module: m, 779 Providers: map[string]ResourceProviderFactory{ 780 "aws": testProviderFuncFixed(p), 781 }, 782 State: &State{ 783 Modules: []*ModuleState{ 784 &ModuleState{ 785 Path: rootModulePath, 786 Resources: map[string]*ResourceState{ 787 "aws_instance.foo": &ResourceState{ 788 Type: "aws_instance", 789 Primary: &InstanceState{ 790 ID: "i-abc123", 791 }, 792 }, 793 }, 794 }, 795 }, 796 }, 797 }) 798 799 plan, err := ctx.Plan() 800 if err != nil { 801 t.Fatalf("err: %s", err) 802 } 803 if !plan.Diff.Empty() { 804 t.Fatalf("Expected empty plan, got %s", plan.String()) 805 } 806 } 807 808 func TestContext2Plan_preventDestroy_destroyPlan(t *testing.T) { 809 m := testModule(t, "plan-prevent-destroy-good") 810 p := testProvider("aws") 811 p.DiffFn = testDiffFn 812 ctx := testContext2(t, &ContextOpts{ 813 Module: m, 814 Providers: map[string]ResourceProviderFactory{ 815 "aws": testProviderFuncFixed(p), 816 }, 817 State: &State{ 818 Modules: []*ModuleState{ 819 &ModuleState{ 820 Path: rootModulePath, 821 Resources: map[string]*ResourceState{ 822 "aws_instance.foo": &ResourceState{ 823 Type: "aws_instance", 824 Primary: &InstanceState{ 825 ID: "i-abc123", 826 }, 827 }, 828 }, 829 }, 830 }, 831 }, 832 Destroy: true, 833 }) 834 835 plan, err := ctx.Plan() 836 837 expectedErr := "aws_instance.foo: the plan would destroy" 838 if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) { 839 t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s", 840 expectedErr, err, plan) 841 } 842 } 843 844 func TestContext2Plan_computed(t *testing.T) { 845 m := testModule(t, "plan-computed") 846 p := testProvider("aws") 847 p.DiffFn = testDiffFn 848 ctx := testContext2(t, &ContextOpts{ 849 Module: m, 850 Providers: map[string]ResourceProviderFactory{ 851 "aws": testProviderFuncFixed(p), 852 }, 853 }) 854 855 plan, err := ctx.Plan() 856 if err != nil { 857 t.Fatalf("err: %s", err) 858 } 859 860 actual := strings.TrimSpace(plan.String()) 861 expected := strings.TrimSpace(testTerraformPlanComputedStr) 862 if actual != expected { 863 t.Fatalf("bad:\n%s", actual) 864 } 865 } 866 867 func TestContext2Plan_computedList(t *testing.T) { 868 m := testModule(t, "plan-computed-list") 869 p := testProvider("aws") 870 p.DiffFn = testDiffFn 871 ctx := testContext2(t, &ContextOpts{ 872 Module: m, 873 Providers: map[string]ResourceProviderFactory{ 874 "aws": testProviderFuncFixed(p), 875 }, 876 }) 877 878 plan, err := ctx.Plan() 879 if err != nil { 880 t.Fatalf("err: %s", err) 881 } 882 883 actual := strings.TrimSpace(plan.String()) 884 expected := strings.TrimSpace(testTerraformPlanComputedListStr) 885 if actual != expected { 886 t.Fatalf("bad:\n%s", actual) 887 } 888 } 889 890 func TestContext2Plan_count(t *testing.T) { 891 m := testModule(t, "plan-count") 892 p := testProvider("aws") 893 p.DiffFn = testDiffFn 894 ctx := testContext2(t, &ContextOpts{ 895 Module: m, 896 Providers: map[string]ResourceProviderFactory{ 897 "aws": testProviderFuncFixed(p), 898 }, 899 }) 900 901 plan, err := ctx.Plan() 902 if err != nil { 903 t.Fatalf("err: %s", err) 904 } 905 906 if len(plan.Diff.RootModule().Resources) < 6 { 907 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 908 } 909 910 actual := strings.TrimSpace(plan.String()) 911 expected := strings.TrimSpace(testTerraformPlanCountStr) 912 if actual != expected { 913 t.Fatalf("bad:\n%s", actual) 914 } 915 } 916 917 func TestContext2Plan_countComputed(t *testing.T) { 918 m := testModule(t, "plan-count-computed") 919 p := testProvider("aws") 920 p.DiffFn = testDiffFn 921 ctx := testContext2(t, &ContextOpts{ 922 Module: m, 923 Providers: map[string]ResourceProviderFactory{ 924 "aws": testProviderFuncFixed(p), 925 }, 926 }) 927 928 _, err := ctx.Plan() 929 if err == nil { 930 t.Fatal("should error") 931 } 932 } 933 934 func TestContext2Plan_countIndex(t *testing.T) { 935 m := testModule(t, "plan-count-index") 936 p := testProvider("aws") 937 p.DiffFn = testDiffFn 938 ctx := testContext2(t, &ContextOpts{ 939 Module: m, 940 Providers: map[string]ResourceProviderFactory{ 941 "aws": testProviderFuncFixed(p), 942 }, 943 }) 944 945 plan, err := ctx.Plan() 946 if err != nil { 947 t.Fatalf("err: %s", err) 948 } 949 950 actual := strings.TrimSpace(plan.String()) 951 expected := strings.TrimSpace(testTerraformPlanCountIndexStr) 952 if actual != expected { 953 t.Fatalf("bad:\n%s", actual) 954 } 955 } 956 957 func TestContext2Plan_countIndexZero(t *testing.T) { 958 m := testModule(t, "plan-count-index-zero") 959 p := testProvider("aws") 960 p.DiffFn = testDiffFn 961 ctx := testContext2(t, &ContextOpts{ 962 Module: m, 963 Providers: map[string]ResourceProviderFactory{ 964 "aws": testProviderFuncFixed(p), 965 }, 966 }) 967 968 plan, err := ctx.Plan() 969 if err != nil { 970 t.Fatalf("err: %s", err) 971 } 972 973 actual := strings.TrimSpace(plan.String()) 974 expected := strings.TrimSpace(testTerraformPlanCountIndexZeroStr) 975 if actual != expected { 976 t.Fatalf("bad:\n%s", actual) 977 } 978 } 979 980 func TestContext2Plan_countVar(t *testing.T) { 981 m := testModule(t, "plan-count-var") 982 p := testProvider("aws") 983 p.DiffFn = testDiffFn 984 ctx := testContext2(t, &ContextOpts{ 985 Module: m, 986 Providers: map[string]ResourceProviderFactory{ 987 "aws": testProviderFuncFixed(p), 988 }, 989 Variables: map[string]string{ 990 "count": "3", 991 }, 992 }) 993 994 plan, err := ctx.Plan() 995 if err != nil { 996 t.Fatalf("err: %s", err) 997 } 998 999 actual := strings.TrimSpace(plan.String()) 1000 expected := strings.TrimSpace(testTerraformPlanCountVarStr) 1001 if actual != expected { 1002 t.Fatalf("bad:\n%s", actual) 1003 } 1004 } 1005 1006 func TestContext2Plan_countZero(t *testing.T) { 1007 m := testModule(t, "plan-count-zero") 1008 p := testProvider("aws") 1009 p.DiffFn = testDiffFn 1010 ctx := testContext2(t, &ContextOpts{ 1011 Module: m, 1012 Providers: map[string]ResourceProviderFactory{ 1013 "aws": testProviderFuncFixed(p), 1014 }, 1015 }) 1016 1017 plan, err := ctx.Plan() 1018 if err != nil { 1019 t.Fatalf("err: %s", err) 1020 } 1021 1022 actual := strings.TrimSpace(plan.String()) 1023 expected := strings.TrimSpace(testTerraformPlanCountZeroStr) 1024 if actual != expected { 1025 t.Fatalf("bad:\n%s", actual) 1026 } 1027 } 1028 1029 func TestContext2Plan_countOneIndex(t *testing.T) { 1030 m := testModule(t, "plan-count-one-index") 1031 p := testProvider("aws") 1032 p.DiffFn = testDiffFn 1033 ctx := testContext2(t, &ContextOpts{ 1034 Module: m, 1035 Providers: map[string]ResourceProviderFactory{ 1036 "aws": testProviderFuncFixed(p), 1037 }, 1038 }) 1039 1040 plan, err := ctx.Plan() 1041 if err != nil { 1042 t.Fatalf("err: %s", err) 1043 } 1044 1045 actual := strings.TrimSpace(plan.String()) 1046 expected := strings.TrimSpace(testTerraformPlanCountOneIndexStr) 1047 if actual != expected { 1048 t.Fatalf("bad:\n%s", actual) 1049 } 1050 } 1051 1052 func TestContext2Plan_countDecreaseToOne(t *testing.T) { 1053 m := testModule(t, "plan-count-dec") 1054 p := testProvider("aws") 1055 p.DiffFn = testDiffFn 1056 s := &State{ 1057 Modules: []*ModuleState{ 1058 &ModuleState{ 1059 Path: rootModulePath, 1060 Resources: map[string]*ResourceState{ 1061 "aws_instance.foo.0": &ResourceState{ 1062 Type: "aws_instance", 1063 Primary: &InstanceState{ 1064 ID: "bar", 1065 Attributes: map[string]string{ 1066 "foo": "foo", 1067 "type": "aws_instance", 1068 }, 1069 }, 1070 }, 1071 "aws_instance.foo.1": &ResourceState{ 1072 Type: "aws_instance", 1073 Primary: &InstanceState{ 1074 ID: "bar", 1075 }, 1076 }, 1077 "aws_instance.foo.2": &ResourceState{ 1078 Type: "aws_instance", 1079 Primary: &InstanceState{ 1080 ID: "bar", 1081 }, 1082 }, 1083 }, 1084 }, 1085 }, 1086 } 1087 ctx := testContext2(t, &ContextOpts{ 1088 Module: m, 1089 Providers: map[string]ResourceProviderFactory{ 1090 "aws": testProviderFuncFixed(p), 1091 }, 1092 State: s, 1093 }) 1094 1095 plan, err := ctx.Plan() 1096 if err != nil { 1097 t.Fatalf("err: %s", err) 1098 } 1099 1100 actual := strings.TrimSpace(plan.String()) 1101 expected := strings.TrimSpace(testTerraformPlanCountDecreaseStr) 1102 if actual != expected { 1103 t.Fatalf("bad:\n%s", actual) 1104 } 1105 } 1106 1107 func TestContext2Plan_countIncreaseFromNotSet(t *testing.T) { 1108 m := testModule(t, "plan-count-inc") 1109 p := testProvider("aws") 1110 p.DiffFn = testDiffFn 1111 s := &State{ 1112 Modules: []*ModuleState{ 1113 &ModuleState{ 1114 Path: rootModulePath, 1115 Resources: map[string]*ResourceState{ 1116 "aws_instance.foo": &ResourceState{ 1117 Type: "aws_instance", 1118 Primary: &InstanceState{ 1119 ID: "bar", 1120 Attributes: map[string]string{ 1121 "foo": "foo", 1122 "type": "aws_instance", 1123 }, 1124 }, 1125 }, 1126 }, 1127 }, 1128 }, 1129 } 1130 ctx := testContext2(t, &ContextOpts{ 1131 Module: m, 1132 Providers: map[string]ResourceProviderFactory{ 1133 "aws": testProviderFuncFixed(p), 1134 }, 1135 State: s, 1136 }) 1137 1138 plan, err := ctx.Plan() 1139 if err != nil { 1140 t.Fatalf("err: %s", err) 1141 } 1142 1143 actual := strings.TrimSpace(plan.String()) 1144 expected := strings.TrimSpace(testTerraformPlanCountIncreaseStr) 1145 if actual != expected { 1146 t.Fatalf("bad:\n%s", actual) 1147 } 1148 } 1149 1150 func TestContext2Plan_countIncreaseFromOne(t *testing.T) { 1151 m := testModule(t, "plan-count-inc") 1152 p := testProvider("aws") 1153 p.DiffFn = testDiffFn 1154 s := &State{ 1155 Modules: []*ModuleState{ 1156 &ModuleState{ 1157 Path: rootModulePath, 1158 Resources: map[string]*ResourceState{ 1159 "aws_instance.foo.0": &ResourceState{ 1160 Type: "aws_instance", 1161 Primary: &InstanceState{ 1162 ID: "bar", 1163 Attributes: map[string]string{ 1164 "foo": "foo", 1165 "type": "aws_instance", 1166 }, 1167 }, 1168 }, 1169 }, 1170 }, 1171 }, 1172 } 1173 ctx := testContext2(t, &ContextOpts{ 1174 Module: m, 1175 Providers: map[string]ResourceProviderFactory{ 1176 "aws": testProviderFuncFixed(p), 1177 }, 1178 State: s, 1179 }) 1180 1181 plan, err := ctx.Plan() 1182 if err != nil { 1183 t.Fatalf("err: %s", err) 1184 } 1185 1186 actual := strings.TrimSpace(plan.String()) 1187 expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneStr) 1188 if actual != expected { 1189 t.Fatalf("bad:\n%s", actual) 1190 } 1191 } 1192 1193 // https://github.com/PeoplePerHour/terraform/pull/11 1194 // 1195 // This tests a case where both a "resource" and "resource.0" are in 1196 // the state file, which apparently is a reasonable backwards compatibility 1197 // concern found in the above 3rd party repo. 1198 func TestContext2Plan_countIncreaseFromOneCorrupted(t *testing.T) { 1199 m := testModule(t, "plan-count-inc") 1200 p := testProvider("aws") 1201 p.DiffFn = testDiffFn 1202 s := &State{ 1203 Modules: []*ModuleState{ 1204 &ModuleState{ 1205 Path: rootModulePath, 1206 Resources: map[string]*ResourceState{ 1207 "aws_instance.foo": &ResourceState{ 1208 Type: "aws_instance", 1209 Primary: &InstanceState{ 1210 ID: "bar", 1211 Attributes: map[string]string{ 1212 "foo": "foo", 1213 "type": "aws_instance", 1214 }, 1215 }, 1216 }, 1217 "aws_instance.foo.0": &ResourceState{ 1218 Type: "aws_instance", 1219 Primary: &InstanceState{ 1220 ID: "bar", 1221 Attributes: map[string]string{ 1222 "foo": "foo", 1223 "type": "aws_instance", 1224 }, 1225 }, 1226 }, 1227 }, 1228 }, 1229 }, 1230 } 1231 ctx := testContext2(t, &ContextOpts{ 1232 Module: m, 1233 Providers: map[string]ResourceProviderFactory{ 1234 "aws": testProviderFuncFixed(p), 1235 }, 1236 State: s, 1237 }) 1238 1239 plan, err := ctx.Plan() 1240 if err != nil { 1241 t.Fatalf("err: %s", err) 1242 } 1243 1244 actual := strings.TrimSpace(plan.String()) 1245 expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneCorruptedStr) 1246 if actual != expected { 1247 t.Fatalf("bad:\n%s", actual) 1248 } 1249 } 1250 1251 func TestContext2Plan_destroy(t *testing.T) { 1252 m := testModule(t, "plan-destroy") 1253 p := testProvider("aws") 1254 p.DiffFn = testDiffFn 1255 s := &State{ 1256 Modules: []*ModuleState{ 1257 &ModuleState{ 1258 Path: rootModulePath, 1259 Resources: map[string]*ResourceState{ 1260 "aws_instance.one": &ResourceState{ 1261 Type: "aws_instance", 1262 Primary: &InstanceState{ 1263 ID: "bar", 1264 }, 1265 }, 1266 "aws_instance.two": &ResourceState{ 1267 Type: "aws_instance", 1268 Primary: &InstanceState{ 1269 ID: "baz", 1270 }, 1271 }, 1272 }, 1273 }, 1274 }, 1275 } 1276 ctx := testContext2(t, &ContextOpts{ 1277 Module: m, 1278 Providers: map[string]ResourceProviderFactory{ 1279 "aws": testProviderFuncFixed(p), 1280 }, 1281 State: s, 1282 Destroy: true, 1283 }) 1284 1285 plan, err := ctx.Plan() 1286 if err != nil { 1287 t.Fatalf("err: %s", err) 1288 } 1289 1290 if len(plan.Diff.RootModule().Resources) != 2 { 1291 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 1292 } 1293 1294 actual := strings.TrimSpace(plan.String()) 1295 expected := strings.TrimSpace(testTerraformPlanDestroyStr) 1296 if actual != expected { 1297 t.Fatalf("bad:\n%s", actual) 1298 } 1299 } 1300 1301 func TestContext2Plan_moduleDestroy(t *testing.T) { 1302 m := testModule(t, "plan-module-destroy") 1303 p := testProvider("aws") 1304 p.DiffFn = testDiffFn 1305 s := &State{ 1306 Modules: []*ModuleState{ 1307 &ModuleState{ 1308 Path: rootModulePath, 1309 Resources: map[string]*ResourceState{ 1310 "aws_instance.foo": &ResourceState{ 1311 Type: "aws_instance", 1312 Primary: &InstanceState{ 1313 ID: "bar", 1314 }, 1315 }, 1316 }, 1317 }, 1318 &ModuleState{ 1319 Path: []string{"root", "child"}, 1320 Resources: map[string]*ResourceState{ 1321 "aws_instance.foo": &ResourceState{ 1322 Type: "aws_instance", 1323 Primary: &InstanceState{ 1324 ID: "bar", 1325 }, 1326 }, 1327 }, 1328 }, 1329 }, 1330 } 1331 ctx := testContext2(t, &ContextOpts{ 1332 Module: m, 1333 Providers: map[string]ResourceProviderFactory{ 1334 "aws": testProviderFuncFixed(p), 1335 }, 1336 State: s, 1337 Destroy: true, 1338 }) 1339 1340 plan, err := ctx.Plan() 1341 if err != nil { 1342 t.Fatalf("err: %s", err) 1343 } 1344 1345 actual := strings.TrimSpace(plan.String()) 1346 expected := strings.TrimSpace(testTerraformPlanModuleDestroyStr) 1347 if actual != expected { 1348 t.Fatalf("bad:\n%s", actual) 1349 } 1350 } 1351 1352 // GH-1835 1353 func TestContext2Plan_moduleDestroyCycle(t *testing.T) { 1354 m := testModule(t, "plan-module-destroy-gh-1835") 1355 p := testProvider("aws") 1356 p.DiffFn = testDiffFn 1357 s := &State{ 1358 Modules: []*ModuleState{ 1359 &ModuleState{ 1360 Path: []string{"root", "a_module"}, 1361 Resources: map[string]*ResourceState{ 1362 "aws_instance.a": &ResourceState{ 1363 Type: "aws_instance", 1364 Primary: &InstanceState{ 1365 ID: "a", 1366 }, 1367 }, 1368 }, 1369 }, 1370 &ModuleState{ 1371 Path: []string{"root", "b_module"}, 1372 Resources: map[string]*ResourceState{ 1373 "aws_instance.b": &ResourceState{ 1374 Type: "aws_instance", 1375 Primary: &InstanceState{ 1376 ID: "b", 1377 }, 1378 }, 1379 }, 1380 }, 1381 }, 1382 } 1383 ctx := testContext2(t, &ContextOpts{ 1384 Module: m, 1385 Providers: map[string]ResourceProviderFactory{ 1386 "aws": testProviderFuncFixed(p), 1387 }, 1388 State: s, 1389 Destroy: true, 1390 }) 1391 1392 plan, err := ctx.Plan() 1393 if err != nil { 1394 t.Fatalf("err: %s", err) 1395 } 1396 1397 actual := strings.TrimSpace(plan.String()) 1398 expected := strings.TrimSpace(testTerraformPlanModuleDestroyCycleStr) 1399 if actual != expected { 1400 t.Fatalf("bad:\n%s", actual) 1401 } 1402 } 1403 1404 func TestContext2Plan_moduleDestroyMultivar(t *testing.T) { 1405 m := testModule(t, "plan-module-destroy-multivar") 1406 p := testProvider("aws") 1407 p.DiffFn = testDiffFn 1408 s := &State{ 1409 Modules: []*ModuleState{ 1410 &ModuleState{ 1411 Path: rootModulePath, 1412 Resources: map[string]*ResourceState{}, 1413 }, 1414 &ModuleState{ 1415 Path: []string{"root", "child"}, 1416 Resources: map[string]*ResourceState{ 1417 "aws_instance.foo.0": &ResourceState{ 1418 Type: "aws_instance", 1419 Primary: &InstanceState{ 1420 ID: "bar0", 1421 }, 1422 }, 1423 "aws_instance.foo.1": &ResourceState{ 1424 Type: "aws_instance", 1425 Primary: &InstanceState{ 1426 ID: "bar1", 1427 }, 1428 }, 1429 }, 1430 }, 1431 }, 1432 } 1433 ctx := testContext2(t, &ContextOpts{ 1434 Module: m, 1435 Providers: map[string]ResourceProviderFactory{ 1436 "aws": testProviderFuncFixed(p), 1437 }, 1438 State: s, 1439 Destroy: true, 1440 }) 1441 1442 plan, err := ctx.Plan() 1443 if err != nil { 1444 t.Fatalf("err: %s", err) 1445 } 1446 1447 actual := strings.TrimSpace(plan.String()) 1448 expected := strings.TrimSpace(testTerraformPlanModuleDestroyMultivarStr) 1449 if actual != expected { 1450 t.Fatalf("bad:\n%s", actual) 1451 } 1452 } 1453 1454 func TestContext2Plan_pathVar(t *testing.T) { 1455 cwd, err := os.Getwd() 1456 if err != nil { 1457 t.Fatalf("err: %s", err) 1458 } 1459 1460 m := testModule(t, "plan-path-var") 1461 p := testProvider("aws") 1462 p.DiffFn = testDiffFn 1463 ctx := testContext2(t, &ContextOpts{ 1464 Module: m, 1465 Providers: map[string]ResourceProviderFactory{ 1466 "aws": testProviderFuncFixed(p), 1467 }, 1468 }) 1469 1470 plan, err := ctx.Plan() 1471 if err != nil { 1472 t.Fatalf("err: %s", err) 1473 } 1474 1475 actual := strings.TrimSpace(plan.String()) 1476 expected := strings.TrimSpace(testTerraformPlanPathVarStr) 1477 1478 // Warning: this ordering REALLY matters for this test. The 1479 // order is: cwd, module, root. 1480 expected = fmt.Sprintf( 1481 expected, 1482 cwd, 1483 m.Config().Dir, 1484 m.Config().Dir) 1485 1486 if actual != expected { 1487 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 1488 } 1489 } 1490 1491 func TestContext2Plan_diffVar(t *testing.T) { 1492 m := testModule(t, "plan-diffvar") 1493 p := testProvider("aws") 1494 s := &State{ 1495 Modules: []*ModuleState{ 1496 &ModuleState{ 1497 Path: rootModulePath, 1498 Resources: map[string]*ResourceState{ 1499 "aws_instance.foo": &ResourceState{ 1500 Primary: &InstanceState{ 1501 ID: "bar", 1502 Attributes: map[string]string{ 1503 "num": "2", 1504 }, 1505 }, 1506 }, 1507 }, 1508 }, 1509 }, 1510 } 1511 ctx := testContext2(t, &ContextOpts{ 1512 Module: m, 1513 Providers: map[string]ResourceProviderFactory{ 1514 "aws": testProviderFuncFixed(p), 1515 }, 1516 State: s, 1517 }) 1518 1519 p.DiffFn = func( 1520 info *InstanceInfo, 1521 s *InstanceState, 1522 c *ResourceConfig) (*InstanceDiff, error) { 1523 if s.ID != "bar" { 1524 return testDiffFn(info, s, c) 1525 } 1526 1527 return &InstanceDiff{ 1528 Attributes: map[string]*ResourceAttrDiff{ 1529 "num": &ResourceAttrDiff{ 1530 Old: "2", 1531 New: "3", 1532 }, 1533 }, 1534 }, nil 1535 } 1536 1537 plan, err := ctx.Plan() 1538 if err != nil { 1539 t.Fatalf("err: %s", err) 1540 } 1541 1542 actual := strings.TrimSpace(plan.String()) 1543 expected := strings.TrimSpace(testTerraformPlanDiffVarStr) 1544 if actual != expected { 1545 t.Fatalf("actual:\n%s\n\nexpected:\n%s", actual, expected) 1546 } 1547 } 1548 1549 func TestContext2Plan_hook(t *testing.T) { 1550 m := testModule(t, "plan-good") 1551 h := new(MockHook) 1552 p := testProvider("aws") 1553 p.DiffFn = testDiffFn 1554 ctx := testContext2(t, &ContextOpts{ 1555 Module: m, 1556 Hooks: []Hook{h}, 1557 Providers: map[string]ResourceProviderFactory{ 1558 "aws": testProviderFuncFixed(p), 1559 }, 1560 }) 1561 1562 _, err := ctx.Plan() 1563 if err != nil { 1564 t.Fatalf("err: %s", err) 1565 } 1566 1567 if !h.PreDiffCalled { 1568 t.Fatal("should be called") 1569 } 1570 if !h.PostDiffCalled { 1571 t.Fatal("should be called") 1572 } 1573 } 1574 1575 func TestContext2Plan_orphan(t *testing.T) { 1576 m := testModule(t, "plan-orphan") 1577 p := testProvider("aws") 1578 p.DiffFn = testDiffFn 1579 s := &State{ 1580 Modules: []*ModuleState{ 1581 &ModuleState{ 1582 Path: rootModulePath, 1583 Resources: map[string]*ResourceState{ 1584 "aws_instance.baz": &ResourceState{ 1585 Type: "aws_instance", 1586 Primary: &InstanceState{ 1587 ID: "bar", 1588 }, 1589 }, 1590 }, 1591 }, 1592 }, 1593 } 1594 ctx := testContext2(t, &ContextOpts{ 1595 Module: m, 1596 Providers: map[string]ResourceProviderFactory{ 1597 "aws": testProviderFuncFixed(p), 1598 }, 1599 State: s, 1600 }) 1601 1602 plan, err := ctx.Plan() 1603 if err != nil { 1604 t.Fatalf("err: %s", err) 1605 } 1606 1607 actual := strings.TrimSpace(plan.String()) 1608 expected := strings.TrimSpace(testTerraformPlanOrphanStr) 1609 if actual != expected { 1610 t.Fatalf("bad:\n%s", actual) 1611 } 1612 } 1613 1614 func TestContext2Plan_state(t *testing.T) { 1615 m := testModule(t, "plan-good") 1616 p := testProvider("aws") 1617 p.DiffFn = testDiffFn 1618 s := &State{ 1619 Modules: []*ModuleState{ 1620 &ModuleState{ 1621 Path: rootModulePath, 1622 Resources: map[string]*ResourceState{ 1623 "aws_instance.foo": &ResourceState{ 1624 Primary: &InstanceState{ 1625 ID: "bar", 1626 }, 1627 }, 1628 }, 1629 }, 1630 }, 1631 } 1632 ctx := testContext2(t, &ContextOpts{ 1633 Module: m, 1634 Providers: map[string]ResourceProviderFactory{ 1635 "aws": testProviderFuncFixed(p), 1636 }, 1637 State: s, 1638 }) 1639 1640 plan, err := ctx.Plan() 1641 if err != nil { 1642 t.Fatalf("err: %s", err) 1643 } 1644 1645 if len(plan.Diff.RootModule().Resources) < 2 { 1646 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 1647 } 1648 1649 actual := strings.TrimSpace(plan.String()) 1650 expected := strings.TrimSpace(testTerraformPlanStateStr) 1651 if actual != expected { 1652 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 1653 } 1654 } 1655 1656 func TestContext2Plan_taint(t *testing.T) { 1657 m := testModule(t, "plan-taint") 1658 p := testProvider("aws") 1659 p.DiffFn = testDiffFn 1660 s := &State{ 1661 Modules: []*ModuleState{ 1662 &ModuleState{ 1663 Path: rootModulePath, 1664 Resources: map[string]*ResourceState{ 1665 "aws_instance.foo": &ResourceState{ 1666 Type: "aws_instance", 1667 Primary: &InstanceState{ 1668 ID: "bar", 1669 Attributes: map[string]string{"num": "2"}, 1670 }, 1671 }, 1672 "aws_instance.bar": &ResourceState{ 1673 Type: "aws_instance", 1674 Tainted: []*InstanceState{ 1675 &InstanceState{ 1676 ID: "baz", 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(testTerraformPlanTaintStr) 1699 if actual != expected { 1700 t.Fatalf("bad:\n%s", actual) 1701 } 1702 } 1703 1704 func TestContext2Plan_multiple_taint(t *testing.T) { 1705 m := testModule(t, "plan-taint") 1706 p := testProvider("aws") 1707 p.DiffFn = testDiffFn 1708 s := &State{ 1709 Modules: []*ModuleState{ 1710 &ModuleState{ 1711 Path: rootModulePath, 1712 Resources: map[string]*ResourceState{ 1713 "aws_instance.foo": &ResourceState{ 1714 Type: "aws_instance", 1715 Primary: &InstanceState{ 1716 ID: "bar", 1717 Attributes: map[string]string{"num": "2"}, 1718 }, 1719 }, 1720 "aws_instance.bar": &ResourceState{ 1721 Type: "aws_instance", 1722 Tainted: []*InstanceState{ 1723 &InstanceState{ 1724 ID: "baz", 1725 }, 1726 &InstanceState{ 1727 ID: "zip", 1728 }, 1729 }, 1730 }, 1731 }, 1732 }, 1733 }, 1734 } 1735 ctx := testContext2(t, &ContextOpts{ 1736 Module: m, 1737 Providers: map[string]ResourceProviderFactory{ 1738 "aws": testProviderFuncFixed(p), 1739 }, 1740 State: s, 1741 }) 1742 1743 plan, err := ctx.Plan() 1744 if err != nil { 1745 t.Fatalf("err: %s", err) 1746 } 1747 1748 actual := strings.TrimSpace(plan.String()) 1749 expected := strings.TrimSpace(testTerraformPlanMultipleTaintStr) 1750 if actual != expected { 1751 t.Fatalf("bad:\n%s", actual) 1752 } 1753 } 1754 1755 // Fails about 50% of the time before the fix for GH-4982, covers the fix. 1756 func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) { 1757 m := testModule(t, "plan-taint-interpolated-count") 1758 p := testProvider("aws") 1759 p.DiffFn = testDiffFn 1760 s := &State{ 1761 Modules: []*ModuleState{ 1762 &ModuleState{ 1763 Path: rootModulePath, 1764 Resources: map[string]*ResourceState{ 1765 "aws_instance.foo.0": &ResourceState{ 1766 Type: "aws_instance", 1767 Tainted: []*InstanceState{ 1768 &InstanceState{ID: "bar"}, 1769 }, 1770 }, 1771 "aws_instance.foo.1": &ResourceState{ 1772 Type: "aws_instance", 1773 Primary: &InstanceState{ID: "bar"}, 1774 }, 1775 "aws_instance.foo.2": &ResourceState{ 1776 Type: "aws_instance", 1777 Primary: &InstanceState{ID: "bar"}, 1778 }, 1779 }, 1780 }, 1781 }, 1782 } 1783 ctx := testContext2(t, &ContextOpts{ 1784 Module: m, 1785 Providers: map[string]ResourceProviderFactory{ 1786 "aws": testProviderFuncFixed(p), 1787 }, 1788 State: s, 1789 }) 1790 1791 for i := 0; i < 100; i++ { 1792 plan, err := ctx.Plan() 1793 if err != nil { 1794 t.Fatalf("err: %s", err) 1795 } 1796 1797 actual := strings.TrimSpace(plan.String()) 1798 expected := strings.TrimSpace(` 1799 DIFF: 1800 1801 DESTROY/CREATE: aws_instance.foo.0 1802 1803 STATE: 1804 1805 aws_instance.foo.0: (1 tainted) 1806 ID = <not created> 1807 Tainted ID 1 = bar 1808 aws_instance.foo.1: 1809 ID = bar 1810 aws_instance.foo.2: 1811 ID = bar 1812 `) 1813 if actual != expected { 1814 t.Fatalf("bad:\n%s", actual) 1815 } 1816 } 1817 } 1818 1819 func TestContext2Plan_targeted(t *testing.T) { 1820 m := testModule(t, "plan-targeted") 1821 p := testProvider("aws") 1822 p.DiffFn = testDiffFn 1823 ctx := testContext2(t, &ContextOpts{ 1824 Module: m, 1825 Providers: map[string]ResourceProviderFactory{ 1826 "aws": testProviderFuncFixed(p), 1827 }, 1828 Targets: []string{"aws_instance.foo"}, 1829 }) 1830 1831 plan, err := ctx.Plan() 1832 if err != nil { 1833 t.Fatalf("err: %s", err) 1834 } 1835 1836 actual := strings.TrimSpace(plan.String()) 1837 expected := strings.TrimSpace(` 1838 DIFF: 1839 1840 CREATE: aws_instance.foo 1841 num: "" => "2" 1842 type: "" => "aws_instance" 1843 1844 STATE: 1845 1846 <no state> 1847 `) 1848 if actual != expected { 1849 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 1850 } 1851 } 1852 1853 func TestContext2Plan_targetedOrphan(t *testing.T) { 1854 m := testModule(t, "plan-targeted-orphan") 1855 p := testProvider("aws") 1856 p.DiffFn = testDiffFn 1857 ctx := testContext2(t, &ContextOpts{ 1858 Module: m, 1859 Providers: map[string]ResourceProviderFactory{ 1860 "aws": testProviderFuncFixed(p), 1861 }, 1862 State: &State{ 1863 Modules: []*ModuleState{ 1864 &ModuleState{ 1865 Path: rootModulePath, 1866 Resources: map[string]*ResourceState{ 1867 "aws_instance.orphan": &ResourceState{ 1868 Type: "aws_instance", 1869 Primary: &InstanceState{ 1870 ID: "i-789xyz", 1871 }, 1872 }, 1873 "aws_instance.nottargeted": &ResourceState{ 1874 Type: "aws_instance", 1875 Primary: &InstanceState{ 1876 ID: "i-abc123", 1877 }, 1878 }, 1879 }, 1880 }, 1881 }, 1882 }, 1883 Destroy: true, 1884 Targets: []string{"aws_instance.orphan"}, 1885 }) 1886 1887 plan, err := ctx.Plan() 1888 if err != nil { 1889 t.Fatalf("err: %s", err) 1890 } 1891 1892 actual := strings.TrimSpace(plan.String()) 1893 expected := strings.TrimSpace(`DIFF: 1894 1895 DESTROY: aws_instance.orphan 1896 1897 STATE: 1898 1899 aws_instance.nottargeted: 1900 ID = i-abc123 1901 aws_instance.orphan: 1902 ID = i-789xyz 1903 `) 1904 if actual != expected { 1905 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 1906 } 1907 } 1908 1909 // https://github.com/hashicorp/terraform/issues/2538 1910 func TestContext2Plan_targetedModuleOrphan(t *testing.T) { 1911 m := testModule(t, "plan-targeted-module-orphan") 1912 p := testProvider("aws") 1913 p.DiffFn = testDiffFn 1914 ctx := testContext2(t, &ContextOpts{ 1915 Module: m, 1916 Providers: map[string]ResourceProviderFactory{ 1917 "aws": testProviderFuncFixed(p), 1918 }, 1919 State: &State{ 1920 Modules: []*ModuleState{ 1921 &ModuleState{ 1922 Path: []string{"root", "child"}, 1923 Resources: map[string]*ResourceState{ 1924 "aws_instance.orphan": &ResourceState{ 1925 Type: "aws_instance", 1926 Primary: &InstanceState{ 1927 ID: "i-789xyz", 1928 }, 1929 }, 1930 "aws_instance.nottargeted": &ResourceState{ 1931 Type: "aws_instance", 1932 Primary: &InstanceState{ 1933 ID: "i-abc123", 1934 }, 1935 }, 1936 }, 1937 }, 1938 }, 1939 }, 1940 Destroy: true, 1941 Targets: []string{"module.child.aws_instance.orphan"}, 1942 }) 1943 1944 plan, err := ctx.Plan() 1945 if err != nil { 1946 t.Fatalf("err: %s", err) 1947 } 1948 1949 actual := strings.TrimSpace(plan.String()) 1950 expected := strings.TrimSpace(`DIFF: 1951 1952 module.child: 1953 DESTROY: aws_instance.orphan 1954 1955 STATE: 1956 1957 module.child: 1958 aws_instance.nottargeted: 1959 ID = i-abc123 1960 aws_instance.orphan: 1961 ID = i-789xyz 1962 `) 1963 if actual != expected { 1964 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 1965 } 1966 } 1967 1968 // https://github.com/hashicorp/terraform/issues/4515 1969 func TestContext2Plan_targetedOverTen(t *testing.T) { 1970 m := testModule(t, "plan-targeted-over-ten") 1971 p := testProvider("aws") 1972 p.DiffFn = testDiffFn 1973 1974 resources := make(map[string]*ResourceState) 1975 var expectedState []string 1976 for i := 0; i < 13; i++ { 1977 key := fmt.Sprintf("aws_instance.foo.%d", i) 1978 id := fmt.Sprintf("i-abc%d", i) 1979 resources[key] = &ResourceState{ 1980 Type: "aws_instance", 1981 Primary: &InstanceState{ID: id}, 1982 } 1983 expectedState = append(expectedState, 1984 fmt.Sprintf("%s:\n ID = %s\n", key, id)) 1985 } 1986 ctx := testContext2(t, &ContextOpts{ 1987 Module: m, 1988 Providers: map[string]ResourceProviderFactory{ 1989 "aws": testProviderFuncFixed(p), 1990 }, 1991 State: &State{ 1992 Modules: []*ModuleState{ 1993 &ModuleState{ 1994 Path: rootModulePath, 1995 Resources: resources, 1996 }, 1997 }, 1998 }, 1999 Targets: []string{"aws_instance.foo[1]"}, 2000 }) 2001 2002 plan, err := ctx.Plan() 2003 if err != nil { 2004 t.Fatalf("err: %s", err) 2005 } 2006 2007 actual := strings.TrimSpace(plan.String()) 2008 sort.Strings(expectedState) 2009 expected := strings.TrimSpace(` 2010 DIFF: 2011 2012 2013 2014 STATE: 2015 2016 aws_instance.foo.0: 2017 ID = i-abc0 2018 aws_instance.foo.1: 2019 ID = i-abc1 2020 aws_instance.foo.10: 2021 ID = i-abc10 2022 aws_instance.foo.11: 2023 ID = i-abc11 2024 aws_instance.foo.12: 2025 ID = i-abc12 2026 aws_instance.foo.2: 2027 ID = i-abc2 2028 aws_instance.foo.3: 2029 ID = i-abc3 2030 aws_instance.foo.4: 2031 ID = i-abc4 2032 aws_instance.foo.5: 2033 ID = i-abc5 2034 aws_instance.foo.6: 2035 ID = i-abc6 2036 aws_instance.foo.7: 2037 ID = i-abc7 2038 aws_instance.foo.8: 2039 ID = i-abc8 2040 aws_instance.foo.9: 2041 ID = i-abc9 2042 `) 2043 if actual != expected { 2044 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2045 } 2046 } 2047 2048 func TestContext2Plan_provider(t *testing.T) { 2049 m := testModule(t, "plan-provider") 2050 p := testProvider("aws") 2051 p.DiffFn = testDiffFn 2052 2053 var value interface{} 2054 p.ConfigureFn = func(c *ResourceConfig) error { 2055 value, _ = c.Get("foo") 2056 return nil 2057 } 2058 2059 ctx := testContext2(t, &ContextOpts{ 2060 Module: m, 2061 Providers: map[string]ResourceProviderFactory{ 2062 "aws": testProviderFuncFixed(p), 2063 }, 2064 Variables: map[string]string{ 2065 "foo": "bar", 2066 }, 2067 }) 2068 2069 if _, err := ctx.Plan(); err != nil { 2070 t.Fatalf("err: %s", err) 2071 } 2072 2073 if value != "bar" { 2074 t.Fatalf("bad: %#v", value) 2075 } 2076 } 2077 2078 func TestContext2Plan_varListErr(t *testing.T) { 2079 m := testModule(t, "plan-var-list-err") 2080 p := testProvider("aws") 2081 ctx := testContext2(t, &ContextOpts{ 2082 Module: m, 2083 Providers: map[string]ResourceProviderFactory{ 2084 "aws": testProviderFuncFixed(p), 2085 }, 2086 }) 2087 2088 _, err := ctx.Plan() 2089 2090 if err == nil { 2091 t.Fatal("should error") 2092 } 2093 } 2094 2095 func TestContext2Plan_ignoreChanges(t *testing.T) { 2096 m := testModule(t, "plan-ignore-changes") 2097 p := testProvider("aws") 2098 p.DiffFn = testDiffFn 2099 s := &State{ 2100 Modules: []*ModuleState{ 2101 &ModuleState{ 2102 Path: rootModulePath, 2103 Resources: map[string]*ResourceState{ 2104 "aws_instance.foo": &ResourceState{ 2105 Primary: &InstanceState{ 2106 ID: "bar", 2107 Attributes: map[string]string{"ami": "ami-abcd1234"}, 2108 }, 2109 }, 2110 }, 2111 }, 2112 }, 2113 } 2114 ctx := testContext2(t, &ContextOpts{ 2115 Module: m, 2116 Providers: map[string]ResourceProviderFactory{ 2117 "aws": testProviderFuncFixed(p), 2118 }, 2119 Variables: map[string]string{ 2120 "foo": "ami-1234abcd", 2121 }, 2122 State: s, 2123 }) 2124 2125 plan, err := ctx.Plan() 2126 if err != nil { 2127 t.Fatalf("err: %s", err) 2128 } 2129 2130 if len(plan.Diff.RootModule().Resources) < 1 { 2131 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 2132 } 2133 2134 actual := strings.TrimSpace(plan.String()) 2135 expected := strings.TrimSpace(testTerraformPlanIgnoreChangesStr) 2136 if actual != expected { 2137 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 2138 } 2139 }