github.com/danrjohnson/terraform@v0.7.0-rc2.0.20160627135212-d0fc1fa086ff/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_computedDataResource(t *testing.T) { 868 m := testModule(t, "plan-computed-data-resource") 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 if got := len(plan.Diff.Modules); got != 1 { 884 t.Fatalf("got %d modules; want 1", got) 885 } 886 887 moduleDiff := plan.Diff.Modules[0] 888 889 if _, ok := moduleDiff.Resources["aws_instance.foo"]; !ok { 890 t.Fatalf("missing diff for aws_instance.foo") 891 } 892 iDiff, ok := moduleDiff.Resources["data.aws_vpc.bar"] 893 if !ok { 894 t.Fatalf("missing diff for data.aws_vpc.bar") 895 } 896 897 expectedDiff := &InstanceDiff{ 898 Attributes: map[string]*ResourceAttrDiff{ 899 "id": { 900 NewComputed: true, 901 RequiresNew: true, 902 Type: DiffAttrOutput, 903 }, 904 }, 905 } 906 if same, _ := expectedDiff.Same(iDiff); !same { 907 t.Fatalf( 908 "incorrect diff for data.aws_vpc.bar\ngot: %#v\nwant: %#v", 909 iDiff, expectedDiff, 910 ) 911 } 912 } 913 914 func TestContext2Plan_dataResourceBecomesComputed(t *testing.T) { 915 m := testModule(t, "plan-data-resource-becomes-computed") 916 p := testProvider("aws") 917 918 p.DiffFn = func(info *InstanceInfo, state *InstanceState, config *ResourceConfig) (*InstanceDiff, error) { 919 if info.Type != "aws_instance" { 920 t.Fatalf("don't know how to diff %s", info.Id) 921 return nil, nil 922 } 923 924 return &InstanceDiff{ 925 Attributes: map[string]*ResourceAttrDiff{ 926 "computed": &ResourceAttrDiff{ 927 Old: "", 928 New: "", 929 NewComputed: true, 930 }, 931 }, 932 }, nil 933 } 934 p.ReadDataDiffReturn = &InstanceDiff{ 935 Attributes: map[string]*ResourceAttrDiff{ 936 "foo": &ResourceAttrDiff{ 937 Old: "", 938 New: "", 939 NewComputed: true, 940 }, 941 }, 942 } 943 944 ctx := testContext2(t, &ContextOpts{ 945 Module: m, 946 Providers: map[string]ResourceProviderFactory{ 947 "aws": testProviderFuncFixed(p), 948 }, 949 State: &State{ 950 Modules: []*ModuleState{ 951 &ModuleState{ 952 Path: rootModulePath, 953 Resources: map[string]*ResourceState{ 954 "data.aws_data_resource.foo": &ResourceState{ 955 Type: "aws_data_resource", 956 Primary: &InstanceState{ 957 ID: "i-abc123", 958 Attributes: map[string]string{ 959 "id": "i-abc123", 960 "value": "baz", 961 }, 962 }, 963 }, 964 }, 965 }, 966 }, 967 }, 968 }) 969 970 plan, err := ctx.Plan() 971 if err != nil { 972 t.Fatalf("err: %s", err) 973 } 974 975 if got := len(plan.Diff.Modules); got != 1 { 976 t.Fatalf("got %d modules; want 1", got) 977 } 978 979 if !p.ReadDataDiffCalled { 980 t.Fatal("ReadDataDiff wasn't called, but should've been") 981 } 982 if got, want := p.ReadDataDiffInfo.Id, "data.aws_data_resource.foo"; got != want { 983 t.Fatalf("ReadDataDiff info id is %s; want %s", got, want) 984 } 985 986 moduleDiff := plan.Diff.Modules[0] 987 988 iDiff, ok := moduleDiff.Resources["data.aws_data_resource.foo"] 989 if !ok { 990 t.Fatalf("missing diff for data.aws_data_resource.foo") 991 } 992 993 if same, _ := p.ReadDataDiffReturn.Same(iDiff); !same { 994 t.Fatalf( 995 "incorrect diff for data.data_resource.foo\ngot: %#v\nwant: %#v", 996 iDiff, p.ReadDataDiffReturn, 997 ) 998 } 999 } 1000 1001 func TestContext2Plan_computedList(t *testing.T) { 1002 m := testModule(t, "plan-computed-list") 1003 p := testProvider("aws") 1004 p.DiffFn = testDiffFn 1005 ctx := testContext2(t, &ContextOpts{ 1006 Module: m, 1007 Providers: map[string]ResourceProviderFactory{ 1008 "aws": testProviderFuncFixed(p), 1009 }, 1010 }) 1011 1012 plan, err := ctx.Plan() 1013 if err != nil { 1014 t.Fatalf("err: %s", err) 1015 } 1016 1017 actual := strings.TrimSpace(plan.String()) 1018 expected := strings.TrimSpace(testTerraformPlanComputedListStr) 1019 if actual != expected { 1020 t.Fatalf("bad:\n%s", actual) 1021 } 1022 } 1023 1024 func TestContext2Plan_count(t *testing.T) { 1025 m := testModule(t, "plan-count") 1026 p := testProvider("aws") 1027 p.DiffFn = testDiffFn 1028 ctx := testContext2(t, &ContextOpts{ 1029 Module: m, 1030 Providers: map[string]ResourceProviderFactory{ 1031 "aws": testProviderFuncFixed(p), 1032 }, 1033 }) 1034 1035 plan, err := ctx.Plan() 1036 if err != nil { 1037 t.Fatalf("err: %s", err) 1038 } 1039 1040 if len(plan.Diff.RootModule().Resources) < 6 { 1041 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 1042 } 1043 1044 actual := strings.TrimSpace(plan.String()) 1045 expected := strings.TrimSpace(testTerraformPlanCountStr) 1046 if actual != expected { 1047 t.Fatalf("bad:\n%s", actual) 1048 } 1049 } 1050 1051 func TestContext2Plan_countComputed(t *testing.T) { 1052 m := testModule(t, "plan-count-computed") 1053 p := testProvider("aws") 1054 p.DiffFn = testDiffFn 1055 ctx := testContext2(t, &ContextOpts{ 1056 Module: m, 1057 Providers: map[string]ResourceProviderFactory{ 1058 "aws": testProviderFuncFixed(p), 1059 }, 1060 }) 1061 1062 _, err := ctx.Plan() 1063 if err == nil { 1064 t.Fatal("should error") 1065 } 1066 } 1067 1068 func TestContext2Plan_countIndex(t *testing.T) { 1069 m := testModule(t, "plan-count-index") 1070 p := testProvider("aws") 1071 p.DiffFn = testDiffFn 1072 ctx := testContext2(t, &ContextOpts{ 1073 Module: m, 1074 Providers: map[string]ResourceProviderFactory{ 1075 "aws": testProviderFuncFixed(p), 1076 }, 1077 }) 1078 1079 plan, err := ctx.Plan() 1080 if err != nil { 1081 t.Fatalf("err: %s", err) 1082 } 1083 1084 actual := strings.TrimSpace(plan.String()) 1085 expected := strings.TrimSpace(testTerraformPlanCountIndexStr) 1086 if actual != expected { 1087 t.Fatalf("bad:\n%s", actual) 1088 } 1089 } 1090 1091 func TestContext2Plan_countIndexZero(t *testing.T) { 1092 m := testModule(t, "plan-count-index-zero") 1093 p := testProvider("aws") 1094 p.DiffFn = testDiffFn 1095 ctx := testContext2(t, &ContextOpts{ 1096 Module: m, 1097 Providers: map[string]ResourceProviderFactory{ 1098 "aws": testProviderFuncFixed(p), 1099 }, 1100 }) 1101 1102 plan, err := ctx.Plan() 1103 if err != nil { 1104 t.Fatalf("err: %s", err) 1105 } 1106 1107 actual := strings.TrimSpace(plan.String()) 1108 expected := strings.TrimSpace(testTerraformPlanCountIndexZeroStr) 1109 if actual != expected { 1110 t.Fatalf("bad:\n%s", actual) 1111 } 1112 } 1113 1114 func TestContext2Plan_countVar(t *testing.T) { 1115 m := testModule(t, "plan-count-var") 1116 p := testProvider("aws") 1117 p.DiffFn = testDiffFn 1118 ctx := testContext2(t, &ContextOpts{ 1119 Module: m, 1120 Providers: map[string]ResourceProviderFactory{ 1121 "aws": testProviderFuncFixed(p), 1122 }, 1123 Variables: map[string]string{ 1124 "count": "3", 1125 }, 1126 }) 1127 1128 plan, err := ctx.Plan() 1129 if err != nil { 1130 t.Fatalf("err: %s", err) 1131 } 1132 1133 actual := strings.TrimSpace(plan.String()) 1134 expected := strings.TrimSpace(testTerraformPlanCountVarStr) 1135 if actual != expected { 1136 t.Fatalf("bad:\n%s", actual) 1137 } 1138 } 1139 1140 func TestContext2Plan_countZero(t *testing.T) { 1141 m := testModule(t, "plan-count-zero") 1142 p := testProvider("aws") 1143 p.DiffFn = testDiffFn 1144 ctx := testContext2(t, &ContextOpts{ 1145 Module: m, 1146 Providers: map[string]ResourceProviderFactory{ 1147 "aws": testProviderFuncFixed(p), 1148 }, 1149 }) 1150 1151 plan, err := ctx.Plan() 1152 if err != nil { 1153 t.Fatalf("err: %s", err) 1154 } 1155 1156 actual := strings.TrimSpace(plan.String()) 1157 expected := strings.TrimSpace(testTerraformPlanCountZeroStr) 1158 if actual != expected { 1159 t.Fatalf("bad:\n%s", actual) 1160 } 1161 } 1162 1163 func TestContext2Plan_countOneIndex(t *testing.T) { 1164 m := testModule(t, "plan-count-one-index") 1165 p := testProvider("aws") 1166 p.DiffFn = testDiffFn 1167 ctx := testContext2(t, &ContextOpts{ 1168 Module: m, 1169 Providers: map[string]ResourceProviderFactory{ 1170 "aws": testProviderFuncFixed(p), 1171 }, 1172 }) 1173 1174 plan, err := ctx.Plan() 1175 if err != nil { 1176 t.Fatalf("err: %s", err) 1177 } 1178 1179 actual := strings.TrimSpace(plan.String()) 1180 expected := strings.TrimSpace(testTerraformPlanCountOneIndexStr) 1181 if actual != expected { 1182 t.Fatalf("bad:\n%s", actual) 1183 } 1184 } 1185 1186 func TestContext2Plan_countDecreaseToOne(t *testing.T) { 1187 m := testModule(t, "plan-count-dec") 1188 p := testProvider("aws") 1189 p.DiffFn = testDiffFn 1190 s := &State{ 1191 Modules: []*ModuleState{ 1192 &ModuleState{ 1193 Path: rootModulePath, 1194 Resources: map[string]*ResourceState{ 1195 "aws_instance.foo.0": &ResourceState{ 1196 Type: "aws_instance", 1197 Primary: &InstanceState{ 1198 ID: "bar", 1199 Attributes: map[string]string{ 1200 "foo": "foo", 1201 "type": "aws_instance", 1202 }, 1203 }, 1204 }, 1205 "aws_instance.foo.1": &ResourceState{ 1206 Type: "aws_instance", 1207 Primary: &InstanceState{ 1208 ID: "bar", 1209 }, 1210 }, 1211 "aws_instance.foo.2": &ResourceState{ 1212 Type: "aws_instance", 1213 Primary: &InstanceState{ 1214 ID: "bar", 1215 }, 1216 }, 1217 }, 1218 }, 1219 }, 1220 } 1221 ctx := testContext2(t, &ContextOpts{ 1222 Module: m, 1223 Providers: map[string]ResourceProviderFactory{ 1224 "aws": testProviderFuncFixed(p), 1225 }, 1226 State: s, 1227 }) 1228 1229 plan, err := ctx.Plan() 1230 if err != nil { 1231 t.Fatalf("err: %s", err) 1232 } 1233 1234 actual := strings.TrimSpace(plan.String()) 1235 expected := strings.TrimSpace(testTerraformPlanCountDecreaseStr) 1236 if actual != expected { 1237 t.Fatalf("bad:\n%s", actual) 1238 } 1239 } 1240 1241 func TestContext2Plan_countIncreaseFromNotSet(t *testing.T) { 1242 m := testModule(t, "plan-count-inc") 1243 p := testProvider("aws") 1244 p.DiffFn = testDiffFn 1245 s := &State{ 1246 Modules: []*ModuleState{ 1247 &ModuleState{ 1248 Path: rootModulePath, 1249 Resources: map[string]*ResourceState{ 1250 "aws_instance.foo": &ResourceState{ 1251 Type: "aws_instance", 1252 Primary: &InstanceState{ 1253 ID: "bar", 1254 Attributes: map[string]string{ 1255 "foo": "foo", 1256 "type": "aws_instance", 1257 }, 1258 }, 1259 }, 1260 }, 1261 }, 1262 }, 1263 } 1264 ctx := testContext2(t, &ContextOpts{ 1265 Module: m, 1266 Providers: map[string]ResourceProviderFactory{ 1267 "aws": testProviderFuncFixed(p), 1268 }, 1269 State: s, 1270 }) 1271 1272 plan, err := ctx.Plan() 1273 if err != nil { 1274 t.Fatalf("err: %s", err) 1275 } 1276 1277 actual := strings.TrimSpace(plan.String()) 1278 expected := strings.TrimSpace(testTerraformPlanCountIncreaseStr) 1279 if actual != expected { 1280 t.Fatalf("bad:\n%s", actual) 1281 } 1282 } 1283 1284 func TestContext2Plan_countIncreaseFromOne(t *testing.T) { 1285 m := testModule(t, "plan-count-inc") 1286 p := testProvider("aws") 1287 p.DiffFn = testDiffFn 1288 s := &State{ 1289 Modules: []*ModuleState{ 1290 &ModuleState{ 1291 Path: rootModulePath, 1292 Resources: map[string]*ResourceState{ 1293 "aws_instance.foo.0": &ResourceState{ 1294 Type: "aws_instance", 1295 Primary: &InstanceState{ 1296 ID: "bar", 1297 Attributes: map[string]string{ 1298 "foo": "foo", 1299 "type": "aws_instance", 1300 }, 1301 }, 1302 }, 1303 }, 1304 }, 1305 }, 1306 } 1307 ctx := testContext2(t, &ContextOpts{ 1308 Module: m, 1309 Providers: map[string]ResourceProviderFactory{ 1310 "aws": testProviderFuncFixed(p), 1311 }, 1312 State: s, 1313 }) 1314 1315 plan, err := ctx.Plan() 1316 if err != nil { 1317 t.Fatalf("err: %s", err) 1318 } 1319 1320 actual := strings.TrimSpace(plan.String()) 1321 expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneStr) 1322 if actual != expected { 1323 t.Fatalf("bad:\n%s", actual) 1324 } 1325 } 1326 1327 // https://github.com/PeoplePerHour/terraform/pull/11 1328 // 1329 // This tests a case where both a "resource" and "resource.0" are in 1330 // the state file, which apparently is a reasonable backwards compatibility 1331 // concern found in the above 3rd party repo. 1332 func TestContext2Plan_countIncreaseFromOneCorrupted(t *testing.T) { 1333 m := testModule(t, "plan-count-inc") 1334 p := testProvider("aws") 1335 p.DiffFn = testDiffFn 1336 s := &State{ 1337 Modules: []*ModuleState{ 1338 &ModuleState{ 1339 Path: rootModulePath, 1340 Resources: map[string]*ResourceState{ 1341 "aws_instance.foo": &ResourceState{ 1342 Type: "aws_instance", 1343 Primary: &InstanceState{ 1344 ID: "bar", 1345 Attributes: map[string]string{ 1346 "foo": "foo", 1347 "type": "aws_instance", 1348 }, 1349 }, 1350 }, 1351 "aws_instance.foo.0": &ResourceState{ 1352 Type: "aws_instance", 1353 Primary: &InstanceState{ 1354 ID: "bar", 1355 Attributes: map[string]string{ 1356 "foo": "foo", 1357 "type": "aws_instance", 1358 }, 1359 }, 1360 }, 1361 }, 1362 }, 1363 }, 1364 } 1365 ctx := testContext2(t, &ContextOpts{ 1366 Module: m, 1367 Providers: map[string]ResourceProviderFactory{ 1368 "aws": testProviderFuncFixed(p), 1369 }, 1370 State: s, 1371 }) 1372 1373 plan, err := ctx.Plan() 1374 if err != nil { 1375 t.Fatalf("err: %s", err) 1376 } 1377 1378 actual := strings.TrimSpace(plan.String()) 1379 expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneCorruptedStr) 1380 if actual != expected { 1381 t.Fatalf("bad:\n%s", actual) 1382 } 1383 } 1384 1385 func TestContext2Plan_destroy(t *testing.T) { 1386 m := testModule(t, "plan-destroy") 1387 p := testProvider("aws") 1388 p.DiffFn = testDiffFn 1389 s := &State{ 1390 Modules: []*ModuleState{ 1391 &ModuleState{ 1392 Path: rootModulePath, 1393 Resources: map[string]*ResourceState{ 1394 "aws_instance.one": &ResourceState{ 1395 Type: "aws_instance", 1396 Primary: &InstanceState{ 1397 ID: "bar", 1398 }, 1399 }, 1400 "aws_instance.two": &ResourceState{ 1401 Type: "aws_instance", 1402 Primary: &InstanceState{ 1403 ID: "baz", 1404 }, 1405 }, 1406 }, 1407 }, 1408 }, 1409 } 1410 ctx := testContext2(t, &ContextOpts{ 1411 Module: m, 1412 Providers: map[string]ResourceProviderFactory{ 1413 "aws": testProviderFuncFixed(p), 1414 }, 1415 State: s, 1416 Destroy: true, 1417 }) 1418 1419 plan, err := ctx.Plan() 1420 if err != nil { 1421 t.Fatalf("err: %s", err) 1422 } 1423 1424 if len(plan.Diff.RootModule().Resources) != 2 { 1425 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 1426 } 1427 1428 actual := strings.TrimSpace(plan.String()) 1429 expected := strings.TrimSpace(testTerraformPlanDestroyStr) 1430 if actual != expected { 1431 t.Fatalf("bad:\n%s", actual) 1432 } 1433 } 1434 1435 func TestContext2Plan_moduleDestroy(t *testing.T) { 1436 m := testModule(t, "plan-module-destroy") 1437 p := testProvider("aws") 1438 p.DiffFn = testDiffFn 1439 s := &State{ 1440 Modules: []*ModuleState{ 1441 &ModuleState{ 1442 Path: rootModulePath, 1443 Resources: map[string]*ResourceState{ 1444 "aws_instance.foo": &ResourceState{ 1445 Type: "aws_instance", 1446 Primary: &InstanceState{ 1447 ID: "bar", 1448 }, 1449 }, 1450 }, 1451 }, 1452 &ModuleState{ 1453 Path: []string{"root", "child"}, 1454 Resources: map[string]*ResourceState{ 1455 "aws_instance.foo": &ResourceState{ 1456 Type: "aws_instance", 1457 Primary: &InstanceState{ 1458 ID: "bar", 1459 }, 1460 }, 1461 }, 1462 }, 1463 }, 1464 } 1465 ctx := testContext2(t, &ContextOpts{ 1466 Module: m, 1467 Providers: map[string]ResourceProviderFactory{ 1468 "aws": testProviderFuncFixed(p), 1469 }, 1470 State: s, 1471 Destroy: true, 1472 }) 1473 1474 plan, err := ctx.Plan() 1475 if err != nil { 1476 t.Fatalf("err: %s", err) 1477 } 1478 1479 actual := strings.TrimSpace(plan.String()) 1480 expected := strings.TrimSpace(testTerraformPlanModuleDestroyStr) 1481 if actual != expected { 1482 t.Fatalf("bad:\n%s", actual) 1483 } 1484 } 1485 1486 // GH-1835 1487 func TestContext2Plan_moduleDestroyCycle(t *testing.T) { 1488 m := testModule(t, "plan-module-destroy-gh-1835") 1489 p := testProvider("aws") 1490 p.DiffFn = testDiffFn 1491 s := &State{ 1492 Modules: []*ModuleState{ 1493 &ModuleState{ 1494 Path: []string{"root", "a_module"}, 1495 Resources: map[string]*ResourceState{ 1496 "aws_instance.a": &ResourceState{ 1497 Type: "aws_instance", 1498 Primary: &InstanceState{ 1499 ID: "a", 1500 }, 1501 }, 1502 }, 1503 }, 1504 &ModuleState{ 1505 Path: []string{"root", "b_module"}, 1506 Resources: map[string]*ResourceState{ 1507 "aws_instance.b": &ResourceState{ 1508 Type: "aws_instance", 1509 Primary: &InstanceState{ 1510 ID: "b", 1511 }, 1512 }, 1513 }, 1514 }, 1515 }, 1516 } 1517 ctx := testContext2(t, &ContextOpts{ 1518 Module: m, 1519 Providers: map[string]ResourceProviderFactory{ 1520 "aws": testProviderFuncFixed(p), 1521 }, 1522 State: s, 1523 Destroy: true, 1524 }) 1525 1526 plan, err := ctx.Plan() 1527 if err != nil { 1528 t.Fatalf("err: %s", err) 1529 } 1530 1531 actual := strings.TrimSpace(plan.String()) 1532 expected := strings.TrimSpace(testTerraformPlanModuleDestroyCycleStr) 1533 if actual != expected { 1534 t.Fatalf("bad:\n%s", actual) 1535 } 1536 } 1537 1538 func TestContext2Plan_moduleDestroyMultivar(t *testing.T) { 1539 m := testModule(t, "plan-module-destroy-multivar") 1540 p := testProvider("aws") 1541 p.DiffFn = testDiffFn 1542 s := &State{ 1543 Modules: []*ModuleState{ 1544 &ModuleState{ 1545 Path: rootModulePath, 1546 Resources: map[string]*ResourceState{}, 1547 }, 1548 &ModuleState{ 1549 Path: []string{"root", "child"}, 1550 Resources: map[string]*ResourceState{ 1551 "aws_instance.foo.0": &ResourceState{ 1552 Type: "aws_instance", 1553 Primary: &InstanceState{ 1554 ID: "bar0", 1555 }, 1556 }, 1557 "aws_instance.foo.1": &ResourceState{ 1558 Type: "aws_instance", 1559 Primary: &InstanceState{ 1560 ID: "bar1", 1561 }, 1562 }, 1563 }, 1564 }, 1565 }, 1566 } 1567 ctx := testContext2(t, &ContextOpts{ 1568 Module: m, 1569 Providers: map[string]ResourceProviderFactory{ 1570 "aws": testProviderFuncFixed(p), 1571 }, 1572 State: s, 1573 Destroy: true, 1574 }) 1575 1576 plan, err := ctx.Plan() 1577 if err != nil { 1578 t.Fatalf("err: %s", err) 1579 } 1580 1581 actual := strings.TrimSpace(plan.String()) 1582 expected := strings.TrimSpace(testTerraformPlanModuleDestroyMultivarStr) 1583 if actual != expected { 1584 t.Fatalf("bad:\n%s", actual) 1585 } 1586 } 1587 1588 func TestContext2Plan_pathVar(t *testing.T) { 1589 cwd, err := os.Getwd() 1590 if err != nil { 1591 t.Fatalf("err: %s", err) 1592 } 1593 1594 m := testModule(t, "plan-path-var") 1595 p := testProvider("aws") 1596 p.DiffFn = testDiffFn 1597 ctx := testContext2(t, &ContextOpts{ 1598 Module: m, 1599 Providers: map[string]ResourceProviderFactory{ 1600 "aws": testProviderFuncFixed(p), 1601 }, 1602 }) 1603 1604 plan, err := ctx.Plan() 1605 if err != nil { 1606 t.Fatalf("err: %s", err) 1607 } 1608 1609 actual := strings.TrimSpace(plan.String()) 1610 expected := strings.TrimSpace(testTerraformPlanPathVarStr) 1611 1612 // Warning: this ordering REALLY matters for this test. The 1613 // order is: cwd, module, root. 1614 expected = fmt.Sprintf( 1615 expected, 1616 cwd, 1617 m.Config().Dir, 1618 m.Config().Dir) 1619 1620 if actual != expected { 1621 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 1622 } 1623 } 1624 1625 func TestContext2Plan_diffVar(t *testing.T) { 1626 m := testModule(t, "plan-diffvar") 1627 p := testProvider("aws") 1628 s := &State{ 1629 Modules: []*ModuleState{ 1630 &ModuleState{ 1631 Path: rootModulePath, 1632 Resources: map[string]*ResourceState{ 1633 "aws_instance.foo": &ResourceState{ 1634 Primary: &InstanceState{ 1635 ID: "bar", 1636 Attributes: map[string]string{ 1637 "num": "2", 1638 }, 1639 }, 1640 }, 1641 }, 1642 }, 1643 }, 1644 } 1645 ctx := testContext2(t, &ContextOpts{ 1646 Module: m, 1647 Providers: map[string]ResourceProviderFactory{ 1648 "aws": testProviderFuncFixed(p), 1649 }, 1650 State: s, 1651 }) 1652 1653 p.DiffFn = func( 1654 info *InstanceInfo, 1655 s *InstanceState, 1656 c *ResourceConfig) (*InstanceDiff, error) { 1657 if s.ID != "bar" { 1658 return testDiffFn(info, s, c) 1659 } 1660 1661 return &InstanceDiff{ 1662 Attributes: map[string]*ResourceAttrDiff{ 1663 "num": &ResourceAttrDiff{ 1664 Old: "2", 1665 New: "3", 1666 }, 1667 }, 1668 }, nil 1669 } 1670 1671 plan, err := ctx.Plan() 1672 if err != nil { 1673 t.Fatalf("err: %s", err) 1674 } 1675 1676 actual := strings.TrimSpace(plan.String()) 1677 expected := strings.TrimSpace(testTerraformPlanDiffVarStr) 1678 if actual != expected { 1679 t.Fatalf("actual:\n%s\n\nexpected:\n%s", actual, expected) 1680 } 1681 } 1682 1683 func TestContext2Plan_hook(t *testing.T) { 1684 m := testModule(t, "plan-good") 1685 h := new(MockHook) 1686 p := testProvider("aws") 1687 p.DiffFn = testDiffFn 1688 ctx := testContext2(t, &ContextOpts{ 1689 Module: m, 1690 Hooks: []Hook{h}, 1691 Providers: map[string]ResourceProviderFactory{ 1692 "aws": testProviderFuncFixed(p), 1693 }, 1694 }) 1695 1696 _, err := ctx.Plan() 1697 if err != nil { 1698 t.Fatalf("err: %s", err) 1699 } 1700 1701 if !h.PreDiffCalled { 1702 t.Fatal("should be called") 1703 } 1704 if !h.PostDiffCalled { 1705 t.Fatal("should be called") 1706 } 1707 } 1708 1709 func TestContext2Plan_orphan(t *testing.T) { 1710 m := testModule(t, "plan-orphan") 1711 p := testProvider("aws") 1712 p.DiffFn = testDiffFn 1713 s := &State{ 1714 Modules: []*ModuleState{ 1715 &ModuleState{ 1716 Path: rootModulePath, 1717 Resources: map[string]*ResourceState{ 1718 "aws_instance.baz": &ResourceState{ 1719 Type: "aws_instance", 1720 Primary: &InstanceState{ 1721 ID: "bar", 1722 }, 1723 }, 1724 }, 1725 }, 1726 }, 1727 } 1728 ctx := testContext2(t, &ContextOpts{ 1729 Module: m, 1730 Providers: map[string]ResourceProviderFactory{ 1731 "aws": testProviderFuncFixed(p), 1732 }, 1733 State: s, 1734 }) 1735 1736 plan, err := ctx.Plan() 1737 if err != nil { 1738 t.Fatalf("err: %s", err) 1739 } 1740 1741 actual := strings.TrimSpace(plan.String()) 1742 expected := strings.TrimSpace(testTerraformPlanOrphanStr) 1743 if actual != expected { 1744 t.Fatalf("bad:\n%s", actual) 1745 } 1746 } 1747 1748 func TestContext2Plan_state(t *testing.T) { 1749 m := testModule(t, "plan-good") 1750 p := testProvider("aws") 1751 p.DiffFn = testDiffFn 1752 s := &State{ 1753 Modules: []*ModuleState{ 1754 &ModuleState{ 1755 Path: rootModulePath, 1756 Resources: map[string]*ResourceState{ 1757 "aws_instance.foo": &ResourceState{ 1758 Primary: &InstanceState{ 1759 ID: "bar", 1760 }, 1761 }, 1762 }, 1763 }, 1764 }, 1765 } 1766 ctx := testContext2(t, &ContextOpts{ 1767 Module: m, 1768 Providers: map[string]ResourceProviderFactory{ 1769 "aws": testProviderFuncFixed(p), 1770 }, 1771 State: s, 1772 }) 1773 1774 plan, err := ctx.Plan() 1775 if err != nil { 1776 t.Fatalf("err: %s", err) 1777 } 1778 1779 if len(plan.Diff.RootModule().Resources) < 2 { 1780 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 1781 } 1782 1783 actual := strings.TrimSpace(plan.String()) 1784 expected := strings.TrimSpace(testTerraformPlanStateStr) 1785 if actual != expected { 1786 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 1787 } 1788 } 1789 1790 func TestContext2Plan_taint(t *testing.T) { 1791 m := testModule(t, "plan-taint") 1792 p := testProvider("aws") 1793 p.DiffFn = testDiffFn 1794 s := &State{ 1795 Modules: []*ModuleState{ 1796 &ModuleState{ 1797 Path: rootModulePath, 1798 Resources: map[string]*ResourceState{ 1799 "aws_instance.foo": &ResourceState{ 1800 Type: "aws_instance", 1801 Primary: &InstanceState{ 1802 ID: "bar", 1803 Attributes: map[string]string{"num": "2"}, 1804 }, 1805 }, 1806 "aws_instance.bar": &ResourceState{ 1807 Type: "aws_instance", 1808 Primary: &InstanceState{ 1809 ID: "baz", 1810 Tainted: true, 1811 }, 1812 }, 1813 }, 1814 }, 1815 }, 1816 } 1817 ctx := testContext2(t, &ContextOpts{ 1818 Module: m, 1819 Providers: map[string]ResourceProviderFactory{ 1820 "aws": testProviderFuncFixed(p), 1821 }, 1822 State: s, 1823 }) 1824 1825 plan, err := ctx.Plan() 1826 if err != nil { 1827 t.Fatalf("err: %s", err) 1828 } 1829 1830 actual := strings.TrimSpace(plan.String()) 1831 expected := strings.TrimSpace(testTerraformPlanTaintStr) 1832 if actual != expected { 1833 t.Fatalf("bad:\n%s", actual) 1834 } 1835 } 1836 1837 // Fails about 50% of the time before the fix for GH-4982, covers the fix. 1838 func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) { 1839 m := testModule(t, "plan-taint-interpolated-count") 1840 p := testProvider("aws") 1841 p.DiffFn = testDiffFn 1842 s := &State{ 1843 Modules: []*ModuleState{ 1844 &ModuleState{ 1845 Path: rootModulePath, 1846 Resources: map[string]*ResourceState{ 1847 "aws_instance.foo.0": &ResourceState{ 1848 Type: "aws_instance", 1849 Primary: &InstanceState{ 1850 ID: "bar", 1851 Tainted: true, 1852 }, 1853 }, 1854 "aws_instance.foo.1": &ResourceState{ 1855 Type: "aws_instance", 1856 Primary: &InstanceState{ID: "bar"}, 1857 }, 1858 "aws_instance.foo.2": &ResourceState{ 1859 Type: "aws_instance", 1860 Primary: &InstanceState{ID: "bar"}, 1861 }, 1862 }, 1863 }, 1864 }, 1865 } 1866 ctx := testContext2(t, &ContextOpts{ 1867 Module: m, 1868 Providers: map[string]ResourceProviderFactory{ 1869 "aws": testProviderFuncFixed(p), 1870 }, 1871 State: s, 1872 }) 1873 1874 for i := 0; i < 100; i++ { 1875 plan, err := ctx.Plan() 1876 if err != nil { 1877 t.Fatalf("err: %s", err) 1878 } 1879 1880 actual := strings.TrimSpace(plan.String()) 1881 expected := strings.TrimSpace(` 1882 DIFF: 1883 1884 DESTROY/CREATE: aws_instance.foo.0 1885 1886 STATE: 1887 1888 aws_instance.foo.0: (tainted) 1889 ID = bar 1890 aws_instance.foo.1: 1891 ID = bar 1892 aws_instance.foo.2: 1893 ID = bar 1894 `) 1895 if actual != expected { 1896 t.Fatalf("bad:\n%s", actual) 1897 } 1898 } 1899 } 1900 1901 func TestContext2Plan_targeted(t *testing.T) { 1902 m := testModule(t, "plan-targeted") 1903 p := testProvider("aws") 1904 p.DiffFn = testDiffFn 1905 ctx := testContext2(t, &ContextOpts{ 1906 Module: m, 1907 Providers: map[string]ResourceProviderFactory{ 1908 "aws": testProviderFuncFixed(p), 1909 }, 1910 Targets: []string{"aws_instance.foo"}, 1911 }) 1912 1913 plan, err := ctx.Plan() 1914 if err != nil { 1915 t.Fatalf("err: %s", err) 1916 } 1917 1918 actual := strings.TrimSpace(plan.String()) 1919 expected := strings.TrimSpace(` 1920 DIFF: 1921 1922 CREATE: aws_instance.foo 1923 num: "" => "2" 1924 type: "" => "aws_instance" 1925 1926 STATE: 1927 1928 <no state> 1929 `) 1930 if actual != expected { 1931 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 1932 } 1933 } 1934 1935 func TestContext2Plan_targetedOrphan(t *testing.T) { 1936 m := testModule(t, "plan-targeted-orphan") 1937 p := testProvider("aws") 1938 p.DiffFn = testDiffFn 1939 ctx := testContext2(t, &ContextOpts{ 1940 Module: m, 1941 Providers: map[string]ResourceProviderFactory{ 1942 "aws": testProviderFuncFixed(p), 1943 }, 1944 State: &State{ 1945 Modules: []*ModuleState{ 1946 &ModuleState{ 1947 Path: rootModulePath, 1948 Resources: map[string]*ResourceState{ 1949 "aws_instance.orphan": &ResourceState{ 1950 Type: "aws_instance", 1951 Primary: &InstanceState{ 1952 ID: "i-789xyz", 1953 }, 1954 }, 1955 "aws_instance.nottargeted": &ResourceState{ 1956 Type: "aws_instance", 1957 Primary: &InstanceState{ 1958 ID: "i-abc123", 1959 }, 1960 }, 1961 }, 1962 }, 1963 }, 1964 }, 1965 Destroy: true, 1966 Targets: []string{"aws_instance.orphan"}, 1967 }) 1968 1969 plan, err := ctx.Plan() 1970 if err != nil { 1971 t.Fatalf("err: %s", err) 1972 } 1973 1974 actual := strings.TrimSpace(plan.String()) 1975 expected := strings.TrimSpace(`DIFF: 1976 1977 DESTROY: aws_instance.orphan 1978 1979 STATE: 1980 1981 aws_instance.nottargeted: 1982 ID = i-abc123 1983 aws_instance.orphan: 1984 ID = i-789xyz 1985 `) 1986 if actual != expected { 1987 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 1988 } 1989 } 1990 1991 // https://github.com/hashicorp/terraform/issues/2538 1992 func TestContext2Plan_targetedModuleOrphan(t *testing.T) { 1993 m := testModule(t, "plan-targeted-module-orphan") 1994 p := testProvider("aws") 1995 p.DiffFn = testDiffFn 1996 ctx := testContext2(t, &ContextOpts{ 1997 Module: m, 1998 Providers: map[string]ResourceProviderFactory{ 1999 "aws": testProviderFuncFixed(p), 2000 }, 2001 State: &State{ 2002 Modules: []*ModuleState{ 2003 &ModuleState{ 2004 Path: []string{"root", "child"}, 2005 Resources: map[string]*ResourceState{ 2006 "aws_instance.orphan": &ResourceState{ 2007 Type: "aws_instance", 2008 Primary: &InstanceState{ 2009 ID: "i-789xyz", 2010 }, 2011 }, 2012 "aws_instance.nottargeted": &ResourceState{ 2013 Type: "aws_instance", 2014 Primary: &InstanceState{ 2015 ID: "i-abc123", 2016 }, 2017 }, 2018 }, 2019 }, 2020 }, 2021 }, 2022 Destroy: true, 2023 Targets: []string{"module.child.aws_instance.orphan"}, 2024 }) 2025 2026 plan, err := ctx.Plan() 2027 if err != nil { 2028 t.Fatalf("err: %s", err) 2029 } 2030 2031 actual := strings.TrimSpace(plan.String()) 2032 expected := strings.TrimSpace(`DIFF: 2033 2034 module.child: 2035 DESTROY: aws_instance.orphan 2036 2037 STATE: 2038 2039 module.child: 2040 aws_instance.nottargeted: 2041 ID = i-abc123 2042 aws_instance.orphan: 2043 ID = i-789xyz 2044 `) 2045 if actual != expected { 2046 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2047 } 2048 } 2049 2050 // https://github.com/hashicorp/terraform/issues/4515 2051 func TestContext2Plan_targetedOverTen(t *testing.T) { 2052 m := testModule(t, "plan-targeted-over-ten") 2053 p := testProvider("aws") 2054 p.DiffFn = testDiffFn 2055 2056 resources := make(map[string]*ResourceState) 2057 var expectedState []string 2058 for i := 0; i < 13; i++ { 2059 key := fmt.Sprintf("aws_instance.foo.%d", i) 2060 id := fmt.Sprintf("i-abc%d", i) 2061 resources[key] = &ResourceState{ 2062 Type: "aws_instance", 2063 Primary: &InstanceState{ID: id}, 2064 } 2065 expectedState = append(expectedState, 2066 fmt.Sprintf("%s:\n ID = %s\n", key, id)) 2067 } 2068 ctx := testContext2(t, &ContextOpts{ 2069 Module: m, 2070 Providers: map[string]ResourceProviderFactory{ 2071 "aws": testProviderFuncFixed(p), 2072 }, 2073 State: &State{ 2074 Modules: []*ModuleState{ 2075 &ModuleState{ 2076 Path: rootModulePath, 2077 Resources: resources, 2078 }, 2079 }, 2080 }, 2081 Targets: []string{"aws_instance.foo[1]"}, 2082 }) 2083 2084 plan, err := ctx.Plan() 2085 if err != nil { 2086 t.Fatalf("err: %s", err) 2087 } 2088 2089 actual := strings.TrimSpace(plan.String()) 2090 sort.Strings(expectedState) 2091 expected := strings.TrimSpace(` 2092 DIFF: 2093 2094 2095 2096 STATE: 2097 2098 aws_instance.foo.0: 2099 ID = i-abc0 2100 aws_instance.foo.1: 2101 ID = i-abc1 2102 aws_instance.foo.10: 2103 ID = i-abc10 2104 aws_instance.foo.11: 2105 ID = i-abc11 2106 aws_instance.foo.12: 2107 ID = i-abc12 2108 aws_instance.foo.2: 2109 ID = i-abc2 2110 aws_instance.foo.3: 2111 ID = i-abc3 2112 aws_instance.foo.4: 2113 ID = i-abc4 2114 aws_instance.foo.5: 2115 ID = i-abc5 2116 aws_instance.foo.6: 2117 ID = i-abc6 2118 aws_instance.foo.7: 2119 ID = i-abc7 2120 aws_instance.foo.8: 2121 ID = i-abc8 2122 aws_instance.foo.9: 2123 ID = i-abc9 2124 `) 2125 if actual != expected { 2126 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2127 } 2128 } 2129 2130 func TestContext2Plan_provider(t *testing.T) { 2131 m := testModule(t, "plan-provider") 2132 p := testProvider("aws") 2133 p.DiffFn = testDiffFn 2134 2135 var value interface{} 2136 p.ConfigureFn = func(c *ResourceConfig) error { 2137 value, _ = c.Get("foo") 2138 return nil 2139 } 2140 2141 ctx := testContext2(t, &ContextOpts{ 2142 Module: m, 2143 Providers: map[string]ResourceProviderFactory{ 2144 "aws": testProviderFuncFixed(p), 2145 }, 2146 Variables: map[string]string{ 2147 "foo": "bar", 2148 }, 2149 }) 2150 2151 if _, err := ctx.Plan(); err != nil { 2152 t.Fatalf("err: %s", err) 2153 } 2154 2155 if value != "bar" { 2156 t.Fatalf("bad: %#v", value) 2157 } 2158 } 2159 2160 func TestContext2Plan_varListErr(t *testing.T) { 2161 m := testModule(t, "plan-var-list-err") 2162 p := testProvider("aws") 2163 ctx := testContext2(t, &ContextOpts{ 2164 Module: m, 2165 Providers: map[string]ResourceProviderFactory{ 2166 "aws": testProviderFuncFixed(p), 2167 }, 2168 }) 2169 2170 _, err := ctx.Plan() 2171 2172 if err == nil { 2173 t.Fatal("should error") 2174 } 2175 } 2176 2177 func TestContext2Plan_ignoreChanges(t *testing.T) { 2178 m := testModule(t, "plan-ignore-changes") 2179 p := testProvider("aws") 2180 p.DiffFn = testDiffFn 2181 s := &State{ 2182 Modules: []*ModuleState{ 2183 &ModuleState{ 2184 Path: rootModulePath, 2185 Resources: map[string]*ResourceState{ 2186 "aws_instance.foo": &ResourceState{ 2187 Primary: &InstanceState{ 2188 ID: "bar", 2189 Attributes: map[string]string{"ami": "ami-abcd1234"}, 2190 }, 2191 }, 2192 }, 2193 }, 2194 }, 2195 } 2196 ctx := testContext2(t, &ContextOpts{ 2197 Module: m, 2198 Providers: map[string]ResourceProviderFactory{ 2199 "aws": testProviderFuncFixed(p), 2200 }, 2201 Variables: map[string]string{ 2202 "foo": "ami-1234abcd", 2203 }, 2204 State: s, 2205 }) 2206 2207 plan, err := ctx.Plan() 2208 if err != nil { 2209 t.Fatalf("err: %s", err) 2210 } 2211 2212 if len(plan.Diff.RootModule().Resources) < 1 { 2213 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 2214 } 2215 2216 actual := strings.TrimSpace(plan.String()) 2217 expected := strings.TrimSpace(testTerraformPlanIgnoreChangesStr) 2218 if actual != expected { 2219 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 2220 } 2221 }