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