github.com/archgrove/terraform@v0.9.5-0.20170502093151-adb789f0f8d2/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 func TestContext2Plan_destroy(t *testing.T) { 1875 m := testModule(t, "plan-destroy") 1876 p := testProvider("aws") 1877 p.DiffFn = testDiffFn 1878 s := &State{ 1879 Modules: []*ModuleState{ 1880 &ModuleState{ 1881 Path: rootModulePath, 1882 Resources: map[string]*ResourceState{ 1883 "aws_instance.one": &ResourceState{ 1884 Type: "aws_instance", 1885 Primary: &InstanceState{ 1886 ID: "bar", 1887 }, 1888 }, 1889 "aws_instance.two": &ResourceState{ 1890 Type: "aws_instance", 1891 Primary: &InstanceState{ 1892 ID: "baz", 1893 }, 1894 }, 1895 }, 1896 }, 1897 }, 1898 } 1899 ctx := testContext2(t, &ContextOpts{ 1900 Module: m, 1901 Providers: map[string]ResourceProviderFactory{ 1902 "aws": testProviderFuncFixed(p), 1903 }, 1904 State: s, 1905 Destroy: true, 1906 }) 1907 1908 plan, err := ctx.Plan() 1909 if err != nil { 1910 t.Fatalf("err: %s", err) 1911 } 1912 1913 if len(plan.Diff.RootModule().Resources) != 2 { 1914 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 1915 } 1916 1917 actual := strings.TrimSpace(plan.String()) 1918 expected := strings.TrimSpace(testTerraformPlanDestroyStr) 1919 if actual != expected { 1920 t.Fatalf("bad:\n%s", actual) 1921 } 1922 } 1923 1924 func TestContext2Plan_moduleDestroy(t *testing.T) { 1925 m := testModule(t, "plan-module-destroy") 1926 p := testProvider("aws") 1927 p.DiffFn = testDiffFn 1928 s := &State{ 1929 Modules: []*ModuleState{ 1930 &ModuleState{ 1931 Path: rootModulePath, 1932 Resources: map[string]*ResourceState{ 1933 "aws_instance.foo": &ResourceState{ 1934 Type: "aws_instance", 1935 Primary: &InstanceState{ 1936 ID: "bar", 1937 }, 1938 }, 1939 }, 1940 }, 1941 &ModuleState{ 1942 Path: []string{"root", "child"}, 1943 Resources: map[string]*ResourceState{ 1944 "aws_instance.foo": &ResourceState{ 1945 Type: "aws_instance", 1946 Primary: &InstanceState{ 1947 ID: "bar", 1948 }, 1949 }, 1950 }, 1951 }, 1952 }, 1953 } 1954 ctx := testContext2(t, &ContextOpts{ 1955 Module: m, 1956 Providers: map[string]ResourceProviderFactory{ 1957 "aws": testProviderFuncFixed(p), 1958 }, 1959 State: s, 1960 Destroy: true, 1961 }) 1962 1963 plan, err := ctx.Plan() 1964 if err != nil { 1965 t.Fatalf("err: %s", err) 1966 } 1967 1968 actual := strings.TrimSpace(plan.String()) 1969 expected := strings.TrimSpace(testTerraformPlanModuleDestroyStr) 1970 if actual != expected { 1971 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 1972 } 1973 } 1974 1975 // GH-1835 1976 func TestContext2Plan_moduleDestroyCycle(t *testing.T) { 1977 m := testModule(t, "plan-module-destroy-gh-1835") 1978 p := testProvider("aws") 1979 p.DiffFn = testDiffFn 1980 s := &State{ 1981 Modules: []*ModuleState{ 1982 &ModuleState{ 1983 Path: []string{"root", "a_module"}, 1984 Resources: map[string]*ResourceState{ 1985 "aws_instance.a": &ResourceState{ 1986 Type: "aws_instance", 1987 Primary: &InstanceState{ 1988 ID: "a", 1989 }, 1990 }, 1991 }, 1992 }, 1993 &ModuleState{ 1994 Path: []string{"root", "b_module"}, 1995 Resources: map[string]*ResourceState{ 1996 "aws_instance.b": &ResourceState{ 1997 Type: "aws_instance", 1998 Primary: &InstanceState{ 1999 ID: "b", 2000 }, 2001 }, 2002 }, 2003 }, 2004 }, 2005 } 2006 ctx := testContext2(t, &ContextOpts{ 2007 Module: m, 2008 Providers: map[string]ResourceProviderFactory{ 2009 "aws": testProviderFuncFixed(p), 2010 }, 2011 State: s, 2012 Destroy: true, 2013 }) 2014 2015 plan, err := ctx.Plan() 2016 if err != nil { 2017 t.Fatalf("err: %s", err) 2018 } 2019 2020 actual := strings.TrimSpace(plan.String()) 2021 expected := strings.TrimSpace(testTerraformPlanModuleDestroyCycleStr) 2022 if actual != expected { 2023 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 2024 } 2025 } 2026 2027 func TestContext2Plan_moduleDestroyMultivar(t *testing.T) { 2028 m := testModule(t, "plan-module-destroy-multivar") 2029 p := testProvider("aws") 2030 p.DiffFn = testDiffFn 2031 s := &State{ 2032 Modules: []*ModuleState{ 2033 &ModuleState{ 2034 Path: rootModulePath, 2035 Resources: map[string]*ResourceState{}, 2036 }, 2037 &ModuleState{ 2038 Path: []string{"root", "child"}, 2039 Resources: map[string]*ResourceState{ 2040 "aws_instance.foo.0": &ResourceState{ 2041 Type: "aws_instance", 2042 Primary: &InstanceState{ 2043 ID: "bar0", 2044 }, 2045 }, 2046 "aws_instance.foo.1": &ResourceState{ 2047 Type: "aws_instance", 2048 Primary: &InstanceState{ 2049 ID: "bar1", 2050 }, 2051 }, 2052 }, 2053 }, 2054 }, 2055 } 2056 ctx := testContext2(t, &ContextOpts{ 2057 Module: m, 2058 Providers: map[string]ResourceProviderFactory{ 2059 "aws": testProviderFuncFixed(p), 2060 }, 2061 State: s, 2062 Destroy: true, 2063 }) 2064 2065 plan, err := ctx.Plan() 2066 if err != nil { 2067 t.Fatalf("err: %s", err) 2068 } 2069 2070 actual := strings.TrimSpace(plan.String()) 2071 expected := strings.TrimSpace(testTerraformPlanModuleDestroyMultivarStr) 2072 if actual != expected { 2073 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 2074 } 2075 } 2076 2077 func TestContext2Plan_pathVar(t *testing.T) { 2078 cwd, err := os.Getwd() 2079 if err != nil { 2080 t.Fatalf("err: %s", err) 2081 } 2082 2083 m := testModule(t, "plan-path-var") 2084 p := testProvider("aws") 2085 p.DiffFn = testDiffFn 2086 ctx := testContext2(t, &ContextOpts{ 2087 Module: m, 2088 Providers: map[string]ResourceProviderFactory{ 2089 "aws": testProviderFuncFixed(p), 2090 }, 2091 }) 2092 2093 plan, err := ctx.Plan() 2094 if err != nil { 2095 t.Fatalf("err: %s", err) 2096 } 2097 2098 actual := strings.TrimSpace(plan.String()) 2099 expected := strings.TrimSpace(testTerraformPlanPathVarStr) 2100 2101 // Warning: this ordering REALLY matters for this test. The 2102 // order is: cwd, module, root. 2103 expected = fmt.Sprintf( 2104 expected, 2105 cwd, 2106 m.Config().Dir, 2107 m.Config().Dir) 2108 2109 if actual != expected { 2110 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 2111 } 2112 } 2113 2114 func TestContext2Plan_diffVar(t *testing.T) { 2115 m := testModule(t, "plan-diffvar") 2116 p := testProvider("aws") 2117 s := &State{ 2118 Modules: []*ModuleState{ 2119 &ModuleState{ 2120 Path: rootModulePath, 2121 Resources: map[string]*ResourceState{ 2122 "aws_instance.foo": &ResourceState{ 2123 Primary: &InstanceState{ 2124 ID: "bar", 2125 Attributes: map[string]string{ 2126 "num": "2", 2127 }, 2128 }, 2129 }, 2130 }, 2131 }, 2132 }, 2133 } 2134 ctx := testContext2(t, &ContextOpts{ 2135 Module: m, 2136 Providers: map[string]ResourceProviderFactory{ 2137 "aws": testProviderFuncFixed(p), 2138 }, 2139 State: s, 2140 }) 2141 2142 p.DiffFn = func( 2143 info *InstanceInfo, 2144 s *InstanceState, 2145 c *ResourceConfig) (*InstanceDiff, error) { 2146 if s.ID != "bar" { 2147 return testDiffFn(info, s, c) 2148 } 2149 2150 return &InstanceDiff{ 2151 Attributes: map[string]*ResourceAttrDiff{ 2152 "num": &ResourceAttrDiff{ 2153 Old: "2", 2154 New: "3", 2155 }, 2156 }, 2157 }, nil 2158 } 2159 2160 plan, err := ctx.Plan() 2161 if err != nil { 2162 t.Fatalf("err: %s", err) 2163 } 2164 2165 actual := strings.TrimSpace(plan.String()) 2166 expected := strings.TrimSpace(testTerraformPlanDiffVarStr) 2167 if actual != expected { 2168 t.Fatalf("actual:\n%s\n\nexpected:\n%s", actual, expected) 2169 } 2170 } 2171 2172 func TestContext2Plan_hook(t *testing.T) { 2173 m := testModule(t, "plan-good") 2174 h := new(MockHook) 2175 p := testProvider("aws") 2176 p.DiffFn = testDiffFn 2177 ctx := testContext2(t, &ContextOpts{ 2178 Module: m, 2179 Hooks: []Hook{h}, 2180 Providers: map[string]ResourceProviderFactory{ 2181 "aws": testProviderFuncFixed(p), 2182 }, 2183 }) 2184 2185 _, err := ctx.Plan() 2186 if err != nil { 2187 t.Fatalf("err: %s", err) 2188 } 2189 2190 if !h.PreDiffCalled { 2191 t.Fatal("should be called") 2192 } 2193 if !h.PostDiffCalled { 2194 t.Fatal("should be called") 2195 } 2196 } 2197 2198 func TestContext2Plan_orphan(t *testing.T) { 2199 m := testModule(t, "plan-orphan") 2200 p := testProvider("aws") 2201 p.DiffFn = testDiffFn 2202 s := &State{ 2203 Modules: []*ModuleState{ 2204 &ModuleState{ 2205 Path: rootModulePath, 2206 Resources: map[string]*ResourceState{ 2207 "aws_instance.baz": &ResourceState{ 2208 Type: "aws_instance", 2209 Primary: &InstanceState{ 2210 ID: "bar", 2211 }, 2212 }, 2213 }, 2214 }, 2215 }, 2216 } 2217 ctx := testContext2(t, &ContextOpts{ 2218 Module: m, 2219 Providers: map[string]ResourceProviderFactory{ 2220 "aws": testProviderFuncFixed(p), 2221 }, 2222 State: s, 2223 }) 2224 2225 plan, err := ctx.Plan() 2226 if err != nil { 2227 t.Fatalf("err: %s", err) 2228 } 2229 2230 actual := strings.TrimSpace(plan.String()) 2231 expected := strings.TrimSpace(testTerraformPlanOrphanStr) 2232 if actual != expected { 2233 t.Fatalf("bad:\n%s", actual) 2234 } 2235 } 2236 2237 // This tests that configurations with UUIDs don't produce errors. 2238 // For shadows, this would produce errors since a UUID changes every time. 2239 func TestContext2Plan_shadowUuid(t *testing.T) { 2240 m := testModule(t, "plan-shadow-uuid") 2241 p := testProvider("aws") 2242 p.DiffFn = testDiffFn 2243 ctx := testContext2(t, &ContextOpts{ 2244 Module: m, 2245 Providers: map[string]ResourceProviderFactory{ 2246 "aws": testProviderFuncFixed(p), 2247 }, 2248 }) 2249 2250 _, err := ctx.Plan() 2251 if err != nil { 2252 t.Fatalf("err: %s", err) 2253 } 2254 } 2255 2256 func TestContext2Plan_state(t *testing.T) { 2257 m := testModule(t, "plan-good") 2258 p := testProvider("aws") 2259 p.DiffFn = testDiffFn 2260 s := &State{ 2261 Modules: []*ModuleState{ 2262 &ModuleState{ 2263 Path: rootModulePath, 2264 Resources: map[string]*ResourceState{ 2265 "aws_instance.foo": &ResourceState{ 2266 Primary: &InstanceState{ 2267 ID: "bar", 2268 }, 2269 }, 2270 }, 2271 }, 2272 }, 2273 } 2274 ctx := testContext2(t, &ContextOpts{ 2275 Module: m, 2276 Providers: map[string]ResourceProviderFactory{ 2277 "aws": testProviderFuncFixed(p), 2278 }, 2279 State: s, 2280 }) 2281 2282 plan, err := ctx.Plan() 2283 if err != nil { 2284 t.Fatalf("err: %s", err) 2285 } 2286 2287 if len(plan.Diff.RootModule().Resources) < 2 { 2288 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 2289 } 2290 2291 actual := strings.TrimSpace(plan.String()) 2292 expected := strings.TrimSpace(testTerraformPlanStateStr) 2293 if actual != expected { 2294 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 2295 } 2296 } 2297 2298 func TestContext2Plan_taint(t *testing.T) { 2299 m := testModule(t, "plan-taint") 2300 p := testProvider("aws") 2301 p.DiffFn = testDiffFn 2302 s := &State{ 2303 Modules: []*ModuleState{ 2304 &ModuleState{ 2305 Path: rootModulePath, 2306 Resources: map[string]*ResourceState{ 2307 "aws_instance.foo": &ResourceState{ 2308 Type: "aws_instance", 2309 Primary: &InstanceState{ 2310 ID: "bar", 2311 Attributes: map[string]string{"num": "2"}, 2312 }, 2313 }, 2314 "aws_instance.bar": &ResourceState{ 2315 Type: "aws_instance", 2316 Primary: &InstanceState{ 2317 ID: "baz", 2318 Tainted: true, 2319 }, 2320 }, 2321 }, 2322 }, 2323 }, 2324 } 2325 ctx := testContext2(t, &ContextOpts{ 2326 Module: m, 2327 Providers: map[string]ResourceProviderFactory{ 2328 "aws": testProviderFuncFixed(p), 2329 }, 2330 State: s, 2331 }) 2332 2333 plan, err := ctx.Plan() 2334 if err != nil { 2335 t.Fatalf("err: %s", err) 2336 } 2337 2338 actual := strings.TrimSpace(plan.String()) 2339 expected := strings.TrimSpace(testTerraformPlanTaintStr) 2340 if actual != expected { 2341 t.Fatalf("bad:\n%s", actual) 2342 } 2343 } 2344 2345 func TestContext2Apply_taintIgnoreChanges(t *testing.T) { 2346 m := testModule(t, "plan-taint-ignore-changes") 2347 p := testProvider("aws") 2348 p.ApplyFn = testApplyFn 2349 p.DiffFn = testDiffFn 2350 s := &State{ 2351 Modules: []*ModuleState{ 2352 &ModuleState{ 2353 Path: rootModulePath, 2354 Resources: map[string]*ResourceState{ 2355 "aws_instance.foo": &ResourceState{ 2356 Type: "aws_instance", 2357 Primary: &InstanceState{ 2358 ID: "foo", 2359 Attributes: map[string]string{ 2360 "vars": "foo", 2361 "type": "aws_instance", 2362 }, 2363 Tainted: true, 2364 }, 2365 }, 2366 }, 2367 }, 2368 }, 2369 } 2370 ctx := testContext2(t, &ContextOpts{ 2371 Module: m, 2372 Providers: map[string]ResourceProviderFactory{ 2373 "aws": testProviderFuncFixed(p), 2374 }, 2375 State: s, 2376 }) 2377 2378 plan, err := ctx.Plan() 2379 if err != nil { 2380 t.Fatalf("err: %s", err) 2381 } 2382 2383 actual := strings.TrimSpace(plan.String()) 2384 expected := strings.TrimSpace(testTerraformPlanTaintIgnoreChangesStr) 2385 if actual != expected { 2386 t.Fatalf("bad:\n%s", actual) 2387 } 2388 } 2389 2390 // Fails about 50% of the time before the fix for GH-4982, covers the fix. 2391 func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) { 2392 m := testModule(t, "plan-taint-interpolated-count") 2393 p := testProvider("aws") 2394 p.DiffFn = testDiffFn 2395 s := &State{ 2396 Modules: []*ModuleState{ 2397 &ModuleState{ 2398 Path: rootModulePath, 2399 Resources: map[string]*ResourceState{ 2400 "aws_instance.foo.0": &ResourceState{ 2401 Type: "aws_instance", 2402 Primary: &InstanceState{ 2403 ID: "bar", 2404 Tainted: true, 2405 }, 2406 }, 2407 "aws_instance.foo.1": &ResourceState{ 2408 Type: "aws_instance", 2409 Primary: &InstanceState{ID: "bar"}, 2410 }, 2411 "aws_instance.foo.2": &ResourceState{ 2412 Type: "aws_instance", 2413 Primary: &InstanceState{ID: "bar"}, 2414 }, 2415 }, 2416 }, 2417 }, 2418 } 2419 ctx := testContext2(t, &ContextOpts{ 2420 Module: m, 2421 Providers: map[string]ResourceProviderFactory{ 2422 "aws": testProviderFuncFixed(p), 2423 }, 2424 State: s, 2425 }) 2426 2427 for i := 0; i < 100; i++ { 2428 plan, err := ctx.Plan() 2429 if err != nil { 2430 t.Fatalf("err: %s", err) 2431 } 2432 2433 actual := strings.TrimSpace(plan.String()) 2434 expected := strings.TrimSpace(` 2435 DIFF: 2436 2437 DESTROY/CREATE: aws_instance.foo.0 2438 type: "" => "aws_instance" 2439 2440 STATE: 2441 2442 aws_instance.foo.0: (tainted) 2443 ID = bar 2444 aws_instance.foo.1: 2445 ID = bar 2446 aws_instance.foo.2: 2447 ID = bar 2448 `) 2449 if actual != expected { 2450 t.Fatalf("[%d] bad:\n%s\nexpected:\n%s\n", i, actual, expected) 2451 } 2452 } 2453 } 2454 2455 func TestContext2Plan_targeted(t *testing.T) { 2456 m := testModule(t, "plan-targeted") 2457 p := testProvider("aws") 2458 p.DiffFn = testDiffFn 2459 ctx := testContext2(t, &ContextOpts{ 2460 Module: m, 2461 Providers: map[string]ResourceProviderFactory{ 2462 "aws": testProviderFuncFixed(p), 2463 }, 2464 Targets: []string{"aws_instance.foo"}, 2465 }) 2466 2467 plan, err := ctx.Plan() 2468 if err != nil { 2469 t.Fatalf("err: %s", err) 2470 } 2471 2472 actual := strings.TrimSpace(plan.String()) 2473 expected := strings.TrimSpace(` 2474 DIFF: 2475 2476 CREATE: aws_instance.foo 2477 num: "" => "2" 2478 type: "" => "aws_instance" 2479 2480 STATE: 2481 2482 <no state> 2483 `) 2484 if actual != expected { 2485 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2486 } 2487 } 2488 2489 // Test that targeting a module properly plans any inputs that depend 2490 // on another module. 2491 func TestContext2Plan_targetedCrossModule(t *testing.T) { 2492 m := testModule(t, "plan-targeted-cross-module") 2493 p := testProvider("aws") 2494 p.DiffFn = testDiffFn 2495 ctx := testContext2(t, &ContextOpts{ 2496 Module: m, 2497 Providers: map[string]ResourceProviderFactory{ 2498 "aws": testProviderFuncFixed(p), 2499 }, 2500 Targets: []string{"module.B"}, 2501 }) 2502 2503 plan, err := ctx.Plan() 2504 if err != nil { 2505 t.Fatalf("err: %s", err) 2506 } 2507 2508 actual := strings.TrimSpace(plan.String()) 2509 expected := strings.TrimSpace(` 2510 DIFF: 2511 2512 module.A: 2513 CREATE: aws_instance.foo 2514 foo: "" => "bar" 2515 type: "" => "aws_instance" 2516 module.B: 2517 CREATE: aws_instance.bar 2518 foo: "" => "<computed>" 2519 type: "" => "aws_instance" 2520 2521 STATE: 2522 2523 <no state> 2524 `) 2525 if actual != expected { 2526 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2527 } 2528 } 2529 2530 func TestContext2Plan_targetedModuleWithProvider(t *testing.T) { 2531 m := testModule(t, "plan-targeted-module-with-provider") 2532 p := testProvider("null") 2533 p.DiffFn = testDiffFn 2534 ctx := testContext2(t, &ContextOpts{ 2535 Module: m, 2536 Providers: map[string]ResourceProviderFactory{ 2537 "null": testProviderFuncFixed(p), 2538 }, 2539 Targets: []string{"module.child2"}, 2540 }) 2541 2542 plan, err := ctx.Plan() 2543 if err != nil { 2544 t.Fatalf("err: %s", err) 2545 } 2546 2547 actual := strings.TrimSpace(plan.String()) 2548 expected := strings.TrimSpace(` 2549 DIFF: 2550 2551 module.child2: 2552 CREATE: null_resource.foo 2553 2554 STATE: 2555 2556 <no state> 2557 `) 2558 if actual != expected { 2559 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2560 } 2561 } 2562 2563 func TestContext2Plan_targetedOrphan(t *testing.T) { 2564 m := testModule(t, "plan-targeted-orphan") 2565 p := testProvider("aws") 2566 p.DiffFn = testDiffFn 2567 ctx := testContext2(t, &ContextOpts{ 2568 Module: m, 2569 Providers: map[string]ResourceProviderFactory{ 2570 "aws": testProviderFuncFixed(p), 2571 }, 2572 State: &State{ 2573 Modules: []*ModuleState{ 2574 &ModuleState{ 2575 Path: rootModulePath, 2576 Resources: map[string]*ResourceState{ 2577 "aws_instance.orphan": &ResourceState{ 2578 Type: "aws_instance", 2579 Primary: &InstanceState{ 2580 ID: "i-789xyz", 2581 }, 2582 }, 2583 "aws_instance.nottargeted": &ResourceState{ 2584 Type: "aws_instance", 2585 Primary: &InstanceState{ 2586 ID: "i-abc123", 2587 }, 2588 }, 2589 }, 2590 }, 2591 }, 2592 }, 2593 Destroy: true, 2594 Targets: []string{"aws_instance.orphan"}, 2595 }) 2596 2597 plan, err := ctx.Plan() 2598 if err != nil { 2599 t.Fatalf("err: %s", err) 2600 } 2601 2602 actual := strings.TrimSpace(plan.String()) 2603 expected := strings.TrimSpace(`DIFF: 2604 2605 DESTROY: aws_instance.orphan 2606 2607 STATE: 2608 2609 aws_instance.nottargeted: 2610 ID = i-abc123 2611 aws_instance.orphan: 2612 ID = i-789xyz 2613 `) 2614 if actual != expected { 2615 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2616 } 2617 } 2618 2619 // https://github.com/hashicorp/terraform/issues/2538 2620 func TestContext2Plan_targetedModuleOrphan(t *testing.T) { 2621 m := testModule(t, "plan-targeted-module-orphan") 2622 p := testProvider("aws") 2623 p.DiffFn = testDiffFn 2624 ctx := testContext2(t, &ContextOpts{ 2625 Module: m, 2626 Providers: map[string]ResourceProviderFactory{ 2627 "aws": testProviderFuncFixed(p), 2628 }, 2629 State: &State{ 2630 Modules: []*ModuleState{ 2631 &ModuleState{ 2632 Path: []string{"root", "child"}, 2633 Resources: map[string]*ResourceState{ 2634 "aws_instance.orphan": &ResourceState{ 2635 Type: "aws_instance", 2636 Primary: &InstanceState{ 2637 ID: "i-789xyz", 2638 }, 2639 }, 2640 "aws_instance.nottargeted": &ResourceState{ 2641 Type: "aws_instance", 2642 Primary: &InstanceState{ 2643 ID: "i-abc123", 2644 }, 2645 }, 2646 }, 2647 }, 2648 }, 2649 }, 2650 Destroy: true, 2651 Targets: []string{"module.child.aws_instance.orphan"}, 2652 }) 2653 2654 plan, err := ctx.Plan() 2655 if err != nil { 2656 t.Fatalf("err: %s", err) 2657 } 2658 2659 actual := strings.TrimSpace(plan.String()) 2660 expected := strings.TrimSpace(`DIFF: 2661 2662 module.child: 2663 DESTROY: aws_instance.orphan 2664 2665 STATE: 2666 2667 module.child: 2668 aws_instance.nottargeted: 2669 ID = i-abc123 2670 aws_instance.orphan: 2671 ID = i-789xyz 2672 `) 2673 if actual != expected { 2674 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2675 } 2676 } 2677 2678 func TestContext2Plan_targetedModuleUntargetedVariable(t *testing.T) { 2679 m := testModule(t, "plan-targeted-module-untargeted-variable") 2680 p := testProvider("aws") 2681 p.DiffFn = testDiffFn 2682 ctx := testContext2(t, &ContextOpts{ 2683 Module: m, 2684 Providers: map[string]ResourceProviderFactory{ 2685 "aws": testProviderFuncFixed(p), 2686 }, 2687 Targets: []string{"aws_instance.blue", "module.blue_mod"}, 2688 }) 2689 2690 plan, err := ctx.Plan() 2691 if err != nil { 2692 t.Fatalf("err: %s", err) 2693 } 2694 2695 actual := strings.TrimSpace(plan.String()) 2696 expected := strings.TrimSpace(` 2697 DIFF: 2698 2699 CREATE: aws_instance.blue 2700 2701 module.blue_mod: 2702 CREATE: aws_instance.mod 2703 type: "" => "aws_instance" 2704 value: "" => "<computed>" 2705 2706 STATE: 2707 2708 <no state> 2709 `) 2710 if actual != expected { 2711 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2712 } 2713 } 2714 2715 // https://github.com/hashicorp/terraform/issues/4515 2716 func TestContext2Plan_targetedOverTen(t *testing.T) { 2717 m := testModule(t, "plan-targeted-over-ten") 2718 p := testProvider("aws") 2719 p.DiffFn = testDiffFn 2720 2721 resources := make(map[string]*ResourceState) 2722 var expectedState []string 2723 for i := 0; i < 13; i++ { 2724 key := fmt.Sprintf("aws_instance.foo.%d", i) 2725 id := fmt.Sprintf("i-abc%d", i) 2726 resources[key] = &ResourceState{ 2727 Type: "aws_instance", 2728 Primary: &InstanceState{ID: id}, 2729 } 2730 expectedState = append(expectedState, 2731 fmt.Sprintf("%s:\n ID = %s\n", key, id)) 2732 } 2733 ctx := testContext2(t, &ContextOpts{ 2734 Module: m, 2735 Providers: map[string]ResourceProviderFactory{ 2736 "aws": testProviderFuncFixed(p), 2737 }, 2738 State: &State{ 2739 Modules: []*ModuleState{ 2740 &ModuleState{ 2741 Path: rootModulePath, 2742 Resources: resources, 2743 }, 2744 }, 2745 }, 2746 Targets: []string{"aws_instance.foo[1]"}, 2747 }) 2748 2749 plan, err := ctx.Plan() 2750 if err != nil { 2751 t.Fatalf("err: %s", err) 2752 } 2753 2754 actual := strings.TrimSpace(plan.String()) 2755 sort.Strings(expectedState) 2756 expected := strings.TrimSpace(` 2757 DIFF: 2758 2759 2760 2761 STATE: 2762 2763 aws_instance.foo.0: 2764 ID = i-abc0 2765 aws_instance.foo.1: 2766 ID = i-abc1 2767 aws_instance.foo.2: 2768 ID = i-abc2 2769 aws_instance.foo.3: 2770 ID = i-abc3 2771 aws_instance.foo.4: 2772 ID = i-abc4 2773 aws_instance.foo.5: 2774 ID = i-abc5 2775 aws_instance.foo.6: 2776 ID = i-abc6 2777 aws_instance.foo.7: 2778 ID = i-abc7 2779 aws_instance.foo.8: 2780 ID = i-abc8 2781 aws_instance.foo.9: 2782 ID = i-abc9 2783 aws_instance.foo.10: 2784 ID = i-abc10 2785 aws_instance.foo.11: 2786 ID = i-abc11 2787 aws_instance.foo.12: 2788 ID = i-abc12 2789 `) 2790 if actual != expected { 2791 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2792 } 2793 } 2794 2795 func TestContext2Plan_provider(t *testing.T) { 2796 m := testModule(t, "plan-provider") 2797 p := testProvider("aws") 2798 p.DiffFn = testDiffFn 2799 2800 var value interface{} 2801 p.ConfigureFn = func(c *ResourceConfig) error { 2802 value, _ = c.Get("foo") 2803 return nil 2804 } 2805 2806 ctx := testContext2(t, &ContextOpts{ 2807 Module: m, 2808 Providers: map[string]ResourceProviderFactory{ 2809 "aws": testProviderFuncFixed(p), 2810 }, 2811 Variables: map[string]interface{}{ 2812 "foo": "bar", 2813 }, 2814 }) 2815 2816 if _, err := ctx.Plan(); err != nil { 2817 t.Fatalf("err: %s", err) 2818 } 2819 2820 if value != "bar" { 2821 t.Fatalf("bad: %#v", value) 2822 } 2823 } 2824 2825 func TestContext2Plan_varListErr(t *testing.T) { 2826 m := testModule(t, "plan-var-list-err") 2827 p := testProvider("aws") 2828 ctx := testContext2(t, &ContextOpts{ 2829 Module: m, 2830 Providers: map[string]ResourceProviderFactory{ 2831 "aws": testProviderFuncFixed(p), 2832 }, 2833 }) 2834 2835 _, err := ctx.Plan() 2836 2837 if err == nil { 2838 t.Fatal("should error") 2839 } 2840 } 2841 2842 func TestContext2Plan_ignoreChanges(t *testing.T) { 2843 m := testModule(t, "plan-ignore-changes") 2844 p := testProvider("aws") 2845 p.DiffFn = testDiffFn 2846 s := &State{ 2847 Modules: []*ModuleState{ 2848 &ModuleState{ 2849 Path: rootModulePath, 2850 Resources: map[string]*ResourceState{ 2851 "aws_instance.foo": &ResourceState{ 2852 Primary: &InstanceState{ 2853 ID: "bar", 2854 Attributes: map[string]string{"ami": "ami-abcd1234"}, 2855 }, 2856 }, 2857 }, 2858 }, 2859 }, 2860 } 2861 ctx := testContext2(t, &ContextOpts{ 2862 Module: m, 2863 Providers: map[string]ResourceProviderFactory{ 2864 "aws": testProviderFuncFixed(p), 2865 }, 2866 Variables: map[string]interface{}{ 2867 "foo": "ami-1234abcd", 2868 }, 2869 State: s, 2870 }) 2871 2872 plan, err := ctx.Plan() 2873 if err != nil { 2874 t.Fatalf("err: %s", err) 2875 } 2876 2877 if len(plan.Diff.RootModule().Resources) < 1 { 2878 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 2879 } 2880 2881 actual := strings.TrimSpace(plan.String()) 2882 expected := strings.TrimSpace(testTerraformPlanIgnoreChangesStr) 2883 if actual != expected { 2884 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 2885 } 2886 } 2887 2888 func TestContext2Plan_ignoreChangesWildcard(t *testing.T) { 2889 m := testModule(t, "plan-ignore-changes-wildcard") 2890 p := testProvider("aws") 2891 p.DiffFn = testDiffFn 2892 s := &State{ 2893 Modules: []*ModuleState{ 2894 &ModuleState{ 2895 Path: rootModulePath, 2896 Resources: map[string]*ResourceState{ 2897 "aws_instance.foo": &ResourceState{ 2898 Primary: &InstanceState{ 2899 ID: "bar", 2900 Attributes: map[string]string{ 2901 "ami": "ami-abcd1234", 2902 "instance_type": "t2.micro", 2903 }, 2904 }, 2905 }, 2906 }, 2907 }, 2908 }, 2909 } 2910 ctx := testContext2(t, &ContextOpts{ 2911 Module: m, 2912 Providers: map[string]ResourceProviderFactory{ 2913 "aws": testProviderFuncFixed(p), 2914 }, 2915 Variables: map[string]interface{}{ 2916 "foo": "ami-1234abcd", 2917 "bar": "t2.small", 2918 }, 2919 State: s, 2920 }) 2921 2922 plan, err := ctx.Plan() 2923 if err != nil { 2924 t.Fatalf("err: %s", err) 2925 } 2926 2927 if len(plan.Diff.RootModule().Resources) > 0 { 2928 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 2929 } 2930 2931 actual := strings.TrimSpace(plan.String()) 2932 expected := strings.TrimSpace(testTerraformPlanIgnoreChangesWildcardStr) 2933 if actual != expected { 2934 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 2935 } 2936 } 2937 2938 func TestContext2Plan_moduleMapLiteral(t *testing.T) { 2939 m := testModule(t, "plan-module-map-literal") 2940 p := testProvider("aws") 2941 p.ApplyFn = testApplyFn 2942 p.DiffFn = func(i *InstanceInfo, s *InstanceState, c *ResourceConfig) (*InstanceDiff, error) { 2943 // Here we verify that both the populated and empty map literals made it 2944 // through to the resource attributes 2945 val, _ := c.Get("tags") 2946 m, ok := val.(map[string]interface{}) 2947 if !ok { 2948 t.Fatalf("Tags attr not map: %#v", val) 2949 } 2950 if m["foo"] != "bar" { 2951 t.Fatalf("Bad value in tags attr: %#v", m) 2952 } 2953 { 2954 val, _ := c.Get("meta") 2955 m, ok := val.(map[string]interface{}) 2956 if !ok { 2957 t.Fatalf("Meta attr not map: %#v", val) 2958 } 2959 if len(m) != 0 { 2960 t.Fatalf("Meta attr not empty: %#v", val) 2961 } 2962 } 2963 return nil, nil 2964 } 2965 ctx := testContext2(t, &ContextOpts{ 2966 Module: m, 2967 Providers: map[string]ResourceProviderFactory{ 2968 "aws": testProviderFuncFixed(p), 2969 }, 2970 }) 2971 2972 if _, err := ctx.Plan(); err != nil { 2973 t.Fatalf("err: %s", err) 2974 } 2975 } 2976 2977 func TestContext2Plan_computedValueInMap(t *testing.T) { 2978 m := testModule(t, "plan-computed-value-in-map") 2979 p := testProvider("aws") 2980 p.DiffFn = func(info *InstanceInfo, state *InstanceState, c *ResourceConfig) (*InstanceDiff, error) { 2981 switch info.Type { 2982 case "aws_computed_source": 2983 return &InstanceDiff{ 2984 Attributes: map[string]*ResourceAttrDiff{ 2985 "computed_read_only": &ResourceAttrDiff{ 2986 NewComputed: true, 2987 }, 2988 }, 2989 }, nil 2990 } 2991 2992 return testDiffFn(info, state, c) 2993 } 2994 ctx := testContext2(t, &ContextOpts{ 2995 Module: m, 2996 Providers: map[string]ResourceProviderFactory{ 2997 "aws": testProviderFuncFixed(p), 2998 }, 2999 }) 3000 3001 if _, err := ctx.Plan(); err != nil { 3002 t.Fatalf("err: %s", err) 3003 } 3004 3005 plan, err := ctx.Plan() 3006 if err != nil { 3007 t.Fatalf("err: %s", err) 3008 } 3009 3010 actual := strings.TrimSpace(plan.String()) 3011 expected := strings.TrimSpace(testTerraformPlanComputedValueInMap) 3012 if actual != expected { 3013 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 3014 } 3015 } 3016 3017 func TestContext2Plan_moduleVariableFromSplat(t *testing.T) { 3018 m := testModule(t, "plan-module-variable-from-splat") 3019 p := testProvider("aws") 3020 p.DiffFn = testDiffFn 3021 ctx := testContext2(t, &ContextOpts{ 3022 Module: m, 3023 Providers: map[string]ResourceProviderFactory{ 3024 "aws": testProviderFuncFixed(p), 3025 }, 3026 }) 3027 3028 if _, err := ctx.Plan(); err != nil { 3029 t.Fatalf("err: %s", err) 3030 } 3031 3032 plan, err := ctx.Plan() 3033 if err != nil { 3034 t.Fatalf("err: %s", err) 3035 } 3036 3037 actual := strings.TrimSpace(plan.String()) 3038 expected := strings.TrimSpace(testTerraformPlanModuleVariableFromSplat) 3039 if actual != expected { 3040 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 3041 } 3042 } 3043 3044 func TestContext2Plan_createBeforeDestroy_depends_datasource(t *testing.T) { 3045 m := testModule(t, "plan-cdb-depends-datasource") 3046 p := testProvider("aws") 3047 p.DiffFn = testDiffFn 3048 ctx := testContext2(t, &ContextOpts{ 3049 Module: m, 3050 Providers: map[string]ResourceProviderFactory{ 3051 "aws": testProviderFuncFixed(p), 3052 }, 3053 }) 3054 3055 plan, err := ctx.Plan() 3056 if err != nil { 3057 t.Fatalf("err: %s", err) 3058 } 3059 3060 if got := len(plan.Diff.Modules); got != 1 { 3061 t.Fatalf("got %d modules; want 1", got) 3062 } 3063 3064 moduleDiff := plan.Diff.Modules[0] 3065 3066 if _, ok := moduleDiff.Resources["aws_instance.foo.0"]; !ok { 3067 t.Fatalf("missing diff for aws_instance.foo.0") 3068 } 3069 if _, ok := moduleDiff.Resources["aws_instance.foo.1"]; !ok { 3070 t.Fatalf("missing diff for aws_instance.foo.1") 3071 } 3072 if _, ok := moduleDiff.Resources["data.aws_vpc.bar.0"]; !ok { 3073 t.Fatalf("missing diff for data.aws_vpc.bar.0") 3074 } 3075 if _, ok := moduleDiff.Resources["data.aws_vpc.bar.1"]; !ok { 3076 t.Fatalf("missing diff for data.aws_vpc.bar.1") 3077 } 3078 } 3079 3080 // interpolated lists need to be stored in the original order. 3081 func TestContext2Plan_listOrder(t *testing.T) { 3082 m := testModule(t, "plan-list-order") 3083 p := testProvider("aws") 3084 p.ApplyFn = testApplyFn 3085 p.DiffFn = testDiffFn 3086 ctx := testContext2(t, &ContextOpts{ 3087 Module: m, 3088 Providers: map[string]ResourceProviderFactory{ 3089 "aws": testProviderFuncFixed(p), 3090 }, 3091 }) 3092 3093 plan, err := ctx.Plan() 3094 if err != nil { 3095 t.Fatalf("err: %s", err) 3096 } 3097 3098 rDiffs := plan.Diff.Modules[0].Resources 3099 rDiffA := rDiffs["aws_instance.a"] 3100 rDiffB := rDiffs["aws_instance.b"] 3101 3102 if !rDiffA.Equal(rDiffB) { 3103 t.Fatal("aws_instance.a and aws_instance.b diffs should match:\n", plan) 3104 } 3105 } 3106 3107 // Make sure ignore-changes doesn't interfere with set/list/map diffs. 3108 // If a resource was being replaced by a RequiresNew attribute that gets 3109 // ignored, we need to filter the diff properly to properly update rather than 3110 // replace. 3111 func TestContext2Plan_ignoreChangesWithFlatmaps(t *testing.T) { 3112 m := testModule(t, "plan-ignore-changes-with-flatmaps") 3113 p := testProvider("aws") 3114 p.DiffFn = testDiffFn 3115 s := &State{ 3116 Modules: []*ModuleState{ 3117 &ModuleState{ 3118 Path: rootModulePath, 3119 Resources: map[string]*ResourceState{ 3120 "aws_instance.foo": &ResourceState{ 3121 Type: "aws_instance", 3122 Primary: &InstanceState{ 3123 ID: "bar", 3124 Attributes: map[string]string{ 3125 "user_data": "x", 3126 "require_new": "", 3127 "set.#": "1", 3128 "set.0.a": "1", 3129 "lst.#": "1", 3130 "lst.0": "j", 3131 }, 3132 }, 3133 }, 3134 }, 3135 }, 3136 }, 3137 } 3138 ctx := testContext2(t, &ContextOpts{ 3139 Module: m, 3140 Providers: map[string]ResourceProviderFactory{ 3141 "aws": testProviderFuncFixed(p), 3142 }, 3143 State: s, 3144 }) 3145 3146 plan, err := ctx.Plan() 3147 if err != nil { 3148 t.Fatalf("err: %s", err) 3149 } 3150 3151 actual := strings.TrimSpace(plan.Diff.String()) 3152 expected := strings.TrimSpace(testTFPlanDiffIgnoreChangesWithFlatmaps) 3153 if actual != expected { 3154 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 3155 } 3156 } 3157 3158 // TestContext2Plan_resourceNestedCount ensures resource sets that depend on 3159 // the count of another resource set (ie: count of a data source that depends 3160 // on another data source's instance count - data.x.foo.*.id) get properly 3161 // normalized to the indexes they should be. This case comes up when there is 3162 // an existing state (after an initial apply). 3163 func TestContext2Plan_resourceNestedCount(t *testing.T) { 3164 m := testModule(t, "nested-resource-count-plan") 3165 p := testProvider("aws") 3166 p.DiffFn = testDiffFn 3167 p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) { 3168 return is, nil 3169 } 3170 s := &State{ 3171 Modules: []*ModuleState{ 3172 &ModuleState{ 3173 Path: rootModulePath, 3174 Resources: map[string]*ResourceState{ 3175 "aws_instance.foo.0": &ResourceState{ 3176 Type: "aws_instance", 3177 Primary: &InstanceState{ 3178 ID: "foo0", 3179 Attributes: map[string]string{ 3180 "id": "foo0", 3181 }, 3182 }, 3183 }, 3184 "aws_instance.foo.1": &ResourceState{ 3185 Type: "aws_instance", 3186 Primary: &InstanceState{ 3187 ID: "foo1", 3188 Attributes: map[string]string{ 3189 "id": "foo1", 3190 }, 3191 }, 3192 }, 3193 "aws_instance.bar.0": &ResourceState{ 3194 Type: "aws_instance", 3195 Dependencies: []string{"aws_instance.foo.*"}, 3196 Primary: &InstanceState{ 3197 ID: "bar0", 3198 Attributes: map[string]string{ 3199 "id": "bar0", 3200 }, 3201 }, 3202 }, 3203 "aws_instance.bar.1": &ResourceState{ 3204 Type: "aws_instance", 3205 Dependencies: []string{"aws_instance.foo.*"}, 3206 Primary: &InstanceState{ 3207 ID: "bar1", 3208 Attributes: map[string]string{ 3209 "id": "bar1", 3210 }, 3211 }, 3212 }, 3213 "aws_instance.baz.0": &ResourceState{ 3214 Type: "aws_instance", 3215 Dependencies: []string{"aws_instance.bar.*"}, 3216 Primary: &InstanceState{ 3217 ID: "baz0", 3218 Attributes: map[string]string{ 3219 "id": "baz0", 3220 }, 3221 }, 3222 }, 3223 "aws_instance.baz.1": &ResourceState{ 3224 Type: "aws_instance", 3225 Dependencies: []string{"aws_instance.bar.*"}, 3226 Primary: &InstanceState{ 3227 ID: "baz1", 3228 Attributes: map[string]string{ 3229 "id": "baz1", 3230 }, 3231 }, 3232 }, 3233 }, 3234 }, 3235 }, 3236 } 3237 ctx := testContext2(t, &ContextOpts{ 3238 Module: m, 3239 Providers: map[string]ResourceProviderFactory{ 3240 "aws": testProviderFuncFixed(p), 3241 }, 3242 State: s, 3243 }) 3244 3245 w, e := ctx.Validate() 3246 if len(w) > 0 { 3247 t.Fatalf("warnings generated on validate: %#v", w) 3248 } 3249 if len(e) > 0 { 3250 t.Fatalf("errors generated on validate: %#v", e) 3251 } 3252 3253 _, err := ctx.Refresh() 3254 if err != nil { 3255 t.Fatalf("refresh err: %s", err) 3256 } 3257 3258 plan, err := ctx.Plan() 3259 if err != nil { 3260 t.Fatalf("plan err: %s", err) 3261 } 3262 3263 actual := strings.TrimSpace(plan.String()) 3264 expected := strings.TrimSpace(` 3265 DIFF: 3266 3267 3268 3269 STATE: 3270 3271 aws_instance.bar.0: 3272 ID = bar0 3273 3274 Dependencies: 3275 aws_instance.foo.* 3276 aws_instance.bar.1: 3277 ID = bar1 3278 3279 Dependencies: 3280 aws_instance.foo.* 3281 aws_instance.baz.0: 3282 ID = baz0 3283 3284 Dependencies: 3285 aws_instance.bar.* 3286 aws_instance.baz.1: 3287 ID = baz1 3288 3289 Dependencies: 3290 aws_instance.bar.* 3291 aws_instance.foo.0: 3292 ID = foo0 3293 aws_instance.foo.1: 3294 ID = foo1 3295 `) 3296 if actual != expected { 3297 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 3298 } 3299 }