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