github.com/tomaszheflik/terraform@v0.7.3-0.20160827060421-32f990b41594/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 // Higher level test at TestResource_dataSourceListPlanPanic 915 func TestContext2Plan_dataSourceTypeMismatch(t *testing.T) { 916 m := testModule(t, "plan-data-source-type-mismatch") 917 p := testProvider("aws") 918 p.ValidateResourceFn = func(t string, c *ResourceConfig) (ws []string, es []error) { 919 // Emulate the type checking behavior of helper/schema based validation 920 if t == "aws_instance" { 921 ami, _ := c.Get("ami") 922 switch a := ami.(type) { 923 case string: 924 // ok 925 default: 926 es = append(es, fmt.Errorf("Expected ami to be string, got %T", a)) 927 } 928 } 929 return 930 } 931 p.DiffFn = func( 932 info *InstanceInfo, 933 state *InstanceState, 934 c *ResourceConfig) (*InstanceDiff, error) { 935 if info.Type == "aws_instance" { 936 // If we get to the diff, we should be able to assume types 937 ami, _ := c.Get("ami") 938 _ = ami.(string) 939 } 940 return nil, nil 941 } 942 ctx := testContext2(t, &ContextOpts{ 943 Module: m, 944 // Pretend like we ran a Refresh and the AZs data source was populated. 945 State: &State{ 946 Modules: []*ModuleState{ 947 &ModuleState{ 948 Path: rootModulePath, 949 Resources: map[string]*ResourceState{ 950 "data.aws_availability_zones.azs": &ResourceState{ 951 Type: "aws_availability_zones", 952 Primary: &InstanceState{ 953 ID: "i-abc123", 954 Attributes: map[string]string{ 955 "names.#": "2", 956 "names.0": "us-east-1a", 957 "names.1": "us-east-1b", 958 }, 959 }, 960 }, 961 }, 962 }, 963 }, 964 }, 965 Providers: map[string]ResourceProviderFactory{ 966 "aws": testProviderFuncFixed(p), 967 }, 968 }) 969 970 _, err := ctx.Plan() 971 972 if err == nil { 973 t.Fatalf("Expected err, got none!") 974 } 975 expected := "Expected ami to be string" 976 if !strings.Contains(err.Error(), expected) { 977 t.Fatalf("expected:\n\n%s\n\nto contain:\n\n%s", err, expected) 978 } 979 } 980 981 func TestContext2Plan_dataResourceBecomesComputed(t *testing.T) { 982 m := testModule(t, "plan-data-resource-becomes-computed") 983 p := testProvider("aws") 984 985 p.DiffFn = func(info *InstanceInfo, state *InstanceState, config *ResourceConfig) (*InstanceDiff, error) { 986 if info.Type != "aws_instance" { 987 t.Fatalf("don't know how to diff %s", info.Id) 988 return nil, nil 989 } 990 991 return &InstanceDiff{ 992 Attributes: map[string]*ResourceAttrDiff{ 993 "computed": &ResourceAttrDiff{ 994 Old: "", 995 New: "", 996 NewComputed: true, 997 }, 998 }, 999 }, nil 1000 } 1001 p.ReadDataDiffReturn = &InstanceDiff{ 1002 Attributes: map[string]*ResourceAttrDiff{ 1003 "foo": &ResourceAttrDiff{ 1004 Old: "", 1005 New: "", 1006 NewComputed: true, 1007 }, 1008 }, 1009 } 1010 1011 ctx := testContext2(t, &ContextOpts{ 1012 Module: m, 1013 Providers: map[string]ResourceProviderFactory{ 1014 "aws": testProviderFuncFixed(p), 1015 }, 1016 State: &State{ 1017 Modules: []*ModuleState{ 1018 &ModuleState{ 1019 Path: rootModulePath, 1020 Resources: map[string]*ResourceState{ 1021 "data.aws_data_resource.foo": &ResourceState{ 1022 Type: "aws_data_resource", 1023 Primary: &InstanceState{ 1024 ID: "i-abc123", 1025 Attributes: map[string]string{ 1026 "id": "i-abc123", 1027 "value": "baz", 1028 }, 1029 }, 1030 }, 1031 }, 1032 }, 1033 }, 1034 }, 1035 }) 1036 1037 plan, err := ctx.Plan() 1038 if err != nil { 1039 t.Fatalf("err: %s", err) 1040 } 1041 1042 if got := len(plan.Diff.Modules); got != 1 { 1043 t.Fatalf("got %d modules; want 1", got) 1044 } 1045 1046 if !p.ReadDataDiffCalled { 1047 t.Fatal("ReadDataDiff wasn't called, but should've been") 1048 } 1049 if got, want := p.ReadDataDiffInfo.Id, "data.aws_data_resource.foo"; got != want { 1050 t.Fatalf("ReadDataDiff info id is %s; want %s", got, want) 1051 } 1052 1053 moduleDiff := plan.Diff.Modules[0] 1054 1055 iDiff, ok := moduleDiff.Resources["data.aws_data_resource.foo"] 1056 if !ok { 1057 t.Fatalf("missing diff for data.aws_data_resource.foo") 1058 } 1059 1060 if same, _ := p.ReadDataDiffReturn.Same(iDiff); !same { 1061 t.Fatalf( 1062 "incorrect diff for data.data_resource.foo\ngot: %#v\nwant: %#v", 1063 iDiff, p.ReadDataDiffReturn, 1064 ) 1065 } 1066 } 1067 1068 func TestContext2Plan_computedList(t *testing.T) { 1069 m := testModule(t, "plan-computed-list") 1070 p := testProvider("aws") 1071 p.DiffFn = testDiffFn 1072 ctx := testContext2(t, &ContextOpts{ 1073 Module: m, 1074 Providers: map[string]ResourceProviderFactory{ 1075 "aws": testProviderFuncFixed(p), 1076 }, 1077 }) 1078 1079 plan, err := ctx.Plan() 1080 if err != nil { 1081 t.Fatalf("err: %s", err) 1082 } 1083 1084 actual := strings.TrimSpace(plan.String()) 1085 expected := strings.TrimSpace(testTerraformPlanComputedListStr) 1086 if actual != expected { 1087 t.Fatalf("bad:\n%s", actual) 1088 } 1089 } 1090 1091 func TestContext2Plan_count(t *testing.T) { 1092 m := testModule(t, "plan-count") 1093 p := testProvider("aws") 1094 p.DiffFn = testDiffFn 1095 ctx := testContext2(t, &ContextOpts{ 1096 Module: m, 1097 Providers: map[string]ResourceProviderFactory{ 1098 "aws": testProviderFuncFixed(p), 1099 }, 1100 }) 1101 1102 plan, err := ctx.Plan() 1103 if err != nil { 1104 t.Fatalf("err: %s", err) 1105 } 1106 1107 if len(plan.Diff.RootModule().Resources) < 6 { 1108 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 1109 } 1110 1111 actual := strings.TrimSpace(plan.String()) 1112 expected := strings.TrimSpace(testTerraformPlanCountStr) 1113 if actual != expected { 1114 t.Fatalf("bad:\n%s", actual) 1115 } 1116 } 1117 1118 func TestContext2Plan_countComputed(t *testing.T) { 1119 m := testModule(t, "plan-count-computed") 1120 p := testProvider("aws") 1121 p.DiffFn = testDiffFn 1122 ctx := testContext2(t, &ContextOpts{ 1123 Module: m, 1124 Providers: map[string]ResourceProviderFactory{ 1125 "aws": testProviderFuncFixed(p), 1126 }, 1127 }) 1128 1129 _, err := ctx.Plan() 1130 if err == nil { 1131 t.Fatal("should error") 1132 } 1133 } 1134 1135 func TestContext2Plan_countIndex(t *testing.T) { 1136 m := testModule(t, "plan-count-index") 1137 p := testProvider("aws") 1138 p.DiffFn = testDiffFn 1139 ctx := testContext2(t, &ContextOpts{ 1140 Module: m, 1141 Providers: map[string]ResourceProviderFactory{ 1142 "aws": testProviderFuncFixed(p), 1143 }, 1144 }) 1145 1146 plan, err := ctx.Plan() 1147 if err != nil { 1148 t.Fatalf("err: %s", err) 1149 } 1150 1151 actual := strings.TrimSpace(plan.String()) 1152 expected := strings.TrimSpace(testTerraformPlanCountIndexStr) 1153 if actual != expected { 1154 t.Fatalf("bad:\n%s", actual) 1155 } 1156 } 1157 1158 func TestContext2Plan_countIndexZero(t *testing.T) { 1159 m := testModule(t, "plan-count-index-zero") 1160 p := testProvider("aws") 1161 p.DiffFn = testDiffFn 1162 ctx := testContext2(t, &ContextOpts{ 1163 Module: m, 1164 Providers: map[string]ResourceProviderFactory{ 1165 "aws": testProviderFuncFixed(p), 1166 }, 1167 }) 1168 1169 plan, err := ctx.Plan() 1170 if err != nil { 1171 t.Fatalf("err: %s", err) 1172 } 1173 1174 actual := strings.TrimSpace(plan.String()) 1175 expected := strings.TrimSpace(testTerraformPlanCountIndexZeroStr) 1176 if actual != expected { 1177 t.Fatalf("bad:\n%s", actual) 1178 } 1179 } 1180 1181 func TestContext2Plan_countVar(t *testing.T) { 1182 m := testModule(t, "plan-count-var") 1183 p := testProvider("aws") 1184 p.DiffFn = testDiffFn 1185 ctx := testContext2(t, &ContextOpts{ 1186 Module: m, 1187 Providers: map[string]ResourceProviderFactory{ 1188 "aws": testProviderFuncFixed(p), 1189 }, 1190 Variables: map[string]interface{}{ 1191 "count": "3", 1192 }, 1193 }) 1194 1195 plan, err := ctx.Plan() 1196 if err != nil { 1197 t.Fatalf("err: %s", err) 1198 } 1199 1200 actual := strings.TrimSpace(plan.String()) 1201 expected := strings.TrimSpace(testTerraformPlanCountVarStr) 1202 if actual != expected { 1203 t.Fatalf("bad:\n%s", actual) 1204 } 1205 } 1206 1207 func TestContext2Plan_countZero(t *testing.T) { 1208 m := testModule(t, "plan-count-zero") 1209 p := testProvider("aws") 1210 p.DiffFn = testDiffFn 1211 ctx := testContext2(t, &ContextOpts{ 1212 Module: m, 1213 Providers: map[string]ResourceProviderFactory{ 1214 "aws": testProviderFuncFixed(p), 1215 }, 1216 }) 1217 1218 plan, err := ctx.Plan() 1219 if err != nil { 1220 t.Fatalf("err: %s", err) 1221 } 1222 1223 actual := strings.TrimSpace(plan.String()) 1224 expected := strings.TrimSpace(testTerraformPlanCountZeroStr) 1225 if actual != expected { 1226 t.Logf("expected:\n%s", expected) 1227 t.Fatalf("bad:\n%s", actual) 1228 } 1229 } 1230 1231 func TestContext2Plan_countOneIndex(t *testing.T) { 1232 m := testModule(t, "plan-count-one-index") 1233 p := testProvider("aws") 1234 p.DiffFn = testDiffFn 1235 ctx := testContext2(t, &ContextOpts{ 1236 Module: m, 1237 Providers: map[string]ResourceProviderFactory{ 1238 "aws": testProviderFuncFixed(p), 1239 }, 1240 }) 1241 1242 plan, err := ctx.Plan() 1243 if err != nil { 1244 t.Fatalf("err: %s", err) 1245 } 1246 1247 actual := strings.TrimSpace(plan.String()) 1248 expected := strings.TrimSpace(testTerraformPlanCountOneIndexStr) 1249 if actual != expected { 1250 t.Fatalf("bad:\n%s", actual) 1251 } 1252 } 1253 1254 func TestContext2Plan_countDecreaseToOne(t *testing.T) { 1255 m := testModule(t, "plan-count-dec") 1256 p := testProvider("aws") 1257 p.DiffFn = testDiffFn 1258 s := &State{ 1259 Modules: []*ModuleState{ 1260 &ModuleState{ 1261 Path: rootModulePath, 1262 Resources: map[string]*ResourceState{ 1263 "aws_instance.foo.0": &ResourceState{ 1264 Type: "aws_instance", 1265 Primary: &InstanceState{ 1266 ID: "bar", 1267 Attributes: map[string]string{ 1268 "foo": "foo", 1269 "type": "aws_instance", 1270 }, 1271 }, 1272 }, 1273 "aws_instance.foo.1": &ResourceState{ 1274 Type: "aws_instance", 1275 Primary: &InstanceState{ 1276 ID: "bar", 1277 }, 1278 }, 1279 "aws_instance.foo.2": &ResourceState{ 1280 Type: "aws_instance", 1281 Primary: &InstanceState{ 1282 ID: "bar", 1283 }, 1284 }, 1285 }, 1286 }, 1287 }, 1288 } 1289 ctx := testContext2(t, &ContextOpts{ 1290 Module: m, 1291 Providers: map[string]ResourceProviderFactory{ 1292 "aws": testProviderFuncFixed(p), 1293 }, 1294 State: s, 1295 }) 1296 1297 plan, err := ctx.Plan() 1298 if err != nil { 1299 t.Fatalf("err: %s", err) 1300 } 1301 1302 actual := strings.TrimSpace(plan.String()) 1303 expected := strings.TrimSpace(testTerraformPlanCountDecreaseStr) 1304 if actual != expected { 1305 t.Fatalf("bad:\n%s", actual) 1306 } 1307 } 1308 1309 func TestContext2Plan_countIncreaseFromNotSet(t *testing.T) { 1310 m := testModule(t, "plan-count-inc") 1311 p := testProvider("aws") 1312 p.DiffFn = testDiffFn 1313 s := &State{ 1314 Modules: []*ModuleState{ 1315 &ModuleState{ 1316 Path: rootModulePath, 1317 Resources: map[string]*ResourceState{ 1318 "aws_instance.foo": &ResourceState{ 1319 Type: "aws_instance", 1320 Primary: &InstanceState{ 1321 ID: "bar", 1322 Attributes: map[string]string{ 1323 "foo": "foo", 1324 "type": "aws_instance", 1325 }, 1326 }, 1327 }, 1328 }, 1329 }, 1330 }, 1331 } 1332 ctx := testContext2(t, &ContextOpts{ 1333 Module: m, 1334 Providers: map[string]ResourceProviderFactory{ 1335 "aws": testProviderFuncFixed(p), 1336 }, 1337 State: s, 1338 }) 1339 1340 plan, err := ctx.Plan() 1341 if err != nil { 1342 t.Fatalf("err: %s", err) 1343 } 1344 1345 actual := strings.TrimSpace(plan.String()) 1346 expected := strings.TrimSpace(testTerraformPlanCountIncreaseStr) 1347 if actual != expected { 1348 t.Fatalf("bad:\n%s", actual) 1349 } 1350 } 1351 1352 func TestContext2Plan_countIncreaseFromOne(t *testing.T) { 1353 m := testModule(t, "plan-count-inc") 1354 p := testProvider("aws") 1355 p.DiffFn = testDiffFn 1356 s := &State{ 1357 Modules: []*ModuleState{ 1358 &ModuleState{ 1359 Path: rootModulePath, 1360 Resources: map[string]*ResourceState{ 1361 "aws_instance.foo.0": &ResourceState{ 1362 Type: "aws_instance", 1363 Primary: &InstanceState{ 1364 ID: "bar", 1365 Attributes: map[string]string{ 1366 "foo": "foo", 1367 "type": "aws_instance", 1368 }, 1369 }, 1370 }, 1371 }, 1372 }, 1373 }, 1374 } 1375 ctx := testContext2(t, &ContextOpts{ 1376 Module: m, 1377 Providers: map[string]ResourceProviderFactory{ 1378 "aws": testProviderFuncFixed(p), 1379 }, 1380 State: s, 1381 }) 1382 1383 plan, err := ctx.Plan() 1384 if err != nil { 1385 t.Fatalf("err: %s", err) 1386 } 1387 1388 actual := strings.TrimSpace(plan.String()) 1389 expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneStr) 1390 if actual != expected { 1391 t.Fatalf("bad:\n%s", actual) 1392 } 1393 } 1394 1395 // https://github.com/PeoplePerHour/terraform/pull/11 1396 // 1397 // This tests a case where both a "resource" and "resource.0" are in 1398 // the state file, which apparently is a reasonable backwards compatibility 1399 // concern found in the above 3rd party repo. 1400 func TestContext2Plan_countIncreaseFromOneCorrupted(t *testing.T) { 1401 m := testModule(t, "plan-count-inc") 1402 p := testProvider("aws") 1403 p.DiffFn = testDiffFn 1404 s := &State{ 1405 Modules: []*ModuleState{ 1406 &ModuleState{ 1407 Path: rootModulePath, 1408 Resources: map[string]*ResourceState{ 1409 "aws_instance.foo": &ResourceState{ 1410 Type: "aws_instance", 1411 Primary: &InstanceState{ 1412 ID: "bar", 1413 Attributes: map[string]string{ 1414 "foo": "foo", 1415 "type": "aws_instance", 1416 }, 1417 }, 1418 }, 1419 "aws_instance.foo.0": &ResourceState{ 1420 Type: "aws_instance", 1421 Primary: &InstanceState{ 1422 ID: "bar", 1423 Attributes: map[string]string{ 1424 "foo": "foo", 1425 "type": "aws_instance", 1426 }, 1427 }, 1428 }, 1429 }, 1430 }, 1431 }, 1432 } 1433 ctx := testContext2(t, &ContextOpts{ 1434 Module: m, 1435 Providers: map[string]ResourceProviderFactory{ 1436 "aws": testProviderFuncFixed(p), 1437 }, 1438 State: s, 1439 }) 1440 1441 plan, err := ctx.Plan() 1442 if err != nil { 1443 t.Fatalf("err: %s", err) 1444 } 1445 1446 actual := strings.TrimSpace(plan.String()) 1447 expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneCorruptedStr) 1448 if actual != expected { 1449 t.Fatalf("bad:\n%s", actual) 1450 } 1451 } 1452 1453 func TestContext2Plan_destroy(t *testing.T) { 1454 m := testModule(t, "plan-destroy") 1455 p := testProvider("aws") 1456 p.DiffFn = testDiffFn 1457 s := &State{ 1458 Modules: []*ModuleState{ 1459 &ModuleState{ 1460 Path: rootModulePath, 1461 Resources: map[string]*ResourceState{ 1462 "aws_instance.one": &ResourceState{ 1463 Type: "aws_instance", 1464 Primary: &InstanceState{ 1465 ID: "bar", 1466 }, 1467 }, 1468 "aws_instance.two": &ResourceState{ 1469 Type: "aws_instance", 1470 Primary: &InstanceState{ 1471 ID: "baz", 1472 }, 1473 }, 1474 }, 1475 }, 1476 }, 1477 } 1478 ctx := testContext2(t, &ContextOpts{ 1479 Module: m, 1480 Providers: map[string]ResourceProviderFactory{ 1481 "aws": testProviderFuncFixed(p), 1482 }, 1483 State: s, 1484 Destroy: true, 1485 }) 1486 1487 plan, err := ctx.Plan() 1488 if err != nil { 1489 t.Fatalf("err: %s", err) 1490 } 1491 1492 if len(plan.Diff.RootModule().Resources) != 2 { 1493 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 1494 } 1495 1496 actual := strings.TrimSpace(plan.String()) 1497 expected := strings.TrimSpace(testTerraformPlanDestroyStr) 1498 if actual != expected { 1499 t.Fatalf("bad:\n%s", actual) 1500 } 1501 } 1502 1503 func TestContext2Plan_moduleDestroy(t *testing.T) { 1504 m := testModule(t, "plan-module-destroy") 1505 p := testProvider("aws") 1506 p.DiffFn = testDiffFn 1507 s := &State{ 1508 Modules: []*ModuleState{ 1509 &ModuleState{ 1510 Path: rootModulePath, 1511 Resources: map[string]*ResourceState{ 1512 "aws_instance.foo": &ResourceState{ 1513 Type: "aws_instance", 1514 Primary: &InstanceState{ 1515 ID: "bar", 1516 }, 1517 }, 1518 }, 1519 }, 1520 &ModuleState{ 1521 Path: []string{"root", "child"}, 1522 Resources: map[string]*ResourceState{ 1523 "aws_instance.foo": &ResourceState{ 1524 Type: "aws_instance", 1525 Primary: &InstanceState{ 1526 ID: "bar", 1527 }, 1528 }, 1529 }, 1530 }, 1531 }, 1532 } 1533 ctx := testContext2(t, &ContextOpts{ 1534 Module: m, 1535 Providers: map[string]ResourceProviderFactory{ 1536 "aws": testProviderFuncFixed(p), 1537 }, 1538 State: s, 1539 Destroy: true, 1540 }) 1541 1542 plan, err := ctx.Plan() 1543 if err != nil { 1544 t.Fatalf("err: %s", err) 1545 } 1546 1547 actual := strings.TrimSpace(plan.String()) 1548 expected := strings.TrimSpace(testTerraformPlanModuleDestroyStr) 1549 if actual != expected { 1550 t.Fatalf("bad:\n%s", actual) 1551 } 1552 } 1553 1554 // GH-1835 1555 func TestContext2Plan_moduleDestroyCycle(t *testing.T) { 1556 m := testModule(t, "plan-module-destroy-gh-1835") 1557 p := testProvider("aws") 1558 p.DiffFn = testDiffFn 1559 s := &State{ 1560 Modules: []*ModuleState{ 1561 &ModuleState{ 1562 Path: []string{"root", "a_module"}, 1563 Resources: map[string]*ResourceState{ 1564 "aws_instance.a": &ResourceState{ 1565 Type: "aws_instance", 1566 Primary: &InstanceState{ 1567 ID: "a", 1568 }, 1569 }, 1570 }, 1571 }, 1572 &ModuleState{ 1573 Path: []string{"root", "b_module"}, 1574 Resources: map[string]*ResourceState{ 1575 "aws_instance.b": &ResourceState{ 1576 Type: "aws_instance", 1577 Primary: &InstanceState{ 1578 ID: "b", 1579 }, 1580 }, 1581 }, 1582 }, 1583 }, 1584 } 1585 ctx := testContext2(t, &ContextOpts{ 1586 Module: m, 1587 Providers: map[string]ResourceProviderFactory{ 1588 "aws": testProviderFuncFixed(p), 1589 }, 1590 State: s, 1591 Destroy: true, 1592 }) 1593 1594 plan, err := ctx.Plan() 1595 if err != nil { 1596 t.Fatalf("err: %s", err) 1597 } 1598 1599 actual := strings.TrimSpace(plan.String()) 1600 expected := strings.TrimSpace(testTerraformPlanModuleDestroyCycleStr) 1601 if actual != expected { 1602 t.Fatalf("bad:\n%s", actual) 1603 } 1604 } 1605 1606 func TestContext2Plan_moduleDestroyMultivar(t *testing.T) { 1607 m := testModule(t, "plan-module-destroy-multivar") 1608 p := testProvider("aws") 1609 p.DiffFn = testDiffFn 1610 s := &State{ 1611 Modules: []*ModuleState{ 1612 &ModuleState{ 1613 Path: rootModulePath, 1614 Resources: map[string]*ResourceState{}, 1615 }, 1616 &ModuleState{ 1617 Path: []string{"root", "child"}, 1618 Resources: map[string]*ResourceState{ 1619 "aws_instance.foo.0": &ResourceState{ 1620 Type: "aws_instance", 1621 Primary: &InstanceState{ 1622 ID: "bar0", 1623 }, 1624 }, 1625 "aws_instance.foo.1": &ResourceState{ 1626 Type: "aws_instance", 1627 Primary: &InstanceState{ 1628 ID: "bar1", 1629 }, 1630 }, 1631 }, 1632 }, 1633 }, 1634 } 1635 ctx := testContext2(t, &ContextOpts{ 1636 Module: m, 1637 Providers: map[string]ResourceProviderFactory{ 1638 "aws": testProviderFuncFixed(p), 1639 }, 1640 State: s, 1641 Destroy: true, 1642 }) 1643 1644 plan, err := ctx.Plan() 1645 if err != nil { 1646 t.Fatalf("err: %s", err) 1647 } 1648 1649 actual := strings.TrimSpace(plan.String()) 1650 expected := strings.TrimSpace(testTerraformPlanModuleDestroyMultivarStr) 1651 if actual != expected { 1652 t.Fatalf("bad:\n%s", actual) 1653 } 1654 } 1655 1656 func TestContext2Plan_pathVar(t *testing.T) { 1657 cwd, err := os.Getwd() 1658 if err != nil { 1659 t.Fatalf("err: %s", err) 1660 } 1661 1662 m := testModule(t, "plan-path-var") 1663 p := testProvider("aws") 1664 p.DiffFn = testDiffFn 1665 ctx := testContext2(t, &ContextOpts{ 1666 Module: m, 1667 Providers: map[string]ResourceProviderFactory{ 1668 "aws": testProviderFuncFixed(p), 1669 }, 1670 }) 1671 1672 plan, err := ctx.Plan() 1673 if err != nil { 1674 t.Fatalf("err: %s", err) 1675 } 1676 1677 actual := strings.TrimSpace(plan.String()) 1678 expected := strings.TrimSpace(testTerraformPlanPathVarStr) 1679 1680 // Warning: this ordering REALLY matters for this test. The 1681 // order is: cwd, module, root. 1682 expected = fmt.Sprintf( 1683 expected, 1684 cwd, 1685 m.Config().Dir, 1686 m.Config().Dir) 1687 1688 if actual != expected { 1689 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 1690 } 1691 } 1692 1693 func TestContext2Plan_diffVar(t *testing.T) { 1694 m := testModule(t, "plan-diffvar") 1695 p := testProvider("aws") 1696 s := &State{ 1697 Modules: []*ModuleState{ 1698 &ModuleState{ 1699 Path: rootModulePath, 1700 Resources: map[string]*ResourceState{ 1701 "aws_instance.foo": &ResourceState{ 1702 Primary: &InstanceState{ 1703 ID: "bar", 1704 Attributes: map[string]string{ 1705 "num": "2", 1706 }, 1707 }, 1708 }, 1709 }, 1710 }, 1711 }, 1712 } 1713 ctx := testContext2(t, &ContextOpts{ 1714 Module: m, 1715 Providers: map[string]ResourceProviderFactory{ 1716 "aws": testProviderFuncFixed(p), 1717 }, 1718 State: s, 1719 }) 1720 1721 p.DiffFn = func( 1722 info *InstanceInfo, 1723 s *InstanceState, 1724 c *ResourceConfig) (*InstanceDiff, error) { 1725 if s.ID != "bar" { 1726 return testDiffFn(info, s, c) 1727 } 1728 1729 return &InstanceDiff{ 1730 Attributes: map[string]*ResourceAttrDiff{ 1731 "num": &ResourceAttrDiff{ 1732 Old: "2", 1733 New: "3", 1734 }, 1735 }, 1736 }, nil 1737 } 1738 1739 plan, err := ctx.Plan() 1740 if err != nil { 1741 t.Fatalf("err: %s", err) 1742 } 1743 1744 actual := strings.TrimSpace(plan.String()) 1745 expected := strings.TrimSpace(testTerraformPlanDiffVarStr) 1746 if actual != expected { 1747 t.Fatalf("actual:\n%s\n\nexpected:\n%s", actual, expected) 1748 } 1749 } 1750 1751 func TestContext2Plan_hook(t *testing.T) { 1752 m := testModule(t, "plan-good") 1753 h := new(MockHook) 1754 p := testProvider("aws") 1755 p.DiffFn = testDiffFn 1756 ctx := testContext2(t, &ContextOpts{ 1757 Module: m, 1758 Hooks: []Hook{h}, 1759 Providers: map[string]ResourceProviderFactory{ 1760 "aws": testProviderFuncFixed(p), 1761 }, 1762 }) 1763 1764 _, err := ctx.Plan() 1765 if err != nil { 1766 t.Fatalf("err: %s", err) 1767 } 1768 1769 if !h.PreDiffCalled { 1770 t.Fatal("should be called") 1771 } 1772 if !h.PostDiffCalled { 1773 t.Fatal("should be called") 1774 } 1775 } 1776 1777 func TestContext2Plan_orphan(t *testing.T) { 1778 m := testModule(t, "plan-orphan") 1779 p := testProvider("aws") 1780 p.DiffFn = testDiffFn 1781 s := &State{ 1782 Modules: []*ModuleState{ 1783 &ModuleState{ 1784 Path: rootModulePath, 1785 Resources: map[string]*ResourceState{ 1786 "aws_instance.baz": &ResourceState{ 1787 Type: "aws_instance", 1788 Primary: &InstanceState{ 1789 ID: "bar", 1790 }, 1791 }, 1792 }, 1793 }, 1794 }, 1795 } 1796 ctx := testContext2(t, &ContextOpts{ 1797 Module: m, 1798 Providers: map[string]ResourceProviderFactory{ 1799 "aws": testProviderFuncFixed(p), 1800 }, 1801 State: s, 1802 }) 1803 1804 plan, err := ctx.Plan() 1805 if err != nil { 1806 t.Fatalf("err: %s", err) 1807 } 1808 1809 actual := strings.TrimSpace(plan.String()) 1810 expected := strings.TrimSpace(testTerraformPlanOrphanStr) 1811 if actual != expected { 1812 t.Fatalf("bad:\n%s", actual) 1813 } 1814 } 1815 1816 func TestContext2Plan_state(t *testing.T) { 1817 m := testModule(t, "plan-good") 1818 p := testProvider("aws") 1819 p.DiffFn = testDiffFn 1820 s := &State{ 1821 Modules: []*ModuleState{ 1822 &ModuleState{ 1823 Path: rootModulePath, 1824 Resources: map[string]*ResourceState{ 1825 "aws_instance.foo": &ResourceState{ 1826 Primary: &InstanceState{ 1827 ID: "bar", 1828 }, 1829 }, 1830 }, 1831 }, 1832 }, 1833 } 1834 ctx := testContext2(t, &ContextOpts{ 1835 Module: m, 1836 Providers: map[string]ResourceProviderFactory{ 1837 "aws": testProviderFuncFixed(p), 1838 }, 1839 State: s, 1840 }) 1841 1842 plan, err := ctx.Plan() 1843 if err != nil { 1844 t.Fatalf("err: %s", err) 1845 } 1846 1847 if len(plan.Diff.RootModule().Resources) < 2 { 1848 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 1849 } 1850 1851 actual := strings.TrimSpace(plan.String()) 1852 expected := strings.TrimSpace(testTerraformPlanStateStr) 1853 if actual != expected { 1854 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 1855 } 1856 } 1857 1858 func TestContext2Plan_taint(t *testing.T) { 1859 m := testModule(t, "plan-taint") 1860 p := testProvider("aws") 1861 p.DiffFn = testDiffFn 1862 s := &State{ 1863 Modules: []*ModuleState{ 1864 &ModuleState{ 1865 Path: rootModulePath, 1866 Resources: map[string]*ResourceState{ 1867 "aws_instance.foo": &ResourceState{ 1868 Type: "aws_instance", 1869 Primary: &InstanceState{ 1870 ID: "bar", 1871 Attributes: map[string]string{"num": "2"}, 1872 }, 1873 }, 1874 "aws_instance.bar": &ResourceState{ 1875 Type: "aws_instance", 1876 Primary: &InstanceState{ 1877 ID: "baz", 1878 Tainted: true, 1879 }, 1880 }, 1881 }, 1882 }, 1883 }, 1884 } 1885 ctx := testContext2(t, &ContextOpts{ 1886 Module: m, 1887 Providers: map[string]ResourceProviderFactory{ 1888 "aws": testProviderFuncFixed(p), 1889 }, 1890 State: s, 1891 }) 1892 1893 plan, err := ctx.Plan() 1894 if err != nil { 1895 t.Fatalf("err: %s", err) 1896 } 1897 1898 actual := strings.TrimSpace(plan.String()) 1899 expected := strings.TrimSpace(testTerraformPlanTaintStr) 1900 if actual != expected { 1901 t.Fatalf("bad:\n%s", actual) 1902 } 1903 } 1904 1905 // Fails about 50% of the time before the fix for GH-4982, covers the fix. 1906 func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) { 1907 m := testModule(t, "plan-taint-interpolated-count") 1908 p := testProvider("aws") 1909 p.DiffFn = testDiffFn 1910 s := &State{ 1911 Modules: []*ModuleState{ 1912 &ModuleState{ 1913 Path: rootModulePath, 1914 Resources: map[string]*ResourceState{ 1915 "aws_instance.foo.0": &ResourceState{ 1916 Type: "aws_instance", 1917 Primary: &InstanceState{ 1918 ID: "bar", 1919 Tainted: true, 1920 }, 1921 }, 1922 "aws_instance.foo.1": &ResourceState{ 1923 Type: "aws_instance", 1924 Primary: &InstanceState{ID: "bar"}, 1925 }, 1926 "aws_instance.foo.2": &ResourceState{ 1927 Type: "aws_instance", 1928 Primary: &InstanceState{ID: "bar"}, 1929 }, 1930 }, 1931 }, 1932 }, 1933 } 1934 ctx := testContext2(t, &ContextOpts{ 1935 Module: m, 1936 Providers: map[string]ResourceProviderFactory{ 1937 "aws": testProviderFuncFixed(p), 1938 }, 1939 State: s, 1940 }) 1941 1942 for i := 0; i < 100; i++ { 1943 plan, err := ctx.Plan() 1944 if err != nil { 1945 t.Fatalf("err: %s", err) 1946 } 1947 1948 actual := strings.TrimSpace(plan.String()) 1949 expected := strings.TrimSpace(` 1950 DIFF: 1951 1952 DESTROY/CREATE: aws_instance.foo.0 1953 type: "" => "aws_instance" 1954 1955 STATE: 1956 1957 aws_instance.foo.0: (tainted) 1958 ID = bar 1959 aws_instance.foo.1: 1960 ID = bar 1961 aws_instance.foo.2: 1962 ID = bar 1963 `) 1964 if actual != expected { 1965 t.Fatalf("[%d] bad:\n%s\nexpected:\n%s\n", i, actual, expected) 1966 } 1967 } 1968 } 1969 1970 func TestContext2Plan_targeted(t *testing.T) { 1971 m := testModule(t, "plan-targeted") 1972 p := testProvider("aws") 1973 p.DiffFn = testDiffFn 1974 ctx := testContext2(t, &ContextOpts{ 1975 Module: m, 1976 Providers: map[string]ResourceProviderFactory{ 1977 "aws": testProviderFuncFixed(p), 1978 }, 1979 Targets: []string{"aws_instance.foo"}, 1980 }) 1981 1982 plan, err := ctx.Plan() 1983 if err != nil { 1984 t.Fatalf("err: %s", err) 1985 } 1986 1987 actual := strings.TrimSpace(plan.String()) 1988 expected := strings.TrimSpace(` 1989 DIFF: 1990 1991 CREATE: aws_instance.foo 1992 num: "" => "2" 1993 type: "" => "aws_instance" 1994 1995 STATE: 1996 1997 <no state> 1998 `) 1999 if actual != expected { 2000 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2001 } 2002 } 2003 2004 func TestContext2Plan_targetedOrphan(t *testing.T) { 2005 m := testModule(t, "plan-targeted-orphan") 2006 p := testProvider("aws") 2007 p.DiffFn = testDiffFn 2008 ctx := testContext2(t, &ContextOpts{ 2009 Module: m, 2010 Providers: map[string]ResourceProviderFactory{ 2011 "aws": testProviderFuncFixed(p), 2012 }, 2013 State: &State{ 2014 Modules: []*ModuleState{ 2015 &ModuleState{ 2016 Path: rootModulePath, 2017 Resources: map[string]*ResourceState{ 2018 "aws_instance.orphan": &ResourceState{ 2019 Type: "aws_instance", 2020 Primary: &InstanceState{ 2021 ID: "i-789xyz", 2022 }, 2023 }, 2024 "aws_instance.nottargeted": &ResourceState{ 2025 Type: "aws_instance", 2026 Primary: &InstanceState{ 2027 ID: "i-abc123", 2028 }, 2029 }, 2030 }, 2031 }, 2032 }, 2033 }, 2034 Destroy: true, 2035 Targets: []string{"aws_instance.orphan"}, 2036 }) 2037 2038 plan, err := ctx.Plan() 2039 if err != nil { 2040 t.Fatalf("err: %s", err) 2041 } 2042 2043 actual := strings.TrimSpace(plan.String()) 2044 expected := strings.TrimSpace(`DIFF: 2045 2046 DESTROY: aws_instance.orphan 2047 2048 STATE: 2049 2050 aws_instance.nottargeted: 2051 ID = i-abc123 2052 aws_instance.orphan: 2053 ID = i-789xyz 2054 `) 2055 if actual != expected { 2056 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2057 } 2058 } 2059 2060 // https://github.com/hashicorp/terraform/issues/2538 2061 func TestContext2Plan_targetedModuleOrphan(t *testing.T) { 2062 m := testModule(t, "plan-targeted-module-orphan") 2063 p := testProvider("aws") 2064 p.DiffFn = testDiffFn 2065 ctx := testContext2(t, &ContextOpts{ 2066 Module: m, 2067 Providers: map[string]ResourceProviderFactory{ 2068 "aws": testProviderFuncFixed(p), 2069 }, 2070 State: &State{ 2071 Modules: []*ModuleState{ 2072 &ModuleState{ 2073 Path: []string{"root", "child"}, 2074 Resources: map[string]*ResourceState{ 2075 "aws_instance.orphan": &ResourceState{ 2076 Type: "aws_instance", 2077 Primary: &InstanceState{ 2078 ID: "i-789xyz", 2079 }, 2080 }, 2081 "aws_instance.nottargeted": &ResourceState{ 2082 Type: "aws_instance", 2083 Primary: &InstanceState{ 2084 ID: "i-abc123", 2085 }, 2086 }, 2087 }, 2088 }, 2089 }, 2090 }, 2091 Destroy: true, 2092 Targets: []string{"module.child.aws_instance.orphan"}, 2093 }) 2094 2095 plan, err := ctx.Plan() 2096 if err != nil { 2097 t.Fatalf("err: %s", err) 2098 } 2099 2100 actual := strings.TrimSpace(plan.String()) 2101 expected := strings.TrimSpace(`DIFF: 2102 2103 module.child: 2104 DESTROY: aws_instance.orphan 2105 2106 STATE: 2107 2108 module.child: 2109 aws_instance.nottargeted: 2110 ID = i-abc123 2111 aws_instance.orphan: 2112 ID = i-789xyz 2113 `) 2114 if actual != expected { 2115 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2116 } 2117 } 2118 2119 func TestContext2Plan_targetedModuleUntargetedVariable(t *testing.T) { 2120 m := testModule(t, "plan-targeted-module-untargeted-variable") 2121 p := testProvider("aws") 2122 p.DiffFn = testDiffFn 2123 ctx := testContext2(t, &ContextOpts{ 2124 Module: m, 2125 Providers: map[string]ResourceProviderFactory{ 2126 "aws": testProviderFuncFixed(p), 2127 }, 2128 Targets: []string{"aws_instance.blue", "module.blue_mod"}, 2129 }) 2130 2131 plan, err := ctx.Plan() 2132 if err != nil { 2133 t.Fatalf("err: %s", err) 2134 } 2135 2136 actual := strings.TrimSpace(plan.String()) 2137 expected := strings.TrimSpace(` 2138 DIFF: 2139 2140 CREATE: aws_instance.blue 2141 2142 module.blue_mod: 2143 CREATE: aws_instance.mod 2144 type: "" => "aws_instance" 2145 value: "" => "<computed>" 2146 2147 STATE: 2148 2149 <no state> 2150 `) 2151 if actual != expected { 2152 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2153 } 2154 } 2155 2156 // https://github.com/hashicorp/terraform/issues/4515 2157 func TestContext2Plan_targetedOverTen(t *testing.T) { 2158 m := testModule(t, "plan-targeted-over-ten") 2159 p := testProvider("aws") 2160 p.DiffFn = testDiffFn 2161 2162 resources := make(map[string]*ResourceState) 2163 var expectedState []string 2164 for i := 0; i < 13; i++ { 2165 key := fmt.Sprintf("aws_instance.foo.%d", i) 2166 id := fmt.Sprintf("i-abc%d", i) 2167 resources[key] = &ResourceState{ 2168 Type: "aws_instance", 2169 Primary: &InstanceState{ID: id}, 2170 } 2171 expectedState = append(expectedState, 2172 fmt.Sprintf("%s:\n ID = %s\n", key, id)) 2173 } 2174 ctx := testContext2(t, &ContextOpts{ 2175 Module: m, 2176 Providers: map[string]ResourceProviderFactory{ 2177 "aws": testProviderFuncFixed(p), 2178 }, 2179 State: &State{ 2180 Modules: []*ModuleState{ 2181 &ModuleState{ 2182 Path: rootModulePath, 2183 Resources: resources, 2184 }, 2185 }, 2186 }, 2187 Targets: []string{"aws_instance.foo[1]"}, 2188 }) 2189 2190 plan, err := ctx.Plan() 2191 if err != nil { 2192 t.Fatalf("err: %s", err) 2193 } 2194 2195 actual := strings.TrimSpace(plan.String()) 2196 sort.Strings(expectedState) 2197 expected := strings.TrimSpace(` 2198 DIFF: 2199 2200 2201 2202 STATE: 2203 2204 aws_instance.foo.0: 2205 ID = i-abc0 2206 aws_instance.foo.1: 2207 ID = i-abc1 2208 aws_instance.foo.10: 2209 ID = i-abc10 2210 aws_instance.foo.11: 2211 ID = i-abc11 2212 aws_instance.foo.12: 2213 ID = i-abc12 2214 aws_instance.foo.2: 2215 ID = i-abc2 2216 aws_instance.foo.3: 2217 ID = i-abc3 2218 aws_instance.foo.4: 2219 ID = i-abc4 2220 aws_instance.foo.5: 2221 ID = i-abc5 2222 aws_instance.foo.6: 2223 ID = i-abc6 2224 aws_instance.foo.7: 2225 ID = i-abc7 2226 aws_instance.foo.8: 2227 ID = i-abc8 2228 aws_instance.foo.9: 2229 ID = i-abc9 2230 `) 2231 if actual != expected { 2232 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 2233 } 2234 } 2235 2236 func TestContext2Plan_provider(t *testing.T) { 2237 m := testModule(t, "plan-provider") 2238 p := testProvider("aws") 2239 p.DiffFn = testDiffFn 2240 2241 var value interface{} 2242 p.ConfigureFn = func(c *ResourceConfig) error { 2243 value, _ = c.Get("foo") 2244 return nil 2245 } 2246 2247 ctx := testContext2(t, &ContextOpts{ 2248 Module: m, 2249 Providers: map[string]ResourceProviderFactory{ 2250 "aws": testProviderFuncFixed(p), 2251 }, 2252 Variables: map[string]interface{}{ 2253 "foo": "bar", 2254 }, 2255 }) 2256 2257 if _, err := ctx.Plan(); err != nil { 2258 t.Fatalf("err: %s", err) 2259 } 2260 2261 if value != "bar" { 2262 t.Fatalf("bad: %#v", value) 2263 } 2264 } 2265 2266 func TestContext2Plan_varListErr(t *testing.T) { 2267 m := testModule(t, "plan-var-list-err") 2268 p := testProvider("aws") 2269 ctx := testContext2(t, &ContextOpts{ 2270 Module: m, 2271 Providers: map[string]ResourceProviderFactory{ 2272 "aws": testProviderFuncFixed(p), 2273 }, 2274 }) 2275 2276 _, err := ctx.Plan() 2277 2278 if err == nil { 2279 t.Fatal("should error") 2280 } 2281 } 2282 2283 func TestContext2Plan_ignoreChanges(t *testing.T) { 2284 m := testModule(t, "plan-ignore-changes") 2285 p := testProvider("aws") 2286 p.DiffFn = testDiffFn 2287 s := &State{ 2288 Modules: []*ModuleState{ 2289 &ModuleState{ 2290 Path: rootModulePath, 2291 Resources: map[string]*ResourceState{ 2292 "aws_instance.foo": &ResourceState{ 2293 Primary: &InstanceState{ 2294 ID: "bar", 2295 Attributes: map[string]string{"ami": "ami-abcd1234"}, 2296 }, 2297 }, 2298 }, 2299 }, 2300 }, 2301 } 2302 ctx := testContext2(t, &ContextOpts{ 2303 Module: m, 2304 Providers: map[string]ResourceProviderFactory{ 2305 "aws": testProviderFuncFixed(p), 2306 }, 2307 Variables: map[string]interface{}{ 2308 "foo": "ami-1234abcd", 2309 }, 2310 State: s, 2311 }) 2312 2313 plan, err := ctx.Plan() 2314 if err != nil { 2315 t.Fatalf("err: %s", err) 2316 } 2317 2318 if len(plan.Diff.RootModule().Resources) < 1 { 2319 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 2320 } 2321 2322 actual := strings.TrimSpace(plan.String()) 2323 expected := strings.TrimSpace(testTerraformPlanIgnoreChangesStr) 2324 if actual != expected { 2325 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 2326 } 2327 } 2328 2329 func TestContext2Plan_moduleMapLiteral(t *testing.T) { 2330 m := testModule(t, "plan-module-map-literal") 2331 p := testProvider("aws") 2332 p.ApplyFn = testApplyFn 2333 p.DiffFn = func(i *InstanceInfo, s *InstanceState, c *ResourceConfig) (*InstanceDiff, error) { 2334 // Here we verify that both the populated and empty map literals made it 2335 // through to the resource attributes 2336 val, _ := c.Get("tags") 2337 m, ok := val.(map[string]interface{}) 2338 if !ok { 2339 t.Fatalf("Tags attr not map: %#v", val) 2340 } 2341 if m["foo"] != "bar" { 2342 t.Fatalf("Bad value in tags attr: %#v", m) 2343 } 2344 { 2345 val, _ := c.Get("meta") 2346 m, ok := val.(map[string]interface{}) 2347 if !ok { 2348 t.Fatalf("Meta attr not map: %#v", val) 2349 } 2350 if len(m) != 0 { 2351 t.Fatalf("Meta attr not empty: %#v", val) 2352 } 2353 } 2354 return nil, nil 2355 } 2356 ctx := testContext2(t, &ContextOpts{ 2357 Module: m, 2358 Providers: map[string]ResourceProviderFactory{ 2359 "aws": testProviderFuncFixed(p), 2360 }, 2361 }) 2362 2363 if _, err := ctx.Plan(); err != nil { 2364 t.Fatalf("err: %s", err) 2365 } 2366 } 2367 2368 func TestContext2Plan_computedValueInMap(t *testing.T) { 2369 m := testModule(t, "plan-computed-value-in-map") 2370 p := testProvider("aws") 2371 p.DiffFn = func(info *InstanceInfo, state *InstanceState, c *ResourceConfig) (*InstanceDiff, error) { 2372 switch info.Type { 2373 case "aws_computed_source": 2374 return &InstanceDiff{ 2375 Attributes: map[string]*ResourceAttrDiff{ 2376 "computed_read_only": &ResourceAttrDiff{ 2377 NewComputed: true, 2378 }, 2379 }, 2380 }, nil 2381 } 2382 2383 return testDiffFn(info, state, c) 2384 } 2385 ctx := testContext2(t, &ContextOpts{ 2386 Module: m, 2387 Providers: map[string]ResourceProviderFactory{ 2388 "aws": testProviderFuncFixed(p), 2389 }, 2390 }) 2391 2392 if _, err := ctx.Plan(); err != nil { 2393 t.Fatalf("err: %s", err) 2394 } 2395 2396 plan, err := ctx.Plan() 2397 if err != nil { 2398 t.Fatalf("err: %s", err) 2399 } 2400 2401 actual := strings.TrimSpace(plan.String()) 2402 expected := strings.TrimSpace(testTerraformPlanComputedValueInMap) 2403 if actual != expected { 2404 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 2405 } 2406 } 2407 2408 func TestContext2Plan_moduleVariableFromSplat(t *testing.T) { 2409 m := testModule(t, "plan-module-variable-from-splat") 2410 p := testProvider("aws") 2411 p.DiffFn = testDiffFn 2412 ctx := testContext2(t, &ContextOpts{ 2413 Module: m, 2414 Providers: map[string]ResourceProviderFactory{ 2415 "aws": testProviderFuncFixed(p), 2416 }, 2417 }) 2418 2419 if _, err := ctx.Plan(); err != nil { 2420 t.Fatalf("err: %s", err) 2421 } 2422 2423 plan, err := ctx.Plan() 2424 if err != nil { 2425 t.Fatalf("err: %s", err) 2426 } 2427 2428 actual := strings.TrimSpace(plan.String()) 2429 expected := strings.TrimSpace(testTerraformPlanModuleVariableFromSplat) 2430 if actual != expected { 2431 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 2432 } 2433 }