github.com/recobe182/terraform@v0.8.5-0.20170117231232-49ab22a935b7/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_basic(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_deposed(t *testing.T) { 42 m := testModule(t, "plan-cbd") 43 p := testProvider("aws") 44 p.DiffFn = testDiffFn 45 46 s := &State{ 47 Modules: []*ModuleState{ 48 &ModuleState{ 49 Path: []string{"root"}, 50 Resources: map[string]*ResourceState{ 51 "aws_instance.foo": &ResourceState{ 52 Type: "aws_instance", 53 Primary: &InstanceState{ 54 ID: "baz", 55 }, 56 Deposed: []*InstanceState{ 57 &InstanceState{ID: "foo"}, 58 }, 59 }, 60 }, 61 }, 62 }, 63 } 64 65 ctx := testContext2(t, &ContextOpts{ 66 Module: m, 67 Providers: map[string]ResourceProviderFactory{ 68 "aws": testProviderFuncFixed(p), 69 }, 70 State: s, 71 }) 72 73 plan, err := ctx.Plan() 74 if err != nil { 75 t.Fatalf("err: %s", err) 76 } 77 78 actual := strings.TrimSpace(plan.String()) 79 expected := strings.TrimSpace(` 80 DIFF: 81 82 DESTROY: aws_instance.foo (deposed only) 83 84 STATE: 85 86 aws_instance.foo: (1 deposed) 87 ID = baz 88 Deposed ID 1 = foo 89 `) 90 if actual != expected { 91 t.Fatalf("expected:\n%s, got:\n%s", expected, actual) 92 } 93 } 94 95 func TestContext2Plan_createBefore_maintainRoot(t *testing.T) { 96 m := testModule(t, "plan-cbd-maintain-root") 97 p := testProvider("aws") 98 p.DiffFn = testDiffFn 99 ctx := testContext2(t, &ContextOpts{ 100 Module: m, 101 Providers: map[string]ResourceProviderFactory{ 102 "aws": testProviderFuncFixed(p), 103 }, 104 Variables: map[string]interface{}{ 105 "in": "a,b,c", 106 }, 107 }) 108 109 plan, err := ctx.Plan() 110 if err != nil { 111 t.Fatalf("err: %s", err) 112 } 113 114 actual := strings.TrimSpace(plan.String()) 115 expected := strings.TrimSpace(` 116 DIFF: 117 118 CREATE: aws_instance.bar.0 119 CREATE: aws_instance.bar.1 120 CREATE: aws_instance.foo.0 121 CREATE: aws_instance.foo.1 122 123 STATE: 124 125 <no state> 126 `) 127 if actual != expected { 128 t.Fatalf("expected:\n%s, got:\n%s", expected, actual) 129 } 130 } 131 132 func TestContext2Plan_emptyDiff(t *testing.T) { 133 m := testModule(t, "plan-empty") 134 p := testProvider("aws") 135 p.DiffFn = func( 136 info *InstanceInfo, 137 s *InstanceState, 138 c *ResourceConfig) (*InstanceDiff, error) { 139 return nil, nil 140 } 141 142 ctx := testContext2(t, &ContextOpts{ 143 Module: m, 144 Providers: map[string]ResourceProviderFactory{ 145 "aws": testProviderFuncFixed(p), 146 }, 147 }) 148 149 plan, err := ctx.Plan() 150 if err != nil { 151 t.Fatalf("err: %s", err) 152 } 153 154 actual := strings.TrimSpace(plan.String()) 155 expected := strings.TrimSpace(testTerraformPlanEmptyStr) 156 if actual != expected { 157 t.Fatalf("bad:\n%s", actual) 158 } 159 } 160 161 func TestContext2Plan_escapedVar(t *testing.T) { 162 m := testModule(t, "plan-escaped-var") 163 p := testProvider("aws") 164 p.DiffFn = testDiffFn 165 ctx := testContext2(t, &ContextOpts{ 166 Module: m, 167 Providers: map[string]ResourceProviderFactory{ 168 "aws": testProviderFuncFixed(p), 169 }, 170 }) 171 172 plan, err := ctx.Plan() 173 if err != nil { 174 t.Fatalf("err: %s", err) 175 } 176 177 actual := strings.TrimSpace(plan.String()) 178 expected := strings.TrimSpace(testTerraformPlanEscapedVarStr) 179 if actual != expected { 180 t.Fatalf("bad:\n%s", actual) 181 } 182 } 183 184 func TestContext2Plan_minimal(t *testing.T) { 185 m := testModule(t, "plan-empty") 186 p := testProvider("aws") 187 p.DiffFn = testDiffFn 188 ctx := testContext2(t, &ContextOpts{ 189 Module: m, 190 Providers: map[string]ResourceProviderFactory{ 191 "aws": testProviderFuncFixed(p), 192 }, 193 }) 194 195 plan, err := ctx.Plan() 196 if err != nil { 197 t.Fatalf("err: %s", err) 198 } 199 200 actual := strings.TrimSpace(plan.String()) 201 expected := strings.TrimSpace(testTerraformPlanEmptyStr) 202 if actual != expected { 203 t.Fatalf("bad:\n%s", actual) 204 } 205 } 206 207 func TestContext2Plan_modules(t *testing.T) { 208 m := testModule(t, "plan-modules") 209 p := testProvider("aws") 210 p.DiffFn = testDiffFn 211 ctx := testContext2(t, &ContextOpts{ 212 Module: m, 213 Providers: map[string]ResourceProviderFactory{ 214 "aws": testProviderFuncFixed(p), 215 }, 216 }) 217 218 plan, err := ctx.Plan() 219 if err != nil { 220 t.Fatalf("err: %s", err) 221 } 222 223 actual := strings.TrimSpace(plan.String()) 224 expected := strings.TrimSpace(testTerraformPlanModulesStr) 225 if actual != expected { 226 t.Fatalf("bad:\n%s", actual) 227 } 228 } 229 230 // GH-1475 231 func TestContext2Plan_moduleCycle(t *testing.T) { 232 m := testModule(t, "plan-module-cycle") 233 p := testProvider("aws") 234 p.DiffFn = testDiffFn 235 ctx := testContext2(t, &ContextOpts{ 236 Module: m, 237 Providers: map[string]ResourceProviderFactory{ 238 "aws": testProviderFuncFixed(p), 239 }, 240 }) 241 242 plan, err := ctx.Plan() 243 if err != nil { 244 t.Fatalf("err: %s", err) 245 } 246 247 actual := strings.TrimSpace(plan.String()) 248 expected := strings.TrimSpace(testTerraformPlanModuleCycleStr) 249 if actual != expected { 250 t.Fatalf("bad:\n%s", actual) 251 } 252 } 253 254 func TestContext2Plan_moduleDeadlock(t *testing.T) { 255 testCheckDeadlock(t, func() { 256 m := testModule(t, "plan-module-deadlock") 257 p := testProvider("aws") 258 p.DiffFn = testDiffFn 259 260 ctx := testContext2(t, &ContextOpts{ 261 Module: m, 262 Providers: map[string]ResourceProviderFactory{ 263 "aws": testProviderFuncFixed(p), 264 }, 265 }) 266 267 plan, err := ctx.Plan() 268 if err != nil { 269 t.Fatalf("err: %s", err) 270 } 271 272 actual := strings.TrimSpace(plan.String()) 273 expected := strings.TrimSpace(` 274 DIFF: 275 276 module.child: 277 CREATE: aws_instance.foo.0 278 CREATE: aws_instance.foo.1 279 CREATE: aws_instance.foo.2 280 281 STATE: 282 283 <no state> 284 `) 285 if actual != expected { 286 t.Fatalf("expected:\n%sgot:\n%s", expected, actual) 287 } 288 }) 289 } 290 291 func TestContext2Plan_moduleInput(t *testing.T) { 292 m := testModule(t, "plan-module-input") 293 p := testProvider("aws") 294 p.DiffFn = testDiffFn 295 ctx := testContext2(t, &ContextOpts{ 296 Module: m, 297 Providers: map[string]ResourceProviderFactory{ 298 "aws": testProviderFuncFixed(p), 299 }, 300 }) 301 302 plan, err := ctx.Plan() 303 if err != nil { 304 t.Fatalf("err: %s", err) 305 } 306 307 actual := strings.TrimSpace(plan.String()) 308 expected := strings.TrimSpace(testTerraformPlanModuleInputStr) 309 if actual != expected { 310 t.Fatalf("bad:\n%s", actual) 311 } 312 } 313 314 func TestContext2Plan_moduleInputComputed(t *testing.T) { 315 m := testModule(t, "plan-module-input-computed") 316 p := testProvider("aws") 317 p.DiffFn = testDiffFn 318 ctx := testContext2(t, &ContextOpts{ 319 Module: m, 320 Providers: map[string]ResourceProviderFactory{ 321 "aws": testProviderFuncFixed(p), 322 }, 323 }) 324 325 plan, err := ctx.Plan() 326 if err != nil { 327 t.Fatalf("err: %s", err) 328 } 329 330 actual := strings.TrimSpace(plan.String()) 331 expected := strings.TrimSpace(testTerraformPlanModuleInputComputedStr) 332 if actual != expected { 333 t.Fatalf("bad:\n%s", actual) 334 } 335 } 336 337 func TestContext2Plan_moduleInputFromVar(t *testing.T) { 338 m := testModule(t, "plan-module-input-var") 339 p := testProvider("aws") 340 p.DiffFn = testDiffFn 341 ctx := testContext2(t, &ContextOpts{ 342 Module: m, 343 Providers: map[string]ResourceProviderFactory{ 344 "aws": testProviderFuncFixed(p), 345 }, 346 Variables: map[string]interface{}{ 347 "foo": "52", 348 }, 349 }) 350 351 plan, err := ctx.Plan() 352 if err != nil { 353 t.Fatalf("err: %s", err) 354 } 355 356 actual := strings.TrimSpace(plan.String()) 357 expected := strings.TrimSpace(testTerraformPlanModuleInputVarStr) 358 if actual != expected { 359 t.Fatalf("bad:\n%s", actual) 360 } 361 } 362 363 func TestContext2Plan_moduleMultiVar(t *testing.T) { 364 m := testModule(t, "plan-module-multi-var") 365 p := testProvider("aws") 366 p.DiffFn = testDiffFn 367 ctx := testContext2(t, &ContextOpts{ 368 Module: m, 369 Providers: map[string]ResourceProviderFactory{ 370 "aws": testProviderFuncFixed(p), 371 }, 372 }) 373 374 plan, err := ctx.Plan() 375 if err != nil { 376 t.Fatalf("err: %s", err) 377 } 378 379 actual := strings.TrimSpace(plan.String()) 380 expected := strings.TrimSpace(testTerraformPlanModuleMultiVarStr) 381 if actual != expected { 382 t.Fatalf("bad:\n%s", actual) 383 } 384 } 385 386 func TestContext2Plan_moduleOrphans(t *testing.T) { 387 m := testModule(t, "plan-modules-remove") 388 p := testProvider("aws") 389 p.DiffFn = testDiffFn 390 s := &State{ 391 Modules: []*ModuleState{ 392 &ModuleState{ 393 Path: []string{"root", "child"}, 394 Resources: map[string]*ResourceState{ 395 "aws_instance.foo": &ResourceState{ 396 Type: "aws_instance", 397 Primary: &InstanceState{ 398 ID: "baz", 399 }, 400 }, 401 }, 402 }, 403 }, 404 } 405 ctx := testContext2(t, &ContextOpts{ 406 Module: m, 407 Providers: map[string]ResourceProviderFactory{ 408 "aws": testProviderFuncFixed(p), 409 }, 410 State: s, 411 }) 412 413 plan, err := ctx.Plan() 414 if err != nil { 415 t.Fatalf("err: %s", err) 416 } 417 418 actual := strings.TrimSpace(plan.String()) 419 expected := strings.TrimSpace(testTerraformPlanModuleOrphansStr) 420 if actual != expected { 421 t.Fatalf("bad:\n%s", actual) 422 } 423 } 424 425 // https://github.com/hashicorp/terraform/issues/3114 426 func TestContext2Plan_moduleOrphansWithProvisioner(t *testing.T) { 427 m := testModule(t, "plan-modules-remove-provisioners") 428 p := testProvider("aws") 429 pr := testProvisioner() 430 p.DiffFn = testDiffFn 431 s := &State{ 432 Modules: []*ModuleState{ 433 &ModuleState{ 434 Path: []string{"root"}, 435 Resources: map[string]*ResourceState{ 436 "aws_instance.top": &ResourceState{ 437 Type: "aws_instance", 438 Primary: &InstanceState{ 439 ID: "top", 440 }, 441 }, 442 }, 443 }, 444 &ModuleState{ 445 Path: []string{"root", "parent", "childone"}, 446 Resources: map[string]*ResourceState{ 447 "aws_instance.foo": &ResourceState{ 448 Type: "aws_instance", 449 Primary: &InstanceState{ 450 ID: "baz", 451 }, 452 }, 453 }, 454 }, 455 &ModuleState{ 456 Path: []string{"root", "parent", "childtwo"}, 457 Resources: map[string]*ResourceState{ 458 "aws_instance.foo": &ResourceState{ 459 Type: "aws_instance", 460 Primary: &InstanceState{ 461 ID: "baz", 462 }, 463 }, 464 }, 465 }, 466 }, 467 } 468 ctx := testContext2(t, &ContextOpts{ 469 Module: m, 470 Providers: map[string]ResourceProviderFactory{ 471 "aws": testProviderFuncFixed(p), 472 }, 473 Provisioners: map[string]ResourceProvisionerFactory{ 474 "shell": testProvisionerFuncFixed(pr), 475 }, 476 State: s, 477 }) 478 479 plan, err := ctx.Plan() 480 if err != nil { 481 t.Fatalf("err: %s", err) 482 } 483 484 actual := strings.TrimSpace(plan.String()) 485 expected := strings.TrimSpace(` 486 DIFF: 487 488 module.parent.childone: 489 DESTROY: aws_instance.foo 490 module.parent.childtwo: 491 DESTROY: aws_instance.foo 492 493 STATE: 494 495 aws_instance.top: 496 ID = top 497 498 module.parent.childone: 499 aws_instance.foo: 500 ID = baz 501 module.parent.childtwo: 502 aws_instance.foo: 503 ID = baz 504 `) 505 if actual != expected { 506 t.Fatalf("bad:\n%s", actual) 507 } 508 } 509 510 func TestContext2Plan_moduleProviderInherit(t *testing.T) { 511 var l sync.Mutex 512 var calls []string 513 514 m := testModule(t, "plan-module-provider-inherit") 515 ctx := testContext2(t, &ContextOpts{ 516 Module: m, 517 Providers: map[string]ResourceProviderFactory{ 518 "aws": func() (ResourceProvider, error) { 519 l.Lock() 520 defer l.Unlock() 521 522 p := testProvider("aws") 523 p.ConfigureFn = func(c *ResourceConfig) error { 524 if v, ok := c.Get("from"); !ok || v.(string) != "root" { 525 return fmt.Errorf("bad") 526 } 527 528 return nil 529 } 530 p.DiffFn = func( 531 info *InstanceInfo, 532 state *InstanceState, 533 c *ResourceConfig) (*InstanceDiff, error) { 534 v, _ := c.Get("from") 535 calls = append(calls, v.(string)) 536 return testDiffFn(info, state, c) 537 } 538 return p, nil 539 }, 540 }, 541 }) 542 543 _, err := ctx.Plan() 544 if err != nil { 545 t.Fatalf("err: %s", err) 546 } 547 548 actual := calls 549 sort.Strings(actual) 550 expected := []string{"child", "root"} 551 if !reflect.DeepEqual(actual, expected) { 552 t.Fatalf("bad: %#v", actual) 553 } 554 } 555 556 func TestContext2Plan_moduleProviderDefaults(t *testing.T) { 557 var l sync.Mutex 558 var calls []string 559 toCount := 0 560 561 m := testModule(t, "plan-module-provider-defaults") 562 ctx := testContext2(t, &ContextOpts{ 563 Module: m, 564 Providers: map[string]ResourceProviderFactory{ 565 "aws": func() (ResourceProvider, error) { 566 l.Lock() 567 defer l.Unlock() 568 569 p := testProvider("aws") 570 p.ConfigureFn = func(c *ResourceConfig) error { 571 if v, ok := c.Get("from"); !ok || v.(string) != "root" { 572 return fmt.Errorf("bad") 573 } 574 if v, ok := c.Get("to"); ok && v.(string) == "child" { 575 toCount++ 576 } 577 578 return nil 579 } 580 p.DiffFn = func( 581 info *InstanceInfo, 582 state *InstanceState, 583 c *ResourceConfig) (*InstanceDiff, error) { 584 v, _ := c.Get("from") 585 calls = append(calls, v.(string)) 586 return testDiffFn(info, state, c) 587 } 588 return p, nil 589 }, 590 }, 591 }) 592 593 _, err := ctx.Plan() 594 if err != nil { 595 t.Fatalf("err: %s", err) 596 } 597 598 if toCount != 1 { 599 t.Fatalf( 600 "provider in child didn't set proper config\n\n"+ 601 "toCount: %d", toCount) 602 } 603 604 actual := calls 605 sort.Strings(actual) 606 expected := []string{"child", "root"} 607 if !reflect.DeepEqual(actual, expected) { 608 t.Fatalf("bad: %#v", actual) 609 } 610 } 611 612 func TestContext2Plan_moduleProviderDefaultsVar(t *testing.T) { 613 var l sync.Mutex 614 var calls []string 615 616 m := testModule(t, "plan-module-provider-defaults-var") 617 ctx := testContext2(t, &ContextOpts{ 618 Module: m, 619 Providers: map[string]ResourceProviderFactory{ 620 "aws": func() (ResourceProvider, error) { 621 l.Lock() 622 defer l.Unlock() 623 624 p := testProvider("aws") 625 p.ConfigureFn = func(c *ResourceConfig) error { 626 var buf bytes.Buffer 627 if v, ok := c.Get("from"); ok { 628 buf.WriteString(v.(string) + "\n") 629 } 630 if v, ok := c.Get("to"); ok { 631 buf.WriteString(v.(string) + "\n") 632 } 633 634 calls = append(calls, buf.String()) 635 return nil 636 } 637 p.DiffFn = testDiffFn 638 return p, nil 639 }, 640 }, 641 Variables: map[string]interface{}{ 642 "foo": "root", 643 }, 644 }) 645 646 _, err := ctx.Plan() 647 if err != nil { 648 t.Fatalf("err: %s", err) 649 } 650 651 expected := []string{ 652 "root\n", 653 "root\nchild\n", 654 } 655 if !reflect.DeepEqual(calls, expected) { 656 t.Fatalf("BAD: %#v", calls) 657 } 658 } 659 660 func TestContext2Plan_moduleProviderVar(t *testing.T) { 661 m := testModule(t, "plan-module-provider-var") 662 p := testProvider("aws") 663 p.DiffFn = testDiffFn 664 ctx := testContext2(t, &ContextOpts{ 665 Module: m, 666 Providers: map[string]ResourceProviderFactory{ 667 "aws": testProviderFuncFixed(p), 668 }, 669 }) 670 671 plan, err := ctx.Plan() 672 if err != nil { 673 t.Fatalf("err: %s", err) 674 } 675 676 actual := strings.TrimSpace(plan.String()) 677 expected := strings.TrimSpace(testTerraformPlanModuleProviderVarStr) 678 if actual != expected { 679 t.Fatalf("bad:\n%s", actual) 680 } 681 } 682 683 func TestContext2Plan_moduleVar(t *testing.T) { 684 m := testModule(t, "plan-module-var") 685 p := testProvider("aws") 686 p.DiffFn = testDiffFn 687 ctx := testContext2(t, &ContextOpts{ 688 Module: m, 689 Providers: map[string]ResourceProviderFactory{ 690 "aws": testProviderFuncFixed(p), 691 }, 692 }) 693 694 plan, err := ctx.Plan() 695 if err != nil { 696 t.Fatalf("err: %s", err) 697 } 698 699 actual := strings.TrimSpace(plan.String()) 700 expected := strings.TrimSpace(testTerraformPlanModuleVarStr) 701 if actual != expected { 702 t.Fatalf("bad:\n%s", actual) 703 } 704 } 705 706 func TestContext2Plan_moduleVarWrongTypeBasic(t *testing.T) { 707 m := testModule(t, "plan-module-wrong-var-type") 708 p := testProvider("aws") 709 p.DiffFn = testDiffFn 710 ctx := testContext2(t, &ContextOpts{ 711 Module: m, 712 Providers: map[string]ResourceProviderFactory{ 713 "aws": testProviderFuncFixed(p), 714 }, 715 }) 716 717 _, err := ctx.Plan() 718 if err == nil { 719 t.Fatalf("should error") 720 } 721 } 722 723 func TestContext2Plan_moduleVarWrongTypeNested(t *testing.T) { 724 m := testModule(t, "plan-module-wrong-var-type-nested") 725 p := testProvider("aws") 726 p.DiffFn = testDiffFn 727 ctx := testContext2(t, &ContextOpts{ 728 Module: m, 729 Providers: map[string]ResourceProviderFactory{ 730 "aws": testProviderFuncFixed(p), 731 }, 732 }) 733 734 _, err := ctx.Plan() 735 if err == nil { 736 t.Fatalf("should error") 737 } 738 } 739 740 func TestContext2Plan_moduleVarWithDefaultValue(t *testing.T) { 741 m := testModule(t, "plan-module-var-with-default-value") 742 p := testProvider("null") 743 p.DiffFn = testDiffFn 744 ctx := testContext2(t, &ContextOpts{ 745 Module: m, 746 Providers: map[string]ResourceProviderFactory{ 747 "null": testProviderFuncFixed(p), 748 }, 749 }) 750 751 _, err := ctx.Plan() 752 if err != nil { 753 t.Fatalf("bad: %s", err) 754 } 755 } 756 757 func TestContext2Plan_moduleVarComputed(t *testing.T) { 758 m := testModule(t, "plan-module-var-computed") 759 p := testProvider("aws") 760 p.DiffFn = testDiffFn 761 ctx := testContext2(t, &ContextOpts{ 762 Module: m, 763 Providers: map[string]ResourceProviderFactory{ 764 "aws": testProviderFuncFixed(p), 765 }, 766 }) 767 768 plan, err := ctx.Plan() 769 if err != nil { 770 t.Fatalf("err: %s", err) 771 } 772 773 actual := strings.TrimSpace(plan.String()) 774 expected := strings.TrimSpace(testTerraformPlanModuleVarComputedStr) 775 if actual != expected { 776 t.Fatalf("bad:\n%s", actual) 777 } 778 } 779 780 func TestContext2Plan_nil(t *testing.T) { 781 m := testModule(t, "plan-nil") 782 p := testProvider("aws") 783 p.DiffFn = testDiffFn 784 ctx := testContext2(t, &ContextOpts{ 785 Module: m, 786 Providers: map[string]ResourceProviderFactory{ 787 "aws": testProviderFuncFixed(p), 788 }, 789 State: &State{ 790 Modules: []*ModuleState{ 791 &ModuleState{ 792 Path: rootModulePath, 793 Resources: map[string]*ResourceState{ 794 "aws_instance.foo": &ResourceState{ 795 Type: "aws_instance", 796 Primary: &InstanceState{ 797 ID: "bar", 798 }, 799 }, 800 }, 801 }, 802 }, 803 }, 804 }) 805 806 plan, err := ctx.Plan() 807 if err != nil { 808 t.Fatalf("err: %s", err) 809 } 810 if len(plan.Diff.RootModule().Resources) != 0 { 811 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 812 } 813 } 814 815 func TestContext2Plan_preventDestroy_bad(t *testing.T) { 816 m := testModule(t, "plan-prevent-destroy-bad") 817 p := testProvider("aws") 818 p.DiffFn = testDiffFn 819 ctx := testContext2(t, &ContextOpts{ 820 Module: m, 821 Providers: map[string]ResourceProviderFactory{ 822 "aws": testProviderFuncFixed(p), 823 }, 824 State: &State{ 825 Modules: []*ModuleState{ 826 &ModuleState{ 827 Path: rootModulePath, 828 Resources: map[string]*ResourceState{ 829 "aws_instance.foo": &ResourceState{ 830 Type: "aws_instance", 831 Primary: &InstanceState{ 832 ID: "i-abc123", 833 }, 834 }, 835 }, 836 }, 837 }, 838 }, 839 }) 840 841 plan, err := ctx.Plan() 842 843 expectedErr := "aws_instance.foo: the plan would destroy" 844 if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) { 845 t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s", 846 expectedErr, err, plan) 847 } 848 } 849 850 func TestContext2Plan_preventDestroy_good(t *testing.T) { 851 m := testModule(t, "plan-prevent-destroy-good") 852 p := testProvider("aws") 853 p.DiffFn = testDiffFn 854 ctx := testContext2(t, &ContextOpts{ 855 Module: m, 856 Providers: map[string]ResourceProviderFactory{ 857 "aws": testProviderFuncFixed(p), 858 }, 859 State: &State{ 860 Modules: []*ModuleState{ 861 &ModuleState{ 862 Path: rootModulePath, 863 Resources: map[string]*ResourceState{ 864 "aws_instance.foo": &ResourceState{ 865 Type: "aws_instance", 866 Primary: &InstanceState{ 867 ID: "i-abc123", 868 }, 869 }, 870 }, 871 }, 872 }, 873 }, 874 }) 875 876 plan, err := ctx.Plan() 877 if err != nil { 878 t.Fatalf("err: %s", err) 879 } 880 if !plan.Diff.Empty() { 881 t.Fatalf("Expected empty plan, got %s", plan.String()) 882 } 883 } 884 885 func TestContext2Plan_preventDestroy_countBad(t *testing.T) { 886 m := testModule(t, "plan-prevent-destroy-count-bad") 887 p := testProvider("aws") 888 p.DiffFn = testDiffFn 889 ctx := testContext2(t, &ContextOpts{ 890 Module: m, 891 Providers: map[string]ResourceProviderFactory{ 892 "aws": testProviderFuncFixed(p), 893 }, 894 State: &State{ 895 Modules: []*ModuleState{ 896 &ModuleState{ 897 Path: rootModulePath, 898 Resources: map[string]*ResourceState{ 899 "aws_instance.foo.0": &ResourceState{ 900 Type: "aws_instance", 901 Primary: &InstanceState{ 902 ID: "i-abc123", 903 }, 904 }, 905 "aws_instance.foo.1": &ResourceState{ 906 Type: "aws_instance", 907 Primary: &InstanceState{ 908 ID: "i-abc345", 909 }, 910 }, 911 }, 912 }, 913 }, 914 }, 915 }) 916 917 plan, err := ctx.Plan() 918 919 expectedErr := "aws_instance.foo.1: the plan would destroy" 920 if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) { 921 t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s", 922 expectedErr, err, plan) 923 } 924 } 925 926 func TestContext2Plan_preventDestroy_countGood(t *testing.T) { 927 m := testModule(t, "plan-prevent-destroy-count-good") 928 p := testProvider("aws") 929 p.DiffFn = testDiffFn 930 ctx := testContext2(t, &ContextOpts{ 931 Module: m, 932 Providers: map[string]ResourceProviderFactory{ 933 "aws": testProviderFuncFixed(p), 934 }, 935 State: &State{ 936 Modules: []*ModuleState{ 937 &ModuleState{ 938 Path: rootModulePath, 939 Resources: map[string]*ResourceState{ 940 "aws_instance.foo.0": &ResourceState{ 941 Type: "aws_instance", 942 Primary: &InstanceState{ 943 ID: "i-abc123", 944 }, 945 }, 946 "aws_instance.foo.1": &ResourceState{ 947 Type: "aws_instance", 948 Primary: &InstanceState{ 949 ID: "i-abc345", 950 }, 951 }, 952 }, 953 }, 954 }, 955 }, 956 }) 957 958 plan, err := ctx.Plan() 959 if err != nil { 960 t.Fatalf("err: %s", err) 961 } 962 if plan.Diff.Empty() { 963 t.Fatalf("Expected non-empty plan, got %s", plan.String()) 964 } 965 } 966 967 func TestContext2Plan_preventDestroy_countGoodNoChange(t *testing.T) { 968 m := testModule(t, "plan-prevent-destroy-count-good") 969 p := testProvider("aws") 970 p.DiffFn = testDiffFn 971 ctx := testContext2(t, &ContextOpts{ 972 Module: m, 973 Providers: map[string]ResourceProviderFactory{ 974 "aws": testProviderFuncFixed(p), 975 }, 976 State: &State{ 977 Modules: []*ModuleState{ 978 &ModuleState{ 979 Path: rootModulePath, 980 Resources: map[string]*ResourceState{ 981 "aws_instance.foo.0": &ResourceState{ 982 Type: "aws_instance", 983 Primary: &InstanceState{ 984 ID: "i-abc123", 985 Attributes: map[string]string{ 986 "current": "0", 987 "type": "aws_instance", 988 }, 989 }, 990 }, 991 }, 992 }, 993 }, 994 }, 995 }) 996 997 plan, err := ctx.Plan() 998 if err != nil { 999 t.Fatalf("err: %s", err) 1000 } 1001 if !plan.Diff.Empty() { 1002 t.Fatalf("Expected empty plan, got %s", plan.String()) 1003 } 1004 } 1005 1006 func TestContext2Plan_preventDestroy_destroyPlan(t *testing.T) { 1007 m := testModule(t, "plan-prevent-destroy-good") 1008 p := testProvider("aws") 1009 p.DiffFn = testDiffFn 1010 ctx := testContext2(t, &ContextOpts{ 1011 Module: m, 1012 Providers: map[string]ResourceProviderFactory{ 1013 "aws": testProviderFuncFixed(p), 1014 }, 1015 State: &State{ 1016 Modules: []*ModuleState{ 1017 &ModuleState{ 1018 Path: rootModulePath, 1019 Resources: map[string]*ResourceState{ 1020 "aws_instance.foo": &ResourceState{ 1021 Type: "aws_instance", 1022 Primary: &InstanceState{ 1023 ID: "i-abc123", 1024 }, 1025 }, 1026 }, 1027 }, 1028 }, 1029 }, 1030 Destroy: true, 1031 }) 1032 1033 plan, err := ctx.Plan() 1034 1035 expectedErr := "aws_instance.foo: the plan would destroy" 1036 if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) { 1037 t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s", 1038 expectedErr, err, plan) 1039 } 1040 } 1041 1042 func TestContext2Plan_provisionerCycle(t *testing.T) { 1043 m := testModule(t, "plan-provisioner-cycle") 1044 p := testProvider("aws") 1045 p.DiffFn = testDiffFn 1046 pr := testProvisioner() 1047 ctx := testContext2(t, &ContextOpts{ 1048 Module: m, 1049 Providers: map[string]ResourceProviderFactory{ 1050 "aws": testProviderFuncFixed(p), 1051 }, 1052 Provisioners: map[string]ResourceProvisionerFactory{ 1053 "local-exec": testProvisionerFuncFixed(pr), 1054 }, 1055 }) 1056 1057 _, err := ctx.Plan() 1058 if err == nil { 1059 t.Fatalf("should error") 1060 } 1061 } 1062 1063 func TestContext2Plan_computed(t *testing.T) { 1064 m := testModule(t, "plan-computed") 1065 p := testProvider("aws") 1066 p.DiffFn = testDiffFn 1067 ctx := testContext2(t, &ContextOpts{ 1068 Module: m, 1069 Providers: map[string]ResourceProviderFactory{ 1070 "aws": testProviderFuncFixed(p), 1071 }, 1072 }) 1073 1074 plan, err := ctx.Plan() 1075 if err != nil { 1076 t.Fatalf("err: %s", err) 1077 } 1078 1079 actual := strings.TrimSpace(plan.String()) 1080 expected := strings.TrimSpace(testTerraformPlanComputedStr) 1081 if actual != expected { 1082 t.Fatalf("bad:\n%s", actual) 1083 } 1084 } 1085 1086 func TestContext2Plan_computedDataResource(t *testing.T) { 1087 m := testModule(t, "plan-computed-data-resource") 1088 p := testProvider("aws") 1089 p.DiffFn = testDiffFn 1090 ctx := testContext2(t, &ContextOpts{ 1091 Module: m, 1092 Providers: map[string]ResourceProviderFactory{ 1093 "aws": testProviderFuncFixed(p), 1094 }, 1095 }) 1096 1097 plan, err := ctx.Plan() 1098 if err != nil { 1099 t.Fatalf("err: %s", err) 1100 } 1101 1102 if got := len(plan.Diff.Modules); got != 1 { 1103 t.Fatalf("got %d modules; want 1", got) 1104 } 1105 1106 moduleDiff := plan.Diff.Modules[0] 1107 1108 if _, ok := moduleDiff.Resources["aws_instance.foo"]; !ok { 1109 t.Fatalf("missing diff for aws_instance.foo") 1110 } 1111 iDiff, ok := moduleDiff.Resources["data.aws_vpc.bar"] 1112 if !ok { 1113 t.Fatalf("missing diff for data.aws_vpc.bar") 1114 } 1115 1116 expectedDiff := &InstanceDiff{ 1117 Attributes: map[string]*ResourceAttrDiff{ 1118 "id": { 1119 NewComputed: true, 1120 RequiresNew: true, 1121 Type: DiffAttrOutput, 1122 }, 1123 }, 1124 } 1125 if same, _ := expectedDiff.Same(iDiff); !same { 1126 t.Fatalf( 1127 "incorrect diff for data.aws_vpc.bar\ngot: %#v\nwant: %#v", 1128 iDiff, expectedDiff, 1129 ) 1130 } 1131 } 1132 1133 func TestContext2Plan_computedDataCountResource(t *testing.T) { 1134 m := testModule(t, "plan-computed-data-count") 1135 p := testProvider("aws") 1136 p.DiffFn = testDiffFn 1137 ctx := testContext2(t, &ContextOpts{ 1138 Module: m, 1139 Providers: map[string]ResourceProviderFactory{ 1140 "aws": testProviderFuncFixed(p), 1141 }, 1142 }) 1143 1144 plan, err := ctx.Plan() 1145 if err != nil { 1146 t.Fatalf("err: %s", err) 1147 } 1148 1149 if got := len(plan.Diff.Modules); got != 1 { 1150 t.Fatalf("got %d modules; want 1", got) 1151 } 1152 1153 moduleDiff := plan.Diff.Modules[0] 1154 1155 // make sure we created 3 "bar"s 1156 for i := 0; i < 3; i++ { 1157 resource := fmt.Sprintf("data.aws_vpc.bar.%d", i) 1158 if _, ok := moduleDiff.Resources[resource]; !ok { 1159 t.Fatalf("missing diff for %s", resource) 1160 } 1161 } 1162 } 1163 1164 // Higher level test at TestResource_dataSourceListPlanPanic 1165 func TestContext2Plan_dataSourceTypeMismatch(t *testing.T) { 1166 m := testModule(t, "plan-data-source-type-mismatch") 1167 p := testProvider("aws") 1168 p.ValidateResourceFn = func(t string, c *ResourceConfig) (ws []string, es []error) { 1169 // Emulate the type checking behavior of helper/schema based validation 1170 if t == "aws_instance" { 1171 ami, _ := c.Get("ami") 1172 switch a := ami.(type) { 1173 case string: 1174 // ok 1175 default: 1176 es = append(es, fmt.Errorf("Expected ami to be string, got %T", a)) 1177 } 1178 } 1179 return 1180 } 1181 p.DiffFn = func( 1182 info *InstanceInfo, 1183 state *InstanceState, 1184 c *ResourceConfig) (*InstanceDiff, error) { 1185 if info.Type == "aws_instance" { 1186 // If we get to the diff, we should be able to assume types 1187 ami, _ := c.Get("ami") 1188 _ = ami.(string) 1189 } 1190 return nil, nil 1191 } 1192 ctx := testContext2(t, &ContextOpts{ 1193 Module: m, 1194 // Pretend like we ran a Refresh and the AZs data source was populated. 1195 State: &State{ 1196 Modules: []*ModuleState{ 1197 &ModuleState{ 1198 Path: rootModulePath, 1199 Resources: map[string]*ResourceState{ 1200 "data.aws_availability_zones.azs": &ResourceState{ 1201 Type: "aws_availability_zones", 1202 Primary: &InstanceState{ 1203 ID: "i-abc123", 1204 Attributes: map[string]string{ 1205 "names.#": "2", 1206 "names.0": "us-east-1a", 1207 "names.1": "us-east-1b", 1208 }, 1209 }, 1210 }, 1211 }, 1212 }, 1213 }, 1214 }, 1215 Providers: map[string]ResourceProviderFactory{ 1216 "aws": testProviderFuncFixed(p), 1217 }, 1218 }) 1219 1220 _, err := ctx.Plan() 1221 1222 if err == nil { 1223 t.Fatalf("Expected err, got none!") 1224 } 1225 expected := "Expected ami to be string" 1226 if !strings.Contains(err.Error(), expected) { 1227 t.Fatalf("expected:\n\n%s\n\nto contain:\n\n%s", err, expected) 1228 } 1229 } 1230 1231 func TestContext2Plan_dataResourceBecomesComputed(t *testing.T) { 1232 m := testModule(t, "plan-data-resource-becomes-computed") 1233 p := testProvider("aws") 1234 1235 p.DiffFn = func(info *InstanceInfo, state *InstanceState, config *ResourceConfig) (*InstanceDiff, error) { 1236 if info.Type != "aws_instance" { 1237 t.Fatalf("don't know how to diff %s", info.Id) 1238 return nil, nil 1239 } 1240 1241 return &InstanceDiff{ 1242 Attributes: map[string]*ResourceAttrDiff{ 1243 "computed": &ResourceAttrDiff{ 1244 Old: "", 1245 New: "", 1246 NewComputed: true, 1247 }, 1248 }, 1249 }, nil 1250 } 1251 p.ReadDataDiffReturn = &InstanceDiff{ 1252 Attributes: map[string]*ResourceAttrDiff{ 1253 "foo": &ResourceAttrDiff{ 1254 Old: "", 1255 New: "", 1256 NewComputed: true, 1257 }, 1258 }, 1259 } 1260 1261 ctx := testContext2(t, &ContextOpts{ 1262 Module: m, 1263 Providers: map[string]ResourceProviderFactory{ 1264 "aws": testProviderFuncFixed(p), 1265 }, 1266 State: &State{ 1267 Modules: []*ModuleState{ 1268 &ModuleState{ 1269 Path: rootModulePath, 1270 Resources: map[string]*ResourceState{ 1271 "data.aws_data_resource.foo": &ResourceState{ 1272 Type: "aws_data_resource", 1273 Primary: &InstanceState{ 1274 ID: "i-abc123", 1275 Attributes: map[string]string{ 1276 "id": "i-abc123", 1277 "value": "baz", 1278 }, 1279 }, 1280 }, 1281 }, 1282 }, 1283 }, 1284 }, 1285 }) 1286 1287 plan, err := ctx.Plan() 1288 if err != nil { 1289 t.Fatalf("err: %s", err) 1290 } 1291 1292 if got := len(plan.Diff.Modules); got != 1 { 1293 t.Fatalf("got %d modules; want 1", got) 1294 } 1295 1296 if !p.ReadDataDiffCalled { 1297 t.Fatal("ReadDataDiff wasn't called, but should've been") 1298 } 1299 if got, want := p.ReadDataDiffInfo.Id, "data.aws_data_resource.foo"; got != want { 1300 t.Fatalf("ReadDataDiff info id is %s; want %s", got, want) 1301 } 1302 1303 moduleDiff := plan.Diff.Modules[0] 1304 1305 iDiff, ok := moduleDiff.Resources["data.aws_data_resource.foo"] 1306 if !ok { 1307 t.Fatalf("missing diff for data.aws_data_resource.foo") 1308 } 1309 1310 // This is added by the diff but we want to verify that we got 1311 // the same diff as above minus the dynamic stuff. 1312 delete(iDiff.Attributes, "id") 1313 1314 if same, _ := p.ReadDataDiffReturn.Same(iDiff); !same { 1315 t.Fatalf( 1316 "incorrect diff for data.data_resource.foo\ngot: %#v\nwant: %#v", 1317 iDiff, p.ReadDataDiffReturn, 1318 ) 1319 } 1320 } 1321 1322 func TestContext2Plan_computedList(t *testing.T) { 1323 m := testModule(t, "plan-computed-list") 1324 p := testProvider("aws") 1325 p.DiffFn = testDiffFn 1326 ctx := testContext2(t, &ContextOpts{ 1327 Module: m, 1328 Providers: map[string]ResourceProviderFactory{ 1329 "aws": testProviderFuncFixed(p), 1330 }, 1331 }) 1332 1333 plan, err := ctx.Plan() 1334 if err != nil { 1335 t.Fatalf("err: %s", err) 1336 } 1337 1338 actual := strings.TrimSpace(plan.String()) 1339 expected := strings.TrimSpace(testTerraformPlanComputedListStr) 1340 if actual != expected { 1341 t.Fatalf("bad:\n%s", actual) 1342 } 1343 } 1344 1345 // GH-8695. This tests that you can index into a computed list on a 1346 // splatted resource. 1347 func TestContext2Plan_computedMultiIndex(t *testing.T) { 1348 m := testModule(t, "plan-computed-multi-index") 1349 p := testProvider("aws") 1350 p.DiffFn = testDiffFn 1351 ctx := testContext2(t, &ContextOpts{ 1352 Module: m, 1353 Providers: map[string]ResourceProviderFactory{ 1354 "aws": testProviderFuncFixed(p), 1355 }, 1356 }) 1357 1358 plan, err := ctx.Plan() 1359 if err != nil { 1360 t.Fatalf("err: %s", err) 1361 } 1362 1363 actual := strings.TrimSpace(plan.String()) 1364 expected := strings.TrimSpace(testTerraformPlanComputedMultiIndexStr) 1365 if actual != expected { 1366 t.Fatalf("bad:\n%s", actual) 1367 } 1368 } 1369 1370 func TestContext2Plan_count(t *testing.T) { 1371 m := testModule(t, "plan-count") 1372 p := testProvider("aws") 1373 p.DiffFn = testDiffFn 1374 ctx := testContext2(t, &ContextOpts{ 1375 Module: m, 1376 Providers: map[string]ResourceProviderFactory{ 1377 "aws": testProviderFuncFixed(p), 1378 }, 1379 }) 1380 1381 plan, err := ctx.Plan() 1382 if err != nil { 1383 t.Fatalf("err: %s", err) 1384 } 1385 1386 if len(plan.Diff.RootModule().Resources) < 6 { 1387 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 1388 } 1389 1390 actual := strings.TrimSpace(plan.String()) 1391 expected := strings.TrimSpace(testTerraformPlanCountStr) 1392 if actual != expected { 1393 t.Fatalf("bad:\n%s", actual) 1394 } 1395 } 1396 1397 func TestContext2Plan_countComputed(t *testing.T) { 1398 m := testModule(t, "plan-count-computed") 1399 p := testProvider("aws") 1400 p.DiffFn = testDiffFn 1401 ctx := testContext2(t, &ContextOpts{ 1402 Module: m, 1403 Providers: map[string]ResourceProviderFactory{ 1404 "aws": testProviderFuncFixed(p), 1405 }, 1406 }) 1407 1408 _, err := ctx.Plan() 1409 if err == nil { 1410 t.Fatal("should error") 1411 } 1412 } 1413 1414 func TestContext2Plan_countComputedModule(t *testing.T) { 1415 m := testModule(t, "plan-count-computed-module") 1416 p := testProvider("aws") 1417 p.DiffFn = testDiffFn 1418 ctx := testContext2(t, &ContextOpts{ 1419 Module: m, 1420 Providers: map[string]ResourceProviderFactory{ 1421 "aws": testProviderFuncFixed(p), 1422 }, 1423 }) 1424 1425 _, err := ctx.Plan() 1426 1427 expectedErr := "aws_instance.bar: value of 'count'" 1428 if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) { 1429 t.Fatalf("expected err would contain %q\nerr: %s\n", 1430 expectedErr, err) 1431 } 1432 } 1433 1434 func TestContext2Plan_countIndex(t *testing.T) { 1435 m := testModule(t, "plan-count-index") 1436 p := testProvider("aws") 1437 p.DiffFn = testDiffFn 1438 ctx := testContext2(t, &ContextOpts{ 1439 Module: m, 1440 Providers: map[string]ResourceProviderFactory{ 1441 "aws": testProviderFuncFixed(p), 1442 }, 1443 }) 1444 1445 plan, err := ctx.Plan() 1446 if err != nil { 1447 t.Fatalf("err: %s", err) 1448 } 1449 1450 actual := strings.TrimSpace(plan.String()) 1451 expected := strings.TrimSpace(testTerraformPlanCountIndexStr) 1452 if actual != expected { 1453 t.Fatalf("bad:\n%s", actual) 1454 } 1455 } 1456 1457 func TestContext2Plan_countIndexZero(t *testing.T) { 1458 m := testModule(t, "plan-count-index-zero") 1459 p := testProvider("aws") 1460 p.DiffFn = testDiffFn 1461 ctx := testContext2(t, &ContextOpts{ 1462 Module: m, 1463 Providers: map[string]ResourceProviderFactory{ 1464 "aws": testProviderFuncFixed(p), 1465 }, 1466 }) 1467 1468 plan, err := ctx.Plan() 1469 if err != nil { 1470 t.Fatalf("err: %s", err) 1471 } 1472 1473 actual := strings.TrimSpace(plan.String()) 1474 expected := strings.TrimSpace(testTerraformPlanCountIndexZeroStr) 1475 if actual != expected { 1476 t.Fatalf("bad:\n%s", actual) 1477 } 1478 } 1479 1480 func TestContext2Plan_countVar(t *testing.T) { 1481 m := testModule(t, "plan-count-var") 1482 p := testProvider("aws") 1483 p.DiffFn = testDiffFn 1484 ctx := testContext2(t, &ContextOpts{ 1485 Module: m, 1486 Providers: map[string]ResourceProviderFactory{ 1487 "aws": testProviderFuncFixed(p), 1488 }, 1489 Variables: map[string]interface{}{ 1490 "count": "3", 1491 }, 1492 }) 1493 1494 plan, err := ctx.Plan() 1495 if err != nil { 1496 t.Fatalf("err: %s", err) 1497 } 1498 1499 actual := strings.TrimSpace(plan.String()) 1500 expected := strings.TrimSpace(testTerraformPlanCountVarStr) 1501 if actual != expected { 1502 t.Fatalf("bad:\n%s", actual) 1503 } 1504 } 1505 1506 func TestContext2Plan_countZero(t *testing.T) { 1507 m := testModule(t, "plan-count-zero") 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(testTerraformPlanCountZeroStr) 1524 if actual != expected { 1525 t.Logf("expected:\n%s", expected) 1526 t.Fatalf("bad:\n%s", actual) 1527 } 1528 } 1529 1530 func TestContext2Plan_countOneIndex(t *testing.T) { 1531 m := testModule(t, "plan-count-one-index") 1532 p := testProvider("aws") 1533 p.DiffFn = testDiffFn 1534 ctx := testContext2(t, &ContextOpts{ 1535 Module: m, 1536 Providers: map[string]ResourceProviderFactory{ 1537 "aws": testProviderFuncFixed(p), 1538 }, 1539 }) 1540 1541 plan, err := ctx.Plan() 1542 if err != nil { 1543 t.Fatalf("err: %s", err) 1544 } 1545 1546 actual := strings.TrimSpace(plan.String()) 1547 expected := strings.TrimSpace(testTerraformPlanCountOneIndexStr) 1548 if actual != expected { 1549 t.Fatalf("bad:\n%s", actual) 1550 } 1551 } 1552 1553 func TestContext2Plan_countDecreaseToOne(t *testing.T) { 1554 m := testModule(t, "plan-count-dec") 1555 p := testProvider("aws") 1556 p.DiffFn = testDiffFn 1557 s := &State{ 1558 Modules: []*ModuleState{ 1559 &ModuleState{ 1560 Path: rootModulePath, 1561 Resources: map[string]*ResourceState{ 1562 "aws_instance.foo.0": &ResourceState{ 1563 Type: "aws_instance", 1564 Primary: &InstanceState{ 1565 ID: "bar", 1566 Attributes: map[string]string{ 1567 "foo": "foo", 1568 "type": "aws_instance", 1569 }, 1570 }, 1571 }, 1572 "aws_instance.foo.1": &ResourceState{ 1573 Type: "aws_instance", 1574 Primary: &InstanceState{ 1575 ID: "bar", 1576 }, 1577 }, 1578 "aws_instance.foo.2": &ResourceState{ 1579 Type: "aws_instance", 1580 Primary: &InstanceState{ 1581 ID: "bar", 1582 }, 1583 }, 1584 }, 1585 }, 1586 }, 1587 } 1588 ctx := testContext2(t, &ContextOpts{ 1589 Module: m, 1590 Providers: map[string]ResourceProviderFactory{ 1591 "aws": testProviderFuncFixed(p), 1592 }, 1593 State: s, 1594 }) 1595 1596 plan, err := ctx.Plan() 1597 if err != nil { 1598 t.Fatalf("err: %s", err) 1599 } 1600 1601 actual := strings.TrimSpace(plan.String()) 1602 expected := strings.TrimSpace(testTerraformPlanCountDecreaseStr) 1603 if actual != expected { 1604 t.Fatalf("bad:\n%s", actual) 1605 } 1606 } 1607 1608 func TestContext2Plan_countIncreaseFromNotSet(t *testing.T) { 1609 m := testModule(t, "plan-count-inc") 1610 p := testProvider("aws") 1611 p.DiffFn = testDiffFn 1612 s := &State{ 1613 Modules: []*ModuleState{ 1614 &ModuleState{ 1615 Path: rootModulePath, 1616 Resources: map[string]*ResourceState{ 1617 "aws_instance.foo": &ResourceState{ 1618 Type: "aws_instance", 1619 Primary: &InstanceState{ 1620 ID: "bar", 1621 Attributes: map[string]string{ 1622 "foo": "foo", 1623 "type": "aws_instance", 1624 }, 1625 }, 1626 }, 1627 }, 1628 }, 1629 }, 1630 } 1631 ctx := testContext2(t, &ContextOpts{ 1632 Module: m, 1633 Providers: map[string]ResourceProviderFactory{ 1634 "aws": testProviderFuncFixed(p), 1635 }, 1636 State: s, 1637 }) 1638 1639 plan, err := ctx.Plan() 1640 if err != nil { 1641 t.Fatalf("err: %s", err) 1642 } 1643 1644 actual := strings.TrimSpace(plan.String()) 1645 expected := strings.TrimSpace(testTerraformPlanCountIncreaseStr) 1646 if actual != expected { 1647 t.Fatalf("bad:\n%s", actual) 1648 } 1649 } 1650 1651 func TestContext2Plan_countIncreaseFromOne(t *testing.T) { 1652 m := testModule(t, "plan-count-inc") 1653 p := testProvider("aws") 1654 p.DiffFn = testDiffFn 1655 s := &State{ 1656 Modules: []*ModuleState{ 1657 &ModuleState{ 1658 Path: rootModulePath, 1659 Resources: map[string]*ResourceState{ 1660 "aws_instance.foo.0": &ResourceState{ 1661 Type: "aws_instance", 1662 Primary: &InstanceState{ 1663 ID: "bar", 1664 Attributes: map[string]string{ 1665 "foo": "foo", 1666 "type": "aws_instance", 1667 }, 1668 }, 1669 }, 1670 }, 1671 }, 1672 }, 1673 } 1674 ctx := testContext2(t, &ContextOpts{ 1675 Module: m, 1676 Providers: map[string]ResourceProviderFactory{ 1677 "aws": testProviderFuncFixed(p), 1678 }, 1679 State: s, 1680 }) 1681 1682 plan, err := ctx.Plan() 1683 if err != nil { 1684 t.Fatalf("err: %s", err) 1685 } 1686 1687 actual := strings.TrimSpace(plan.String()) 1688 expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneStr) 1689 if actual != expected { 1690 t.Fatalf("bad:\n%s", actual) 1691 } 1692 } 1693 1694 // https://github.com/PeoplePerHour/terraform/pull/11 1695 // 1696 // This tests a case where both a "resource" and "resource.0" are in 1697 // the state file, which apparently is a reasonable backwards compatibility 1698 // concern found in the above 3rd party repo. 1699 func TestContext2Plan_countIncreaseFromOneCorrupted(t *testing.T) { 1700 m := testModule(t, "plan-count-inc") 1701 p := testProvider("aws") 1702 p.DiffFn = testDiffFn 1703 s := &State{ 1704 Modules: []*ModuleState{ 1705 &ModuleState{ 1706 Path: rootModulePath, 1707 Resources: map[string]*ResourceState{ 1708 "aws_instance.foo": &ResourceState{ 1709 Type: "aws_instance", 1710 Primary: &InstanceState{ 1711 ID: "bar", 1712 Attributes: map[string]string{ 1713 "foo": "foo", 1714 "type": "aws_instance", 1715 }, 1716 }, 1717 }, 1718 "aws_instance.foo.0": &ResourceState{ 1719 Type: "aws_instance", 1720 Primary: &InstanceState{ 1721 ID: "bar", 1722 Attributes: map[string]string{ 1723 "foo": "foo", 1724 "type": "aws_instance", 1725 }, 1726 }, 1727 }, 1728 }, 1729 }, 1730 }, 1731 } 1732 ctx := testContext2(t, &ContextOpts{ 1733 Module: m, 1734 Providers: map[string]ResourceProviderFactory{ 1735 "aws": testProviderFuncFixed(p), 1736 }, 1737 State: s, 1738 }) 1739 1740 plan, err := ctx.Plan() 1741 if err != nil { 1742 t.Fatalf("err: %s", err) 1743 } 1744 1745 actual := strings.TrimSpace(plan.String()) 1746 expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneCorruptedStr) 1747 if actual != expected { 1748 t.Fatalf("bad:\n%s", actual) 1749 } 1750 } 1751 1752 func TestContext2Plan_destroy(t *testing.T) { 1753 m := testModule(t, "plan-destroy") 1754 p := testProvider("aws") 1755 p.DiffFn = testDiffFn 1756 s := &State{ 1757 Modules: []*ModuleState{ 1758 &ModuleState{ 1759 Path: rootModulePath, 1760 Resources: map[string]*ResourceState{ 1761 "aws_instance.one": &ResourceState{ 1762 Type: "aws_instance", 1763 Primary: &InstanceState{ 1764 ID: "bar", 1765 }, 1766 }, 1767 "aws_instance.two": &ResourceState{ 1768 Type: "aws_instance", 1769 Primary: &InstanceState{ 1770 ID: "baz", 1771 }, 1772 }, 1773 }, 1774 }, 1775 }, 1776 } 1777 ctx := testContext2(t, &ContextOpts{ 1778 Module: m, 1779 Providers: map[string]ResourceProviderFactory{ 1780 "aws": testProviderFuncFixed(p), 1781 }, 1782 State: s, 1783 Destroy: true, 1784 }) 1785 1786 plan, err := ctx.Plan() 1787 if err != nil { 1788 t.Fatalf("err: %s", err) 1789 } 1790 1791 if len(plan.Diff.RootModule().Resources) != 2 { 1792 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 1793 } 1794 1795 actual := strings.TrimSpace(plan.String()) 1796 expected := strings.TrimSpace(testTerraformPlanDestroyStr) 1797 if actual != expected { 1798 t.Fatalf("bad:\n%s", actual) 1799 } 1800 } 1801 1802 func TestContext2Plan_moduleDestroy(t *testing.T) { 1803 m := testModule(t, "plan-module-destroy") 1804 p := testProvider("aws") 1805 p.DiffFn = testDiffFn 1806 s := &State{ 1807 Modules: []*ModuleState{ 1808 &ModuleState{ 1809 Path: rootModulePath, 1810 Resources: map[string]*ResourceState{ 1811 "aws_instance.foo": &ResourceState{ 1812 Type: "aws_instance", 1813 Primary: &InstanceState{ 1814 ID: "bar", 1815 }, 1816 }, 1817 }, 1818 }, 1819 &ModuleState{ 1820 Path: []string{"root", "child"}, 1821 Resources: map[string]*ResourceState{ 1822 "aws_instance.foo": &ResourceState{ 1823 Type: "aws_instance", 1824 Primary: &InstanceState{ 1825 ID: "bar", 1826 }, 1827 }, 1828 }, 1829 }, 1830 }, 1831 } 1832 ctx := testContext2(t, &ContextOpts{ 1833 Module: m, 1834 Providers: map[string]ResourceProviderFactory{ 1835 "aws": testProviderFuncFixed(p), 1836 }, 1837 State: s, 1838 Destroy: true, 1839 }) 1840 1841 plan, err := ctx.Plan() 1842 if err != nil { 1843 t.Fatalf("err: %s", err) 1844 } 1845 1846 actual := strings.TrimSpace(plan.String()) 1847 expected := strings.TrimSpace(testTerraformPlanModuleDestroyStr) 1848 if actual != expected { 1849 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 1850 } 1851 } 1852 1853 // GH-1835 1854 func TestContext2Plan_moduleDestroyCycle(t *testing.T) { 1855 m := testModule(t, "plan-module-destroy-gh-1835") 1856 p := testProvider("aws") 1857 p.DiffFn = testDiffFn 1858 s := &State{ 1859 Modules: []*ModuleState{ 1860 &ModuleState{ 1861 Path: []string{"root", "a_module"}, 1862 Resources: map[string]*ResourceState{ 1863 "aws_instance.a": &ResourceState{ 1864 Type: "aws_instance", 1865 Primary: &InstanceState{ 1866 ID: "a", 1867 }, 1868 }, 1869 }, 1870 }, 1871 &ModuleState{ 1872 Path: []string{"root", "b_module"}, 1873 Resources: map[string]*ResourceState{ 1874 "aws_instance.b": &ResourceState{ 1875 Type: "aws_instance", 1876 Primary: &InstanceState{ 1877 ID: "b", 1878 }, 1879 }, 1880 }, 1881 }, 1882 }, 1883 } 1884 ctx := testContext2(t, &ContextOpts{ 1885 Module: m, 1886 Providers: map[string]ResourceProviderFactory{ 1887 "aws": testProviderFuncFixed(p), 1888 }, 1889 State: s, 1890 Destroy: true, 1891 }) 1892 1893 plan, err := ctx.Plan() 1894 if err != nil { 1895 t.Fatalf("err: %s", err) 1896 } 1897 1898 actual := strings.TrimSpace(plan.String()) 1899 expected := strings.TrimSpace(testTerraformPlanModuleDestroyCycleStr) 1900 if actual != expected { 1901 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 1902 } 1903 } 1904 1905 func TestContext2Plan_moduleDestroyMultivar(t *testing.T) { 1906 m := testModule(t, "plan-module-destroy-multivar") 1907 p := testProvider("aws") 1908 p.DiffFn = testDiffFn 1909 s := &State{ 1910 Modules: []*ModuleState{ 1911 &ModuleState{ 1912 Path: rootModulePath, 1913 Resources: map[string]*ResourceState{}, 1914 }, 1915 &ModuleState{ 1916 Path: []string{"root", "child"}, 1917 Resources: map[string]*ResourceState{ 1918 "aws_instance.foo.0": &ResourceState{ 1919 Type: "aws_instance", 1920 Primary: &InstanceState{ 1921 ID: "bar0", 1922 }, 1923 }, 1924 "aws_instance.foo.1": &ResourceState{ 1925 Type: "aws_instance", 1926 Primary: &InstanceState{ 1927 ID: "bar1", 1928 }, 1929 }, 1930 }, 1931 }, 1932 }, 1933 } 1934 ctx := testContext2(t, &ContextOpts{ 1935 Module: m, 1936 Providers: map[string]ResourceProviderFactory{ 1937 "aws": testProviderFuncFixed(p), 1938 }, 1939 State: s, 1940 Destroy: true, 1941 }) 1942 1943 plan, err := ctx.Plan() 1944 if err != nil { 1945 t.Fatalf("err: %s", err) 1946 } 1947 1948 actual := strings.TrimSpace(plan.String()) 1949 expected := strings.TrimSpace(testTerraformPlanModuleDestroyMultivarStr) 1950 if actual != expected { 1951 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 1952 } 1953 } 1954 1955 func TestContext2Plan_pathVar(t *testing.T) { 1956 cwd, err := os.Getwd() 1957 if err != nil { 1958 t.Fatalf("err: %s", err) 1959 } 1960 1961 m := testModule(t, "plan-path-var") 1962 p := testProvider("aws") 1963 p.DiffFn = testDiffFn 1964 ctx := testContext2(t, &ContextOpts{ 1965 Module: m, 1966 Providers: map[string]ResourceProviderFactory{ 1967 "aws": testProviderFuncFixed(p), 1968 }, 1969 }) 1970 1971 plan, err := ctx.Plan() 1972 if err != nil { 1973 t.Fatalf("err: %s", err) 1974 } 1975 1976 actual := strings.TrimSpace(plan.String()) 1977 expected := strings.TrimSpace(testTerraformPlanPathVarStr) 1978 1979 // Warning: this ordering REALLY matters for this test. The 1980 // order is: cwd, module, root. 1981 expected = fmt.Sprintf( 1982 expected, 1983 cwd, 1984 m.Config().Dir, 1985 m.Config().Dir) 1986 1987 if actual != expected { 1988 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 1989 } 1990 } 1991 1992 func TestContext2Plan_diffVar(t *testing.T) { 1993 m := testModule(t, "plan-diffvar") 1994 p := testProvider("aws") 1995 s := &State{ 1996 Modules: []*ModuleState{ 1997 &ModuleState{ 1998 Path: rootModulePath, 1999 Resources: map[string]*ResourceState{ 2000 "aws_instance.foo": &ResourceState{ 2001 Primary: &InstanceState{ 2002 ID: "bar", 2003 Attributes: map[string]string{ 2004 "num": "2", 2005 }, 2006 }, 2007 }, 2008 }, 2009 }, 2010 }, 2011 } 2012 ctx := testContext2(t, &ContextOpts{ 2013 Module: m, 2014 Providers: map[string]ResourceProviderFactory{ 2015 "aws": testProviderFuncFixed(p), 2016 }, 2017 State: s, 2018 }) 2019 2020 p.DiffFn = func( 2021 info *InstanceInfo, 2022 s *InstanceState, 2023 c *ResourceConfig) (*InstanceDiff, error) { 2024 if s.ID != "bar" { 2025 return testDiffFn(info, s, c) 2026 } 2027 2028 return &InstanceDiff{ 2029 Attributes: map[string]*ResourceAttrDiff{ 2030 "num": &ResourceAttrDiff{ 2031 Old: "2", 2032 New: "3", 2033 }, 2034 }, 2035 }, nil 2036 } 2037 2038 plan, err := ctx.Plan() 2039 if err != nil { 2040 t.Fatalf("err: %s", err) 2041 } 2042 2043 actual := strings.TrimSpace(plan.String()) 2044 expected := strings.TrimSpace(testTerraformPlanDiffVarStr) 2045 if actual != expected { 2046 t.Fatalf("actual:\n%s\n\nexpected:\n%s", actual, expected) 2047 } 2048 } 2049 2050 func TestContext2Plan_hook(t *testing.T) { 2051 m := testModule(t, "plan-good") 2052 h := new(MockHook) 2053 p := testProvider("aws") 2054 p.DiffFn = testDiffFn 2055 ctx := testContext2(t, &ContextOpts{ 2056 Module: m, 2057 Hooks: []Hook{h}, 2058 Providers: map[string]ResourceProviderFactory{ 2059 "aws": testProviderFuncFixed(p), 2060 }, 2061 }) 2062 2063 _, err := ctx.Plan() 2064 if err != nil { 2065 t.Fatalf("err: %s", err) 2066 } 2067 2068 if !h.PreDiffCalled { 2069 t.Fatal("should be called") 2070 } 2071 if !h.PostDiffCalled { 2072 t.Fatal("should be called") 2073 } 2074 } 2075 2076 func TestContext2Plan_orphan(t *testing.T) { 2077 m := testModule(t, "plan-orphan") 2078 p := testProvider("aws") 2079 p.DiffFn = testDiffFn 2080 s := &State{ 2081 Modules: []*ModuleState{ 2082 &ModuleState{ 2083 Path: rootModulePath, 2084 Resources: map[string]*ResourceState{ 2085 "aws_instance.baz": &ResourceState{ 2086 Type: "aws_instance", 2087 Primary: &InstanceState{ 2088 ID: "bar", 2089 }, 2090 }, 2091 }, 2092 }, 2093 }, 2094 } 2095 ctx := testContext2(t, &ContextOpts{ 2096 Module: m, 2097 Providers: map[string]ResourceProviderFactory{ 2098 "aws": testProviderFuncFixed(p), 2099 }, 2100 State: s, 2101 }) 2102 2103 plan, err := ctx.Plan() 2104 if err != nil { 2105 t.Fatalf("err: %s", err) 2106 } 2107 2108 actual := strings.TrimSpace(plan.String()) 2109 expected := strings.TrimSpace(testTerraformPlanOrphanStr) 2110 if actual != expected { 2111 t.Fatalf("bad:\n%s", actual) 2112 } 2113 } 2114 2115 // This tests that configurations with UUIDs don't produce errors. 2116 // For shadows, this would produce errors since a UUID changes every time. 2117 func TestContext2Plan_shadowUuid(t *testing.T) { 2118 m := testModule(t, "plan-shadow-uuid") 2119 p := testProvider("aws") 2120 p.DiffFn = testDiffFn 2121 ctx := testContext2(t, &ContextOpts{ 2122 Module: m, 2123 Providers: map[string]ResourceProviderFactory{ 2124 "aws": testProviderFuncFixed(p), 2125 }, 2126 }) 2127 2128 _, err := ctx.Plan() 2129 if err != nil { 2130 t.Fatalf("err: %s", err) 2131 } 2132 } 2133 2134 func TestContext2Plan_state(t *testing.T) { 2135 m := testModule(t, "plan-good") 2136 p := testProvider("aws") 2137 p.DiffFn = testDiffFn 2138 s := &State{ 2139 Modules: []*ModuleState{ 2140 &ModuleState{ 2141 Path: rootModulePath, 2142 Resources: map[string]*ResourceState{ 2143 "aws_instance.foo": &ResourceState{ 2144 Primary: &InstanceState{ 2145 ID: "bar", 2146 }, 2147 }, 2148 }, 2149 }, 2150 }, 2151 } 2152 ctx := testContext2(t, &ContextOpts{ 2153 Module: m, 2154 Providers: map[string]ResourceProviderFactory{ 2155 "aws": testProviderFuncFixed(p), 2156 }, 2157 State: s, 2158 }) 2159 2160 plan, err := ctx.Plan() 2161 if err != nil { 2162 t.Fatalf("err: %s", err) 2163 } 2164 2165 if len(plan.Diff.RootModule().Resources) < 2 { 2166 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 2167 } 2168 2169 actual := strings.TrimSpace(plan.String()) 2170 expected := strings.TrimSpace(testTerraformPlanStateStr) 2171 if actual != expected { 2172 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 2173 } 2174 } 2175 2176 func TestContext2Plan_taint(t *testing.T) { 2177 m := testModule(t, "plan-taint") 2178 p := testProvider("aws") 2179 p.DiffFn = testDiffFn 2180 s := &State{ 2181 Modules: []*ModuleState{ 2182 &ModuleState{ 2183 Path: rootModulePath, 2184 Resources: map[string]*ResourceState{ 2185 "aws_instance.foo": &ResourceState{ 2186 Type: "aws_instance", 2187 Primary: &InstanceState{ 2188 ID: "bar", 2189 Attributes: map[string]string{"num": "2"}, 2190 }, 2191 }, 2192 "aws_instance.bar": &ResourceState{ 2193 Type: "aws_instance", 2194 Primary: &InstanceState{ 2195 ID: "baz", 2196 Tainted: true, 2197 }, 2198 }, 2199 }, 2200 }, 2201 }, 2202 } 2203 ctx := testContext2(t, &ContextOpts{ 2204 Module: m, 2205 Providers: map[string]ResourceProviderFactory{ 2206 "aws": testProviderFuncFixed(p), 2207 }, 2208 State: s, 2209 }) 2210 2211 plan, err := ctx.Plan() 2212 if err != nil { 2213 t.Fatalf("err: %s", err) 2214 } 2215 2216 actual := strings.TrimSpace(plan.String()) 2217 expected := strings.TrimSpace(testTerraformPlanTaintStr) 2218 if actual != expected { 2219 t.Fatalf("bad:\n%s", actual) 2220 } 2221 } 2222 2223 func TestContext2Apply_taintIgnoreChanges(t *testing.T) { 2224 m := testModule(t, "plan-taint-ignore-changes") 2225 p := testProvider("aws") 2226 p.ApplyFn = testApplyFn 2227 p.DiffFn = testDiffFn 2228 s := &State{ 2229 Modules: []*ModuleState{ 2230 &ModuleState{ 2231 Path: rootModulePath, 2232 Resources: map[string]*ResourceState{ 2233 "aws_instance.foo": &ResourceState{ 2234 Type: "aws_instance", 2235 Primary: &InstanceState{ 2236 ID: "foo", 2237 Attributes: map[string]string{ 2238 "vars": "foo", 2239 "type": "aws_instance", 2240 }, 2241 Tainted: true, 2242 }, 2243 }, 2244 }, 2245 }, 2246 }, 2247 } 2248 ctx := testContext2(t, &ContextOpts{ 2249 Module: m, 2250 Providers: map[string]ResourceProviderFactory{ 2251 "aws": testProviderFuncFixed(p), 2252 }, 2253 State: s, 2254 }) 2255 2256 plan, err := ctx.Plan() 2257 if err != nil { 2258 t.Fatalf("err: %s", err) 2259 } 2260 2261 actual := strings.TrimSpace(plan.String()) 2262 expected := strings.TrimSpace(testTerraformPlanTaintIgnoreChangesStr) 2263 if actual != expected { 2264 t.Fatalf("bad:\n%s", actual) 2265 } 2266 } 2267 2268 // Fails about 50% of the time before the fix for GH-4982, covers the fix. 2269 func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) { 2270 m := testModule(t, "plan-taint-interpolated-count") 2271 p := testProvider("aws") 2272 p.DiffFn = testDiffFn 2273 s := &State{ 2274 Modules: []*ModuleState{ 2275 &ModuleState{ 2276 Path: rootModulePath, 2277 Resources: map[string]*ResourceState{ 2278 "aws_instance.foo.0": &ResourceState{ 2279 Type: "aws_instance", 2280 Primary: &InstanceState{ 2281 ID: "bar", 2282 Tainted: true, 2283 }, 2284 }, 2285 "aws_instance.foo.1": &ResourceState{ 2286 Type: "aws_instance", 2287 Primary: &InstanceState{ID: "bar"}, 2288 }, 2289 "aws_instance.foo.2": &ResourceState{ 2290 Type: "aws_instance", 2291 Primary: &InstanceState{ID: "bar"}, 2292 }, 2293 }, 2294 }, 2295 }, 2296 } 2297 ctx := testContext2(t, &ContextOpts{ 2298 Module: m, 2299 Providers: map[string]ResourceProviderFactory{ 2300 "aws": testProviderFuncFixed(p), 2301 }, 2302 State: s, 2303 }) 2304 2305 for i := 0; i < 100; i++ { 2306 plan, err := ctx.Plan() 2307 if err != nil { 2308 t.Fatalf("err: %s", err) 2309 } 2310 2311 actual := strings.TrimSpace(plan.String()) 2312 expected := strings.TrimSpace(` 2313 DIFF: 2314 2315 DESTROY/CREATE: aws_instance.foo.0 2316 type: "" => "aws_instance" 2317 2318 STATE: 2319 2320 aws_instance.foo.0: (tainted) 2321 ID = bar 2322 aws_instance.foo.1: 2323 ID = bar 2324 aws_instance.foo.2: 2325 ID = bar 2326 `) 2327 if actual != expected { 2328 t.Fatalf("[%d] bad:\n%s\nexpected:\n%s\n", i, actual, expected) 2329 } 2330 } 2331 } 2332 2333 func TestContext2Plan_targeted(t *testing.T) { 2334 m := testModule(t, "plan-targeted") 2335 p := testProvider("aws") 2336 p.DiffFn = testDiffFn 2337 ctx := testContext2(t, &ContextOpts{ 2338 Module: m, 2339 Providers: map[string]ResourceProviderFactory{ 2340 "aws": testProviderFuncFixed(p), 2341 }, 2342 Targets: []string{"aws_instance.foo"}, 2343 }) 2344 2345 plan, err := ctx.Plan() 2346 if err != nil { 2347 t.Fatalf("err: %s", err) 2348 } 2349 2350 actual := strings.TrimSpace(plan.String()) 2351 expected := strings.TrimSpace(` 2352 DIFF: 2353 2354 CREATE: aws_instance.foo 2355 num: "" => "2" 2356 type: "" => "aws_instance" 2357 2358 STATE: 2359 2360 <no state> 2361 `) 2362 if actual != expected { 2363 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2364 } 2365 } 2366 2367 // Test that targeting a module properly plans any inputs that depend 2368 // on another module. 2369 func TestContext2Plan_targetedCrossModule(t *testing.T) { 2370 m := testModule(t, "plan-targeted-cross-module") 2371 p := testProvider("aws") 2372 p.DiffFn = testDiffFn 2373 ctx := testContext2(t, &ContextOpts{ 2374 Module: m, 2375 Providers: map[string]ResourceProviderFactory{ 2376 "aws": testProviderFuncFixed(p), 2377 }, 2378 Targets: []string{"module.B"}, 2379 }) 2380 2381 plan, err := ctx.Plan() 2382 if err != nil { 2383 t.Fatalf("err: %s", err) 2384 } 2385 2386 actual := strings.TrimSpace(plan.String()) 2387 expected := strings.TrimSpace(` 2388 DIFF: 2389 2390 module.A: 2391 CREATE: aws_instance.foo 2392 foo: "" => "bar" 2393 type: "" => "aws_instance" 2394 module.B: 2395 CREATE: aws_instance.bar 2396 foo: "" => "<computed>" 2397 type: "" => "aws_instance" 2398 2399 STATE: 2400 2401 <no state> 2402 `) 2403 if actual != expected { 2404 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2405 } 2406 } 2407 2408 func TestContext2Plan_targetedOrphan(t *testing.T) { 2409 m := testModule(t, "plan-targeted-orphan") 2410 p := testProvider("aws") 2411 p.DiffFn = testDiffFn 2412 ctx := testContext2(t, &ContextOpts{ 2413 Module: m, 2414 Providers: map[string]ResourceProviderFactory{ 2415 "aws": testProviderFuncFixed(p), 2416 }, 2417 State: &State{ 2418 Modules: []*ModuleState{ 2419 &ModuleState{ 2420 Path: rootModulePath, 2421 Resources: map[string]*ResourceState{ 2422 "aws_instance.orphan": &ResourceState{ 2423 Type: "aws_instance", 2424 Primary: &InstanceState{ 2425 ID: "i-789xyz", 2426 }, 2427 }, 2428 "aws_instance.nottargeted": &ResourceState{ 2429 Type: "aws_instance", 2430 Primary: &InstanceState{ 2431 ID: "i-abc123", 2432 }, 2433 }, 2434 }, 2435 }, 2436 }, 2437 }, 2438 Destroy: true, 2439 Targets: []string{"aws_instance.orphan"}, 2440 }) 2441 2442 plan, err := ctx.Plan() 2443 if err != nil { 2444 t.Fatalf("err: %s", err) 2445 } 2446 2447 actual := strings.TrimSpace(plan.String()) 2448 expected := strings.TrimSpace(`DIFF: 2449 2450 DESTROY: aws_instance.orphan 2451 2452 STATE: 2453 2454 aws_instance.nottargeted: 2455 ID = i-abc123 2456 aws_instance.orphan: 2457 ID = i-789xyz 2458 `) 2459 if actual != expected { 2460 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2461 } 2462 } 2463 2464 // https://github.com/hashicorp/terraform/issues/2538 2465 func TestContext2Plan_targetedModuleOrphan(t *testing.T) { 2466 m := testModule(t, "plan-targeted-module-orphan") 2467 p := testProvider("aws") 2468 p.DiffFn = testDiffFn 2469 ctx := testContext2(t, &ContextOpts{ 2470 Module: m, 2471 Providers: map[string]ResourceProviderFactory{ 2472 "aws": testProviderFuncFixed(p), 2473 }, 2474 State: &State{ 2475 Modules: []*ModuleState{ 2476 &ModuleState{ 2477 Path: []string{"root", "child"}, 2478 Resources: map[string]*ResourceState{ 2479 "aws_instance.orphan": &ResourceState{ 2480 Type: "aws_instance", 2481 Primary: &InstanceState{ 2482 ID: "i-789xyz", 2483 }, 2484 }, 2485 "aws_instance.nottargeted": &ResourceState{ 2486 Type: "aws_instance", 2487 Primary: &InstanceState{ 2488 ID: "i-abc123", 2489 }, 2490 }, 2491 }, 2492 }, 2493 }, 2494 }, 2495 Destroy: true, 2496 Targets: []string{"module.child.aws_instance.orphan"}, 2497 }) 2498 2499 plan, err := ctx.Plan() 2500 if err != nil { 2501 t.Fatalf("err: %s", err) 2502 } 2503 2504 actual := strings.TrimSpace(plan.String()) 2505 expected := strings.TrimSpace(`DIFF: 2506 2507 module.child: 2508 DESTROY: aws_instance.orphan 2509 2510 STATE: 2511 2512 module.child: 2513 aws_instance.nottargeted: 2514 ID = i-abc123 2515 aws_instance.orphan: 2516 ID = i-789xyz 2517 `) 2518 if actual != expected { 2519 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2520 } 2521 } 2522 2523 func TestContext2Plan_targetedModuleUntargetedVariable(t *testing.T) { 2524 m := testModule(t, "plan-targeted-module-untargeted-variable") 2525 p := testProvider("aws") 2526 p.DiffFn = testDiffFn 2527 ctx := testContext2(t, &ContextOpts{ 2528 Module: m, 2529 Providers: map[string]ResourceProviderFactory{ 2530 "aws": testProviderFuncFixed(p), 2531 }, 2532 Targets: []string{"aws_instance.blue", "module.blue_mod"}, 2533 }) 2534 2535 plan, err := ctx.Plan() 2536 if err != nil { 2537 t.Fatalf("err: %s", err) 2538 } 2539 2540 actual := strings.TrimSpace(plan.String()) 2541 expected := strings.TrimSpace(` 2542 DIFF: 2543 2544 CREATE: aws_instance.blue 2545 2546 module.blue_mod: 2547 CREATE: aws_instance.mod 2548 type: "" => "aws_instance" 2549 value: "" => "<computed>" 2550 2551 STATE: 2552 2553 <no state> 2554 `) 2555 if actual != expected { 2556 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2557 } 2558 } 2559 2560 // https://github.com/hashicorp/terraform/issues/4515 2561 func TestContext2Plan_targetedOverTen(t *testing.T) { 2562 m := testModule(t, "plan-targeted-over-ten") 2563 p := testProvider("aws") 2564 p.DiffFn = testDiffFn 2565 2566 resources := make(map[string]*ResourceState) 2567 var expectedState []string 2568 for i := 0; i < 13; i++ { 2569 key := fmt.Sprintf("aws_instance.foo.%d", i) 2570 id := fmt.Sprintf("i-abc%d", i) 2571 resources[key] = &ResourceState{ 2572 Type: "aws_instance", 2573 Primary: &InstanceState{ID: id}, 2574 } 2575 expectedState = append(expectedState, 2576 fmt.Sprintf("%s:\n ID = %s\n", key, id)) 2577 } 2578 ctx := testContext2(t, &ContextOpts{ 2579 Module: m, 2580 Providers: map[string]ResourceProviderFactory{ 2581 "aws": testProviderFuncFixed(p), 2582 }, 2583 State: &State{ 2584 Modules: []*ModuleState{ 2585 &ModuleState{ 2586 Path: rootModulePath, 2587 Resources: resources, 2588 }, 2589 }, 2590 }, 2591 Targets: []string{"aws_instance.foo[1]"}, 2592 }) 2593 2594 plan, err := ctx.Plan() 2595 if err != nil { 2596 t.Fatalf("err: %s", err) 2597 } 2598 2599 actual := strings.TrimSpace(plan.String()) 2600 sort.Strings(expectedState) 2601 expected := strings.TrimSpace(` 2602 DIFF: 2603 2604 2605 2606 STATE: 2607 2608 aws_instance.foo.0: 2609 ID = i-abc0 2610 aws_instance.foo.1: 2611 ID = i-abc1 2612 aws_instance.foo.10: 2613 ID = i-abc10 2614 aws_instance.foo.11: 2615 ID = i-abc11 2616 aws_instance.foo.12: 2617 ID = i-abc12 2618 aws_instance.foo.2: 2619 ID = i-abc2 2620 aws_instance.foo.3: 2621 ID = i-abc3 2622 aws_instance.foo.4: 2623 ID = i-abc4 2624 aws_instance.foo.5: 2625 ID = i-abc5 2626 aws_instance.foo.6: 2627 ID = i-abc6 2628 aws_instance.foo.7: 2629 ID = i-abc7 2630 aws_instance.foo.8: 2631 ID = i-abc8 2632 aws_instance.foo.9: 2633 ID = i-abc9 2634 `) 2635 if actual != expected { 2636 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2637 } 2638 } 2639 2640 func TestContext2Plan_provider(t *testing.T) { 2641 m := testModule(t, "plan-provider") 2642 p := testProvider("aws") 2643 p.DiffFn = testDiffFn 2644 2645 var value interface{} 2646 p.ConfigureFn = func(c *ResourceConfig) error { 2647 value, _ = c.Get("foo") 2648 return nil 2649 } 2650 2651 ctx := testContext2(t, &ContextOpts{ 2652 Module: m, 2653 Providers: map[string]ResourceProviderFactory{ 2654 "aws": testProviderFuncFixed(p), 2655 }, 2656 Variables: map[string]interface{}{ 2657 "foo": "bar", 2658 }, 2659 }) 2660 2661 if _, err := ctx.Plan(); err != nil { 2662 t.Fatalf("err: %s", err) 2663 } 2664 2665 if value != "bar" { 2666 t.Fatalf("bad: %#v", value) 2667 } 2668 } 2669 2670 func TestContext2Plan_varListErr(t *testing.T) { 2671 m := testModule(t, "plan-var-list-err") 2672 p := testProvider("aws") 2673 ctx := testContext2(t, &ContextOpts{ 2674 Module: m, 2675 Providers: map[string]ResourceProviderFactory{ 2676 "aws": testProviderFuncFixed(p), 2677 }, 2678 }) 2679 2680 _, err := ctx.Plan() 2681 2682 if err == nil { 2683 t.Fatal("should error") 2684 } 2685 } 2686 2687 func TestContext2Plan_ignoreChanges(t *testing.T) { 2688 m := testModule(t, "plan-ignore-changes") 2689 p := testProvider("aws") 2690 p.DiffFn = testDiffFn 2691 s := &State{ 2692 Modules: []*ModuleState{ 2693 &ModuleState{ 2694 Path: rootModulePath, 2695 Resources: map[string]*ResourceState{ 2696 "aws_instance.foo": &ResourceState{ 2697 Primary: &InstanceState{ 2698 ID: "bar", 2699 Attributes: map[string]string{"ami": "ami-abcd1234"}, 2700 }, 2701 }, 2702 }, 2703 }, 2704 }, 2705 } 2706 ctx := testContext2(t, &ContextOpts{ 2707 Module: m, 2708 Providers: map[string]ResourceProviderFactory{ 2709 "aws": testProviderFuncFixed(p), 2710 }, 2711 Variables: map[string]interface{}{ 2712 "foo": "ami-1234abcd", 2713 }, 2714 State: s, 2715 }) 2716 2717 plan, err := ctx.Plan() 2718 if err != nil { 2719 t.Fatalf("err: %s", err) 2720 } 2721 2722 if len(plan.Diff.RootModule().Resources) < 1 { 2723 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 2724 } 2725 2726 actual := strings.TrimSpace(plan.String()) 2727 expected := strings.TrimSpace(testTerraformPlanIgnoreChangesStr) 2728 if actual != expected { 2729 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 2730 } 2731 } 2732 2733 func TestContext2Plan_ignoreChangesWildcard(t *testing.T) { 2734 m := testModule(t, "plan-ignore-changes-wildcard") 2735 p := testProvider("aws") 2736 p.DiffFn = testDiffFn 2737 s := &State{ 2738 Modules: []*ModuleState{ 2739 &ModuleState{ 2740 Path: rootModulePath, 2741 Resources: map[string]*ResourceState{ 2742 "aws_instance.foo": &ResourceState{ 2743 Primary: &InstanceState{ 2744 ID: "bar", 2745 Attributes: map[string]string{ 2746 "ami": "ami-abcd1234", 2747 "instance_type": "t2.micro", 2748 }, 2749 }, 2750 }, 2751 }, 2752 }, 2753 }, 2754 } 2755 ctx := testContext2(t, &ContextOpts{ 2756 Module: m, 2757 Providers: map[string]ResourceProviderFactory{ 2758 "aws": testProviderFuncFixed(p), 2759 }, 2760 Variables: map[string]interface{}{ 2761 "foo": "ami-1234abcd", 2762 "bar": "t2.small", 2763 }, 2764 State: s, 2765 }) 2766 2767 plan, err := ctx.Plan() 2768 if err != nil { 2769 t.Fatalf("err: %s", err) 2770 } 2771 2772 if len(plan.Diff.RootModule().Resources) > 0 { 2773 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 2774 } 2775 2776 actual := strings.TrimSpace(plan.String()) 2777 expected := strings.TrimSpace(testTerraformPlanIgnoreChangesWildcardStr) 2778 if actual != expected { 2779 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 2780 } 2781 } 2782 2783 func TestContext2Plan_moduleMapLiteral(t *testing.T) { 2784 m := testModule(t, "plan-module-map-literal") 2785 p := testProvider("aws") 2786 p.ApplyFn = testApplyFn 2787 p.DiffFn = func(i *InstanceInfo, s *InstanceState, c *ResourceConfig) (*InstanceDiff, error) { 2788 // Here we verify that both the populated and empty map literals made it 2789 // through to the resource attributes 2790 val, _ := c.Get("tags") 2791 m, ok := val.(map[string]interface{}) 2792 if !ok { 2793 t.Fatalf("Tags attr not map: %#v", val) 2794 } 2795 if m["foo"] != "bar" { 2796 t.Fatalf("Bad value in tags attr: %#v", m) 2797 } 2798 { 2799 val, _ := c.Get("meta") 2800 m, ok := val.(map[string]interface{}) 2801 if !ok { 2802 t.Fatalf("Meta attr not map: %#v", val) 2803 } 2804 if len(m) != 0 { 2805 t.Fatalf("Meta attr not empty: %#v", val) 2806 } 2807 } 2808 return nil, nil 2809 } 2810 ctx := testContext2(t, &ContextOpts{ 2811 Module: m, 2812 Providers: map[string]ResourceProviderFactory{ 2813 "aws": testProviderFuncFixed(p), 2814 }, 2815 }) 2816 2817 if _, err := ctx.Plan(); err != nil { 2818 t.Fatalf("err: %s", err) 2819 } 2820 } 2821 2822 func TestContext2Plan_computedValueInMap(t *testing.T) { 2823 m := testModule(t, "plan-computed-value-in-map") 2824 p := testProvider("aws") 2825 p.DiffFn = func(info *InstanceInfo, state *InstanceState, c *ResourceConfig) (*InstanceDiff, error) { 2826 switch info.Type { 2827 case "aws_computed_source": 2828 return &InstanceDiff{ 2829 Attributes: map[string]*ResourceAttrDiff{ 2830 "computed_read_only": &ResourceAttrDiff{ 2831 NewComputed: true, 2832 }, 2833 }, 2834 }, nil 2835 } 2836 2837 return testDiffFn(info, state, c) 2838 } 2839 ctx := testContext2(t, &ContextOpts{ 2840 Module: m, 2841 Providers: map[string]ResourceProviderFactory{ 2842 "aws": testProviderFuncFixed(p), 2843 }, 2844 }) 2845 2846 if _, err := ctx.Plan(); err != nil { 2847 t.Fatalf("err: %s", err) 2848 } 2849 2850 plan, err := ctx.Plan() 2851 if err != nil { 2852 t.Fatalf("err: %s", err) 2853 } 2854 2855 actual := strings.TrimSpace(plan.String()) 2856 expected := strings.TrimSpace(testTerraformPlanComputedValueInMap) 2857 if actual != expected { 2858 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 2859 } 2860 } 2861 2862 func TestContext2Plan_moduleVariableFromSplat(t *testing.T) { 2863 m := testModule(t, "plan-module-variable-from-splat") 2864 p := testProvider("aws") 2865 p.DiffFn = testDiffFn 2866 ctx := testContext2(t, &ContextOpts{ 2867 Module: m, 2868 Providers: map[string]ResourceProviderFactory{ 2869 "aws": testProviderFuncFixed(p), 2870 }, 2871 }) 2872 2873 if _, err := ctx.Plan(); err != nil { 2874 t.Fatalf("err: %s", err) 2875 } 2876 2877 plan, err := ctx.Plan() 2878 if err != nil { 2879 t.Fatalf("err: %s", err) 2880 } 2881 2882 actual := strings.TrimSpace(plan.String()) 2883 expected := strings.TrimSpace(testTerraformPlanModuleVariableFromSplat) 2884 if actual != expected { 2885 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 2886 } 2887 } 2888 2889 func TestContext2Plan_createBeforeDestroy_depends_datasource(t *testing.T) { 2890 m := testModule(t, "plan-cdb-depends-datasource") 2891 p := testProvider("aws") 2892 p.DiffFn = testDiffFn 2893 ctx := testContext2(t, &ContextOpts{ 2894 Module: m, 2895 Providers: map[string]ResourceProviderFactory{ 2896 "aws": testProviderFuncFixed(p), 2897 }, 2898 }) 2899 2900 plan, err := ctx.Plan() 2901 if err != nil { 2902 t.Fatalf("err: %s", err) 2903 } 2904 2905 if got := len(plan.Diff.Modules); got != 1 { 2906 t.Fatalf("got %d modules; want 1", got) 2907 } 2908 2909 moduleDiff := plan.Diff.Modules[0] 2910 2911 if _, ok := moduleDiff.Resources["aws_instance.foo.0"]; !ok { 2912 t.Fatalf("missing diff for aws_instance.foo.0") 2913 } 2914 if _, ok := moduleDiff.Resources["aws_instance.foo.1"]; !ok { 2915 t.Fatalf("missing diff for aws_instance.foo.1") 2916 } 2917 if _, ok := moduleDiff.Resources["data.aws_vpc.bar.0"]; !ok { 2918 t.Fatalf("missing diff for data.aws_vpc.bar.0") 2919 } 2920 if _, ok := moduleDiff.Resources["data.aws_vpc.bar.1"]; !ok { 2921 t.Fatalf("missing diff for data.aws_vpc.bar.1") 2922 } 2923 } 2924 2925 // interpolated lists need to be stored in the original order. 2926 func TestContext2Plan_listOrder(t *testing.T) { 2927 m := testModule(t, "plan-list-order") 2928 p := testProvider("aws") 2929 p.ApplyFn = testApplyFn 2930 p.DiffFn = testDiffFn 2931 ctx := testContext2(t, &ContextOpts{ 2932 Module: m, 2933 Providers: map[string]ResourceProviderFactory{ 2934 "aws": testProviderFuncFixed(p), 2935 }, 2936 }) 2937 2938 plan, err := ctx.Plan() 2939 if err != nil { 2940 t.Fatalf("err: %s", err) 2941 } 2942 2943 rDiffs := plan.Diff.Modules[0].Resources 2944 rDiffA := rDiffs["aws_instance.a"] 2945 rDiffB := rDiffs["aws_instance.b"] 2946 2947 if !rDiffA.Equal(rDiffB) { 2948 t.Fatal("aws_instance.a and aws_instance.b diffs should match:\n", plan) 2949 } 2950 }