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