github.com/erriapo/terraform@v0.6.12-0.20160203182612-0340ea72354f/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]string{ 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]string{ 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 func TestContext2Plan_moduleProviderInherit(t *testing.T) { 372 var l sync.Mutex 373 var calls []string 374 375 m := testModule(t, "plan-module-provider-inherit") 376 ctx := testContext2(t, &ContextOpts{ 377 Module: m, 378 Providers: map[string]ResourceProviderFactory{ 379 "aws": func() (ResourceProvider, error) { 380 l.Lock() 381 defer l.Unlock() 382 383 p := testProvider("aws") 384 p.ConfigureFn = func(c *ResourceConfig) error { 385 if v, ok := c.Get("from"); !ok || v.(string) != "root" { 386 return fmt.Errorf("bad") 387 } 388 389 return nil 390 } 391 p.DiffFn = func( 392 info *InstanceInfo, 393 state *InstanceState, 394 c *ResourceConfig) (*InstanceDiff, error) { 395 v, _ := c.Get("from") 396 calls = append(calls, v.(string)) 397 return testDiffFn(info, state, c) 398 } 399 return p, nil 400 }, 401 }, 402 }) 403 404 _, err := ctx.Plan() 405 if err != nil { 406 t.Fatalf("err: %s", err) 407 } 408 409 actual := calls 410 sort.Strings(actual) 411 expected := []string{"child", "root"} 412 if !reflect.DeepEqual(actual, expected) { 413 t.Fatalf("bad: %#v", actual) 414 } 415 } 416 417 func TestContext2Plan_moduleProviderDefaults(t *testing.T) { 418 var l sync.Mutex 419 var calls []string 420 toCount := 0 421 422 m := testModule(t, "plan-module-provider-defaults") 423 ctx := testContext2(t, &ContextOpts{ 424 Module: m, 425 Providers: map[string]ResourceProviderFactory{ 426 "aws": func() (ResourceProvider, error) { 427 l.Lock() 428 defer l.Unlock() 429 430 p := testProvider("aws") 431 p.ConfigureFn = func(c *ResourceConfig) error { 432 if v, ok := c.Get("from"); !ok || v.(string) != "root" { 433 return fmt.Errorf("bad") 434 } 435 if v, ok := c.Get("to"); ok && v.(string) == "child" { 436 toCount++ 437 } 438 439 return nil 440 } 441 p.DiffFn = func( 442 info *InstanceInfo, 443 state *InstanceState, 444 c *ResourceConfig) (*InstanceDiff, error) { 445 v, _ := c.Get("from") 446 calls = append(calls, v.(string)) 447 return testDiffFn(info, state, c) 448 } 449 return p, nil 450 }, 451 }, 452 }) 453 454 _, err := ctx.Plan() 455 if err != nil { 456 t.Fatalf("err: %s", err) 457 } 458 459 if toCount != 1 { 460 t.Fatalf( 461 "provider in child didn't set proper config\n\n"+ 462 "toCount: %d", toCount) 463 } 464 465 actual := calls 466 sort.Strings(actual) 467 expected := []string{"child", "root"} 468 if !reflect.DeepEqual(actual, expected) { 469 t.Fatalf("bad: %#v", actual) 470 } 471 } 472 473 func TestContext2Plan_moduleProviderDefaultsVar(t *testing.T) { 474 var l sync.Mutex 475 var calls []string 476 477 m := testModule(t, "plan-module-provider-defaults-var") 478 ctx := testContext2(t, &ContextOpts{ 479 Module: m, 480 Providers: map[string]ResourceProviderFactory{ 481 "aws": func() (ResourceProvider, error) { 482 l.Lock() 483 defer l.Unlock() 484 485 p := testProvider("aws") 486 p.ConfigureFn = func(c *ResourceConfig) error { 487 var buf bytes.Buffer 488 if v, ok := c.Get("from"); ok { 489 buf.WriteString(v.(string) + "\n") 490 } 491 if v, ok := c.Get("to"); ok { 492 buf.WriteString(v.(string) + "\n") 493 } 494 495 calls = append(calls, buf.String()) 496 return nil 497 } 498 p.DiffFn = testDiffFn 499 return p, nil 500 }, 501 }, 502 Variables: map[string]string{ 503 "foo": "root", 504 }, 505 }) 506 507 _, err := ctx.Plan() 508 if err != nil { 509 t.Fatalf("err: %s", err) 510 } 511 512 expected := []string{ 513 "root\n", 514 "root\nchild\n", 515 } 516 if !reflect.DeepEqual(calls, expected) { 517 t.Fatalf("BAD: %#v", calls) 518 } 519 } 520 521 func TestContext2Plan_moduleVar(t *testing.T) { 522 m := testModule(t, "plan-module-var") 523 p := testProvider("aws") 524 p.DiffFn = testDiffFn 525 ctx := testContext2(t, &ContextOpts{ 526 Module: m, 527 Providers: map[string]ResourceProviderFactory{ 528 "aws": testProviderFuncFixed(p), 529 }, 530 }) 531 532 plan, err := ctx.Plan() 533 if err != nil { 534 t.Fatalf("err: %s", err) 535 } 536 537 actual := strings.TrimSpace(plan.String()) 538 expected := strings.TrimSpace(testTerraformPlanModuleVarStr) 539 if actual != expected { 540 t.Fatalf("bad:\n%s", actual) 541 } 542 } 543 544 func TestContext2Plan_moduleVarComputed(t *testing.T) { 545 m := testModule(t, "plan-module-var-computed") 546 p := testProvider("aws") 547 p.DiffFn = testDiffFn 548 ctx := testContext2(t, &ContextOpts{ 549 Module: m, 550 Providers: map[string]ResourceProviderFactory{ 551 "aws": testProviderFuncFixed(p), 552 }, 553 }) 554 555 plan, err := ctx.Plan() 556 if err != nil { 557 t.Fatalf("err: %s", err) 558 } 559 560 actual := strings.TrimSpace(plan.String()) 561 expected := strings.TrimSpace(testTerraformPlanModuleVarComputedStr) 562 if actual != expected { 563 t.Fatalf("bad:\n%s", actual) 564 } 565 } 566 567 func TestContext2Plan_nil(t *testing.T) { 568 m := testModule(t, "plan-nil") 569 p := testProvider("aws") 570 p.DiffFn = testDiffFn 571 ctx := testContext2(t, &ContextOpts{ 572 Module: m, 573 Providers: map[string]ResourceProviderFactory{ 574 "aws": testProviderFuncFixed(p), 575 }, 576 State: &State{ 577 Modules: []*ModuleState{ 578 &ModuleState{ 579 Path: rootModulePath, 580 Resources: map[string]*ResourceState{ 581 "aws_instance.foo": &ResourceState{ 582 Type: "aws_instance", 583 Primary: &InstanceState{ 584 ID: "bar", 585 }, 586 }, 587 }, 588 }, 589 }, 590 }, 591 }) 592 593 plan, err := ctx.Plan() 594 if err != nil { 595 t.Fatalf("err: %s", err) 596 } 597 if len(plan.Diff.RootModule().Resources) != 0 { 598 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 599 } 600 } 601 602 func TestContext2Plan_preventDestroy_bad(t *testing.T) { 603 m := testModule(t, "plan-prevent-destroy-bad") 604 p := testProvider("aws") 605 p.DiffFn = testDiffFn 606 ctx := testContext2(t, &ContextOpts{ 607 Module: m, 608 Providers: map[string]ResourceProviderFactory{ 609 "aws": testProviderFuncFixed(p), 610 }, 611 State: &State{ 612 Modules: []*ModuleState{ 613 &ModuleState{ 614 Path: rootModulePath, 615 Resources: map[string]*ResourceState{ 616 "aws_instance.foo": &ResourceState{ 617 Type: "aws_instance", 618 Primary: &InstanceState{ 619 ID: "i-abc123", 620 }, 621 }, 622 }, 623 }, 624 }, 625 }, 626 }) 627 628 plan, err := ctx.Plan() 629 630 expectedErr := "aws_instance.foo: the plan would destroy" 631 if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) { 632 t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s", 633 expectedErr, err, plan) 634 } 635 } 636 637 func TestContext2Plan_preventDestroy_good(t *testing.T) { 638 m := testModule(t, "plan-prevent-destroy-good") 639 p := testProvider("aws") 640 p.DiffFn = testDiffFn 641 ctx := testContext2(t, &ContextOpts{ 642 Module: m, 643 Providers: map[string]ResourceProviderFactory{ 644 "aws": testProviderFuncFixed(p), 645 }, 646 State: &State{ 647 Modules: []*ModuleState{ 648 &ModuleState{ 649 Path: rootModulePath, 650 Resources: map[string]*ResourceState{ 651 "aws_instance.foo": &ResourceState{ 652 Type: "aws_instance", 653 Primary: &InstanceState{ 654 ID: "i-abc123", 655 }, 656 }, 657 }, 658 }, 659 }, 660 }, 661 }) 662 663 plan, err := ctx.Plan() 664 if err != nil { 665 t.Fatalf("err: %s", err) 666 } 667 if !plan.Diff.Empty() { 668 t.Fatalf("Expected empty plan, got %s", plan.String()) 669 } 670 } 671 672 func TestContext2Plan_preventDestroy_destroyPlan(t *testing.T) { 673 m := testModule(t, "plan-prevent-destroy-good") 674 p := testProvider("aws") 675 p.DiffFn = testDiffFn 676 ctx := testContext2(t, &ContextOpts{ 677 Module: m, 678 Providers: map[string]ResourceProviderFactory{ 679 "aws": testProviderFuncFixed(p), 680 }, 681 State: &State{ 682 Modules: []*ModuleState{ 683 &ModuleState{ 684 Path: rootModulePath, 685 Resources: map[string]*ResourceState{ 686 "aws_instance.foo": &ResourceState{ 687 Type: "aws_instance", 688 Primary: &InstanceState{ 689 ID: "i-abc123", 690 }, 691 }, 692 }, 693 }, 694 }, 695 }, 696 Destroy: true, 697 }) 698 699 plan, err := ctx.Plan() 700 701 expectedErr := "aws_instance.foo: the plan would destroy" 702 if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) { 703 t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s", 704 expectedErr, err, plan) 705 } 706 } 707 708 func TestContext2Plan_computed(t *testing.T) { 709 m := testModule(t, "plan-computed") 710 p := testProvider("aws") 711 p.DiffFn = testDiffFn 712 ctx := testContext2(t, &ContextOpts{ 713 Module: m, 714 Providers: map[string]ResourceProviderFactory{ 715 "aws": testProviderFuncFixed(p), 716 }, 717 }) 718 719 plan, err := ctx.Plan() 720 if err != nil { 721 t.Fatalf("err: %s", err) 722 } 723 724 actual := strings.TrimSpace(plan.String()) 725 expected := strings.TrimSpace(testTerraformPlanComputedStr) 726 if actual != expected { 727 t.Fatalf("bad:\n%s", actual) 728 } 729 } 730 731 func TestContext2Plan_computedList(t *testing.T) { 732 m := testModule(t, "plan-computed-list") 733 p := testProvider("aws") 734 p.DiffFn = testDiffFn 735 ctx := testContext2(t, &ContextOpts{ 736 Module: m, 737 Providers: map[string]ResourceProviderFactory{ 738 "aws": testProviderFuncFixed(p), 739 }, 740 }) 741 742 plan, err := ctx.Plan() 743 if err != nil { 744 t.Fatalf("err: %s", err) 745 } 746 747 actual := strings.TrimSpace(plan.String()) 748 expected := strings.TrimSpace(testTerraformPlanComputedListStr) 749 if actual != expected { 750 t.Fatalf("bad:\n%s", actual) 751 } 752 } 753 754 func TestContext2Plan_count(t *testing.T) { 755 m := testModule(t, "plan-count") 756 p := testProvider("aws") 757 p.DiffFn = testDiffFn 758 ctx := testContext2(t, &ContextOpts{ 759 Module: m, 760 Providers: map[string]ResourceProviderFactory{ 761 "aws": testProviderFuncFixed(p), 762 }, 763 }) 764 765 plan, err := ctx.Plan() 766 if err != nil { 767 t.Fatalf("err: %s", err) 768 } 769 770 if len(plan.Diff.RootModule().Resources) < 6 { 771 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 772 } 773 774 actual := strings.TrimSpace(plan.String()) 775 expected := strings.TrimSpace(testTerraformPlanCountStr) 776 if actual != expected { 777 t.Fatalf("bad:\n%s", actual) 778 } 779 } 780 781 func TestContext2Plan_countComputed(t *testing.T) { 782 m := testModule(t, "plan-count-computed") 783 p := testProvider("aws") 784 p.DiffFn = testDiffFn 785 ctx := testContext2(t, &ContextOpts{ 786 Module: m, 787 Providers: map[string]ResourceProviderFactory{ 788 "aws": testProviderFuncFixed(p), 789 }, 790 }) 791 792 _, err := ctx.Plan() 793 if err == nil { 794 t.Fatal("should error") 795 } 796 } 797 798 func TestContext2Plan_countIndex(t *testing.T) { 799 m := testModule(t, "plan-count-index") 800 p := testProvider("aws") 801 p.DiffFn = testDiffFn 802 ctx := testContext2(t, &ContextOpts{ 803 Module: m, 804 Providers: map[string]ResourceProviderFactory{ 805 "aws": testProviderFuncFixed(p), 806 }, 807 }) 808 809 plan, err := ctx.Plan() 810 if err != nil { 811 t.Fatalf("err: %s", err) 812 } 813 814 actual := strings.TrimSpace(plan.String()) 815 expected := strings.TrimSpace(testTerraformPlanCountIndexStr) 816 if actual != expected { 817 t.Fatalf("bad:\n%s", actual) 818 } 819 } 820 821 func TestContext2Plan_countIndexZero(t *testing.T) { 822 m := testModule(t, "plan-count-index-zero") 823 p := testProvider("aws") 824 p.DiffFn = testDiffFn 825 ctx := testContext2(t, &ContextOpts{ 826 Module: m, 827 Providers: map[string]ResourceProviderFactory{ 828 "aws": testProviderFuncFixed(p), 829 }, 830 }) 831 832 plan, err := ctx.Plan() 833 if err != nil { 834 t.Fatalf("err: %s", err) 835 } 836 837 actual := strings.TrimSpace(plan.String()) 838 expected := strings.TrimSpace(testTerraformPlanCountIndexZeroStr) 839 if actual != expected { 840 t.Fatalf("bad:\n%s", actual) 841 } 842 } 843 844 func TestContext2Plan_countVar(t *testing.T) { 845 m := testModule(t, "plan-count-var") 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 Variables: map[string]string{ 854 "count": "3", 855 }, 856 }) 857 858 plan, err := ctx.Plan() 859 if err != nil { 860 t.Fatalf("err: %s", err) 861 } 862 863 actual := strings.TrimSpace(plan.String()) 864 expected := strings.TrimSpace(testTerraformPlanCountVarStr) 865 if actual != expected { 866 t.Fatalf("bad:\n%s", actual) 867 } 868 } 869 870 func TestContext2Plan_countZero(t *testing.T) { 871 m := testModule(t, "plan-count-zero") 872 p := testProvider("aws") 873 p.DiffFn = testDiffFn 874 ctx := testContext2(t, &ContextOpts{ 875 Module: m, 876 Providers: map[string]ResourceProviderFactory{ 877 "aws": testProviderFuncFixed(p), 878 }, 879 }) 880 881 plan, err := ctx.Plan() 882 if err != nil { 883 t.Fatalf("err: %s", err) 884 } 885 886 actual := strings.TrimSpace(plan.String()) 887 expected := strings.TrimSpace(testTerraformPlanCountZeroStr) 888 if actual != expected { 889 t.Fatalf("bad:\n%s", actual) 890 } 891 } 892 893 func TestContext2Plan_countOneIndex(t *testing.T) { 894 m := testModule(t, "plan-count-one-index") 895 p := testProvider("aws") 896 p.DiffFn = testDiffFn 897 ctx := testContext2(t, &ContextOpts{ 898 Module: m, 899 Providers: map[string]ResourceProviderFactory{ 900 "aws": testProviderFuncFixed(p), 901 }, 902 }) 903 904 plan, err := ctx.Plan() 905 if err != nil { 906 t.Fatalf("err: %s", err) 907 } 908 909 actual := strings.TrimSpace(plan.String()) 910 expected := strings.TrimSpace(testTerraformPlanCountOneIndexStr) 911 if actual != expected { 912 t.Fatalf("bad:\n%s", actual) 913 } 914 } 915 916 func TestContext2Plan_countDecreaseToOne(t *testing.T) { 917 m := testModule(t, "plan-count-dec") 918 p := testProvider("aws") 919 p.DiffFn = testDiffFn 920 s := &State{ 921 Modules: []*ModuleState{ 922 &ModuleState{ 923 Path: rootModulePath, 924 Resources: map[string]*ResourceState{ 925 "aws_instance.foo.0": &ResourceState{ 926 Type: "aws_instance", 927 Primary: &InstanceState{ 928 ID: "bar", 929 Attributes: map[string]string{ 930 "foo": "foo", 931 "type": "aws_instance", 932 }, 933 }, 934 }, 935 "aws_instance.foo.1": &ResourceState{ 936 Type: "aws_instance", 937 Primary: &InstanceState{ 938 ID: "bar", 939 }, 940 }, 941 "aws_instance.foo.2": &ResourceState{ 942 Type: "aws_instance", 943 Primary: &InstanceState{ 944 ID: "bar", 945 }, 946 }, 947 }, 948 }, 949 }, 950 } 951 ctx := testContext2(t, &ContextOpts{ 952 Module: m, 953 Providers: map[string]ResourceProviderFactory{ 954 "aws": testProviderFuncFixed(p), 955 }, 956 State: s, 957 }) 958 959 plan, err := ctx.Plan() 960 if err != nil { 961 t.Fatalf("err: %s", err) 962 } 963 964 actual := strings.TrimSpace(plan.String()) 965 expected := strings.TrimSpace(testTerraformPlanCountDecreaseStr) 966 if actual != expected { 967 t.Fatalf("bad:\n%s", actual) 968 } 969 } 970 971 func TestContext2Plan_countIncreaseFromNotSet(t *testing.T) { 972 m := testModule(t, "plan-count-inc") 973 p := testProvider("aws") 974 p.DiffFn = testDiffFn 975 s := &State{ 976 Modules: []*ModuleState{ 977 &ModuleState{ 978 Path: rootModulePath, 979 Resources: map[string]*ResourceState{ 980 "aws_instance.foo": &ResourceState{ 981 Type: "aws_instance", 982 Primary: &InstanceState{ 983 ID: "bar", 984 Attributes: map[string]string{ 985 "foo": "foo", 986 "type": "aws_instance", 987 }, 988 }, 989 }, 990 }, 991 }, 992 }, 993 } 994 ctx := testContext2(t, &ContextOpts{ 995 Module: m, 996 Providers: map[string]ResourceProviderFactory{ 997 "aws": testProviderFuncFixed(p), 998 }, 999 State: s, 1000 }) 1001 1002 plan, err := ctx.Plan() 1003 if err != nil { 1004 t.Fatalf("err: %s", err) 1005 } 1006 1007 actual := strings.TrimSpace(plan.String()) 1008 expected := strings.TrimSpace(testTerraformPlanCountIncreaseStr) 1009 if actual != expected { 1010 t.Fatalf("bad:\n%s", actual) 1011 } 1012 } 1013 1014 func TestContext2Plan_countIncreaseFromOne(t *testing.T) { 1015 m := testModule(t, "plan-count-inc") 1016 p := testProvider("aws") 1017 p.DiffFn = testDiffFn 1018 s := &State{ 1019 Modules: []*ModuleState{ 1020 &ModuleState{ 1021 Path: rootModulePath, 1022 Resources: map[string]*ResourceState{ 1023 "aws_instance.foo.0": &ResourceState{ 1024 Type: "aws_instance", 1025 Primary: &InstanceState{ 1026 ID: "bar", 1027 Attributes: map[string]string{ 1028 "foo": "foo", 1029 "type": "aws_instance", 1030 }, 1031 }, 1032 }, 1033 }, 1034 }, 1035 }, 1036 } 1037 ctx := testContext2(t, &ContextOpts{ 1038 Module: m, 1039 Providers: map[string]ResourceProviderFactory{ 1040 "aws": testProviderFuncFixed(p), 1041 }, 1042 State: s, 1043 }) 1044 1045 plan, err := ctx.Plan() 1046 if err != nil { 1047 t.Fatalf("err: %s", err) 1048 } 1049 1050 actual := strings.TrimSpace(plan.String()) 1051 expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneStr) 1052 if actual != expected { 1053 t.Fatalf("bad:\n%s", actual) 1054 } 1055 } 1056 1057 // https://github.com/PeoplePerHour/terraform/pull/11 1058 // 1059 // This tests a case where both a "resource" and "resource.0" are in 1060 // the state file, which apparently is a reasonable backwards compatibility 1061 // concern found in the above 3rd party repo. 1062 func TestContext2Plan_countIncreaseFromOneCorrupted(t *testing.T) { 1063 m := testModule(t, "plan-count-inc") 1064 p := testProvider("aws") 1065 p.DiffFn = testDiffFn 1066 s := &State{ 1067 Modules: []*ModuleState{ 1068 &ModuleState{ 1069 Path: rootModulePath, 1070 Resources: map[string]*ResourceState{ 1071 "aws_instance.foo": &ResourceState{ 1072 Type: "aws_instance", 1073 Primary: &InstanceState{ 1074 ID: "bar", 1075 Attributes: map[string]string{ 1076 "foo": "foo", 1077 "type": "aws_instance", 1078 }, 1079 }, 1080 }, 1081 "aws_instance.foo.0": &ResourceState{ 1082 Type: "aws_instance", 1083 Primary: &InstanceState{ 1084 ID: "bar", 1085 Attributes: map[string]string{ 1086 "foo": "foo", 1087 "type": "aws_instance", 1088 }, 1089 }, 1090 }, 1091 }, 1092 }, 1093 }, 1094 } 1095 ctx := testContext2(t, &ContextOpts{ 1096 Module: m, 1097 Providers: map[string]ResourceProviderFactory{ 1098 "aws": testProviderFuncFixed(p), 1099 }, 1100 State: s, 1101 }) 1102 1103 plan, err := ctx.Plan() 1104 if err != nil { 1105 t.Fatalf("err: %s", err) 1106 } 1107 1108 actual := strings.TrimSpace(plan.String()) 1109 expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneCorruptedStr) 1110 if actual != expected { 1111 t.Fatalf("bad:\n%s", actual) 1112 } 1113 } 1114 1115 func TestContext2Plan_destroy(t *testing.T) { 1116 m := testModule(t, "plan-destroy") 1117 p := testProvider("aws") 1118 p.DiffFn = testDiffFn 1119 s := &State{ 1120 Modules: []*ModuleState{ 1121 &ModuleState{ 1122 Path: rootModulePath, 1123 Resources: map[string]*ResourceState{ 1124 "aws_instance.one": &ResourceState{ 1125 Type: "aws_instance", 1126 Primary: &InstanceState{ 1127 ID: "bar", 1128 }, 1129 }, 1130 "aws_instance.two": &ResourceState{ 1131 Type: "aws_instance", 1132 Primary: &InstanceState{ 1133 ID: "baz", 1134 }, 1135 }, 1136 }, 1137 }, 1138 }, 1139 } 1140 ctx := testContext2(t, &ContextOpts{ 1141 Module: m, 1142 Providers: map[string]ResourceProviderFactory{ 1143 "aws": testProviderFuncFixed(p), 1144 }, 1145 State: s, 1146 Destroy: true, 1147 }) 1148 1149 plan, err := ctx.Plan() 1150 if err != nil { 1151 t.Fatalf("err: %s", err) 1152 } 1153 1154 if len(plan.Diff.RootModule().Resources) != 2 { 1155 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 1156 } 1157 1158 actual := strings.TrimSpace(plan.String()) 1159 expected := strings.TrimSpace(testTerraformPlanDestroyStr) 1160 if actual != expected { 1161 t.Fatalf("bad:\n%s", actual) 1162 } 1163 } 1164 1165 func TestContext2Plan_moduleDestroy(t *testing.T) { 1166 m := testModule(t, "plan-module-destroy") 1167 p := testProvider("aws") 1168 p.DiffFn = testDiffFn 1169 s := &State{ 1170 Modules: []*ModuleState{ 1171 &ModuleState{ 1172 Path: rootModulePath, 1173 Resources: map[string]*ResourceState{ 1174 "aws_instance.foo": &ResourceState{ 1175 Type: "aws_instance", 1176 Primary: &InstanceState{ 1177 ID: "bar", 1178 }, 1179 }, 1180 }, 1181 }, 1182 &ModuleState{ 1183 Path: []string{"root", "child"}, 1184 Resources: map[string]*ResourceState{ 1185 "aws_instance.foo": &ResourceState{ 1186 Type: "aws_instance", 1187 Primary: &InstanceState{ 1188 ID: "bar", 1189 }, 1190 }, 1191 }, 1192 }, 1193 }, 1194 } 1195 ctx := testContext2(t, &ContextOpts{ 1196 Module: m, 1197 Providers: map[string]ResourceProviderFactory{ 1198 "aws": testProviderFuncFixed(p), 1199 }, 1200 State: s, 1201 Destroy: true, 1202 }) 1203 1204 plan, err := ctx.Plan() 1205 if err != nil { 1206 t.Fatalf("err: %s", err) 1207 } 1208 1209 actual := strings.TrimSpace(plan.String()) 1210 expected := strings.TrimSpace(testTerraformPlanModuleDestroyStr) 1211 if actual != expected { 1212 t.Fatalf("bad:\n%s", actual) 1213 } 1214 } 1215 1216 // GH-1835 1217 func TestContext2Plan_moduleDestroyCycle(t *testing.T) { 1218 m := testModule(t, "plan-module-destroy-gh-1835") 1219 p := testProvider("aws") 1220 p.DiffFn = testDiffFn 1221 s := &State{ 1222 Modules: []*ModuleState{ 1223 &ModuleState{ 1224 Path: []string{"root", "a_module"}, 1225 Resources: map[string]*ResourceState{ 1226 "aws_instance.a": &ResourceState{ 1227 Type: "aws_instance", 1228 Primary: &InstanceState{ 1229 ID: "a", 1230 }, 1231 }, 1232 }, 1233 }, 1234 &ModuleState{ 1235 Path: []string{"root", "b_module"}, 1236 Resources: map[string]*ResourceState{ 1237 "aws_instance.b": &ResourceState{ 1238 Type: "aws_instance", 1239 Primary: &InstanceState{ 1240 ID: "b", 1241 }, 1242 }, 1243 }, 1244 }, 1245 }, 1246 } 1247 ctx := testContext2(t, &ContextOpts{ 1248 Module: m, 1249 Providers: map[string]ResourceProviderFactory{ 1250 "aws": testProviderFuncFixed(p), 1251 }, 1252 State: s, 1253 Destroy: true, 1254 }) 1255 1256 plan, err := ctx.Plan() 1257 if err != nil { 1258 t.Fatalf("err: %s", err) 1259 } 1260 1261 actual := strings.TrimSpace(plan.String()) 1262 expected := strings.TrimSpace(testTerraformPlanModuleDestroyCycleStr) 1263 if actual != expected { 1264 t.Fatalf("bad:\n%s", actual) 1265 } 1266 } 1267 1268 func TestContext2Plan_moduleDestroyMultivar(t *testing.T) { 1269 m := testModule(t, "plan-module-destroy-multivar") 1270 p := testProvider("aws") 1271 p.DiffFn = testDiffFn 1272 s := &State{ 1273 Modules: []*ModuleState{ 1274 &ModuleState{ 1275 Path: rootModulePath, 1276 Resources: map[string]*ResourceState{}, 1277 }, 1278 &ModuleState{ 1279 Path: []string{"root", "child"}, 1280 Resources: map[string]*ResourceState{ 1281 "aws_instance.foo.0": &ResourceState{ 1282 Type: "aws_instance", 1283 Primary: &InstanceState{ 1284 ID: "bar0", 1285 }, 1286 }, 1287 "aws_instance.foo.1": &ResourceState{ 1288 Type: "aws_instance", 1289 Primary: &InstanceState{ 1290 ID: "bar1", 1291 }, 1292 }, 1293 }, 1294 }, 1295 }, 1296 } 1297 ctx := testContext2(t, &ContextOpts{ 1298 Module: m, 1299 Providers: map[string]ResourceProviderFactory{ 1300 "aws": testProviderFuncFixed(p), 1301 }, 1302 State: s, 1303 Destroy: true, 1304 }) 1305 1306 plan, err := ctx.Plan() 1307 if err != nil { 1308 t.Fatalf("err: %s", err) 1309 } 1310 1311 actual := strings.TrimSpace(plan.String()) 1312 expected := strings.TrimSpace(testTerraformPlanModuleDestroyMultivarStr) 1313 if actual != expected { 1314 t.Fatalf("bad:\n%s", actual) 1315 } 1316 } 1317 1318 func TestContext2Plan_pathVar(t *testing.T) { 1319 cwd, err := os.Getwd() 1320 if err != nil { 1321 t.Fatalf("err: %s", err) 1322 } 1323 1324 m := testModule(t, "plan-path-var") 1325 p := testProvider("aws") 1326 p.DiffFn = testDiffFn 1327 ctx := testContext2(t, &ContextOpts{ 1328 Module: m, 1329 Providers: map[string]ResourceProviderFactory{ 1330 "aws": testProviderFuncFixed(p), 1331 }, 1332 }) 1333 1334 plan, err := ctx.Plan() 1335 if err != nil { 1336 t.Fatalf("err: %s", err) 1337 } 1338 1339 actual := strings.TrimSpace(plan.String()) 1340 expected := strings.TrimSpace(testTerraformPlanPathVarStr) 1341 1342 // Warning: this ordering REALLY matters for this test. The 1343 // order is: cwd, module, root. 1344 expected = fmt.Sprintf( 1345 expected, 1346 cwd, 1347 m.Config().Dir, 1348 m.Config().Dir) 1349 1350 if actual != expected { 1351 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 1352 } 1353 } 1354 1355 func TestContext2Plan_diffVar(t *testing.T) { 1356 m := testModule(t, "plan-diffvar") 1357 p := testProvider("aws") 1358 s := &State{ 1359 Modules: []*ModuleState{ 1360 &ModuleState{ 1361 Path: rootModulePath, 1362 Resources: map[string]*ResourceState{ 1363 "aws_instance.foo": &ResourceState{ 1364 Primary: &InstanceState{ 1365 ID: "bar", 1366 Attributes: map[string]string{ 1367 "num": "2", 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 p.DiffFn = func( 1384 info *InstanceInfo, 1385 s *InstanceState, 1386 c *ResourceConfig) (*InstanceDiff, error) { 1387 if s.ID != "bar" { 1388 return testDiffFn(info, s, c) 1389 } 1390 1391 return &InstanceDiff{ 1392 Attributes: map[string]*ResourceAttrDiff{ 1393 "num": &ResourceAttrDiff{ 1394 Old: "2", 1395 New: "3", 1396 }, 1397 }, 1398 }, nil 1399 } 1400 1401 plan, err := ctx.Plan() 1402 if err != nil { 1403 t.Fatalf("err: %s", err) 1404 } 1405 1406 actual := strings.TrimSpace(plan.String()) 1407 expected := strings.TrimSpace(testTerraformPlanDiffVarStr) 1408 if actual != expected { 1409 t.Fatalf("actual:\n%s\n\nexpected:\n%s", actual, expected) 1410 } 1411 } 1412 1413 func TestContext2Plan_hook(t *testing.T) { 1414 m := testModule(t, "plan-good") 1415 h := new(MockHook) 1416 p := testProvider("aws") 1417 p.DiffFn = testDiffFn 1418 ctx := testContext2(t, &ContextOpts{ 1419 Module: m, 1420 Hooks: []Hook{h}, 1421 Providers: map[string]ResourceProviderFactory{ 1422 "aws": testProviderFuncFixed(p), 1423 }, 1424 }) 1425 1426 _, err := ctx.Plan() 1427 if err != nil { 1428 t.Fatalf("err: %s", err) 1429 } 1430 1431 if !h.PreDiffCalled { 1432 t.Fatal("should be called") 1433 } 1434 if !h.PostDiffCalled { 1435 t.Fatal("should be called") 1436 } 1437 } 1438 1439 func TestContext2Plan_orphan(t *testing.T) { 1440 m := testModule(t, "plan-orphan") 1441 p := testProvider("aws") 1442 p.DiffFn = testDiffFn 1443 s := &State{ 1444 Modules: []*ModuleState{ 1445 &ModuleState{ 1446 Path: rootModulePath, 1447 Resources: map[string]*ResourceState{ 1448 "aws_instance.baz": &ResourceState{ 1449 Type: "aws_instance", 1450 Primary: &InstanceState{ 1451 ID: "bar", 1452 }, 1453 }, 1454 }, 1455 }, 1456 }, 1457 } 1458 ctx := testContext2(t, &ContextOpts{ 1459 Module: m, 1460 Providers: map[string]ResourceProviderFactory{ 1461 "aws": testProviderFuncFixed(p), 1462 }, 1463 State: s, 1464 }) 1465 1466 plan, err := ctx.Plan() 1467 if err != nil { 1468 t.Fatalf("err: %s", err) 1469 } 1470 1471 actual := strings.TrimSpace(plan.String()) 1472 expected := strings.TrimSpace(testTerraformPlanOrphanStr) 1473 if actual != expected { 1474 t.Fatalf("bad:\n%s", actual) 1475 } 1476 } 1477 1478 func TestContext2Plan_state(t *testing.T) { 1479 m := testModule(t, "plan-good") 1480 p := testProvider("aws") 1481 p.DiffFn = testDiffFn 1482 s := &State{ 1483 Modules: []*ModuleState{ 1484 &ModuleState{ 1485 Path: rootModulePath, 1486 Resources: map[string]*ResourceState{ 1487 "aws_instance.foo": &ResourceState{ 1488 Primary: &InstanceState{ 1489 ID: "bar", 1490 }, 1491 }, 1492 }, 1493 }, 1494 }, 1495 } 1496 ctx := testContext2(t, &ContextOpts{ 1497 Module: m, 1498 Providers: map[string]ResourceProviderFactory{ 1499 "aws": testProviderFuncFixed(p), 1500 }, 1501 State: s, 1502 }) 1503 1504 plan, err := ctx.Plan() 1505 if err != nil { 1506 t.Fatalf("err: %s", err) 1507 } 1508 1509 if len(plan.Diff.RootModule().Resources) < 2 { 1510 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 1511 } 1512 1513 actual := strings.TrimSpace(plan.String()) 1514 expected := strings.TrimSpace(testTerraformPlanStateStr) 1515 if actual != expected { 1516 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 1517 } 1518 } 1519 1520 func TestContext2Plan_taint(t *testing.T) { 1521 m := testModule(t, "plan-taint") 1522 p := testProvider("aws") 1523 p.DiffFn = testDiffFn 1524 s := &State{ 1525 Modules: []*ModuleState{ 1526 &ModuleState{ 1527 Path: rootModulePath, 1528 Resources: map[string]*ResourceState{ 1529 "aws_instance.foo": &ResourceState{ 1530 Type: "aws_instance", 1531 Primary: &InstanceState{ 1532 ID: "bar", 1533 Attributes: map[string]string{"num": "2"}, 1534 }, 1535 }, 1536 "aws_instance.bar": &ResourceState{ 1537 Type: "aws_instance", 1538 Tainted: []*InstanceState{ 1539 &InstanceState{ 1540 ID: "baz", 1541 }, 1542 }, 1543 }, 1544 }, 1545 }, 1546 }, 1547 } 1548 ctx := testContext2(t, &ContextOpts{ 1549 Module: m, 1550 Providers: map[string]ResourceProviderFactory{ 1551 "aws": testProviderFuncFixed(p), 1552 }, 1553 State: s, 1554 }) 1555 1556 plan, err := ctx.Plan() 1557 if err != nil { 1558 t.Fatalf("err: %s", err) 1559 } 1560 1561 actual := strings.TrimSpace(plan.String()) 1562 expected := strings.TrimSpace(testTerraformPlanTaintStr) 1563 if actual != expected { 1564 t.Fatalf("bad:\n%s", actual) 1565 } 1566 } 1567 1568 func TestContext2Plan_multiple_taint(t *testing.T) { 1569 m := testModule(t, "plan-taint") 1570 p := testProvider("aws") 1571 p.DiffFn = testDiffFn 1572 s := &State{ 1573 Modules: []*ModuleState{ 1574 &ModuleState{ 1575 Path: rootModulePath, 1576 Resources: map[string]*ResourceState{ 1577 "aws_instance.foo": &ResourceState{ 1578 Type: "aws_instance", 1579 Primary: &InstanceState{ 1580 ID: "bar", 1581 Attributes: map[string]string{"num": "2"}, 1582 }, 1583 }, 1584 "aws_instance.bar": &ResourceState{ 1585 Type: "aws_instance", 1586 Tainted: []*InstanceState{ 1587 &InstanceState{ 1588 ID: "baz", 1589 }, 1590 &InstanceState{ 1591 ID: "zip", 1592 }, 1593 }, 1594 }, 1595 }, 1596 }, 1597 }, 1598 } 1599 ctx := testContext2(t, &ContextOpts{ 1600 Module: m, 1601 Providers: map[string]ResourceProviderFactory{ 1602 "aws": testProviderFuncFixed(p), 1603 }, 1604 State: s, 1605 }) 1606 1607 plan, err := ctx.Plan() 1608 if err != nil { 1609 t.Fatalf("err: %s", err) 1610 } 1611 1612 actual := strings.TrimSpace(plan.String()) 1613 expected := strings.TrimSpace(testTerraformPlanMultipleTaintStr) 1614 if actual != expected { 1615 t.Fatalf("bad:\n%s", actual) 1616 } 1617 } 1618 1619 func TestContext2Plan_targeted(t *testing.T) { 1620 m := testModule(t, "plan-targeted") 1621 p := testProvider("aws") 1622 p.DiffFn = testDiffFn 1623 ctx := testContext2(t, &ContextOpts{ 1624 Module: m, 1625 Providers: map[string]ResourceProviderFactory{ 1626 "aws": testProviderFuncFixed(p), 1627 }, 1628 Targets: []string{"aws_instance.foo"}, 1629 }) 1630 1631 plan, err := ctx.Plan() 1632 if err != nil { 1633 t.Fatalf("err: %s", err) 1634 } 1635 1636 actual := strings.TrimSpace(plan.String()) 1637 expected := strings.TrimSpace(` 1638 DIFF: 1639 1640 CREATE: aws_instance.foo 1641 num: "" => "2" 1642 type: "" => "aws_instance" 1643 1644 STATE: 1645 1646 <no state> 1647 `) 1648 if actual != expected { 1649 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 1650 } 1651 } 1652 1653 func TestContext2Plan_targetedOrphan(t *testing.T) { 1654 m := testModule(t, "plan-targeted-orphan") 1655 p := testProvider("aws") 1656 p.DiffFn = testDiffFn 1657 ctx := testContext2(t, &ContextOpts{ 1658 Module: m, 1659 Providers: map[string]ResourceProviderFactory{ 1660 "aws": testProviderFuncFixed(p), 1661 }, 1662 State: &State{ 1663 Modules: []*ModuleState{ 1664 &ModuleState{ 1665 Path: rootModulePath, 1666 Resources: map[string]*ResourceState{ 1667 "aws_instance.orphan": &ResourceState{ 1668 Type: "aws_instance", 1669 Primary: &InstanceState{ 1670 ID: "i-789xyz", 1671 }, 1672 }, 1673 "aws_instance.nottargeted": &ResourceState{ 1674 Type: "aws_instance", 1675 Primary: &InstanceState{ 1676 ID: "i-abc123", 1677 }, 1678 }, 1679 }, 1680 }, 1681 }, 1682 }, 1683 Destroy: true, 1684 Targets: []string{"aws_instance.orphan"}, 1685 }) 1686 1687 plan, err := ctx.Plan() 1688 if err != nil { 1689 t.Fatalf("err: %s", err) 1690 } 1691 1692 actual := strings.TrimSpace(plan.String()) 1693 expected := strings.TrimSpace(`DIFF: 1694 1695 DESTROY: aws_instance.orphan 1696 1697 STATE: 1698 1699 aws_instance.nottargeted: 1700 ID = i-abc123 1701 aws_instance.orphan: 1702 ID = i-789xyz 1703 `) 1704 if actual != expected { 1705 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 1706 } 1707 } 1708 1709 // https://github.com/hashicorp/terraform/issues/2538 1710 func TestContext2Plan_targetedModuleOrphan(t *testing.T) { 1711 m := testModule(t, "plan-targeted-module-orphan") 1712 p := testProvider("aws") 1713 p.DiffFn = testDiffFn 1714 ctx := testContext2(t, &ContextOpts{ 1715 Module: m, 1716 Providers: map[string]ResourceProviderFactory{ 1717 "aws": testProviderFuncFixed(p), 1718 }, 1719 State: &State{ 1720 Modules: []*ModuleState{ 1721 &ModuleState{ 1722 Path: []string{"root", "child"}, 1723 Resources: map[string]*ResourceState{ 1724 "aws_instance.orphan": &ResourceState{ 1725 Type: "aws_instance", 1726 Primary: &InstanceState{ 1727 ID: "i-789xyz", 1728 }, 1729 }, 1730 "aws_instance.nottargeted": &ResourceState{ 1731 Type: "aws_instance", 1732 Primary: &InstanceState{ 1733 ID: "i-abc123", 1734 }, 1735 }, 1736 }, 1737 }, 1738 }, 1739 }, 1740 Destroy: true, 1741 Targets: []string{"module.child.aws_instance.orphan"}, 1742 }) 1743 1744 plan, err := ctx.Plan() 1745 if err != nil { 1746 t.Fatalf("err: %s", err) 1747 } 1748 1749 actual := strings.TrimSpace(plan.String()) 1750 expected := strings.TrimSpace(`DIFF: 1751 1752 module.child: 1753 DESTROY: aws_instance.orphan 1754 1755 STATE: 1756 1757 module.child: 1758 aws_instance.nottargeted: 1759 ID = i-abc123 1760 aws_instance.orphan: 1761 ID = i-789xyz 1762 `) 1763 if actual != expected { 1764 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 1765 } 1766 } 1767 1768 // https://github.com/hashicorp/terraform/issues/4515 1769 func TestContext2Plan_targetedOverTen(t *testing.T) { 1770 m := testModule(t, "plan-targeted-over-ten") 1771 p := testProvider("aws") 1772 p.DiffFn = testDiffFn 1773 1774 resources := make(map[string]*ResourceState) 1775 var expectedState []string 1776 for i := 0; i < 13; i++ { 1777 key := fmt.Sprintf("aws_instance.foo.%d", i) 1778 id := fmt.Sprintf("i-abc%d", i) 1779 resources[key] = &ResourceState{ 1780 Type: "aws_instance", 1781 Primary: &InstanceState{ID: id}, 1782 } 1783 expectedState = append(expectedState, 1784 fmt.Sprintf("%s:\n ID = %s\n", key, id)) 1785 } 1786 ctx := testContext2(t, &ContextOpts{ 1787 Module: m, 1788 Providers: map[string]ResourceProviderFactory{ 1789 "aws": testProviderFuncFixed(p), 1790 }, 1791 State: &State{ 1792 Modules: []*ModuleState{ 1793 &ModuleState{ 1794 Path: rootModulePath, 1795 Resources: resources, 1796 }, 1797 }, 1798 }, 1799 Targets: []string{"aws_instance.foo[1]"}, 1800 }) 1801 1802 plan, err := ctx.Plan() 1803 if err != nil { 1804 t.Fatalf("err: %s", err) 1805 } 1806 1807 actual := strings.TrimSpace(plan.String()) 1808 sort.Strings(expectedState) 1809 expected := strings.TrimSpace(` 1810 DIFF: 1811 1812 1813 1814 STATE: 1815 1816 aws_instance.foo.0: 1817 ID = i-abc0 1818 aws_instance.foo.1: 1819 ID = i-abc1 1820 aws_instance.foo.10: 1821 ID = i-abc10 1822 aws_instance.foo.11: 1823 ID = i-abc11 1824 aws_instance.foo.12: 1825 ID = i-abc12 1826 aws_instance.foo.2: 1827 ID = i-abc2 1828 aws_instance.foo.3: 1829 ID = i-abc3 1830 aws_instance.foo.4: 1831 ID = i-abc4 1832 aws_instance.foo.5: 1833 ID = i-abc5 1834 aws_instance.foo.6: 1835 ID = i-abc6 1836 aws_instance.foo.7: 1837 ID = i-abc7 1838 aws_instance.foo.8: 1839 ID = i-abc8 1840 aws_instance.foo.9: 1841 ID = i-abc9 1842 `) 1843 if actual != expected { 1844 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 1845 } 1846 } 1847 1848 func TestContext2Plan_provider(t *testing.T) { 1849 m := testModule(t, "plan-provider") 1850 p := testProvider("aws") 1851 p.DiffFn = testDiffFn 1852 1853 var value interface{} 1854 p.ConfigureFn = func(c *ResourceConfig) error { 1855 value, _ = c.Get("foo") 1856 return nil 1857 } 1858 1859 ctx := testContext2(t, &ContextOpts{ 1860 Module: m, 1861 Providers: map[string]ResourceProviderFactory{ 1862 "aws": testProviderFuncFixed(p), 1863 }, 1864 Variables: map[string]string{ 1865 "foo": "bar", 1866 }, 1867 }) 1868 1869 if _, err := ctx.Plan(); err != nil { 1870 t.Fatalf("err: %s", err) 1871 } 1872 1873 if value != "bar" { 1874 t.Fatalf("bad: %#v", value) 1875 } 1876 } 1877 1878 func TestContext2Plan_varListErr(t *testing.T) { 1879 m := testModule(t, "plan-var-list-err") 1880 p := testProvider("aws") 1881 ctx := testContext2(t, &ContextOpts{ 1882 Module: m, 1883 Providers: map[string]ResourceProviderFactory{ 1884 "aws": testProviderFuncFixed(p), 1885 }, 1886 }) 1887 1888 _, err := ctx.Plan() 1889 if err == nil { 1890 t.Fatal("should error") 1891 } 1892 } 1893 1894 func TestContext2Plan_ignoreChanges(t *testing.T) { 1895 m := testModule(t, "plan-ignore-changes") 1896 p := testProvider("aws") 1897 p.DiffFn = testDiffFn 1898 s := &State{ 1899 Modules: []*ModuleState{ 1900 &ModuleState{ 1901 Path: rootModulePath, 1902 Resources: map[string]*ResourceState{ 1903 "aws_instance.foo": &ResourceState{ 1904 Primary: &InstanceState{ 1905 ID: "bar", 1906 Attributes: map[string]string{"ami": "ami-abcd1234"}, 1907 }, 1908 }, 1909 }, 1910 }, 1911 }, 1912 } 1913 ctx := testContext2(t, &ContextOpts{ 1914 Module: m, 1915 Providers: map[string]ResourceProviderFactory{ 1916 "aws": testProviderFuncFixed(p), 1917 }, 1918 Variables: map[string]string{ 1919 "foo": "ami-1234abcd", 1920 }, 1921 State: s, 1922 }) 1923 1924 plan, err := ctx.Plan() 1925 if err != nil { 1926 t.Fatalf("err: %s", err) 1927 } 1928 1929 if len(plan.Diff.RootModule().Resources) < 1 { 1930 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 1931 } 1932 1933 actual := strings.TrimSpace(plan.String()) 1934 expected := strings.TrimSpace(testTerraformPlanIgnoreChangesStr) 1935 if actual != expected { 1936 t.Fatalf("bad:\n%s\n\nexpected\n\n%s", actual, expected) 1937 } 1938 }