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