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