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