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