github.com/chentex/terraform@v0.11.2-0.20171208003256-252e8145842e/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_orphan(t *testing.T) { 2405 m := testModule(t, "plan-orphan") 2406 p := testProvider("aws") 2407 p.DiffFn = testDiffFn 2408 s := &State{ 2409 Modules: []*ModuleState{ 2410 &ModuleState{ 2411 Path: rootModulePath, 2412 Resources: map[string]*ResourceState{ 2413 "aws_instance.baz": &ResourceState{ 2414 Type: "aws_instance", 2415 Primary: &InstanceState{ 2416 ID: "bar", 2417 }, 2418 }, 2419 }, 2420 }, 2421 }, 2422 } 2423 ctx := testContext2(t, &ContextOpts{ 2424 Module: m, 2425 ProviderResolver: ResourceProviderResolverFixed( 2426 map[string]ResourceProviderFactory{ 2427 "aws": testProviderFuncFixed(p), 2428 }, 2429 ), 2430 State: s, 2431 }) 2432 2433 plan, err := ctx.Plan() 2434 if err != nil { 2435 t.Fatalf("err: %s", err) 2436 } 2437 2438 actual := strings.TrimSpace(plan.String()) 2439 expected := strings.TrimSpace(testTerraformPlanOrphanStr) 2440 if actual != expected { 2441 t.Fatalf("bad:\n%s", actual) 2442 } 2443 } 2444 2445 // This tests that configurations with UUIDs don't produce errors. 2446 // For shadows, this would produce errors since a UUID changes every time. 2447 func TestContext2Plan_shadowUuid(t *testing.T) { 2448 m := testModule(t, "plan-shadow-uuid") 2449 p := testProvider("aws") 2450 p.DiffFn = testDiffFn 2451 ctx := testContext2(t, &ContextOpts{ 2452 Module: m, 2453 ProviderResolver: ResourceProviderResolverFixed( 2454 map[string]ResourceProviderFactory{ 2455 "aws": testProviderFuncFixed(p), 2456 }, 2457 ), 2458 }) 2459 2460 _, err := ctx.Plan() 2461 if err != nil { 2462 t.Fatalf("err: %s", err) 2463 } 2464 } 2465 2466 func TestContext2Plan_state(t *testing.T) { 2467 m := testModule(t, "plan-good") 2468 p := testProvider("aws") 2469 p.DiffFn = testDiffFn 2470 s := &State{ 2471 Modules: []*ModuleState{ 2472 &ModuleState{ 2473 Path: rootModulePath, 2474 Resources: map[string]*ResourceState{ 2475 "aws_instance.foo": &ResourceState{ 2476 Type: "aws_instance", 2477 Primary: &InstanceState{ 2478 ID: "bar", 2479 }, 2480 }, 2481 }, 2482 }, 2483 }, 2484 } 2485 ctx := testContext2(t, &ContextOpts{ 2486 Module: m, 2487 ProviderResolver: ResourceProviderResolverFixed( 2488 map[string]ResourceProviderFactory{ 2489 "aws": testProviderFuncFixed(p), 2490 }, 2491 ), 2492 State: s, 2493 }) 2494 2495 plan, err := ctx.Plan() 2496 if err != nil { 2497 t.Fatalf("err: %s", err) 2498 } 2499 2500 if len(plan.Diff.RootModule().Resources) < 2 { 2501 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 2502 } 2503 2504 actual := strings.TrimSpace(plan.String()) 2505 expected := strings.TrimSpace(testTerraformPlanStateStr) 2506 if actual != expected { 2507 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 2508 } 2509 } 2510 2511 func TestContext2Plan_taint(t *testing.T) { 2512 m := testModule(t, "plan-taint") 2513 p := testProvider("aws") 2514 p.DiffFn = testDiffFn 2515 s := &State{ 2516 Modules: []*ModuleState{ 2517 &ModuleState{ 2518 Path: rootModulePath, 2519 Resources: map[string]*ResourceState{ 2520 "aws_instance.foo": &ResourceState{ 2521 Type: "aws_instance", 2522 Primary: &InstanceState{ 2523 ID: "bar", 2524 Attributes: map[string]string{"num": "2"}, 2525 }, 2526 }, 2527 "aws_instance.bar": &ResourceState{ 2528 Type: "aws_instance", 2529 Primary: &InstanceState{ 2530 ID: "baz", 2531 Tainted: true, 2532 }, 2533 }, 2534 }, 2535 }, 2536 }, 2537 } 2538 ctx := testContext2(t, &ContextOpts{ 2539 Module: m, 2540 ProviderResolver: ResourceProviderResolverFixed( 2541 map[string]ResourceProviderFactory{ 2542 "aws": testProviderFuncFixed(p), 2543 }, 2544 ), 2545 State: s, 2546 }) 2547 2548 plan, err := ctx.Plan() 2549 if err != nil { 2550 t.Fatalf("err: %s", err) 2551 } 2552 2553 actual := strings.TrimSpace(plan.String()) 2554 expected := strings.TrimSpace(testTerraformPlanTaintStr) 2555 if actual != expected { 2556 t.Fatalf("bad:\n%s", actual) 2557 } 2558 } 2559 2560 func TestContext2Apply_taintIgnoreChanges(t *testing.T) { 2561 m := testModule(t, "plan-taint-ignore-changes") 2562 p := testProvider("aws") 2563 p.ApplyFn = testApplyFn 2564 p.DiffFn = testDiffFn 2565 s := &State{ 2566 Modules: []*ModuleState{ 2567 &ModuleState{ 2568 Path: rootModulePath, 2569 Resources: map[string]*ResourceState{ 2570 "aws_instance.foo": &ResourceState{ 2571 Type: "aws_instance", 2572 Primary: &InstanceState{ 2573 ID: "foo", 2574 Attributes: map[string]string{ 2575 "vars": "foo", 2576 "type": "aws_instance", 2577 }, 2578 Tainted: true, 2579 }, 2580 }, 2581 }, 2582 }, 2583 }, 2584 } 2585 ctx := testContext2(t, &ContextOpts{ 2586 Module: m, 2587 ProviderResolver: ResourceProviderResolverFixed( 2588 map[string]ResourceProviderFactory{ 2589 "aws": testProviderFuncFixed(p), 2590 }, 2591 ), 2592 State: s, 2593 }) 2594 2595 plan, err := ctx.Plan() 2596 if err != nil { 2597 t.Fatalf("err: %s", err) 2598 } 2599 2600 actual := strings.TrimSpace(plan.String()) 2601 expected := strings.TrimSpace(testTerraformPlanTaintIgnoreChangesStr) 2602 if actual != expected { 2603 t.Fatalf("bad:\n%s", actual) 2604 } 2605 } 2606 2607 // Fails about 50% of the time before the fix for GH-4982, covers the fix. 2608 func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) { 2609 m := testModule(t, "plan-taint-interpolated-count") 2610 p := testProvider("aws") 2611 p.DiffFn = testDiffFn 2612 s := &State{ 2613 Modules: []*ModuleState{ 2614 &ModuleState{ 2615 Path: rootModulePath, 2616 Resources: map[string]*ResourceState{ 2617 "aws_instance.foo.0": &ResourceState{ 2618 Type: "aws_instance", 2619 Primary: &InstanceState{ 2620 ID: "bar", 2621 Tainted: true, 2622 }, 2623 }, 2624 "aws_instance.foo.1": &ResourceState{ 2625 Type: "aws_instance", 2626 Primary: &InstanceState{ID: "bar"}, 2627 }, 2628 "aws_instance.foo.2": &ResourceState{ 2629 Type: "aws_instance", 2630 Primary: &InstanceState{ID: "bar"}, 2631 }, 2632 }, 2633 }, 2634 }, 2635 } 2636 ctx := testContext2(t, &ContextOpts{ 2637 Module: m, 2638 ProviderResolver: ResourceProviderResolverFixed( 2639 map[string]ResourceProviderFactory{ 2640 "aws": testProviderFuncFixed(p), 2641 }, 2642 ), 2643 State: s, 2644 }) 2645 2646 for i := 0; i < 100; i++ { 2647 plan, err := ctx.Plan() 2648 if err != nil { 2649 t.Fatalf("err: %s", err) 2650 } 2651 2652 actual := strings.TrimSpace(plan.String()) 2653 expected := strings.TrimSpace(` 2654 DIFF: 2655 2656 DESTROY/CREATE: aws_instance.foo.0 2657 type: "" => "aws_instance" 2658 2659 STATE: 2660 2661 aws_instance.foo.0: (tainted) 2662 ID = bar 2663 aws_instance.foo.1: 2664 ID = bar 2665 aws_instance.foo.2: 2666 ID = bar 2667 `) 2668 if actual != expected { 2669 t.Fatalf("[%d] bad:\n%s\nexpected:\n%s\n", i, actual, expected) 2670 } 2671 } 2672 } 2673 2674 func TestContext2Plan_targeted(t *testing.T) { 2675 m := testModule(t, "plan-targeted") 2676 p := testProvider("aws") 2677 p.DiffFn = testDiffFn 2678 ctx := testContext2(t, &ContextOpts{ 2679 Module: m, 2680 ProviderResolver: ResourceProviderResolverFixed( 2681 map[string]ResourceProviderFactory{ 2682 "aws": testProviderFuncFixed(p), 2683 }, 2684 ), 2685 Targets: []string{"aws_instance.foo"}, 2686 }) 2687 2688 plan, err := ctx.Plan() 2689 if err != nil { 2690 t.Fatalf("err: %s", err) 2691 } 2692 2693 actual := strings.TrimSpace(plan.String()) 2694 expected := strings.TrimSpace(` 2695 DIFF: 2696 2697 CREATE: aws_instance.foo 2698 num: "" => "2" 2699 type: "" => "aws_instance" 2700 2701 STATE: 2702 2703 <no state> 2704 `) 2705 if actual != expected { 2706 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2707 } 2708 } 2709 2710 // Test that targeting a module properly plans any inputs that depend 2711 // on another module. 2712 func TestContext2Plan_targetedCrossModule(t *testing.T) { 2713 m := testModule(t, "plan-targeted-cross-module") 2714 p := testProvider("aws") 2715 p.DiffFn = testDiffFn 2716 ctx := testContext2(t, &ContextOpts{ 2717 Module: m, 2718 ProviderResolver: ResourceProviderResolverFixed( 2719 map[string]ResourceProviderFactory{ 2720 "aws": testProviderFuncFixed(p), 2721 }, 2722 ), 2723 Targets: []string{"module.B"}, 2724 }) 2725 2726 plan, err := ctx.Plan() 2727 if err != nil { 2728 t.Fatalf("err: %s", err) 2729 } 2730 2731 actual := strings.TrimSpace(plan.String()) 2732 expected := strings.TrimSpace(` 2733 DIFF: 2734 2735 module.A: 2736 CREATE: aws_instance.foo 2737 foo: "" => "bar" 2738 type: "" => "aws_instance" 2739 module.B: 2740 CREATE: aws_instance.bar 2741 foo: "" => "<computed>" 2742 type: "" => "aws_instance" 2743 2744 STATE: 2745 2746 <no state> 2747 `) 2748 if actual != expected { 2749 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2750 } 2751 } 2752 2753 func TestContext2Plan_targetedModuleWithProvider(t *testing.T) { 2754 m := testModule(t, "plan-targeted-module-with-provider") 2755 p := testProvider("null") 2756 p.DiffFn = testDiffFn 2757 ctx := testContext2(t, &ContextOpts{ 2758 Module: m, 2759 ProviderResolver: ResourceProviderResolverFixed( 2760 map[string]ResourceProviderFactory{ 2761 "null": testProviderFuncFixed(p), 2762 }, 2763 ), 2764 Targets: []string{"module.child2"}, 2765 }) 2766 2767 plan, err := ctx.Plan() 2768 if err != nil { 2769 t.Fatalf("err: %s", err) 2770 } 2771 2772 actual := strings.TrimSpace(plan.String()) 2773 expected := strings.TrimSpace(` 2774 DIFF: 2775 2776 module.child2: 2777 CREATE: null_resource.foo 2778 2779 STATE: 2780 2781 <no state> 2782 `) 2783 if actual != expected { 2784 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2785 } 2786 } 2787 2788 func TestContext2Plan_targetedOrphan(t *testing.T) { 2789 m := testModule(t, "plan-targeted-orphan") 2790 p := testProvider("aws") 2791 p.DiffFn = testDiffFn 2792 ctx := testContext2(t, &ContextOpts{ 2793 Module: m, 2794 ProviderResolver: ResourceProviderResolverFixed( 2795 map[string]ResourceProviderFactory{ 2796 "aws": testProviderFuncFixed(p), 2797 }, 2798 ), 2799 State: &State{ 2800 Modules: []*ModuleState{ 2801 &ModuleState{ 2802 Path: rootModulePath, 2803 Resources: map[string]*ResourceState{ 2804 "aws_instance.orphan": &ResourceState{ 2805 Type: "aws_instance", 2806 Primary: &InstanceState{ 2807 ID: "i-789xyz", 2808 }, 2809 }, 2810 "aws_instance.nottargeted": &ResourceState{ 2811 Type: "aws_instance", 2812 Primary: &InstanceState{ 2813 ID: "i-abc123", 2814 }, 2815 }, 2816 }, 2817 }, 2818 }, 2819 }, 2820 Destroy: true, 2821 Targets: []string{"aws_instance.orphan"}, 2822 }) 2823 2824 plan, err := ctx.Plan() 2825 if err != nil { 2826 t.Fatalf("err: %s", err) 2827 } 2828 2829 actual := strings.TrimSpace(plan.String()) 2830 expected := strings.TrimSpace(`DIFF: 2831 2832 DESTROY: aws_instance.orphan 2833 2834 STATE: 2835 2836 aws_instance.nottargeted: 2837 ID = i-abc123 2838 aws_instance.orphan: 2839 ID = i-789xyz 2840 `) 2841 if actual != expected { 2842 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2843 } 2844 } 2845 2846 // https://github.com/hashicorp/terraform/issues/2538 2847 func TestContext2Plan_targetedModuleOrphan(t *testing.T) { 2848 m := testModule(t, "plan-targeted-module-orphan") 2849 p := testProvider("aws") 2850 p.DiffFn = testDiffFn 2851 ctx := testContext2(t, &ContextOpts{ 2852 Module: m, 2853 ProviderResolver: ResourceProviderResolverFixed( 2854 map[string]ResourceProviderFactory{ 2855 "aws": testProviderFuncFixed(p), 2856 }, 2857 ), 2858 State: &State{ 2859 Modules: []*ModuleState{ 2860 &ModuleState{ 2861 Path: []string{"root", "child"}, 2862 Resources: map[string]*ResourceState{ 2863 "aws_instance.orphan": &ResourceState{ 2864 Type: "aws_instance", 2865 Primary: &InstanceState{ 2866 ID: "i-789xyz", 2867 }, 2868 }, 2869 "aws_instance.nottargeted": &ResourceState{ 2870 Type: "aws_instance", 2871 Primary: &InstanceState{ 2872 ID: "i-abc123", 2873 }, 2874 }, 2875 }, 2876 }, 2877 }, 2878 }, 2879 Destroy: true, 2880 Targets: []string{"module.child.aws_instance.orphan"}, 2881 }) 2882 2883 plan, err := ctx.Plan() 2884 if err != nil { 2885 t.Fatalf("err: %s", err) 2886 } 2887 2888 actual := strings.TrimSpace(plan.String()) 2889 expected := strings.TrimSpace(`DIFF: 2890 2891 module.child: 2892 DESTROY: aws_instance.orphan 2893 2894 STATE: 2895 2896 module.child: 2897 aws_instance.nottargeted: 2898 ID = i-abc123 2899 aws_instance.orphan: 2900 ID = i-789xyz 2901 `) 2902 if actual != expected { 2903 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2904 } 2905 } 2906 2907 func TestContext2Plan_targetedModuleUntargetedVariable(t *testing.T) { 2908 m := testModule(t, "plan-targeted-module-untargeted-variable") 2909 p := testProvider("aws") 2910 p.DiffFn = testDiffFn 2911 ctx := testContext2(t, &ContextOpts{ 2912 Module: m, 2913 ProviderResolver: ResourceProviderResolverFixed( 2914 map[string]ResourceProviderFactory{ 2915 "aws": testProviderFuncFixed(p), 2916 }, 2917 ), 2918 Targets: []string{"aws_instance.blue", "module.blue_mod"}, 2919 }) 2920 2921 plan, err := ctx.Plan() 2922 if err != nil { 2923 t.Fatalf("err: %s", err) 2924 } 2925 2926 actual := strings.TrimSpace(plan.String()) 2927 expected := strings.TrimSpace(` 2928 DIFF: 2929 2930 CREATE: aws_instance.blue 2931 2932 module.blue_mod: 2933 CREATE: aws_instance.mod 2934 type: "" => "aws_instance" 2935 value: "" => "<computed>" 2936 2937 STATE: 2938 2939 <no state> 2940 `) 2941 if actual != expected { 2942 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2943 } 2944 } 2945 2946 // https://github.com/hashicorp/terraform/issues/4515 2947 func TestContext2Plan_targetedOverTen(t *testing.T) { 2948 m := testModule(t, "plan-targeted-over-ten") 2949 p := testProvider("aws") 2950 p.DiffFn = testDiffFn 2951 2952 resources := make(map[string]*ResourceState) 2953 var expectedState []string 2954 for i := 0; i < 13; i++ { 2955 key := fmt.Sprintf("aws_instance.foo.%d", i) 2956 id := fmt.Sprintf("i-abc%d", i) 2957 resources[key] = &ResourceState{ 2958 Type: "aws_instance", 2959 Primary: &InstanceState{ID: id}, 2960 } 2961 expectedState = append(expectedState, 2962 fmt.Sprintf("%s:\n ID = %s\n", key, id)) 2963 } 2964 ctx := testContext2(t, &ContextOpts{ 2965 Module: m, 2966 ProviderResolver: ResourceProviderResolverFixed( 2967 map[string]ResourceProviderFactory{ 2968 "aws": testProviderFuncFixed(p), 2969 }, 2970 ), 2971 State: &State{ 2972 Modules: []*ModuleState{ 2973 &ModuleState{ 2974 Path: rootModulePath, 2975 Resources: resources, 2976 }, 2977 }, 2978 }, 2979 Targets: []string{"aws_instance.foo[1]"}, 2980 }) 2981 2982 plan, err := ctx.Plan() 2983 if err != nil { 2984 t.Fatalf("err: %s", err) 2985 } 2986 2987 actual := strings.TrimSpace(plan.String()) 2988 sort.Strings(expectedState) 2989 expected := strings.TrimSpace(` 2990 DIFF: 2991 2992 2993 2994 STATE: 2995 2996 aws_instance.foo.0: 2997 ID = i-abc0 2998 aws_instance.foo.1: 2999 ID = i-abc1 3000 aws_instance.foo.2: 3001 ID = i-abc2 3002 aws_instance.foo.3: 3003 ID = i-abc3 3004 aws_instance.foo.4: 3005 ID = i-abc4 3006 aws_instance.foo.5: 3007 ID = i-abc5 3008 aws_instance.foo.6: 3009 ID = i-abc6 3010 aws_instance.foo.7: 3011 ID = i-abc7 3012 aws_instance.foo.8: 3013 ID = i-abc8 3014 aws_instance.foo.9: 3015 ID = i-abc9 3016 aws_instance.foo.10: 3017 ID = i-abc10 3018 aws_instance.foo.11: 3019 ID = i-abc11 3020 aws_instance.foo.12: 3021 ID = i-abc12 3022 `) 3023 if actual != expected { 3024 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 3025 } 3026 } 3027 3028 func TestContext2Plan_provider(t *testing.T) { 3029 m := testModule(t, "plan-provider") 3030 p := testProvider("aws") 3031 p.DiffFn = testDiffFn 3032 3033 var value interface{} 3034 p.ConfigureFn = func(c *ResourceConfig) error { 3035 value, _ = c.Get("foo") 3036 return nil 3037 } 3038 3039 ctx := testContext2(t, &ContextOpts{ 3040 Module: m, 3041 ProviderResolver: ResourceProviderResolverFixed( 3042 map[string]ResourceProviderFactory{ 3043 "aws": testProviderFuncFixed(p), 3044 }, 3045 ), 3046 Variables: map[string]interface{}{ 3047 "foo": "bar", 3048 }, 3049 }) 3050 3051 if _, err := ctx.Plan(); err != nil { 3052 t.Fatalf("err: %s", err) 3053 } 3054 3055 if value != "bar" { 3056 t.Fatalf("bad: %#v", value) 3057 } 3058 } 3059 3060 func TestContext2Plan_varListErr(t *testing.T) { 3061 m := testModule(t, "plan-var-list-err") 3062 p := testProvider("aws") 3063 ctx := testContext2(t, &ContextOpts{ 3064 Module: m, 3065 ProviderResolver: ResourceProviderResolverFixed( 3066 map[string]ResourceProviderFactory{ 3067 "aws": testProviderFuncFixed(p), 3068 }, 3069 ), 3070 }) 3071 3072 _, err := ctx.Plan() 3073 3074 if err == nil { 3075 t.Fatal("should error") 3076 } 3077 } 3078 3079 func TestContext2Plan_ignoreChanges(t *testing.T) { 3080 m := testModule(t, "plan-ignore-changes") 3081 p := testProvider("aws") 3082 p.DiffFn = testDiffFn 3083 s := &State{ 3084 Modules: []*ModuleState{ 3085 &ModuleState{ 3086 Path: rootModulePath, 3087 Resources: map[string]*ResourceState{ 3088 "aws_instance.foo": &ResourceState{ 3089 Type: "aws_instance", 3090 Primary: &InstanceState{ 3091 ID: "bar", 3092 Attributes: map[string]string{"ami": "ami-abcd1234"}, 3093 }, 3094 }, 3095 }, 3096 }, 3097 }, 3098 } 3099 ctx := testContext2(t, &ContextOpts{ 3100 Module: m, 3101 ProviderResolver: ResourceProviderResolverFixed( 3102 map[string]ResourceProviderFactory{ 3103 "aws": testProviderFuncFixed(p), 3104 }, 3105 ), 3106 Variables: map[string]interface{}{ 3107 "foo": "ami-1234abcd", 3108 }, 3109 State: s, 3110 }) 3111 3112 plan, err := ctx.Plan() 3113 if err != nil { 3114 t.Fatalf("err: %s", err) 3115 } 3116 3117 if len(plan.Diff.RootModule().Resources) < 1 { 3118 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 3119 } 3120 3121 actual := strings.TrimSpace(plan.String()) 3122 expected := strings.TrimSpace(testTerraformPlanIgnoreChangesStr) 3123 if actual != expected { 3124 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 3125 } 3126 } 3127 3128 func TestContext2Plan_ignoreChangesWildcard(t *testing.T) { 3129 m := testModule(t, "plan-ignore-changes-wildcard") 3130 p := testProvider("aws") 3131 p.DiffFn = testDiffFn 3132 s := &State{ 3133 Modules: []*ModuleState{ 3134 &ModuleState{ 3135 Path: rootModulePath, 3136 Resources: map[string]*ResourceState{ 3137 "aws_instance.foo": &ResourceState{ 3138 Type: "aws_instance", 3139 Primary: &InstanceState{ 3140 ID: "bar", 3141 Attributes: map[string]string{ 3142 "ami": "ami-abcd1234", 3143 "instance_type": "t2.micro", 3144 }, 3145 }, 3146 }, 3147 }, 3148 }, 3149 }, 3150 } 3151 ctx := testContext2(t, &ContextOpts{ 3152 Module: m, 3153 ProviderResolver: ResourceProviderResolverFixed( 3154 map[string]ResourceProviderFactory{ 3155 "aws": testProviderFuncFixed(p), 3156 }, 3157 ), 3158 Variables: map[string]interface{}{ 3159 "foo": "ami-1234abcd", 3160 "bar": "t2.small", 3161 }, 3162 State: s, 3163 }) 3164 3165 plan, err := ctx.Plan() 3166 if err != nil { 3167 t.Fatalf("err: %s", err) 3168 } 3169 3170 if len(plan.Diff.RootModule().Resources) > 0 { 3171 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 3172 } 3173 3174 actual := strings.TrimSpace(plan.String()) 3175 expected := strings.TrimSpace(testTerraformPlanIgnoreChangesWildcardStr) 3176 if actual != expected { 3177 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 3178 } 3179 } 3180 3181 func TestContext2Plan_moduleMapLiteral(t *testing.T) { 3182 m := testModule(t, "plan-module-map-literal") 3183 p := testProvider("aws") 3184 p.ApplyFn = testApplyFn 3185 p.DiffFn = func(i *InstanceInfo, s *InstanceState, c *ResourceConfig) (*InstanceDiff, error) { 3186 // Here we verify that both the populated and empty map literals made it 3187 // through to the resource attributes 3188 val, _ := c.Get("tags") 3189 m, ok := val.(map[string]interface{}) 3190 if !ok { 3191 t.Fatalf("Tags attr not map: %#v", val) 3192 } 3193 if m["foo"] != "bar" { 3194 t.Fatalf("Bad value in tags attr: %#v", m) 3195 } 3196 { 3197 val, _ := c.Get("meta") 3198 m, ok := val.(map[string]interface{}) 3199 if !ok { 3200 t.Fatalf("Meta attr not map: %#v", val) 3201 } 3202 if len(m) != 0 { 3203 t.Fatalf("Meta attr not empty: %#v", val) 3204 } 3205 } 3206 return nil, nil 3207 } 3208 ctx := testContext2(t, &ContextOpts{ 3209 Module: m, 3210 ProviderResolver: ResourceProviderResolverFixed( 3211 map[string]ResourceProviderFactory{ 3212 "aws": testProviderFuncFixed(p), 3213 }, 3214 ), 3215 }) 3216 3217 if _, err := ctx.Plan(); err != nil { 3218 t.Fatalf("err: %s", err) 3219 } 3220 } 3221 3222 func TestContext2Plan_computedValueInMap(t *testing.T) { 3223 m := testModule(t, "plan-computed-value-in-map") 3224 p := testProvider("aws") 3225 p.DiffFn = func(info *InstanceInfo, state *InstanceState, c *ResourceConfig) (*InstanceDiff, error) { 3226 switch info.Type { 3227 case "aws_computed_source": 3228 return &InstanceDiff{ 3229 Attributes: map[string]*ResourceAttrDiff{ 3230 "computed_read_only": &ResourceAttrDiff{ 3231 NewComputed: true, 3232 }, 3233 }, 3234 }, nil 3235 } 3236 3237 return testDiffFn(info, state, c) 3238 } 3239 ctx := testContext2(t, &ContextOpts{ 3240 Module: m, 3241 ProviderResolver: ResourceProviderResolverFixed( 3242 map[string]ResourceProviderFactory{ 3243 "aws": testProviderFuncFixed(p), 3244 }, 3245 ), 3246 }) 3247 3248 if _, err := ctx.Plan(); err != nil { 3249 t.Fatalf("err: %s", err) 3250 } 3251 3252 plan, err := ctx.Plan() 3253 if err != nil { 3254 t.Fatalf("err: %s", err) 3255 } 3256 3257 actual := strings.TrimSpace(plan.String()) 3258 expected := strings.TrimSpace(testTerraformPlanComputedValueInMap) 3259 if actual != expected { 3260 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 3261 } 3262 } 3263 3264 func TestContext2Plan_moduleVariableFromSplat(t *testing.T) { 3265 m := testModule(t, "plan-module-variable-from-splat") 3266 p := testProvider("aws") 3267 p.DiffFn = testDiffFn 3268 ctx := testContext2(t, &ContextOpts{ 3269 Module: m, 3270 ProviderResolver: ResourceProviderResolverFixed( 3271 map[string]ResourceProviderFactory{ 3272 "aws": testProviderFuncFixed(p), 3273 }, 3274 ), 3275 }) 3276 3277 if _, err := ctx.Plan(); err != nil { 3278 t.Fatalf("err: %s", err) 3279 } 3280 3281 plan, err := ctx.Plan() 3282 if err != nil { 3283 t.Fatalf("err: %s", err) 3284 } 3285 3286 actual := strings.TrimSpace(plan.String()) 3287 expected := strings.TrimSpace(testTerraformPlanModuleVariableFromSplat) 3288 if actual != expected { 3289 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 3290 } 3291 } 3292 3293 func TestContext2Plan_createBeforeDestroy_depends_datasource(t *testing.T) { 3294 m := testModule(t, "plan-cdb-depends-datasource") 3295 p := testProvider("aws") 3296 p.DiffFn = testDiffFn 3297 ctx := testContext2(t, &ContextOpts{ 3298 Module: m, 3299 ProviderResolver: ResourceProviderResolverFixed( 3300 map[string]ResourceProviderFactory{ 3301 "aws": testProviderFuncFixed(p), 3302 }, 3303 ), 3304 }) 3305 3306 plan, err := ctx.Plan() 3307 if err != nil { 3308 t.Fatalf("err: %s", err) 3309 } 3310 3311 if got := len(plan.Diff.Modules); got != 1 { 3312 t.Fatalf("got %d modules; want 1", got) 3313 } 3314 3315 moduleDiff := plan.Diff.Modules[0] 3316 3317 if _, ok := moduleDiff.Resources["aws_instance.foo.0"]; !ok { 3318 t.Fatalf("missing diff for aws_instance.foo.0") 3319 } 3320 if _, ok := moduleDiff.Resources["aws_instance.foo.1"]; !ok { 3321 t.Fatalf("missing diff for aws_instance.foo.1") 3322 } 3323 if _, ok := moduleDiff.Resources["data.aws_vpc.bar.0"]; !ok { 3324 t.Fatalf("missing diff for data.aws_vpc.bar.0") 3325 } 3326 if _, ok := moduleDiff.Resources["data.aws_vpc.bar.1"]; !ok { 3327 t.Fatalf("missing diff for data.aws_vpc.bar.1") 3328 } 3329 } 3330 3331 // interpolated lists need to be stored in the original order. 3332 func TestContext2Plan_listOrder(t *testing.T) { 3333 m := testModule(t, "plan-list-order") 3334 p := testProvider("aws") 3335 p.ApplyFn = testApplyFn 3336 p.DiffFn = testDiffFn 3337 ctx := testContext2(t, &ContextOpts{ 3338 Module: m, 3339 ProviderResolver: ResourceProviderResolverFixed( 3340 map[string]ResourceProviderFactory{ 3341 "aws": testProviderFuncFixed(p), 3342 }, 3343 ), 3344 }) 3345 3346 plan, err := ctx.Plan() 3347 if err != nil { 3348 t.Fatalf("err: %s", err) 3349 } 3350 3351 rDiffs := plan.Diff.Modules[0].Resources 3352 rDiffA := rDiffs["aws_instance.a"] 3353 rDiffB := rDiffs["aws_instance.b"] 3354 3355 if !rDiffA.Equal(rDiffB) { 3356 t.Fatal("aws_instance.a and aws_instance.b diffs should match:\n", plan) 3357 } 3358 } 3359 3360 // Make sure ignore-changes doesn't interfere with set/list/map diffs. 3361 // If a resource was being replaced by a RequiresNew attribute that gets 3362 // ignored, we need to filter the diff properly to properly update rather than 3363 // replace. 3364 func TestContext2Plan_ignoreChangesWithFlatmaps(t *testing.T) { 3365 m := testModule(t, "plan-ignore-changes-with-flatmaps") 3366 p := testProvider("aws") 3367 p.DiffFn = testDiffFn 3368 s := &State{ 3369 Modules: []*ModuleState{ 3370 &ModuleState{ 3371 Path: rootModulePath, 3372 Resources: map[string]*ResourceState{ 3373 "aws_instance.foo": &ResourceState{ 3374 Type: "aws_instance", 3375 Primary: &InstanceState{ 3376 ID: "bar", 3377 Attributes: map[string]string{ 3378 "user_data": "x", 3379 "require_new": "", 3380 "set.#": "1", 3381 "set.0.a": "1", 3382 "lst.#": "1", 3383 "lst.0": "j", 3384 }, 3385 }, 3386 }, 3387 }, 3388 }, 3389 }, 3390 } 3391 ctx := testContext2(t, &ContextOpts{ 3392 Module: m, 3393 ProviderResolver: ResourceProviderResolverFixed( 3394 map[string]ResourceProviderFactory{ 3395 "aws": testProviderFuncFixed(p), 3396 }, 3397 ), 3398 State: s, 3399 }) 3400 3401 plan, err := ctx.Plan() 3402 if err != nil { 3403 t.Fatalf("err: %s", err) 3404 } 3405 3406 actual := strings.TrimSpace(plan.Diff.String()) 3407 expected := strings.TrimSpace(testTFPlanDiffIgnoreChangesWithFlatmaps) 3408 if actual != expected { 3409 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 3410 } 3411 } 3412 3413 // TestContext2Plan_resourceNestedCount ensures resource sets that depend on 3414 // the count of another resource set (ie: count of a data source that depends 3415 // on another data source's instance count - data.x.foo.*.id) get properly 3416 // normalized to the indexes they should be. This case comes up when there is 3417 // an existing state (after an initial apply). 3418 func TestContext2Plan_resourceNestedCount(t *testing.T) { 3419 m := testModule(t, "nested-resource-count-plan") 3420 p := testProvider("aws") 3421 p.DiffFn = testDiffFn 3422 p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) { 3423 return is, nil 3424 } 3425 s := &State{ 3426 Modules: []*ModuleState{ 3427 &ModuleState{ 3428 Path: rootModulePath, 3429 Resources: map[string]*ResourceState{ 3430 "aws_instance.foo.0": &ResourceState{ 3431 Type: "aws_instance", 3432 Primary: &InstanceState{ 3433 ID: "foo0", 3434 Attributes: map[string]string{ 3435 "id": "foo0", 3436 }, 3437 }, 3438 }, 3439 "aws_instance.foo.1": &ResourceState{ 3440 Type: "aws_instance", 3441 Primary: &InstanceState{ 3442 ID: "foo1", 3443 Attributes: map[string]string{ 3444 "id": "foo1", 3445 }, 3446 }, 3447 }, 3448 "aws_instance.bar.0": &ResourceState{ 3449 Type: "aws_instance", 3450 Dependencies: []string{"aws_instance.foo.*"}, 3451 Primary: &InstanceState{ 3452 ID: "bar0", 3453 Attributes: map[string]string{ 3454 "id": "bar0", 3455 }, 3456 }, 3457 }, 3458 "aws_instance.bar.1": &ResourceState{ 3459 Type: "aws_instance", 3460 Dependencies: []string{"aws_instance.foo.*"}, 3461 Primary: &InstanceState{ 3462 ID: "bar1", 3463 Attributes: map[string]string{ 3464 "id": "bar1", 3465 }, 3466 }, 3467 }, 3468 "aws_instance.baz.0": &ResourceState{ 3469 Type: "aws_instance", 3470 Dependencies: []string{"aws_instance.bar.*"}, 3471 Primary: &InstanceState{ 3472 ID: "baz0", 3473 Attributes: map[string]string{ 3474 "id": "baz0", 3475 }, 3476 }, 3477 }, 3478 "aws_instance.baz.1": &ResourceState{ 3479 Type: "aws_instance", 3480 Dependencies: []string{"aws_instance.bar.*"}, 3481 Primary: &InstanceState{ 3482 ID: "baz1", 3483 Attributes: map[string]string{ 3484 "id": "baz1", 3485 }, 3486 }, 3487 }, 3488 }, 3489 }, 3490 }, 3491 } 3492 ctx := testContext2(t, &ContextOpts{ 3493 Module: m, 3494 ProviderResolver: ResourceProviderResolverFixed( 3495 map[string]ResourceProviderFactory{ 3496 "aws": testProviderFuncFixed(p), 3497 }, 3498 ), 3499 State: s, 3500 }) 3501 3502 diags := ctx.Validate() 3503 if len(diags) != 0 { 3504 t.Fatalf("bad: %#v", diags) 3505 } 3506 3507 _, err := ctx.Refresh() 3508 if err != nil { 3509 t.Fatalf("refresh err: %s", err) 3510 } 3511 3512 plan, err := ctx.Plan() 3513 if err != nil { 3514 t.Fatalf("plan err: %s", err) 3515 } 3516 3517 actual := strings.TrimSpace(plan.String()) 3518 expected := strings.TrimSpace(` 3519 DIFF: 3520 3521 3522 3523 STATE: 3524 3525 aws_instance.bar.0: 3526 ID = bar0 3527 provider = provider.aws 3528 3529 Dependencies: 3530 aws_instance.foo.* 3531 aws_instance.bar.1: 3532 ID = bar1 3533 provider = provider.aws 3534 3535 Dependencies: 3536 aws_instance.foo.* 3537 aws_instance.baz.0: 3538 ID = baz0 3539 provider = provider.aws 3540 3541 Dependencies: 3542 aws_instance.bar.* 3543 aws_instance.baz.1: 3544 ID = baz1 3545 provider = provider.aws 3546 3547 Dependencies: 3548 aws_instance.bar.* 3549 aws_instance.foo.0: 3550 ID = foo0 3551 provider = provider.aws 3552 aws_instance.foo.1: 3553 ID = foo1 3554 provider = provider.aws 3555 `) 3556 if actual != expected { 3557 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 3558 } 3559 } 3560 3561 func TestContext2Plan_invalidOutput(t *testing.T) { 3562 m := testModuleInline(t, map[string]string{ 3563 "main.tf": ` 3564 data "aws_instance" "name" {} 3565 3566 output "out" { 3567 value = "${data.aws_instance.name.missing}" 3568 }`, 3569 }) 3570 3571 p := testProvider("aws") 3572 ctx := testContext2(t, &ContextOpts{ 3573 Module: m, 3574 ProviderResolver: ResourceProviderResolverFixed( 3575 map[string]ResourceProviderFactory{ 3576 "aws": testProviderFuncFixed(p), 3577 }, 3578 ), 3579 }) 3580 3581 // if this ever fails to pass validate, add a resource to reference in the config 3582 diags := ctx.Validate() 3583 if len(diags) != 0 { 3584 t.Fatalf("bad: %#v", diags) 3585 } 3586 3587 _, err := ctx.Refresh() 3588 if err != nil { 3589 t.Fatalf("refresh err: %s", err) 3590 } 3591 3592 _, err = ctx.Plan() 3593 if err == nil { 3594 t.Fatal("expected error") 3595 } 3596 } 3597 3598 func TestContext2Plan_invalidModuleOutput(t *testing.T) { 3599 m := testModuleInline(t, map[string]string{ 3600 "child/main.tf": ` 3601 data "aws_instance" "name" {} 3602 3603 output "out" { 3604 value = "${data.aws_instance.name.missing}" 3605 }`, 3606 "main.tf": ` 3607 module "child" { 3608 source = "./child" 3609 } 3610 3611 resource "aws_instance" "foo" { 3612 foo = "${module.child.out}" 3613 }`, 3614 }) 3615 3616 p := testProvider("aws") 3617 ctx := testContext2(t, &ContextOpts{ 3618 Module: m, 3619 ProviderResolver: ResourceProviderResolverFixed( 3620 map[string]ResourceProviderFactory{ 3621 "aws": testProviderFuncFixed(p), 3622 }, 3623 ), 3624 }) 3625 3626 // if this ever fails to pass validate, add a resource to reference in the config 3627 diags := ctx.Validate() 3628 if len(diags) != 0 { 3629 t.Fatalf("bad: %#v", diags) 3630 } 3631 3632 _, err := ctx.Refresh() 3633 if err != nil { 3634 t.Fatalf("refresh err: %s", err) 3635 } 3636 3637 _, err = ctx.Plan() 3638 if err == nil { 3639 t.Fatal("expected error") 3640 } 3641 }