github.com/wikibal01/hashicorp-terraform@v0.11.12-beta1/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 func TestContext2Plan_targetEmpty(t *testing.T) { 2737 m := testModule(t, "plan-targeted") 2738 p := testProvider("aws") 2739 p.DiffFn = testDiffFn 2740 ctx := testContext2(t, &ContextOpts{ 2741 Module: m, 2742 ProviderResolver: ResourceProviderResolverFixed( 2743 map[string]ResourceProviderFactory{ 2744 "aws": testProviderFuncFixed(p), 2745 }, 2746 ), 2747 Targets: []string{""}, 2748 }) 2749 2750 _, err := ctx.Plan() 2751 if err == nil { 2752 t.Fatal("should error") 2753 } 2754 } 2755 2756 // Test that targeting a module properly plans any inputs that depend 2757 // on another module. 2758 func TestContext2Plan_targetedCrossModule(t *testing.T) { 2759 m := testModule(t, "plan-targeted-cross-module") 2760 p := testProvider("aws") 2761 p.DiffFn = testDiffFn 2762 ctx := testContext2(t, &ContextOpts{ 2763 Module: m, 2764 ProviderResolver: ResourceProviderResolverFixed( 2765 map[string]ResourceProviderFactory{ 2766 "aws": testProviderFuncFixed(p), 2767 }, 2768 ), 2769 Targets: []string{"module.B"}, 2770 }) 2771 2772 plan, err := ctx.Plan() 2773 if err != nil { 2774 t.Fatalf("err: %s", err) 2775 } 2776 2777 actual := strings.TrimSpace(plan.String()) 2778 expected := strings.TrimSpace(` 2779 DIFF: 2780 2781 module.A: 2782 CREATE: aws_instance.foo 2783 foo: "" => "bar" 2784 type: "" => "aws_instance" 2785 module.B: 2786 CREATE: aws_instance.bar 2787 foo: "" => "<computed>" 2788 type: "" => "aws_instance" 2789 2790 STATE: 2791 2792 <no state> 2793 `) 2794 if actual != expected { 2795 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2796 } 2797 } 2798 2799 func TestContext2Plan_targetedModuleWithProvider(t *testing.T) { 2800 m := testModule(t, "plan-targeted-module-with-provider") 2801 p := testProvider("null") 2802 p.DiffFn = testDiffFn 2803 ctx := testContext2(t, &ContextOpts{ 2804 Module: m, 2805 ProviderResolver: ResourceProviderResolverFixed( 2806 map[string]ResourceProviderFactory{ 2807 "null": testProviderFuncFixed(p), 2808 }, 2809 ), 2810 Targets: []string{"module.child2"}, 2811 }) 2812 2813 plan, err := ctx.Plan() 2814 if err != nil { 2815 t.Fatalf("err: %s", err) 2816 } 2817 2818 actual := strings.TrimSpace(plan.String()) 2819 expected := strings.TrimSpace(` 2820 DIFF: 2821 2822 module.child2: 2823 CREATE: null_resource.foo 2824 2825 STATE: 2826 2827 <no state> 2828 `) 2829 if actual != expected { 2830 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2831 } 2832 } 2833 2834 func TestContext2Plan_targetedOrphan(t *testing.T) { 2835 m := testModule(t, "plan-targeted-orphan") 2836 p := testProvider("aws") 2837 p.DiffFn = testDiffFn 2838 ctx := testContext2(t, &ContextOpts{ 2839 Module: m, 2840 ProviderResolver: ResourceProviderResolverFixed( 2841 map[string]ResourceProviderFactory{ 2842 "aws": testProviderFuncFixed(p), 2843 }, 2844 ), 2845 State: &State{ 2846 Modules: []*ModuleState{ 2847 &ModuleState{ 2848 Path: rootModulePath, 2849 Resources: map[string]*ResourceState{ 2850 "aws_instance.orphan": &ResourceState{ 2851 Type: "aws_instance", 2852 Primary: &InstanceState{ 2853 ID: "i-789xyz", 2854 }, 2855 }, 2856 "aws_instance.nottargeted": &ResourceState{ 2857 Type: "aws_instance", 2858 Primary: &InstanceState{ 2859 ID: "i-abc123", 2860 }, 2861 }, 2862 }, 2863 }, 2864 }, 2865 }, 2866 Destroy: true, 2867 Targets: []string{"aws_instance.orphan"}, 2868 }) 2869 2870 plan, err := ctx.Plan() 2871 if err != nil { 2872 t.Fatalf("err: %s", err) 2873 } 2874 2875 actual := strings.TrimSpace(plan.String()) 2876 expected := strings.TrimSpace(`DIFF: 2877 2878 DESTROY: aws_instance.orphan 2879 2880 STATE: 2881 2882 aws_instance.nottargeted: 2883 ID = i-abc123 2884 aws_instance.orphan: 2885 ID = i-789xyz 2886 `) 2887 if actual != expected { 2888 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2889 } 2890 } 2891 2892 // https://github.com/hashicorp/terraform/issues/2538 2893 func TestContext2Plan_targetedModuleOrphan(t *testing.T) { 2894 m := testModule(t, "plan-targeted-module-orphan") 2895 p := testProvider("aws") 2896 p.DiffFn = testDiffFn 2897 ctx := testContext2(t, &ContextOpts{ 2898 Module: m, 2899 ProviderResolver: ResourceProviderResolverFixed( 2900 map[string]ResourceProviderFactory{ 2901 "aws": testProviderFuncFixed(p), 2902 }, 2903 ), 2904 State: &State{ 2905 Modules: []*ModuleState{ 2906 &ModuleState{ 2907 Path: []string{"root", "child"}, 2908 Resources: map[string]*ResourceState{ 2909 "aws_instance.orphan": &ResourceState{ 2910 Type: "aws_instance", 2911 Primary: &InstanceState{ 2912 ID: "i-789xyz", 2913 }, 2914 }, 2915 "aws_instance.nottargeted": &ResourceState{ 2916 Type: "aws_instance", 2917 Primary: &InstanceState{ 2918 ID: "i-abc123", 2919 }, 2920 }, 2921 }, 2922 }, 2923 }, 2924 }, 2925 Destroy: true, 2926 Targets: []string{"module.child.aws_instance.orphan"}, 2927 }) 2928 2929 plan, err := ctx.Plan() 2930 if err != nil { 2931 t.Fatalf("err: %s", err) 2932 } 2933 2934 actual := strings.TrimSpace(plan.String()) 2935 expected := strings.TrimSpace(`DIFF: 2936 2937 module.child: 2938 DESTROY: aws_instance.orphan 2939 2940 STATE: 2941 2942 module.child: 2943 aws_instance.nottargeted: 2944 ID = i-abc123 2945 aws_instance.orphan: 2946 ID = i-789xyz 2947 `) 2948 if actual != expected { 2949 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2950 } 2951 } 2952 2953 func TestContext2Plan_targetedModuleUntargetedVariable(t *testing.T) { 2954 m := testModule(t, "plan-targeted-module-untargeted-variable") 2955 p := testProvider("aws") 2956 p.DiffFn = testDiffFn 2957 ctx := testContext2(t, &ContextOpts{ 2958 Module: m, 2959 ProviderResolver: ResourceProviderResolverFixed( 2960 map[string]ResourceProviderFactory{ 2961 "aws": testProviderFuncFixed(p), 2962 }, 2963 ), 2964 Targets: []string{"aws_instance.blue", "module.blue_mod"}, 2965 }) 2966 2967 plan, err := ctx.Plan() 2968 if err != nil { 2969 t.Fatalf("err: %s", err) 2970 } 2971 2972 actual := strings.TrimSpace(plan.String()) 2973 expected := strings.TrimSpace(` 2974 DIFF: 2975 2976 CREATE: aws_instance.blue 2977 2978 module.blue_mod: 2979 CREATE: aws_instance.mod 2980 type: "" => "aws_instance" 2981 value: "" => "<computed>" 2982 2983 STATE: 2984 2985 <no state> 2986 `) 2987 if actual != expected { 2988 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2989 } 2990 } 2991 2992 // ensure that outputs missing references due to targetting are removed from 2993 // the graph. 2994 func TestContext2Plan_outputContainsTargetedResource(t *testing.T) { 2995 m := testModule(t, "plan-untargeted-resource-output") 2996 p := testProvider("aws") 2997 p.DiffFn = testDiffFn 2998 ctx := testContext2(t, &ContextOpts{ 2999 Module: m, 3000 ProviderResolver: ResourceProviderResolverFixed( 3001 map[string]ResourceProviderFactory{ 3002 "aws": testProviderFuncFixed(p), 3003 }, 3004 ), 3005 Targets: []string{"module.mod.aws_instance.a"}, 3006 }) 3007 3008 _, err := ctx.Plan() 3009 if err != nil { 3010 t.Fatalf("err: %s", err) 3011 } 3012 } 3013 3014 // https://github.com/hashicorp/terraform/issues/4515 3015 func TestContext2Plan_targetedOverTen(t *testing.T) { 3016 m := testModule(t, "plan-targeted-over-ten") 3017 p := testProvider("aws") 3018 p.DiffFn = testDiffFn 3019 3020 resources := make(map[string]*ResourceState) 3021 var expectedState []string 3022 for i := 0; i < 13; i++ { 3023 key := fmt.Sprintf("aws_instance.foo.%d", i) 3024 id := fmt.Sprintf("i-abc%d", i) 3025 resources[key] = &ResourceState{ 3026 Type: "aws_instance", 3027 Primary: &InstanceState{ID: id}, 3028 } 3029 expectedState = append(expectedState, 3030 fmt.Sprintf("%s:\n ID = %s\n", key, id)) 3031 } 3032 ctx := testContext2(t, &ContextOpts{ 3033 Module: m, 3034 ProviderResolver: ResourceProviderResolverFixed( 3035 map[string]ResourceProviderFactory{ 3036 "aws": testProviderFuncFixed(p), 3037 }, 3038 ), 3039 State: &State{ 3040 Modules: []*ModuleState{ 3041 &ModuleState{ 3042 Path: rootModulePath, 3043 Resources: resources, 3044 }, 3045 }, 3046 }, 3047 Targets: []string{"aws_instance.foo[1]"}, 3048 }) 3049 3050 plan, err := ctx.Plan() 3051 if err != nil { 3052 t.Fatalf("err: %s", err) 3053 } 3054 3055 actual := strings.TrimSpace(plan.String()) 3056 sort.Strings(expectedState) 3057 expected := strings.TrimSpace(` 3058 DIFF: 3059 3060 3061 3062 STATE: 3063 3064 aws_instance.foo.0: 3065 ID = i-abc0 3066 aws_instance.foo.1: 3067 ID = i-abc1 3068 aws_instance.foo.2: 3069 ID = i-abc2 3070 aws_instance.foo.3: 3071 ID = i-abc3 3072 aws_instance.foo.4: 3073 ID = i-abc4 3074 aws_instance.foo.5: 3075 ID = i-abc5 3076 aws_instance.foo.6: 3077 ID = i-abc6 3078 aws_instance.foo.7: 3079 ID = i-abc7 3080 aws_instance.foo.8: 3081 ID = i-abc8 3082 aws_instance.foo.9: 3083 ID = i-abc9 3084 aws_instance.foo.10: 3085 ID = i-abc10 3086 aws_instance.foo.11: 3087 ID = i-abc11 3088 aws_instance.foo.12: 3089 ID = i-abc12 3090 `) 3091 if actual != expected { 3092 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 3093 } 3094 } 3095 3096 func TestContext2Plan_provider(t *testing.T) { 3097 m := testModule(t, "plan-provider") 3098 p := testProvider("aws") 3099 p.DiffFn = testDiffFn 3100 3101 var value interface{} 3102 p.ConfigureFn = func(c *ResourceConfig) error { 3103 value, _ = c.Get("foo") 3104 return nil 3105 } 3106 3107 ctx := testContext2(t, &ContextOpts{ 3108 Module: m, 3109 ProviderResolver: ResourceProviderResolverFixed( 3110 map[string]ResourceProviderFactory{ 3111 "aws": testProviderFuncFixed(p), 3112 }, 3113 ), 3114 Variables: map[string]interface{}{ 3115 "foo": "bar", 3116 }, 3117 }) 3118 3119 if _, err := ctx.Plan(); err != nil { 3120 t.Fatalf("err: %s", err) 3121 } 3122 3123 if value != "bar" { 3124 t.Fatalf("bad: %#v", value) 3125 } 3126 } 3127 3128 func TestContext2Plan_varListErr(t *testing.T) { 3129 m := testModule(t, "plan-var-list-err") 3130 p := testProvider("aws") 3131 ctx := testContext2(t, &ContextOpts{ 3132 Module: m, 3133 ProviderResolver: ResourceProviderResolverFixed( 3134 map[string]ResourceProviderFactory{ 3135 "aws": testProviderFuncFixed(p), 3136 }, 3137 ), 3138 }) 3139 3140 _, err := ctx.Plan() 3141 3142 if err == nil { 3143 t.Fatal("should error") 3144 } 3145 } 3146 3147 func TestContext2Plan_ignoreChanges(t *testing.T) { 3148 m := testModule(t, "plan-ignore-changes") 3149 p := testProvider("aws") 3150 p.DiffFn = testDiffFn 3151 s := &State{ 3152 Modules: []*ModuleState{ 3153 &ModuleState{ 3154 Path: rootModulePath, 3155 Resources: map[string]*ResourceState{ 3156 "aws_instance.foo": &ResourceState{ 3157 Type: "aws_instance", 3158 Primary: &InstanceState{ 3159 ID: "bar", 3160 Attributes: map[string]string{"ami": "ami-abcd1234"}, 3161 }, 3162 }, 3163 }, 3164 }, 3165 }, 3166 } 3167 ctx := testContext2(t, &ContextOpts{ 3168 Module: m, 3169 ProviderResolver: ResourceProviderResolverFixed( 3170 map[string]ResourceProviderFactory{ 3171 "aws": testProviderFuncFixed(p), 3172 }, 3173 ), 3174 Variables: map[string]interface{}{ 3175 "foo": "ami-1234abcd", 3176 }, 3177 State: s, 3178 }) 3179 3180 plan, err := ctx.Plan() 3181 if err != nil { 3182 t.Fatalf("err: %s", err) 3183 } 3184 3185 if len(plan.Diff.RootModule().Resources) < 1 { 3186 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 3187 } 3188 3189 actual := strings.TrimSpace(plan.String()) 3190 expected := strings.TrimSpace(testTerraformPlanIgnoreChangesStr) 3191 if actual != expected { 3192 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 3193 } 3194 } 3195 3196 func TestContext2Plan_ignoreChangesWildcard(t *testing.T) { 3197 m := testModule(t, "plan-ignore-changes-wildcard") 3198 p := testProvider("aws") 3199 p.DiffFn = testDiffFn 3200 s := &State{ 3201 Modules: []*ModuleState{ 3202 &ModuleState{ 3203 Path: rootModulePath, 3204 Resources: map[string]*ResourceState{ 3205 "aws_instance.foo": &ResourceState{ 3206 Type: "aws_instance", 3207 Primary: &InstanceState{ 3208 ID: "bar", 3209 Attributes: map[string]string{ 3210 "ami": "ami-abcd1234", 3211 "instance_type": "t2.micro", 3212 }, 3213 }, 3214 }, 3215 }, 3216 }, 3217 }, 3218 } 3219 ctx := testContext2(t, &ContextOpts{ 3220 Module: m, 3221 ProviderResolver: ResourceProviderResolverFixed( 3222 map[string]ResourceProviderFactory{ 3223 "aws": testProviderFuncFixed(p), 3224 }, 3225 ), 3226 Variables: map[string]interface{}{ 3227 "foo": "ami-1234abcd", 3228 "bar": "t2.small", 3229 }, 3230 State: s, 3231 }) 3232 3233 plan, err := ctx.Plan() 3234 if err != nil { 3235 t.Fatalf("err: %s", err) 3236 } 3237 3238 if len(plan.Diff.RootModule().Resources) > 0 { 3239 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 3240 } 3241 3242 actual := strings.TrimSpace(plan.String()) 3243 expected := strings.TrimSpace(testTerraformPlanIgnoreChangesWildcardStr) 3244 if actual != expected { 3245 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 3246 } 3247 } 3248 3249 func TestContext2Plan_moduleMapLiteral(t *testing.T) { 3250 m := testModule(t, "plan-module-map-literal") 3251 p := testProvider("aws") 3252 p.ApplyFn = testApplyFn 3253 p.DiffFn = func(i *InstanceInfo, s *InstanceState, c *ResourceConfig) (*InstanceDiff, error) { 3254 // Here we verify that both the populated and empty map literals made it 3255 // through to the resource attributes 3256 val, _ := c.Get("tags") 3257 m, ok := val.(map[string]interface{}) 3258 if !ok { 3259 t.Fatalf("Tags attr not map: %#v", val) 3260 } 3261 if m["foo"] != "bar" { 3262 t.Fatalf("Bad value in tags attr: %#v", m) 3263 } 3264 { 3265 val, _ := c.Get("meta") 3266 m, ok := val.(map[string]interface{}) 3267 if !ok { 3268 t.Fatalf("Meta attr not map: %#v", val) 3269 } 3270 if len(m) != 0 { 3271 t.Fatalf("Meta attr not empty: %#v", val) 3272 } 3273 } 3274 return nil, nil 3275 } 3276 ctx := testContext2(t, &ContextOpts{ 3277 Module: m, 3278 ProviderResolver: ResourceProviderResolverFixed( 3279 map[string]ResourceProviderFactory{ 3280 "aws": testProviderFuncFixed(p), 3281 }, 3282 ), 3283 }) 3284 3285 if _, err := ctx.Plan(); err != nil { 3286 t.Fatalf("err: %s", err) 3287 } 3288 } 3289 3290 func TestContext2Plan_computedValueInMap(t *testing.T) { 3291 m := testModule(t, "plan-computed-value-in-map") 3292 p := testProvider("aws") 3293 p.DiffFn = func(info *InstanceInfo, state *InstanceState, c *ResourceConfig) (*InstanceDiff, error) { 3294 switch info.Type { 3295 case "aws_computed_source": 3296 return &InstanceDiff{ 3297 Attributes: map[string]*ResourceAttrDiff{ 3298 "computed_read_only": &ResourceAttrDiff{ 3299 NewComputed: true, 3300 }, 3301 }, 3302 }, nil 3303 } 3304 3305 return testDiffFn(info, state, c) 3306 } 3307 ctx := testContext2(t, &ContextOpts{ 3308 Module: m, 3309 ProviderResolver: ResourceProviderResolverFixed( 3310 map[string]ResourceProviderFactory{ 3311 "aws": testProviderFuncFixed(p), 3312 }, 3313 ), 3314 }) 3315 3316 if _, err := ctx.Plan(); err != nil { 3317 t.Fatalf("err: %s", err) 3318 } 3319 3320 plan, err := ctx.Plan() 3321 if err != nil { 3322 t.Fatalf("err: %s", err) 3323 } 3324 3325 actual := strings.TrimSpace(plan.String()) 3326 expected := strings.TrimSpace(testTerraformPlanComputedValueInMap) 3327 if actual != expected { 3328 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 3329 } 3330 } 3331 3332 func TestContext2Plan_moduleVariableFromSplat(t *testing.T) { 3333 m := testModule(t, "plan-module-variable-from-splat") 3334 p := testProvider("aws") 3335 p.DiffFn = testDiffFn 3336 ctx := testContext2(t, &ContextOpts{ 3337 Module: m, 3338 ProviderResolver: ResourceProviderResolverFixed( 3339 map[string]ResourceProviderFactory{ 3340 "aws": testProviderFuncFixed(p), 3341 }, 3342 ), 3343 }) 3344 3345 if _, err := ctx.Plan(); err != nil { 3346 t.Fatalf("err: %s", err) 3347 } 3348 3349 plan, err := ctx.Plan() 3350 if err != nil { 3351 t.Fatalf("err: %s", err) 3352 } 3353 3354 actual := strings.TrimSpace(plan.String()) 3355 expected := strings.TrimSpace(testTerraformPlanModuleVariableFromSplat) 3356 if actual != expected { 3357 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 3358 } 3359 } 3360 3361 func TestContext2Plan_createBeforeDestroy_depends_datasource(t *testing.T) { 3362 m := testModule(t, "plan-cdb-depends-datasource") 3363 p := testProvider("aws") 3364 p.DiffFn = testDiffFn 3365 ctx := testContext2(t, &ContextOpts{ 3366 Module: m, 3367 ProviderResolver: ResourceProviderResolverFixed( 3368 map[string]ResourceProviderFactory{ 3369 "aws": testProviderFuncFixed(p), 3370 }, 3371 ), 3372 }) 3373 3374 plan, err := ctx.Plan() 3375 if err != nil { 3376 t.Fatalf("err: %s", err) 3377 } 3378 3379 if got := len(plan.Diff.Modules); got != 1 { 3380 t.Fatalf("got %d modules; want 1", got) 3381 } 3382 3383 moduleDiff := plan.Diff.Modules[0] 3384 3385 if _, ok := moduleDiff.Resources["aws_instance.foo.0"]; !ok { 3386 t.Fatalf("missing diff for aws_instance.foo.0") 3387 } 3388 if _, ok := moduleDiff.Resources["aws_instance.foo.1"]; !ok { 3389 t.Fatalf("missing diff for aws_instance.foo.1") 3390 } 3391 if _, ok := moduleDiff.Resources["data.aws_vpc.bar.0"]; !ok { 3392 t.Fatalf("missing diff for data.aws_vpc.bar.0") 3393 } 3394 if _, ok := moduleDiff.Resources["data.aws_vpc.bar.1"]; !ok { 3395 t.Fatalf("missing diff for data.aws_vpc.bar.1") 3396 } 3397 } 3398 3399 // interpolated lists need to be stored in the original order. 3400 func TestContext2Plan_listOrder(t *testing.T) { 3401 m := testModule(t, "plan-list-order") 3402 p := testProvider("aws") 3403 p.ApplyFn = testApplyFn 3404 p.DiffFn = testDiffFn 3405 ctx := testContext2(t, &ContextOpts{ 3406 Module: m, 3407 ProviderResolver: ResourceProviderResolverFixed( 3408 map[string]ResourceProviderFactory{ 3409 "aws": testProviderFuncFixed(p), 3410 }, 3411 ), 3412 }) 3413 3414 plan, err := ctx.Plan() 3415 if err != nil { 3416 t.Fatalf("err: %s", err) 3417 } 3418 3419 rDiffs := plan.Diff.Modules[0].Resources 3420 rDiffA := rDiffs["aws_instance.a"] 3421 rDiffB := rDiffs["aws_instance.b"] 3422 3423 if !rDiffA.Equal(rDiffB) { 3424 t.Fatal("aws_instance.a and aws_instance.b diffs should match:\n", plan) 3425 } 3426 } 3427 3428 // Make sure ignore-changes doesn't interfere with set/list/map diffs. 3429 // If a resource was being replaced by a RequiresNew attribute that gets 3430 // ignored, we need to filter the diff properly to properly update rather than 3431 // replace. 3432 func TestContext2Plan_ignoreChangesWithFlatmaps(t *testing.T) { 3433 m := testModule(t, "plan-ignore-changes-with-flatmaps") 3434 p := testProvider("aws") 3435 p.DiffFn = testDiffFn 3436 s := &State{ 3437 Modules: []*ModuleState{ 3438 &ModuleState{ 3439 Path: rootModulePath, 3440 Resources: map[string]*ResourceState{ 3441 "aws_instance.foo": &ResourceState{ 3442 Type: "aws_instance", 3443 Primary: &InstanceState{ 3444 ID: "bar", 3445 Attributes: map[string]string{ 3446 "user_data": "x", 3447 "require_new": "", 3448 "set.#": "1", 3449 "set.0.a": "1", 3450 "lst.#": "1", 3451 "lst.0": "j", 3452 }, 3453 }, 3454 }, 3455 }, 3456 }, 3457 }, 3458 } 3459 ctx := testContext2(t, &ContextOpts{ 3460 Module: m, 3461 ProviderResolver: ResourceProviderResolverFixed( 3462 map[string]ResourceProviderFactory{ 3463 "aws": testProviderFuncFixed(p), 3464 }, 3465 ), 3466 State: s, 3467 }) 3468 3469 plan, err := ctx.Plan() 3470 if err != nil { 3471 t.Fatalf("err: %s", err) 3472 } 3473 3474 actual := strings.TrimSpace(plan.Diff.String()) 3475 expected := strings.TrimSpace(testTFPlanDiffIgnoreChangesWithFlatmaps) 3476 if actual != expected { 3477 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 3478 } 3479 } 3480 3481 // TestContext2Plan_resourceNestedCount ensures resource sets that depend on 3482 // the count of another resource set (ie: count of a data source that depends 3483 // on another data source's instance count - data.x.foo.*.id) get properly 3484 // normalized to the indexes they should be. This case comes up when there is 3485 // an existing state (after an initial apply). 3486 func TestContext2Plan_resourceNestedCount(t *testing.T) { 3487 m := testModule(t, "nested-resource-count-plan") 3488 p := testProvider("aws") 3489 p.DiffFn = testDiffFn 3490 p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) { 3491 return is, nil 3492 } 3493 s := &State{ 3494 Modules: []*ModuleState{ 3495 &ModuleState{ 3496 Path: rootModulePath, 3497 Resources: map[string]*ResourceState{ 3498 "aws_instance.foo.0": &ResourceState{ 3499 Type: "aws_instance", 3500 Primary: &InstanceState{ 3501 ID: "foo0", 3502 Attributes: map[string]string{ 3503 "id": "foo0", 3504 }, 3505 }, 3506 }, 3507 "aws_instance.foo.1": &ResourceState{ 3508 Type: "aws_instance", 3509 Primary: &InstanceState{ 3510 ID: "foo1", 3511 Attributes: map[string]string{ 3512 "id": "foo1", 3513 }, 3514 }, 3515 }, 3516 "aws_instance.bar.0": &ResourceState{ 3517 Type: "aws_instance", 3518 Dependencies: []string{"aws_instance.foo.*"}, 3519 Primary: &InstanceState{ 3520 ID: "bar0", 3521 Attributes: map[string]string{ 3522 "id": "bar0", 3523 }, 3524 }, 3525 }, 3526 "aws_instance.bar.1": &ResourceState{ 3527 Type: "aws_instance", 3528 Dependencies: []string{"aws_instance.foo.*"}, 3529 Primary: &InstanceState{ 3530 ID: "bar1", 3531 Attributes: map[string]string{ 3532 "id": "bar1", 3533 }, 3534 }, 3535 }, 3536 "aws_instance.baz.0": &ResourceState{ 3537 Type: "aws_instance", 3538 Dependencies: []string{"aws_instance.bar.*"}, 3539 Primary: &InstanceState{ 3540 ID: "baz0", 3541 Attributes: map[string]string{ 3542 "id": "baz0", 3543 }, 3544 }, 3545 }, 3546 "aws_instance.baz.1": &ResourceState{ 3547 Type: "aws_instance", 3548 Dependencies: []string{"aws_instance.bar.*"}, 3549 Primary: &InstanceState{ 3550 ID: "baz1", 3551 Attributes: map[string]string{ 3552 "id": "baz1", 3553 }, 3554 }, 3555 }, 3556 }, 3557 }, 3558 }, 3559 } 3560 ctx := testContext2(t, &ContextOpts{ 3561 Module: m, 3562 ProviderResolver: ResourceProviderResolverFixed( 3563 map[string]ResourceProviderFactory{ 3564 "aws": testProviderFuncFixed(p), 3565 }, 3566 ), 3567 State: s, 3568 }) 3569 3570 diags := ctx.Validate() 3571 if len(diags) != 0 { 3572 t.Fatalf("bad: %#v", diags) 3573 } 3574 3575 _, err := ctx.Refresh() 3576 if err != nil { 3577 t.Fatalf("refresh err: %s", err) 3578 } 3579 3580 plan, err := ctx.Plan() 3581 if err != nil { 3582 t.Fatalf("plan err: %s", err) 3583 } 3584 3585 actual := strings.TrimSpace(plan.String()) 3586 expected := strings.TrimSpace(` 3587 DIFF: 3588 3589 3590 3591 STATE: 3592 3593 aws_instance.bar.0: 3594 ID = bar0 3595 provider = provider.aws 3596 3597 Dependencies: 3598 aws_instance.foo.* 3599 aws_instance.bar.1: 3600 ID = bar1 3601 provider = provider.aws 3602 3603 Dependencies: 3604 aws_instance.foo.* 3605 aws_instance.baz.0: 3606 ID = baz0 3607 provider = provider.aws 3608 3609 Dependencies: 3610 aws_instance.bar.* 3611 aws_instance.baz.1: 3612 ID = baz1 3613 provider = provider.aws 3614 3615 Dependencies: 3616 aws_instance.bar.* 3617 aws_instance.foo.0: 3618 ID = foo0 3619 provider = provider.aws 3620 aws_instance.foo.1: 3621 ID = foo1 3622 provider = provider.aws 3623 `) 3624 if actual != expected { 3625 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 3626 } 3627 } 3628 3629 func TestContext2Plan_invalidOutput(t *testing.T) { 3630 m := testModuleInline(t, map[string]string{ 3631 "main.tf": ` 3632 data "aws_instance" "name" {} 3633 3634 output "out" { 3635 value = "${data.aws_instance.name.missing}" 3636 }`, 3637 }) 3638 3639 p := testProvider("aws") 3640 ctx := testContext2(t, &ContextOpts{ 3641 Module: m, 3642 ProviderResolver: ResourceProviderResolverFixed( 3643 map[string]ResourceProviderFactory{ 3644 "aws": testProviderFuncFixed(p), 3645 }, 3646 ), 3647 }) 3648 3649 // if this ever fails to pass validate, add a resource to reference in the config 3650 diags := ctx.Validate() 3651 if len(diags) != 0 { 3652 t.Fatalf("bad: %#v", diags) 3653 } 3654 3655 _, err := ctx.Refresh() 3656 if err != nil { 3657 t.Fatalf("refresh err: %s", err) 3658 } 3659 3660 _, err = ctx.Plan() 3661 if err == nil { 3662 t.Fatal("expected error") 3663 } 3664 } 3665 3666 func TestContext2Plan_invalidModuleOutput(t *testing.T) { 3667 m := testModuleInline(t, map[string]string{ 3668 "child/main.tf": ` 3669 data "aws_instance" "name" {} 3670 3671 output "out" { 3672 value = "${data.aws_instance.name.missing}" 3673 }`, 3674 "main.tf": ` 3675 module "child" { 3676 source = "./child" 3677 } 3678 3679 resource "aws_instance" "foo" { 3680 foo = "${module.child.out}" 3681 }`, 3682 }) 3683 3684 p := testProvider("aws") 3685 ctx := testContext2(t, &ContextOpts{ 3686 Module: m, 3687 ProviderResolver: ResourceProviderResolverFixed( 3688 map[string]ResourceProviderFactory{ 3689 "aws": testProviderFuncFixed(p), 3690 }, 3691 ), 3692 }) 3693 3694 // if this ever fails to pass validate, add a resource to reference in the config 3695 diags := ctx.Validate() 3696 if len(diags) != 0 { 3697 t.Fatalf("bad: %#v", diags) 3698 } 3699 3700 _, err := ctx.Refresh() 3701 if err != nil { 3702 t.Fatalf("refresh err: %s", err) 3703 } 3704 3705 _, err = ctx.Plan() 3706 if err == nil { 3707 t.Fatal("expected error") 3708 } 3709 }