github.com/alexissmirnov/terraform@v0.4.3-0.20150423153700-1ef9731a2f14/terraform/context_test.go (about) 1 package terraform 2 3 import ( 4 "bytes" 5 "fmt" 6 "os" 7 "reflect" 8 "sort" 9 "strings" 10 "sync" 11 "sync/atomic" 12 "testing" 13 "time" 14 ) 15 16 func TestContext2Plan(t *testing.T) { 17 m := testModule(t, "plan-good") 18 p := testProvider("aws") 19 p.DiffFn = testDiffFn 20 ctx := testContext2(t, &ContextOpts{ 21 Module: m, 22 Providers: map[string]ResourceProviderFactory{ 23 "aws": testProviderFuncFixed(p), 24 }, 25 }) 26 27 plan, err := ctx.Plan() 28 if err != nil { 29 t.Fatalf("err: %s", err) 30 } 31 32 if len(plan.Diff.RootModule().Resources) < 2 { 33 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 34 } 35 36 actual := strings.TrimSpace(plan.String()) 37 expected := strings.TrimSpace(testTerraformPlanStr) 38 if actual != expected { 39 t.Fatalf("bad:\n%s", actual) 40 } 41 } 42 43 func TestContext2Plan_emptyDiff(t *testing.T) { 44 m := testModule(t, "plan-empty") 45 p := testProvider("aws") 46 p.DiffFn = func( 47 info *InstanceInfo, 48 s *InstanceState, 49 c *ResourceConfig) (*InstanceDiff, error) { 50 return nil, nil 51 } 52 53 ctx := testContext2(t, &ContextOpts{ 54 Module: m, 55 Providers: map[string]ResourceProviderFactory{ 56 "aws": testProviderFuncFixed(p), 57 }, 58 }) 59 60 plan, err := ctx.Plan() 61 if err != nil { 62 t.Fatalf("err: %s", err) 63 } 64 65 actual := strings.TrimSpace(plan.String()) 66 expected := strings.TrimSpace(testTerraformPlanEmptyStr) 67 if actual != expected { 68 t.Fatalf("bad:\n%s", actual) 69 } 70 } 71 72 func TestContext2Plan_minimal(t *testing.T) { 73 m := testModule(t, "plan-empty") 74 p := testProvider("aws") 75 p.DiffFn = testDiffFn 76 ctx := testContext2(t, &ContextOpts{ 77 Module: m, 78 Providers: map[string]ResourceProviderFactory{ 79 "aws": testProviderFuncFixed(p), 80 }, 81 }) 82 83 plan, err := ctx.Plan() 84 if err != nil { 85 t.Fatalf("err: %s", err) 86 } 87 88 actual := strings.TrimSpace(plan.String()) 89 expected := strings.TrimSpace(testTerraformPlanEmptyStr) 90 if actual != expected { 91 t.Fatalf("bad:\n%s", actual) 92 } 93 } 94 95 func TestContext2Plan_modules(t *testing.T) { 96 m := testModule(t, "plan-modules") 97 p := testProvider("aws") 98 p.DiffFn = testDiffFn 99 ctx := testContext2(t, &ContextOpts{ 100 Module: m, 101 Providers: map[string]ResourceProviderFactory{ 102 "aws": testProviderFuncFixed(p), 103 }, 104 }) 105 106 plan, err := ctx.Plan() 107 if err != nil { 108 t.Fatalf("err: %s", err) 109 } 110 111 actual := strings.TrimSpace(plan.String()) 112 expected := strings.TrimSpace(testTerraformPlanModulesStr) 113 if actual != expected { 114 t.Fatalf("bad:\n%s", actual) 115 } 116 } 117 118 // GH-1475 119 func TestContext2Plan_moduleCycle(t *testing.T) { 120 m := testModule(t, "plan-module-cycle") 121 p := testProvider("aws") 122 p.DiffFn = testDiffFn 123 ctx := testContext2(t, &ContextOpts{ 124 Module: m, 125 Providers: map[string]ResourceProviderFactory{ 126 "aws": testProviderFuncFixed(p), 127 }, 128 }) 129 130 plan, err := ctx.Plan() 131 if err != nil { 132 t.Fatalf("err: %s", err) 133 } 134 135 actual := strings.TrimSpace(plan.String()) 136 expected := strings.TrimSpace(testTerraformPlanModuleCycleStr) 137 if actual != expected { 138 t.Fatalf("bad:\n%s", actual) 139 } 140 } 141 142 func TestContext2Plan_moduleInput(t *testing.T) { 143 m := testModule(t, "plan-module-input") 144 p := testProvider("aws") 145 p.DiffFn = testDiffFn 146 ctx := testContext2(t, &ContextOpts{ 147 Module: m, 148 Providers: map[string]ResourceProviderFactory{ 149 "aws": testProviderFuncFixed(p), 150 }, 151 }) 152 153 plan, err := ctx.Plan() 154 if err != nil { 155 t.Fatalf("err: %s", err) 156 } 157 158 actual := strings.TrimSpace(plan.String()) 159 expected := strings.TrimSpace(testTerraformPlanModuleInputStr) 160 if actual != expected { 161 t.Fatalf("bad:\n%s", actual) 162 } 163 } 164 165 func TestContext2Plan_moduleInputComputed(t *testing.T) { 166 m := testModule(t, "plan-module-input-computed") 167 p := testProvider("aws") 168 p.DiffFn = testDiffFn 169 ctx := testContext2(t, &ContextOpts{ 170 Module: m, 171 Providers: map[string]ResourceProviderFactory{ 172 "aws": testProviderFuncFixed(p), 173 }, 174 }) 175 176 plan, err := ctx.Plan() 177 if err != nil { 178 t.Fatalf("err: %s", err) 179 } 180 181 actual := strings.TrimSpace(plan.String()) 182 expected := strings.TrimSpace(testTerraformPlanModuleInputComputedStr) 183 if actual != expected { 184 t.Fatalf("bad:\n%s", actual) 185 } 186 } 187 188 func TestContext2Plan_moduleInputFromVar(t *testing.T) { 189 m := testModule(t, "plan-module-input-var") 190 p := testProvider("aws") 191 p.DiffFn = testDiffFn 192 ctx := testContext2(t, &ContextOpts{ 193 Module: m, 194 Providers: map[string]ResourceProviderFactory{ 195 "aws": testProviderFuncFixed(p), 196 }, 197 Variables: map[string]string{ 198 "foo": "52", 199 }, 200 }) 201 202 plan, err := ctx.Plan() 203 if err != nil { 204 t.Fatalf("err: %s", err) 205 } 206 207 actual := strings.TrimSpace(plan.String()) 208 expected := strings.TrimSpace(testTerraformPlanModuleInputVarStr) 209 if actual != expected { 210 t.Fatalf("bad:\n%s", actual) 211 } 212 } 213 214 func TestContext2Plan_moduleMultiVar(t *testing.T) { 215 m := testModule(t, "plan-module-multi-var") 216 p := testProvider("aws") 217 p.DiffFn = testDiffFn 218 ctx := testContext2(t, &ContextOpts{ 219 Module: m, 220 Providers: map[string]ResourceProviderFactory{ 221 "aws": testProviderFuncFixed(p), 222 }, 223 }) 224 225 plan, err := ctx.Plan() 226 if err != nil { 227 t.Fatalf("err: %s", err) 228 } 229 230 actual := strings.TrimSpace(plan.String()) 231 expected := strings.TrimSpace(testTerraformPlanModuleMultiVarStr) 232 if actual != expected { 233 t.Fatalf("bad:\n%s", actual) 234 } 235 } 236 237 func TestContext2Plan_moduleOrphans(t *testing.T) { 238 m := testModule(t, "plan-modules-remove") 239 p := testProvider("aws") 240 p.DiffFn = testDiffFn 241 s := &State{ 242 Modules: []*ModuleState{ 243 &ModuleState{ 244 Path: []string{"root", "child"}, 245 Resources: map[string]*ResourceState{ 246 "aws_instance.foo": &ResourceState{ 247 Type: "aws_instance", 248 Primary: &InstanceState{ 249 ID: "baz", 250 }, 251 }, 252 }, 253 }, 254 }, 255 } 256 ctx := testContext2(t, &ContextOpts{ 257 Module: m, 258 Providers: map[string]ResourceProviderFactory{ 259 "aws": testProviderFuncFixed(p), 260 }, 261 State: s, 262 }) 263 264 plan, err := ctx.Plan() 265 if err != nil { 266 t.Fatalf("err: %s", err) 267 } 268 269 actual := strings.TrimSpace(plan.String()) 270 expected := strings.TrimSpace(testTerraformPlanModuleOrphansStr) 271 if actual != expected { 272 t.Fatalf("bad:\n%s", actual) 273 } 274 } 275 276 func TestContext2Plan_moduleProviderInherit(t *testing.T) { 277 var l sync.Mutex 278 var calls []string 279 280 m := testModule(t, "plan-module-provider-inherit") 281 ctx := testContext2(t, &ContextOpts{ 282 Module: m, 283 Providers: map[string]ResourceProviderFactory{ 284 "aws": func() (ResourceProvider, error) { 285 l.Lock() 286 defer l.Unlock() 287 288 p := testProvider("aws") 289 p.ConfigureFn = func(c *ResourceConfig) error { 290 if v, ok := c.Get("from"); !ok || v.(string) != "root" { 291 return fmt.Errorf("bad") 292 } 293 294 return nil 295 } 296 p.DiffFn = func( 297 info *InstanceInfo, 298 state *InstanceState, 299 c *ResourceConfig) (*InstanceDiff, error) { 300 v, _ := c.Get("from") 301 calls = append(calls, v.(string)) 302 return testDiffFn(info, state, c) 303 } 304 return p, nil 305 }, 306 }, 307 }) 308 309 _, err := ctx.Plan() 310 if err != nil { 311 t.Fatalf("err: %s", err) 312 } 313 314 actual := calls 315 sort.Strings(actual) 316 expected := []string{"child", "root"} 317 if !reflect.DeepEqual(actual, expected) { 318 t.Fatalf("bad: %#v", actual) 319 } 320 } 321 322 func TestContext2Plan_moduleProviderDefaults(t *testing.T) { 323 var l sync.Mutex 324 var calls []string 325 toCount := 0 326 327 m := testModule(t, "plan-module-provider-defaults") 328 ctx := testContext2(t, &ContextOpts{ 329 Module: m, 330 Providers: map[string]ResourceProviderFactory{ 331 "aws": func() (ResourceProvider, error) { 332 l.Lock() 333 defer l.Unlock() 334 335 p := testProvider("aws") 336 p.ConfigureFn = func(c *ResourceConfig) error { 337 if v, ok := c.Get("from"); !ok || v.(string) != "root" { 338 return fmt.Errorf("bad") 339 } 340 if v, ok := c.Get("to"); ok && v.(string) == "child" { 341 toCount++ 342 } 343 344 return nil 345 } 346 p.DiffFn = func( 347 info *InstanceInfo, 348 state *InstanceState, 349 c *ResourceConfig) (*InstanceDiff, error) { 350 v, _ := c.Get("from") 351 calls = append(calls, v.(string)) 352 return testDiffFn(info, state, c) 353 } 354 return p, nil 355 }, 356 }, 357 }) 358 359 _, err := ctx.Plan() 360 if err != nil { 361 t.Fatalf("err: %s", err) 362 } 363 364 if toCount != 1 { 365 t.Fatalf( 366 "provider in child didn't set proper config\n\n"+ 367 "toCount: %d", toCount) 368 } 369 370 actual := calls 371 sort.Strings(actual) 372 expected := []string{"child", "root"} 373 if !reflect.DeepEqual(actual, expected) { 374 t.Fatalf("bad: %#v", actual) 375 } 376 } 377 378 func TestContext2Plan_moduleProviderDefaultsVar(t *testing.T) { 379 var l sync.Mutex 380 var calls []string 381 382 m := testModule(t, "plan-module-provider-defaults-var") 383 ctx := testContext2(t, &ContextOpts{ 384 Module: m, 385 Providers: map[string]ResourceProviderFactory{ 386 "aws": func() (ResourceProvider, error) { 387 l.Lock() 388 defer l.Unlock() 389 390 p := testProvider("aws") 391 p.ConfigureFn = func(c *ResourceConfig) error { 392 var buf bytes.Buffer 393 if v, ok := c.Get("from"); ok { 394 buf.WriteString(v.(string) + "\n") 395 } 396 if v, ok := c.Get("to"); ok { 397 buf.WriteString(v.(string) + "\n") 398 } 399 400 calls = append(calls, buf.String()) 401 return nil 402 } 403 p.DiffFn = testDiffFn 404 return p, nil 405 }, 406 }, 407 Variables: map[string]string{ 408 "foo": "root", 409 }, 410 }) 411 412 _, err := ctx.Plan() 413 if err != nil { 414 t.Fatalf("err: %s", err) 415 } 416 417 expected := []string{ 418 "root\n", 419 "root\nchild\n", 420 } 421 if !reflect.DeepEqual(calls, expected) { 422 t.Fatalf("BAD: %#v", calls) 423 } 424 } 425 426 func TestContext2Plan_moduleVar(t *testing.T) { 427 m := testModule(t, "plan-module-var") 428 p := testProvider("aws") 429 p.DiffFn = testDiffFn 430 ctx := testContext2(t, &ContextOpts{ 431 Module: m, 432 Providers: map[string]ResourceProviderFactory{ 433 "aws": testProviderFuncFixed(p), 434 }, 435 }) 436 437 plan, err := ctx.Plan() 438 if err != nil { 439 t.Fatalf("err: %s", err) 440 } 441 442 actual := strings.TrimSpace(plan.String()) 443 expected := strings.TrimSpace(testTerraformPlanModuleVarStr) 444 if actual != expected { 445 t.Fatalf("bad:\n%s", actual) 446 } 447 } 448 449 func TestContext2Plan_moduleVarComputed(t *testing.T) { 450 m := testModule(t, "plan-module-var-computed") 451 p := testProvider("aws") 452 p.DiffFn = testDiffFn 453 ctx := testContext2(t, &ContextOpts{ 454 Module: m, 455 Providers: map[string]ResourceProviderFactory{ 456 "aws": testProviderFuncFixed(p), 457 }, 458 }) 459 460 plan, err := ctx.Plan() 461 if err != nil { 462 t.Fatalf("err: %s", err) 463 } 464 465 actual := strings.TrimSpace(plan.String()) 466 expected := strings.TrimSpace(testTerraformPlanModuleVarComputedStr) 467 if actual != expected { 468 t.Fatalf("bad:\n%s", actual) 469 } 470 } 471 472 func TestContext2Plan_nil(t *testing.T) { 473 m := testModule(t, "plan-nil") 474 p := testProvider("aws") 475 p.DiffFn = testDiffFn 476 ctx := testContext2(t, &ContextOpts{ 477 Module: m, 478 Providers: map[string]ResourceProviderFactory{ 479 "aws": testProviderFuncFixed(p), 480 }, 481 State: &State{ 482 Modules: []*ModuleState{ 483 &ModuleState{ 484 Path: rootModulePath, 485 Resources: map[string]*ResourceState{ 486 "aws_instance.foo": &ResourceState{ 487 Type: "aws_instance", 488 Primary: &InstanceState{ 489 ID: "bar", 490 }, 491 }, 492 }, 493 }, 494 }, 495 }, 496 }) 497 498 plan, err := ctx.Plan() 499 if err != nil { 500 t.Fatalf("err: %s", err) 501 } 502 if len(plan.Diff.RootModule().Resources) != 0 { 503 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 504 } 505 } 506 507 func TestContext2Plan_preventDestroy_bad(t *testing.T) { 508 m := testModule(t, "plan-prevent-destroy-bad") 509 p := testProvider("aws") 510 p.DiffFn = testDiffFn 511 ctx := testContext2(t, &ContextOpts{ 512 Module: m, 513 Providers: map[string]ResourceProviderFactory{ 514 "aws": testProviderFuncFixed(p), 515 }, 516 State: &State{ 517 Modules: []*ModuleState{ 518 &ModuleState{ 519 Path: rootModulePath, 520 Resources: map[string]*ResourceState{ 521 "aws_instance.foo": &ResourceState{ 522 Type: "aws_instance", 523 Primary: &InstanceState{ 524 ID: "i-abc123", 525 }, 526 }, 527 }, 528 }, 529 }, 530 }, 531 }) 532 533 plan, err := ctx.Plan() 534 535 expectedErr := "aws_instance.foo: plan would destroy" 536 if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) { 537 t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s", 538 expectedErr, err, plan) 539 } 540 } 541 542 func TestContext2Plan_preventDestroy_good(t *testing.T) { 543 m := testModule(t, "plan-prevent-destroy-good") 544 p := testProvider("aws") 545 p.DiffFn = testDiffFn 546 ctx := testContext2(t, &ContextOpts{ 547 Module: m, 548 Providers: map[string]ResourceProviderFactory{ 549 "aws": testProviderFuncFixed(p), 550 }, 551 State: &State{ 552 Modules: []*ModuleState{ 553 &ModuleState{ 554 Path: rootModulePath, 555 Resources: map[string]*ResourceState{ 556 "aws_instance.foo": &ResourceState{ 557 Type: "aws_instance", 558 Primary: &InstanceState{ 559 ID: "i-abc123", 560 }, 561 }, 562 }, 563 }, 564 }, 565 }, 566 }) 567 568 plan, err := ctx.Plan() 569 if err != nil { 570 t.Fatalf("err: %s", err) 571 } 572 if !plan.Diff.Empty() { 573 t.Fatalf("Expected empty plan, got %s", plan.String()) 574 } 575 } 576 577 func TestContext2Plan_preventDestroy_destroyPlan(t *testing.T) { 578 m := testModule(t, "plan-prevent-destroy-good") 579 p := testProvider("aws") 580 p.DiffFn = testDiffFn 581 ctx := testContext2(t, &ContextOpts{ 582 Module: m, 583 Providers: map[string]ResourceProviderFactory{ 584 "aws": testProviderFuncFixed(p), 585 }, 586 State: &State{ 587 Modules: []*ModuleState{ 588 &ModuleState{ 589 Path: rootModulePath, 590 Resources: map[string]*ResourceState{ 591 "aws_instance.foo": &ResourceState{ 592 Type: "aws_instance", 593 Primary: &InstanceState{ 594 ID: "i-abc123", 595 }, 596 }, 597 }, 598 }, 599 }, 600 }, 601 Destroy: true, 602 }) 603 604 plan, err := ctx.Plan() 605 606 expectedErr := "aws_instance.foo: plan would destroy" 607 if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) { 608 t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s", 609 expectedErr, err, plan) 610 } 611 } 612 613 func TestContext2Plan_providerAliasMissing(t *testing.T) { 614 m := testModule(t, "apply-provider-alias-missing") 615 p := testProvider("aws") 616 p.ApplyFn = testApplyFn 617 p.DiffFn = testDiffFn 618 state := &State{ 619 Modules: []*ModuleState{ 620 &ModuleState{ 621 Path: rootModulePath, 622 Resources: map[string]*ResourceState{ 623 "aws_instance.foo": &ResourceState{ 624 Type: "aws_instance", 625 Provider: "aws.foo", 626 Primary: &InstanceState{ 627 ID: "bar", 628 Attributes: map[string]string{ 629 "require_new": "abc", 630 }, 631 }, 632 }, 633 }, 634 }, 635 }, 636 } 637 ctx := testContext2(t, &ContextOpts{ 638 Module: m, 639 Providers: map[string]ResourceProviderFactory{ 640 "aws": testProviderFuncFixed(p), 641 }, 642 State: state, 643 }) 644 645 if _, err := ctx.Plan(); err == nil { 646 t.Fatal("should err") 647 } 648 } 649 650 func TestContext2Plan_computed(t *testing.T) { 651 m := testModule(t, "plan-computed") 652 p := testProvider("aws") 653 p.DiffFn = testDiffFn 654 ctx := testContext2(t, &ContextOpts{ 655 Module: m, 656 Providers: map[string]ResourceProviderFactory{ 657 "aws": testProviderFuncFixed(p), 658 }, 659 }) 660 661 plan, err := ctx.Plan() 662 if err != nil { 663 t.Fatalf("err: %s", err) 664 } 665 666 actual := strings.TrimSpace(plan.String()) 667 expected := strings.TrimSpace(testTerraformPlanComputedStr) 668 if actual != expected { 669 t.Fatalf("bad:\n%s", actual) 670 } 671 } 672 673 func TestContext2Plan_computedList(t *testing.T) { 674 m := testModule(t, "plan-computed-list") 675 p := testProvider("aws") 676 p.DiffFn = testDiffFn 677 ctx := testContext2(t, &ContextOpts{ 678 Module: m, 679 Providers: map[string]ResourceProviderFactory{ 680 "aws": testProviderFuncFixed(p), 681 }, 682 }) 683 684 plan, err := ctx.Plan() 685 if err != nil { 686 t.Fatalf("err: %s", err) 687 } 688 689 actual := strings.TrimSpace(plan.String()) 690 expected := strings.TrimSpace(testTerraformPlanComputedListStr) 691 if actual != expected { 692 t.Fatalf("bad:\n%s", actual) 693 } 694 } 695 696 func TestContext2Plan_count(t *testing.T) { 697 m := testModule(t, "plan-count") 698 p := testProvider("aws") 699 p.DiffFn = testDiffFn 700 ctx := testContext2(t, &ContextOpts{ 701 Module: m, 702 Providers: map[string]ResourceProviderFactory{ 703 "aws": testProviderFuncFixed(p), 704 }, 705 }) 706 707 plan, err := ctx.Plan() 708 if err != nil { 709 t.Fatalf("err: %s", err) 710 } 711 712 if len(plan.Diff.RootModule().Resources) < 6 { 713 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 714 } 715 716 actual := strings.TrimSpace(plan.String()) 717 expected := strings.TrimSpace(testTerraformPlanCountStr) 718 if actual != expected { 719 t.Fatalf("bad:\n%s", actual) 720 } 721 } 722 723 func TestContext2Plan_countComputed(t *testing.T) { 724 m := testModule(t, "plan-count-computed") 725 p := testProvider("aws") 726 p.DiffFn = testDiffFn 727 ctx := testContext2(t, &ContextOpts{ 728 Module: m, 729 Providers: map[string]ResourceProviderFactory{ 730 "aws": testProviderFuncFixed(p), 731 }, 732 }) 733 734 _, err := ctx.Plan() 735 if err == nil { 736 t.Fatal("should error") 737 } 738 } 739 740 func TestContext2Plan_countIndex(t *testing.T) { 741 m := testModule(t, "plan-count-index") 742 p := testProvider("aws") 743 p.DiffFn = testDiffFn 744 ctx := testContext2(t, &ContextOpts{ 745 Module: m, 746 Providers: map[string]ResourceProviderFactory{ 747 "aws": testProviderFuncFixed(p), 748 }, 749 }) 750 751 plan, err := ctx.Plan() 752 if err != nil { 753 t.Fatalf("err: %s", err) 754 } 755 756 actual := strings.TrimSpace(plan.String()) 757 expected := strings.TrimSpace(testTerraformPlanCountIndexStr) 758 if actual != expected { 759 t.Fatalf("bad:\n%s", actual) 760 } 761 } 762 763 func TestContext2Plan_countIndexZero(t *testing.T) { 764 m := testModule(t, "plan-count-index-zero") 765 p := testProvider("aws") 766 p.DiffFn = testDiffFn 767 ctx := testContext2(t, &ContextOpts{ 768 Module: m, 769 Providers: map[string]ResourceProviderFactory{ 770 "aws": testProviderFuncFixed(p), 771 }, 772 }) 773 774 plan, err := ctx.Plan() 775 if err != nil { 776 t.Fatalf("err: %s", err) 777 } 778 779 actual := strings.TrimSpace(plan.String()) 780 expected := strings.TrimSpace(testTerraformPlanCountIndexZeroStr) 781 if actual != expected { 782 t.Fatalf("bad:\n%s", actual) 783 } 784 } 785 786 func TestContext2Plan_countVar(t *testing.T) { 787 m := testModule(t, "plan-count-var") 788 p := testProvider("aws") 789 p.DiffFn = testDiffFn 790 ctx := testContext2(t, &ContextOpts{ 791 Module: m, 792 Providers: map[string]ResourceProviderFactory{ 793 "aws": testProviderFuncFixed(p), 794 }, 795 Variables: map[string]string{ 796 "count": "3", 797 }, 798 }) 799 800 plan, err := ctx.Plan() 801 if err != nil { 802 t.Fatalf("err: %s", err) 803 } 804 805 actual := strings.TrimSpace(plan.String()) 806 expected := strings.TrimSpace(testTerraformPlanCountVarStr) 807 if actual != expected { 808 t.Fatalf("bad:\n%s", actual) 809 } 810 } 811 812 func TestContext2Plan_countZero(t *testing.T) { 813 m := testModule(t, "plan-count-zero") 814 p := testProvider("aws") 815 p.DiffFn = testDiffFn 816 ctx := testContext2(t, &ContextOpts{ 817 Module: m, 818 Providers: map[string]ResourceProviderFactory{ 819 "aws": testProviderFuncFixed(p), 820 }, 821 }) 822 823 plan, err := ctx.Plan() 824 if err != nil { 825 t.Fatalf("err: %s", err) 826 } 827 828 actual := strings.TrimSpace(plan.String()) 829 expected := strings.TrimSpace(testTerraformPlanCountZeroStr) 830 if actual != expected { 831 t.Fatalf("bad:\n%s", actual) 832 } 833 } 834 835 func TestContext2Plan_countOneIndex(t *testing.T) { 836 m := testModule(t, "plan-count-one-index") 837 p := testProvider("aws") 838 p.DiffFn = testDiffFn 839 ctx := testContext2(t, &ContextOpts{ 840 Module: m, 841 Providers: map[string]ResourceProviderFactory{ 842 "aws": testProviderFuncFixed(p), 843 }, 844 }) 845 846 plan, err := ctx.Plan() 847 if err != nil { 848 t.Fatalf("err: %s", err) 849 } 850 851 actual := strings.TrimSpace(plan.String()) 852 expected := strings.TrimSpace(testTerraformPlanCountOneIndexStr) 853 if actual != expected { 854 t.Fatalf("bad:\n%s", actual) 855 } 856 } 857 858 func TestContext2Plan_countDecreaseToOne(t *testing.T) { 859 m := testModule(t, "plan-count-dec") 860 p := testProvider("aws") 861 p.DiffFn = testDiffFn 862 s := &State{ 863 Modules: []*ModuleState{ 864 &ModuleState{ 865 Path: rootModulePath, 866 Resources: map[string]*ResourceState{ 867 "aws_instance.foo.0": &ResourceState{ 868 Type: "aws_instance", 869 Primary: &InstanceState{ 870 ID: "bar", 871 Attributes: map[string]string{ 872 "foo": "foo", 873 "type": "aws_instance", 874 }, 875 }, 876 }, 877 "aws_instance.foo.1": &ResourceState{ 878 Type: "aws_instance", 879 Primary: &InstanceState{ 880 ID: "bar", 881 }, 882 }, 883 "aws_instance.foo.2": &ResourceState{ 884 Type: "aws_instance", 885 Primary: &InstanceState{ 886 ID: "bar", 887 }, 888 }, 889 }, 890 }, 891 }, 892 } 893 ctx := testContext2(t, &ContextOpts{ 894 Module: m, 895 Providers: map[string]ResourceProviderFactory{ 896 "aws": testProviderFuncFixed(p), 897 }, 898 State: s, 899 }) 900 901 plan, err := ctx.Plan() 902 if err != nil { 903 t.Fatalf("err: %s", err) 904 } 905 906 actual := strings.TrimSpace(plan.String()) 907 expected := strings.TrimSpace(testTerraformPlanCountDecreaseStr) 908 if actual != expected { 909 t.Fatalf("bad:\n%s", actual) 910 } 911 } 912 913 func TestContext2Plan_countIncreaseFromNotSet(t *testing.T) { 914 m := testModule(t, "plan-count-inc") 915 p := testProvider("aws") 916 p.DiffFn = testDiffFn 917 s := &State{ 918 Modules: []*ModuleState{ 919 &ModuleState{ 920 Path: rootModulePath, 921 Resources: map[string]*ResourceState{ 922 "aws_instance.foo": &ResourceState{ 923 Type: "aws_instance", 924 Primary: &InstanceState{ 925 ID: "bar", 926 Attributes: map[string]string{ 927 "foo": "foo", 928 "type": "aws_instance", 929 }, 930 }, 931 }, 932 }, 933 }, 934 }, 935 } 936 ctx := testContext2(t, &ContextOpts{ 937 Module: m, 938 Providers: map[string]ResourceProviderFactory{ 939 "aws": testProviderFuncFixed(p), 940 }, 941 State: s, 942 }) 943 944 plan, err := ctx.Plan() 945 if err != nil { 946 t.Fatalf("err: %s", err) 947 } 948 949 actual := strings.TrimSpace(plan.String()) 950 expected := strings.TrimSpace(testTerraformPlanCountIncreaseStr) 951 if actual != expected { 952 t.Fatalf("bad:\n%s", actual) 953 } 954 } 955 956 func TestContext2Plan_countIncreaseFromOne(t *testing.T) { 957 m := testModule(t, "plan-count-inc") 958 p := testProvider("aws") 959 p.DiffFn = testDiffFn 960 s := &State{ 961 Modules: []*ModuleState{ 962 &ModuleState{ 963 Path: rootModulePath, 964 Resources: map[string]*ResourceState{ 965 "aws_instance.foo.0": &ResourceState{ 966 Type: "aws_instance", 967 Primary: &InstanceState{ 968 ID: "bar", 969 Attributes: map[string]string{ 970 "foo": "foo", 971 "type": "aws_instance", 972 }, 973 }, 974 }, 975 }, 976 }, 977 }, 978 } 979 ctx := testContext2(t, &ContextOpts{ 980 Module: m, 981 Providers: map[string]ResourceProviderFactory{ 982 "aws": testProviderFuncFixed(p), 983 }, 984 State: s, 985 }) 986 987 plan, err := ctx.Plan() 988 if err != nil { 989 t.Fatalf("err: %s", err) 990 } 991 992 actual := strings.TrimSpace(plan.String()) 993 expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneStr) 994 if actual != expected { 995 t.Fatalf("bad:\n%s", actual) 996 } 997 } 998 999 // https://github.com/PeoplePerHour/terraform/pull/11 1000 // 1001 // This tests a case where both a "resource" and "resource.0" are in 1002 // the state file, which apparently is a reasonable backwards compatibility 1003 // concern found in the above 3rd party repo. 1004 func TestContext2Plan_countIncreaseFromOneCorrupted(t *testing.T) { 1005 m := testModule(t, "plan-count-inc") 1006 p := testProvider("aws") 1007 p.DiffFn = testDiffFn 1008 s := &State{ 1009 Modules: []*ModuleState{ 1010 &ModuleState{ 1011 Path: rootModulePath, 1012 Resources: map[string]*ResourceState{ 1013 "aws_instance.foo": &ResourceState{ 1014 Type: "aws_instance", 1015 Primary: &InstanceState{ 1016 ID: "bar", 1017 Attributes: map[string]string{ 1018 "foo": "foo", 1019 "type": "aws_instance", 1020 }, 1021 }, 1022 }, 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(testTerraformPlanCountIncreaseFromOneCorruptedStr) 1052 if actual != expected { 1053 t.Fatalf("bad:\n%s", actual) 1054 } 1055 } 1056 1057 func TestContext2Plan_destroy(t *testing.T) { 1058 m := testModule(t, "plan-destroy") 1059 p := testProvider("aws") 1060 p.DiffFn = testDiffFn 1061 s := &State{ 1062 Modules: []*ModuleState{ 1063 &ModuleState{ 1064 Path: rootModulePath, 1065 Resources: map[string]*ResourceState{ 1066 "aws_instance.one": &ResourceState{ 1067 Type: "aws_instance", 1068 Primary: &InstanceState{ 1069 ID: "bar", 1070 }, 1071 }, 1072 "aws_instance.two": &ResourceState{ 1073 Type: "aws_instance", 1074 Primary: &InstanceState{ 1075 ID: "baz", 1076 }, 1077 }, 1078 }, 1079 }, 1080 }, 1081 } 1082 ctx := testContext2(t, &ContextOpts{ 1083 Module: m, 1084 Providers: map[string]ResourceProviderFactory{ 1085 "aws": testProviderFuncFixed(p), 1086 }, 1087 State: s, 1088 Destroy: true, 1089 }) 1090 1091 plan, err := ctx.Plan() 1092 if err != nil { 1093 t.Fatalf("err: %s", err) 1094 } 1095 1096 if len(plan.Diff.RootModule().Resources) != 2 { 1097 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 1098 } 1099 1100 actual := strings.TrimSpace(plan.String()) 1101 expected := strings.TrimSpace(testTerraformPlanDestroyStr) 1102 if actual != expected { 1103 t.Fatalf("bad:\n%s", actual) 1104 } 1105 } 1106 1107 func TestContext2Plan_moduleDestroy(t *testing.T) { 1108 m := testModule(t, "plan-module-destroy") 1109 p := testProvider("aws") 1110 p.DiffFn = testDiffFn 1111 s := &State{ 1112 Modules: []*ModuleState{ 1113 &ModuleState{ 1114 Path: rootModulePath, 1115 Resources: map[string]*ResourceState{ 1116 "aws_instance.foo": &ResourceState{ 1117 Type: "aws_instance", 1118 Primary: &InstanceState{ 1119 ID: "bar", 1120 }, 1121 }, 1122 }, 1123 }, 1124 &ModuleState{ 1125 Path: []string{"root", "child"}, 1126 Resources: map[string]*ResourceState{ 1127 "aws_instance.foo": &ResourceState{ 1128 Type: "aws_instance", 1129 Primary: &InstanceState{ 1130 ID: "bar", 1131 }, 1132 }, 1133 }, 1134 }, 1135 }, 1136 } 1137 ctx := testContext2(t, &ContextOpts{ 1138 Module: m, 1139 Providers: map[string]ResourceProviderFactory{ 1140 "aws": testProviderFuncFixed(p), 1141 }, 1142 State: s, 1143 Destroy: true, 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(testTerraformPlanModuleDestroyStr) 1153 if actual != expected { 1154 t.Fatalf("bad:\n%s", actual) 1155 } 1156 } 1157 1158 func TestContext2Plan_moduleDestroyMultivar(t *testing.T) { 1159 m := testModule(t, "plan-module-destroy-multivar") 1160 p := testProvider("aws") 1161 p.DiffFn = testDiffFn 1162 s := &State{ 1163 Modules: []*ModuleState{ 1164 &ModuleState{ 1165 Path: rootModulePath, 1166 Resources: map[string]*ResourceState{}, 1167 }, 1168 &ModuleState{ 1169 Path: []string{"root", "child"}, 1170 Resources: map[string]*ResourceState{ 1171 "aws_instance.foo.0": &ResourceState{ 1172 Type: "aws_instance", 1173 Primary: &InstanceState{ 1174 ID: "bar0", 1175 }, 1176 }, 1177 "aws_instance.foo.1": &ResourceState{ 1178 Type: "aws_instance", 1179 Primary: &InstanceState{ 1180 ID: "bar1", 1181 }, 1182 }, 1183 }, 1184 }, 1185 }, 1186 } 1187 ctx := testContext2(t, &ContextOpts{ 1188 Module: m, 1189 Providers: map[string]ResourceProviderFactory{ 1190 "aws": testProviderFuncFixed(p), 1191 }, 1192 State: s, 1193 Destroy: true, 1194 }) 1195 1196 plan, err := ctx.Plan() 1197 if err != nil { 1198 t.Fatalf("err: %s", err) 1199 } 1200 1201 actual := strings.TrimSpace(plan.String()) 1202 expected := strings.TrimSpace(testTerraformPlanModuleDestroyMultivarStr) 1203 if actual != expected { 1204 t.Fatalf("bad:\n%s", actual) 1205 } 1206 } 1207 1208 func TestContext2Plan_pathVar(t *testing.T) { 1209 cwd, err := os.Getwd() 1210 if err != nil { 1211 t.Fatalf("err: %s", err) 1212 } 1213 1214 m := testModule(t, "plan-path-var") 1215 p := testProvider("aws") 1216 p.DiffFn = testDiffFn 1217 ctx := testContext2(t, &ContextOpts{ 1218 Module: m, 1219 Providers: map[string]ResourceProviderFactory{ 1220 "aws": testProviderFuncFixed(p), 1221 }, 1222 }) 1223 1224 plan, err := ctx.Plan() 1225 if err != nil { 1226 t.Fatalf("err: %s", err) 1227 } 1228 1229 actual := strings.TrimSpace(plan.String()) 1230 expected := strings.TrimSpace(testTerraformPlanPathVarStr) 1231 1232 // Warning: this ordering REALLY matters for this test. The 1233 // order is: cwd, module, root. 1234 expected = fmt.Sprintf( 1235 expected, 1236 cwd, 1237 m.Config().Dir, 1238 m.Config().Dir) 1239 1240 if actual != expected { 1241 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 1242 } 1243 } 1244 1245 func TestContext2Plan_diffVar(t *testing.T) { 1246 m := testModule(t, "plan-diffvar") 1247 p := testProvider("aws") 1248 s := &State{ 1249 Modules: []*ModuleState{ 1250 &ModuleState{ 1251 Path: rootModulePath, 1252 Resources: map[string]*ResourceState{ 1253 "aws_instance.foo": &ResourceState{ 1254 Primary: &InstanceState{ 1255 ID: "bar", 1256 Attributes: map[string]string{ 1257 "num": "2", 1258 }, 1259 }, 1260 }, 1261 }, 1262 }, 1263 }, 1264 } 1265 ctx := testContext2(t, &ContextOpts{ 1266 Module: m, 1267 Providers: map[string]ResourceProviderFactory{ 1268 "aws": testProviderFuncFixed(p), 1269 }, 1270 State: s, 1271 }) 1272 1273 p.DiffFn = func( 1274 info *InstanceInfo, 1275 s *InstanceState, 1276 c *ResourceConfig) (*InstanceDiff, error) { 1277 if s.ID != "bar" { 1278 return testDiffFn(info, s, c) 1279 } 1280 1281 return &InstanceDiff{ 1282 Attributes: map[string]*ResourceAttrDiff{ 1283 "num": &ResourceAttrDiff{ 1284 Old: "2", 1285 New: "3", 1286 }, 1287 }, 1288 }, nil 1289 } 1290 1291 plan, err := ctx.Plan() 1292 if err != nil { 1293 t.Fatalf("err: %s", err) 1294 } 1295 1296 actual := strings.TrimSpace(plan.String()) 1297 expected := strings.TrimSpace(testTerraformPlanDiffVarStr) 1298 if actual != expected { 1299 t.Fatalf("actual:\n%s\n\nexpected:\n%s", actual, expected) 1300 } 1301 } 1302 1303 func TestContext2Plan_hook(t *testing.T) { 1304 m := testModule(t, "plan-good") 1305 h := new(MockHook) 1306 p := testProvider("aws") 1307 p.DiffFn = testDiffFn 1308 ctx := testContext2(t, &ContextOpts{ 1309 Module: m, 1310 Hooks: []Hook{h}, 1311 Providers: map[string]ResourceProviderFactory{ 1312 "aws": testProviderFuncFixed(p), 1313 }, 1314 }) 1315 1316 _, err := ctx.Plan() 1317 if err != nil { 1318 t.Fatalf("err: %s", err) 1319 } 1320 1321 if !h.PreDiffCalled { 1322 t.Fatal("should be called") 1323 } 1324 if !h.PostDiffCalled { 1325 t.Fatal("should be called") 1326 } 1327 } 1328 1329 func TestContext2Plan_orphan(t *testing.T) { 1330 m := testModule(t, "plan-orphan") 1331 p := testProvider("aws") 1332 p.DiffFn = testDiffFn 1333 s := &State{ 1334 Modules: []*ModuleState{ 1335 &ModuleState{ 1336 Path: rootModulePath, 1337 Resources: map[string]*ResourceState{ 1338 "aws_instance.baz": &ResourceState{ 1339 Type: "aws_instance", 1340 Primary: &InstanceState{ 1341 ID: "bar", 1342 }, 1343 }, 1344 }, 1345 }, 1346 }, 1347 } 1348 ctx := testContext2(t, &ContextOpts{ 1349 Module: m, 1350 Providers: map[string]ResourceProviderFactory{ 1351 "aws": testProviderFuncFixed(p), 1352 }, 1353 State: s, 1354 }) 1355 1356 plan, err := ctx.Plan() 1357 if err != nil { 1358 t.Fatalf("err: %s", err) 1359 } 1360 1361 actual := strings.TrimSpace(plan.String()) 1362 expected := strings.TrimSpace(testTerraformPlanOrphanStr) 1363 if actual != expected { 1364 t.Fatalf("bad:\n%s", actual) 1365 } 1366 } 1367 1368 func TestContext2Plan_state(t *testing.T) { 1369 m := testModule(t, "plan-good") 1370 p := testProvider("aws") 1371 p.DiffFn = testDiffFn 1372 s := &State{ 1373 Modules: []*ModuleState{ 1374 &ModuleState{ 1375 Path: rootModulePath, 1376 Resources: map[string]*ResourceState{ 1377 "aws_instance.foo": &ResourceState{ 1378 Primary: &InstanceState{ 1379 ID: "bar", 1380 }, 1381 }, 1382 }, 1383 }, 1384 }, 1385 } 1386 ctx := testContext2(t, &ContextOpts{ 1387 Module: m, 1388 Providers: map[string]ResourceProviderFactory{ 1389 "aws": testProviderFuncFixed(p), 1390 }, 1391 State: s, 1392 }) 1393 1394 plan, err := ctx.Plan() 1395 if err != nil { 1396 t.Fatalf("err: %s", err) 1397 } 1398 1399 if len(plan.Diff.RootModule().Resources) < 2 { 1400 t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources) 1401 } 1402 1403 actual := strings.TrimSpace(plan.String()) 1404 expected := strings.TrimSpace(testTerraformPlanStateStr) 1405 if actual != expected { 1406 t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) 1407 } 1408 } 1409 1410 func TestContext2Plan_taint(t *testing.T) { 1411 m := testModule(t, "plan-taint") 1412 p := testProvider("aws") 1413 p.DiffFn = testDiffFn 1414 s := &State{ 1415 Modules: []*ModuleState{ 1416 &ModuleState{ 1417 Path: rootModulePath, 1418 Resources: map[string]*ResourceState{ 1419 "aws_instance.foo": &ResourceState{ 1420 Type: "aws_instance", 1421 Primary: &InstanceState{ 1422 ID: "bar", 1423 Attributes: map[string]string{"num": "2"}, 1424 }, 1425 }, 1426 "aws_instance.bar": &ResourceState{ 1427 Type: "aws_instance", 1428 Tainted: []*InstanceState{ 1429 &InstanceState{ 1430 ID: "baz", 1431 }, 1432 }, 1433 }, 1434 }, 1435 }, 1436 }, 1437 } 1438 ctx := testContext2(t, &ContextOpts{ 1439 Module: m, 1440 Providers: map[string]ResourceProviderFactory{ 1441 "aws": testProviderFuncFixed(p), 1442 }, 1443 State: s, 1444 }) 1445 1446 plan, err := ctx.Plan() 1447 if err != nil { 1448 t.Fatalf("err: %s", err) 1449 } 1450 1451 actual := strings.TrimSpace(plan.String()) 1452 expected := strings.TrimSpace(testTerraformPlanTaintStr) 1453 if actual != expected { 1454 t.Fatalf("bad:\n%s", actual) 1455 } 1456 } 1457 1458 func TestContext2Plan_multiple_taint(t *testing.T) { 1459 m := testModule(t, "plan-taint") 1460 p := testProvider("aws") 1461 p.DiffFn = testDiffFn 1462 s := &State{ 1463 Modules: []*ModuleState{ 1464 &ModuleState{ 1465 Path: rootModulePath, 1466 Resources: map[string]*ResourceState{ 1467 "aws_instance.foo": &ResourceState{ 1468 Type: "aws_instance", 1469 Primary: &InstanceState{ 1470 ID: "bar", 1471 Attributes: map[string]string{"num": "2"}, 1472 }, 1473 }, 1474 "aws_instance.bar": &ResourceState{ 1475 Type: "aws_instance", 1476 Tainted: []*InstanceState{ 1477 &InstanceState{ 1478 ID: "baz", 1479 }, 1480 &InstanceState{ 1481 ID: "zip", 1482 }, 1483 }, 1484 }, 1485 }, 1486 }, 1487 }, 1488 } 1489 ctx := testContext2(t, &ContextOpts{ 1490 Module: m, 1491 Providers: map[string]ResourceProviderFactory{ 1492 "aws": testProviderFuncFixed(p), 1493 }, 1494 State: s, 1495 }) 1496 1497 plan, err := ctx.Plan() 1498 if err != nil { 1499 t.Fatalf("err: %s", err) 1500 } 1501 1502 actual := strings.TrimSpace(plan.String()) 1503 expected := strings.TrimSpace(testTerraformPlanMultipleTaintStr) 1504 if actual != expected { 1505 t.Fatalf("bad:\n%s", actual) 1506 } 1507 } 1508 1509 func TestContext2Plan_targeted(t *testing.T) { 1510 m := testModule(t, "plan-targeted") 1511 p := testProvider("aws") 1512 p.DiffFn = testDiffFn 1513 ctx := testContext2(t, &ContextOpts{ 1514 Module: m, 1515 Providers: map[string]ResourceProviderFactory{ 1516 "aws": testProviderFuncFixed(p), 1517 }, 1518 Targets: []string{"aws_instance.foo"}, 1519 }) 1520 1521 plan, err := ctx.Plan() 1522 if err != nil { 1523 t.Fatalf("err: %s", err) 1524 } 1525 1526 actual := strings.TrimSpace(plan.String()) 1527 expected := strings.TrimSpace(` 1528 DIFF: 1529 1530 CREATE: aws_instance.foo 1531 num: "" => "2" 1532 type: "" => "aws_instance" 1533 1534 STATE: 1535 1536 <no state> 1537 `) 1538 if actual != expected { 1539 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 1540 } 1541 } 1542 1543 func TestContext2Plan_provider(t *testing.T) { 1544 m := testModule(t, "plan-provider") 1545 p := testProvider("aws") 1546 p.DiffFn = testDiffFn 1547 1548 var value interface{} 1549 p.ConfigureFn = func(c *ResourceConfig) error { 1550 value, _ = c.Get("foo") 1551 return nil 1552 } 1553 1554 ctx := testContext2(t, &ContextOpts{ 1555 Module: m, 1556 Providers: map[string]ResourceProviderFactory{ 1557 "aws": testProviderFuncFixed(p), 1558 }, 1559 Variables: map[string]string{ 1560 "foo": "bar", 1561 }, 1562 }) 1563 1564 if _, err := ctx.Plan(); err != nil { 1565 t.Fatalf("err: %s", err) 1566 } 1567 1568 if value != "bar" { 1569 t.Fatalf("bad: %#v", value) 1570 } 1571 } 1572 1573 func TestContext2Plan_varMultiCountOne(t *testing.T) { 1574 m := testModule(t, "plan-var-multi-count-one") 1575 p := testProvider("aws") 1576 p.DiffFn = testDiffFn 1577 ctx := testContext2(t, &ContextOpts{ 1578 Module: m, 1579 Providers: map[string]ResourceProviderFactory{ 1580 "aws": testProviderFuncFixed(p), 1581 }, 1582 }) 1583 1584 plan, err := ctx.Plan() 1585 if err != nil { 1586 t.Fatalf("err: %s", err) 1587 } 1588 1589 actual := strings.TrimSpace(plan.String()) 1590 expected := strings.TrimSpace(testTerraformPlanVarMultiCountOneStr) 1591 if actual != expected { 1592 t.Fatalf("bad:\n%s", actual) 1593 } 1594 } 1595 1596 func TestContext2Plan_varListErr(t *testing.T) { 1597 m := testModule(t, "plan-var-list-err") 1598 p := testProvider("aws") 1599 ctx := testContext2(t, &ContextOpts{ 1600 Module: m, 1601 Providers: map[string]ResourceProviderFactory{ 1602 "aws": testProviderFuncFixed(p), 1603 }, 1604 }) 1605 1606 _, err := ctx.Plan() 1607 if err == nil { 1608 t.Fatal("should error") 1609 } 1610 } 1611 1612 func TestContext2Refresh(t *testing.T) { 1613 p := testProvider("aws") 1614 m := testModule(t, "refresh-basic") 1615 ctx := testContext2(t, &ContextOpts{ 1616 Module: m, 1617 Providers: map[string]ResourceProviderFactory{ 1618 "aws": testProviderFuncFixed(p), 1619 }, 1620 State: &State{ 1621 Modules: []*ModuleState{ 1622 &ModuleState{ 1623 Path: rootModulePath, 1624 Resources: map[string]*ResourceState{ 1625 "aws_instance.web": &ResourceState{ 1626 Type: "aws_instance", 1627 Primary: &InstanceState{ 1628 ID: "foo", 1629 }, 1630 }, 1631 }, 1632 }, 1633 }, 1634 }, 1635 }) 1636 1637 p.RefreshFn = nil 1638 p.RefreshReturn = &InstanceState{ 1639 ID: "foo", 1640 } 1641 1642 s, err := ctx.Refresh() 1643 mod := s.RootModule() 1644 if err != nil { 1645 t.Fatalf("err: %s", err) 1646 } 1647 if !p.RefreshCalled { 1648 t.Fatal("refresh should be called") 1649 } 1650 if p.RefreshState.ID != "foo" { 1651 t.Fatalf("bad: %#v", p.RefreshState) 1652 } 1653 if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) { 1654 t.Fatalf("bad: %#v %#v", mod.Resources["aws_instance.web"], p.RefreshReturn) 1655 } 1656 1657 for _, r := range mod.Resources { 1658 if r.Type == "" { 1659 t.Fatalf("no type: %#v", r) 1660 } 1661 } 1662 } 1663 1664 func TestContext2Refresh_targeted(t *testing.T) { 1665 p := testProvider("aws") 1666 m := testModule(t, "refresh-targeted") 1667 ctx := testContext2(t, &ContextOpts{ 1668 Module: m, 1669 Providers: map[string]ResourceProviderFactory{ 1670 "aws": testProviderFuncFixed(p), 1671 }, 1672 State: &State{ 1673 Modules: []*ModuleState{ 1674 &ModuleState{ 1675 Path: rootModulePath, 1676 Resources: map[string]*ResourceState{ 1677 "aws_vpc.metoo": resourceState("aws_vpc", "vpc-abc123"), 1678 "aws_instance.notme": resourceState("aws_instance", "i-bcd345"), 1679 "aws_instance.me": resourceState("aws_instance", "i-abc123"), 1680 "aws_elb.meneither": resourceState("aws_elb", "lb-abc123"), 1681 }, 1682 }, 1683 }, 1684 }, 1685 Targets: []string{"aws_instance.me"}, 1686 }) 1687 1688 refreshedResources := make([]string, 0, 2) 1689 p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) { 1690 refreshedResources = append(refreshedResources, i.Id) 1691 return is, nil 1692 } 1693 1694 _, err := ctx.Refresh() 1695 if err != nil { 1696 t.Fatalf("err: %s", err) 1697 } 1698 1699 expected := []string{"aws_vpc.metoo", "aws_instance.me"} 1700 if !reflect.DeepEqual(refreshedResources, expected) { 1701 t.Fatalf("expected: %#v, got: %#v", expected, refreshedResources) 1702 } 1703 } 1704 1705 func TestContext2Refresh_targetedCount(t *testing.T) { 1706 p := testProvider("aws") 1707 m := testModule(t, "refresh-targeted-count") 1708 ctx := testContext2(t, &ContextOpts{ 1709 Module: m, 1710 Providers: map[string]ResourceProviderFactory{ 1711 "aws": testProviderFuncFixed(p), 1712 }, 1713 State: &State{ 1714 Modules: []*ModuleState{ 1715 &ModuleState{ 1716 Path: rootModulePath, 1717 Resources: map[string]*ResourceState{ 1718 "aws_vpc.metoo": resourceState("aws_vpc", "vpc-abc123"), 1719 "aws_instance.notme": resourceState("aws_instance", "i-bcd345"), 1720 "aws_instance.me.0": resourceState("aws_instance", "i-abc123"), 1721 "aws_instance.me.1": resourceState("aws_instance", "i-cde567"), 1722 "aws_instance.me.2": resourceState("aws_instance", "i-cde789"), 1723 "aws_elb.meneither": resourceState("aws_elb", "lb-abc123"), 1724 }, 1725 }, 1726 }, 1727 }, 1728 Targets: []string{"aws_instance.me"}, 1729 }) 1730 1731 refreshedResources := make([]string, 0, 2) 1732 p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) { 1733 refreshedResources = append(refreshedResources, i.Id) 1734 return is, nil 1735 } 1736 1737 _, err := ctx.Refresh() 1738 if err != nil { 1739 t.Fatalf("err: %s", err) 1740 } 1741 1742 // Target didn't specify index, so we should get all our instances 1743 expected := []string{ 1744 "aws_vpc.metoo", 1745 "aws_instance.me.0", 1746 "aws_instance.me.1", 1747 "aws_instance.me.2", 1748 } 1749 sort.Strings(expected) 1750 sort.Strings(refreshedResources) 1751 if !reflect.DeepEqual(refreshedResources, expected) { 1752 t.Fatalf("expected: %#v, got: %#v", expected, refreshedResources) 1753 } 1754 } 1755 1756 func TestContext2Refresh_targetedCountIndex(t *testing.T) { 1757 p := testProvider("aws") 1758 m := testModule(t, "refresh-targeted-count") 1759 ctx := testContext2(t, &ContextOpts{ 1760 Module: m, 1761 Providers: map[string]ResourceProviderFactory{ 1762 "aws": testProviderFuncFixed(p), 1763 }, 1764 State: &State{ 1765 Modules: []*ModuleState{ 1766 &ModuleState{ 1767 Path: rootModulePath, 1768 Resources: map[string]*ResourceState{ 1769 "aws_vpc.metoo": resourceState("aws_vpc", "vpc-abc123"), 1770 "aws_instance.notme": resourceState("aws_instance", "i-bcd345"), 1771 "aws_instance.me.0": resourceState("aws_instance", "i-abc123"), 1772 "aws_instance.me.1": resourceState("aws_instance", "i-cde567"), 1773 "aws_instance.me.2": resourceState("aws_instance", "i-cde789"), 1774 "aws_elb.meneither": resourceState("aws_elb", "lb-abc123"), 1775 }, 1776 }, 1777 }, 1778 }, 1779 Targets: []string{"aws_instance.me[0]"}, 1780 }) 1781 1782 refreshedResources := make([]string, 0, 2) 1783 p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) { 1784 refreshedResources = append(refreshedResources, i.Id) 1785 return is, nil 1786 } 1787 1788 _, err := ctx.Refresh() 1789 if err != nil { 1790 t.Fatalf("err: %s", err) 1791 } 1792 1793 expected := []string{"aws_vpc.metoo", "aws_instance.me.0"} 1794 if !reflect.DeepEqual(refreshedResources, expected) { 1795 t.Fatalf("expected: %#v, got: %#v", expected, refreshedResources) 1796 } 1797 } 1798 1799 func TestContext2Refresh_delete(t *testing.T) { 1800 p := testProvider("aws") 1801 m := testModule(t, "refresh-basic") 1802 ctx := testContext2(t, &ContextOpts{ 1803 Module: m, 1804 Providers: map[string]ResourceProviderFactory{ 1805 "aws": testProviderFuncFixed(p), 1806 }, 1807 State: &State{ 1808 Modules: []*ModuleState{ 1809 &ModuleState{ 1810 Path: rootModulePath, 1811 Resources: map[string]*ResourceState{ 1812 "aws_instance.web": &ResourceState{ 1813 Type: "aws_instance", 1814 Primary: &InstanceState{ 1815 ID: "foo", 1816 }, 1817 }, 1818 }, 1819 }, 1820 }, 1821 }, 1822 }) 1823 1824 p.RefreshFn = nil 1825 p.RefreshReturn = nil 1826 1827 s, err := ctx.Refresh() 1828 if err != nil { 1829 t.Fatalf("err: %s", err) 1830 } 1831 1832 mod := s.RootModule() 1833 if len(mod.Resources) > 0 { 1834 t.Fatal("resources should be empty") 1835 } 1836 } 1837 1838 func TestContext2Refresh_ignoreUncreated(t *testing.T) { 1839 p := testProvider("aws") 1840 m := testModule(t, "refresh-basic") 1841 ctx := testContext2(t, &ContextOpts{ 1842 Module: m, 1843 Providers: map[string]ResourceProviderFactory{ 1844 "aws": testProviderFuncFixed(p), 1845 }, 1846 State: nil, 1847 }) 1848 1849 p.RefreshFn = nil 1850 p.RefreshReturn = &InstanceState{ 1851 ID: "foo", 1852 } 1853 1854 _, err := ctx.Refresh() 1855 if err != nil { 1856 t.Fatalf("err: %s", err) 1857 } 1858 if p.RefreshCalled { 1859 t.Fatal("refresh should not be called") 1860 } 1861 } 1862 1863 func TestContext2Refresh_hook(t *testing.T) { 1864 h := new(MockHook) 1865 p := testProvider("aws") 1866 m := testModule(t, "refresh-basic") 1867 ctx := testContext2(t, &ContextOpts{ 1868 Module: m, 1869 Hooks: []Hook{h}, 1870 Providers: map[string]ResourceProviderFactory{ 1871 "aws": testProviderFuncFixed(p), 1872 }, 1873 State: &State{ 1874 Modules: []*ModuleState{ 1875 &ModuleState{ 1876 Path: rootModulePath, 1877 Resources: map[string]*ResourceState{ 1878 "aws_instance.web": &ResourceState{ 1879 Type: "aws_instance", 1880 Primary: &InstanceState{ 1881 ID: "foo", 1882 }, 1883 }, 1884 }, 1885 }, 1886 }, 1887 }, 1888 }) 1889 1890 if _, err := ctx.Refresh(); err != nil { 1891 t.Fatalf("err: %s", err) 1892 } 1893 if !h.PreRefreshCalled { 1894 t.Fatal("should be called") 1895 } 1896 if !h.PostRefreshCalled { 1897 t.Fatal("should be called") 1898 } 1899 } 1900 1901 func TestContext2Refresh_modules(t *testing.T) { 1902 p := testProvider("aws") 1903 m := testModule(t, "refresh-modules") 1904 state := &State{ 1905 Modules: []*ModuleState{ 1906 &ModuleState{ 1907 Path: rootModulePath, 1908 Resources: map[string]*ResourceState{ 1909 "aws_instance.web": &ResourceState{ 1910 Type: "aws_instance", 1911 Tainted: []*InstanceState{ 1912 &InstanceState{ 1913 ID: "bar", 1914 }, 1915 }, 1916 }, 1917 }, 1918 }, 1919 1920 &ModuleState{ 1921 Path: []string{"root", "child"}, 1922 Resources: map[string]*ResourceState{ 1923 "aws_instance.web": &ResourceState{ 1924 Type: "aws_instance", 1925 Primary: &InstanceState{ 1926 ID: "baz", 1927 }, 1928 }, 1929 }, 1930 }, 1931 }, 1932 } 1933 ctx := testContext2(t, &ContextOpts{ 1934 Module: m, 1935 Providers: map[string]ResourceProviderFactory{ 1936 "aws": testProviderFuncFixed(p), 1937 }, 1938 State: state, 1939 }) 1940 1941 p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) { 1942 if s.ID != "baz" { 1943 return s, nil 1944 } 1945 1946 s.ID = "new" 1947 return s, nil 1948 } 1949 1950 s, err := ctx.Refresh() 1951 if err != nil { 1952 t.Fatalf("err: %s", err) 1953 } 1954 1955 actual := strings.TrimSpace(s.String()) 1956 expected := strings.TrimSpace(testContextRefreshModuleStr) 1957 if actual != expected { 1958 t.Fatalf("bad:\n\n%s\n\n%s", actual, expected) 1959 } 1960 } 1961 1962 func TestContext2Refresh_moduleInputComputedOutput(t *testing.T) { 1963 m := testModule(t, "refresh-module-input-computed-output") 1964 p := testProvider("aws") 1965 p.DiffFn = testDiffFn 1966 ctx := testContext2(t, &ContextOpts{ 1967 Module: m, 1968 Providers: map[string]ResourceProviderFactory{ 1969 "aws": testProviderFuncFixed(p), 1970 }, 1971 }) 1972 1973 if _, err := ctx.Refresh(); err != nil { 1974 t.Fatalf("err: %s", err) 1975 } 1976 } 1977 1978 func TestContext2Refresh_moduleVarModule(t *testing.T) { 1979 m := testModule(t, "refresh-module-var-module") 1980 p := testProvider("aws") 1981 p.DiffFn = testDiffFn 1982 ctx := testContext2(t, &ContextOpts{ 1983 Module: m, 1984 Providers: map[string]ResourceProviderFactory{ 1985 "aws": testProviderFuncFixed(p), 1986 }, 1987 }) 1988 1989 if _, err := ctx.Refresh(); err != nil { 1990 t.Fatalf("err: %s", err) 1991 } 1992 } 1993 1994 // GH-70 1995 func TestContext2Refresh_noState(t *testing.T) { 1996 p := testProvider("aws") 1997 m := testModule(t, "refresh-no-state") 1998 ctx := testContext2(t, &ContextOpts{ 1999 Module: m, 2000 Providers: map[string]ResourceProviderFactory{ 2001 "aws": testProviderFuncFixed(p), 2002 }, 2003 }) 2004 2005 p.RefreshFn = nil 2006 p.RefreshReturn = &InstanceState{ 2007 ID: "foo", 2008 } 2009 2010 if _, err := ctx.Refresh(); err != nil { 2011 t.Fatalf("err: %s", err) 2012 } 2013 } 2014 2015 func TestContext2Refresh_output(t *testing.T) { 2016 p := testProvider("aws") 2017 m := testModule(t, "refresh-output") 2018 ctx := testContext2(t, &ContextOpts{ 2019 Module: m, 2020 Providers: map[string]ResourceProviderFactory{ 2021 "aws": testProviderFuncFixed(p), 2022 }, 2023 State: &State{ 2024 Modules: []*ModuleState{ 2025 &ModuleState{ 2026 Path: rootModulePath, 2027 Resources: map[string]*ResourceState{ 2028 "aws_instance.web": &ResourceState{ 2029 Type: "aws_instance", 2030 Primary: &InstanceState{ 2031 ID: "foo", 2032 Attributes: map[string]string{ 2033 "foo": "bar", 2034 }, 2035 }, 2036 }, 2037 }, 2038 2039 Outputs: map[string]string{ 2040 "foo": "foo", 2041 }, 2042 }, 2043 }, 2044 }, 2045 }) 2046 2047 p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) { 2048 return s, nil 2049 } 2050 2051 s, err := ctx.Refresh() 2052 if err != nil { 2053 t.Fatalf("err: %s", err) 2054 } 2055 2056 actual := strings.TrimSpace(s.String()) 2057 expected := strings.TrimSpace(testContextRefreshOutputStr) 2058 if actual != expected { 2059 t.Fatalf("bad:\n\n%s\n\n%s", actual, expected) 2060 } 2061 } 2062 2063 func TestContext2Refresh_outputPartial(t *testing.T) { 2064 p := testProvider("aws") 2065 m := testModule(t, "refresh-output-partial") 2066 ctx := testContext2(t, &ContextOpts{ 2067 Module: m, 2068 Providers: map[string]ResourceProviderFactory{ 2069 "aws": testProviderFuncFixed(p), 2070 }, 2071 State: &State{ 2072 Modules: []*ModuleState{ 2073 &ModuleState{ 2074 Path: rootModulePath, 2075 Resources: map[string]*ResourceState{ 2076 "aws_instance.foo": &ResourceState{ 2077 Type: "aws_instance", 2078 Primary: &InstanceState{ 2079 ID: "foo", 2080 }, 2081 }, 2082 }, 2083 }, 2084 }, 2085 }, 2086 }) 2087 2088 p.RefreshFn = nil 2089 p.RefreshReturn = nil 2090 2091 s, err := ctx.Refresh() 2092 if err != nil { 2093 t.Fatalf("err: %s", err) 2094 } 2095 2096 actual := strings.TrimSpace(s.String()) 2097 expected := strings.TrimSpace(testContextRefreshOutputPartialStr) 2098 if actual != expected { 2099 t.Fatalf("bad:\n\n%s\n\n%s", actual, expected) 2100 } 2101 } 2102 2103 func TestContext2Refresh_state(t *testing.T) { 2104 p := testProvider("aws") 2105 m := testModule(t, "refresh-basic") 2106 state := &State{ 2107 Modules: []*ModuleState{ 2108 &ModuleState{ 2109 Path: rootModulePath, 2110 Resources: map[string]*ResourceState{ 2111 "aws_instance.web": &ResourceState{ 2112 Primary: &InstanceState{ 2113 ID: "bar", 2114 }, 2115 }, 2116 }, 2117 }, 2118 }, 2119 } 2120 ctx := testContext2(t, &ContextOpts{ 2121 Module: m, 2122 Providers: map[string]ResourceProviderFactory{ 2123 "aws": testProviderFuncFixed(p), 2124 }, 2125 State: state, 2126 }) 2127 2128 p.RefreshFn = nil 2129 p.RefreshReturn = &InstanceState{ 2130 ID: "foo", 2131 } 2132 2133 s, err := ctx.Refresh() 2134 if err != nil { 2135 t.Fatalf("err: %s", err) 2136 } 2137 originalMod := state.RootModule() 2138 mod := s.RootModule() 2139 if !p.RefreshCalled { 2140 t.Fatal("refresh should be called") 2141 } 2142 if !reflect.DeepEqual(p.RefreshState, originalMod.Resources["aws_instance.web"].Primary) { 2143 t.Fatalf( 2144 "bad:\n\n%#v\n\n%#v", 2145 p.RefreshState, 2146 originalMod.Resources["aws_instance.web"].Primary) 2147 } 2148 if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) { 2149 t.Fatalf("bad: %#v", mod.Resources) 2150 } 2151 } 2152 2153 func TestContext2Refresh_tainted(t *testing.T) { 2154 p := testProvider("aws") 2155 m := testModule(t, "refresh-basic") 2156 state := &State{ 2157 Modules: []*ModuleState{ 2158 &ModuleState{ 2159 Path: rootModulePath, 2160 Resources: map[string]*ResourceState{ 2161 "aws_instance.web": &ResourceState{ 2162 Type: "aws_instance", 2163 Tainted: []*InstanceState{ 2164 &InstanceState{ 2165 ID: "bar", 2166 }, 2167 }, 2168 }, 2169 }, 2170 }, 2171 }, 2172 } 2173 ctx := testContext2(t, &ContextOpts{ 2174 Module: m, 2175 Providers: map[string]ResourceProviderFactory{ 2176 "aws": testProviderFuncFixed(p), 2177 }, 2178 State: state, 2179 }) 2180 2181 p.RefreshFn = nil 2182 p.RefreshReturn = &InstanceState{ 2183 ID: "foo", 2184 } 2185 2186 s, err := ctx.Refresh() 2187 if err != nil { 2188 t.Fatalf("err: %s", err) 2189 } 2190 if !p.RefreshCalled { 2191 t.Fatal("refresh should be called") 2192 } 2193 2194 actual := strings.TrimSpace(s.String()) 2195 expected := strings.TrimSpace(testContextRefreshTaintedStr) 2196 if actual != expected { 2197 t.Fatalf("bad:\n\n%s\n\n%s", actual, expected) 2198 } 2199 } 2200 2201 // Doing a Refresh (or any operation really, but Refresh usually 2202 // happens first) with a config with an unknown provider should result in 2203 // an error. The key bug this found was that this wasn't happening if 2204 // Providers was _empty_. 2205 func TestContext2Refresh_unknownProvider(t *testing.T) { 2206 m := testModule(t, "refresh-unknown-provider") 2207 p := testProvider("aws") 2208 p.ApplyFn = testApplyFn 2209 p.DiffFn = testDiffFn 2210 ctx := testContext2(t, &ContextOpts{ 2211 Module: m, 2212 Providers: map[string]ResourceProviderFactory{}, 2213 }) 2214 2215 if _, err := ctx.Refresh(); err == nil { 2216 t.Fatal("should error") 2217 } 2218 } 2219 2220 func TestContext2Refresh_vars(t *testing.T) { 2221 p := testProvider("aws") 2222 m := testModule(t, "refresh-vars") 2223 ctx := testContext2(t, &ContextOpts{ 2224 Module: m, 2225 Providers: map[string]ResourceProviderFactory{ 2226 "aws": testProviderFuncFixed(p), 2227 }, 2228 State: &State{ 2229 2230 Modules: []*ModuleState{ 2231 &ModuleState{ 2232 Path: rootModulePath, 2233 Resources: map[string]*ResourceState{ 2234 "aws_instance.web": &ResourceState{ 2235 Type: "aws_instance", 2236 Primary: &InstanceState{ 2237 ID: "foo", 2238 }, 2239 }, 2240 }, 2241 }, 2242 }, 2243 }, 2244 }) 2245 2246 p.RefreshFn = nil 2247 p.RefreshReturn = &InstanceState{ 2248 ID: "foo", 2249 } 2250 2251 s, err := ctx.Refresh() 2252 if err != nil { 2253 t.Fatalf("err: %s", err) 2254 } 2255 mod := s.RootModule() 2256 if !p.RefreshCalled { 2257 t.Fatal("refresh should be called") 2258 } 2259 if p.RefreshState.ID != "foo" { 2260 t.Fatalf("bad: %#v", p.RefreshState) 2261 } 2262 if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) { 2263 t.Fatalf("bad: %#v", mod.Resources["aws_instance.web"]) 2264 } 2265 2266 for _, r := range mod.Resources { 2267 if r.Type == "" { 2268 t.Fatalf("no type: %#v", r) 2269 } 2270 } 2271 } 2272 2273 func TestContext2Validate(t *testing.T) { 2274 p := testProvider("aws") 2275 m := testModule(t, "validate-good") 2276 c := testContext2(t, &ContextOpts{ 2277 Module: m, 2278 Providers: map[string]ResourceProviderFactory{ 2279 "aws": testProviderFuncFixed(p), 2280 }, 2281 }) 2282 2283 w, e := c.Validate() 2284 if len(w) > 0 { 2285 t.Fatalf("bad: %#v", w) 2286 } 2287 if len(e) > 0 { 2288 t.Fatalf("bad: %s", e) 2289 } 2290 } 2291 2292 func TestContext2Validate_badVar(t *testing.T) { 2293 p := testProvider("aws") 2294 m := testModule(t, "validate-bad-var") 2295 c := testContext2(t, &ContextOpts{ 2296 Module: m, 2297 Providers: map[string]ResourceProviderFactory{ 2298 "aws": testProviderFuncFixed(p), 2299 }, 2300 }) 2301 2302 w, e := c.Validate() 2303 if len(w) > 0 { 2304 t.Fatalf("bad: %#v", w) 2305 } 2306 if len(e) == 0 { 2307 t.Fatalf("bad: %#v", e) 2308 } 2309 } 2310 2311 func TestContext2Validate_countNegative(t *testing.T) { 2312 p := testProvider("aws") 2313 m := testModule(t, "validate-count-negative") 2314 c := testContext2(t, &ContextOpts{ 2315 Module: m, 2316 Providers: map[string]ResourceProviderFactory{ 2317 "aws": testProviderFuncFixed(p), 2318 }, 2319 }) 2320 2321 w, e := c.Validate() 2322 if len(w) > 0 { 2323 t.Fatalf("bad: %#v", w) 2324 } 2325 if len(e) == 0 { 2326 t.Fatalf("bad: %#v", e) 2327 } 2328 } 2329 2330 func TestContext2Validate_countVariable(t *testing.T) { 2331 p := testProvider("aws") 2332 m := testModule(t, "apply-count-variable") 2333 c := testContext2(t, &ContextOpts{ 2334 Module: m, 2335 Providers: map[string]ResourceProviderFactory{ 2336 "aws": testProviderFuncFixed(p), 2337 }, 2338 }) 2339 2340 w, e := c.Validate() 2341 if len(w) > 0 { 2342 t.Fatalf("bad: %#v", w) 2343 } 2344 if len(e) > 0 { 2345 t.Fatalf("bad: %s", e) 2346 } 2347 } 2348 2349 func TestContext2Validate_countVariableNoDefault(t *testing.T) { 2350 p := testProvider("aws") 2351 m := testModule(t, "validate-count-variable") 2352 c := testContext2(t, &ContextOpts{ 2353 Module: m, 2354 Providers: map[string]ResourceProviderFactory{ 2355 "aws": testProviderFuncFixed(p), 2356 }, 2357 }) 2358 2359 w, e := c.Validate() 2360 if len(w) > 0 { 2361 t.Fatalf("bad: %#v", w) 2362 } 2363 if len(e) != 1 { 2364 t.Fatalf("bad: %s", e) 2365 } 2366 } 2367 2368 func TestContext2Validate_moduleBadOutput(t *testing.T) { 2369 p := testProvider("aws") 2370 m := testModule(t, "validate-bad-module-output") 2371 c := testContext2(t, &ContextOpts{ 2372 Module: m, 2373 Providers: map[string]ResourceProviderFactory{ 2374 "aws": testProviderFuncFixed(p), 2375 }, 2376 }) 2377 2378 w, e := c.Validate() 2379 if len(w) > 0 { 2380 t.Fatalf("bad: %#v", w) 2381 } 2382 if len(e) == 0 { 2383 t.Fatalf("bad: %s", e) 2384 } 2385 } 2386 2387 func TestContext2Validate_moduleGood(t *testing.T) { 2388 p := testProvider("aws") 2389 m := testModule(t, "validate-good-module") 2390 c := testContext2(t, &ContextOpts{ 2391 Module: m, 2392 Providers: map[string]ResourceProviderFactory{ 2393 "aws": testProviderFuncFixed(p), 2394 }, 2395 }) 2396 2397 w, e := c.Validate() 2398 if len(w) > 0 { 2399 t.Fatalf("bad: %#v", w) 2400 } 2401 if len(e) > 0 { 2402 t.Fatalf("bad: %#v", e) 2403 } 2404 } 2405 2406 func TestContext2Validate_moduleBadResource(t *testing.T) { 2407 m := testModule(t, "validate-module-bad-rc") 2408 p := testProvider("aws") 2409 c := testContext2(t, &ContextOpts{ 2410 Module: m, 2411 Providers: map[string]ResourceProviderFactory{ 2412 "aws": testProviderFuncFixed(p), 2413 }, 2414 }) 2415 2416 p.ValidateResourceReturnErrors = []error{fmt.Errorf("bad")} 2417 2418 w, e := c.Validate() 2419 if len(w) > 0 { 2420 t.Fatalf("bad: %#v", w) 2421 } 2422 if len(e) == 0 { 2423 t.Fatalf("bad: %#v", e) 2424 } 2425 } 2426 2427 func TestContext2Validate_moduleProviderInherit(t *testing.T) { 2428 m := testModule(t, "validate-module-pc-inherit") 2429 p := testProvider("aws") 2430 c := testContext2(t, &ContextOpts{ 2431 Module: m, 2432 Providers: map[string]ResourceProviderFactory{ 2433 "aws": testProviderFuncFixed(p), 2434 }, 2435 }) 2436 2437 p.ValidateFn = func(c *ResourceConfig) ([]string, []error) { 2438 return nil, c.CheckSet([]string{"set"}) 2439 } 2440 2441 w, e := c.Validate() 2442 if len(w) > 0 { 2443 t.Fatalf("bad: %#v", w) 2444 } 2445 if len(e) > 0 { 2446 t.Fatalf("bad: %s", e) 2447 } 2448 } 2449 2450 func TestContext2Validate_moduleProviderVar(t *testing.T) { 2451 m := testModule(t, "validate-module-pc-vars") 2452 p := testProvider("aws") 2453 c := testContext2(t, &ContextOpts{ 2454 Module: m, 2455 Providers: map[string]ResourceProviderFactory{ 2456 "aws": testProviderFuncFixed(p), 2457 }, 2458 Variables: map[string]string{ 2459 "provider_var": "bar", 2460 }, 2461 }) 2462 2463 p.ValidateFn = func(c *ResourceConfig) ([]string, []error) { 2464 return nil, c.CheckSet([]string{"foo"}) 2465 } 2466 2467 w, e := c.Validate() 2468 if len(w) > 0 { 2469 t.Fatalf("bad: %#v", w) 2470 } 2471 if len(e) > 0 { 2472 t.Fatalf("bad: %s", e) 2473 } 2474 } 2475 2476 func TestContext2Validate_moduleProviderInheritUnused(t *testing.T) { 2477 m := testModule(t, "validate-module-pc-inherit-unused") 2478 p := testProvider("aws") 2479 c := testContext2(t, &ContextOpts{ 2480 Module: m, 2481 Providers: map[string]ResourceProviderFactory{ 2482 "aws": testProviderFuncFixed(p), 2483 }, 2484 }) 2485 2486 p.ValidateFn = func(c *ResourceConfig) ([]string, []error) { 2487 return nil, c.CheckSet([]string{"foo"}) 2488 } 2489 2490 w, e := c.Validate() 2491 if len(w) > 0 { 2492 t.Fatalf("bad: %#v", w) 2493 } 2494 if len(e) > 0 { 2495 t.Fatalf("bad: %s", e) 2496 } 2497 } 2498 2499 func TestContext2Validate_orphans(t *testing.T) { 2500 p := testProvider("aws") 2501 m := testModule(t, "validate-good") 2502 state := &State{ 2503 Modules: []*ModuleState{ 2504 &ModuleState{ 2505 Path: rootModulePath, 2506 Resources: map[string]*ResourceState{ 2507 "aws_instance.web": &ResourceState{ 2508 Type: "aws_instance", 2509 Primary: &InstanceState{ 2510 ID: "bar", 2511 }, 2512 }, 2513 }, 2514 }, 2515 }, 2516 } 2517 c := testContext2(t, &ContextOpts{ 2518 Module: m, 2519 Providers: map[string]ResourceProviderFactory{ 2520 "aws": testProviderFuncFixed(p), 2521 }, 2522 State: state, 2523 }) 2524 2525 p.ValidateResourceFn = func( 2526 t string, c *ResourceConfig) ([]string, []error) { 2527 return nil, c.CheckSet([]string{"foo"}) 2528 } 2529 2530 w, e := c.Validate() 2531 if len(w) > 0 { 2532 t.Fatalf("bad: %#v", w) 2533 } 2534 if len(e) > 0 { 2535 t.Fatalf("bad: %s", e) 2536 } 2537 } 2538 2539 func TestContext2Validate_providerConfig_bad(t *testing.T) { 2540 m := testModule(t, "validate-bad-pc") 2541 p := testProvider("aws") 2542 c := testContext2(t, &ContextOpts{ 2543 Module: m, 2544 Providers: map[string]ResourceProviderFactory{ 2545 "aws": testProviderFuncFixed(p), 2546 }, 2547 }) 2548 2549 p.ValidateReturnErrors = []error{fmt.Errorf("bad")} 2550 2551 w, e := c.Validate() 2552 if len(w) > 0 { 2553 t.Fatalf("bad: %#v", w) 2554 } 2555 if len(e) == 0 { 2556 t.Fatalf("bad: %s", e) 2557 } 2558 if !strings.Contains(fmt.Sprintf("%s", e), "bad") { 2559 t.Fatalf("bad: %s", e) 2560 } 2561 } 2562 2563 func TestContext2Validate_providerConfig_badEmpty(t *testing.T) { 2564 m := testModule(t, "validate-bad-pc-empty") 2565 p := testProvider("aws") 2566 c := testContext2(t, &ContextOpts{ 2567 Module: m, 2568 Providers: map[string]ResourceProviderFactory{ 2569 "aws": testProviderFuncFixed(p), 2570 }, 2571 }) 2572 2573 p.ValidateReturnErrors = []error{fmt.Errorf("bad")} 2574 2575 w, e := c.Validate() 2576 if len(w) > 0 { 2577 t.Fatalf("bad: %#v", w) 2578 } 2579 if len(e) == 0 { 2580 t.Fatalf("bad: %#v", e) 2581 } 2582 } 2583 2584 func TestContext2Validate_providerConfig_good(t *testing.T) { 2585 m := testModule(t, "validate-bad-pc") 2586 p := testProvider("aws") 2587 c := testContext2(t, &ContextOpts{ 2588 Module: m, 2589 Providers: map[string]ResourceProviderFactory{ 2590 "aws": testProviderFuncFixed(p), 2591 }, 2592 }) 2593 2594 w, e := c.Validate() 2595 if len(w) > 0 { 2596 t.Fatalf("bad: %#v", w) 2597 } 2598 if len(e) > 0 { 2599 t.Fatalf("bad: %#v", e) 2600 } 2601 } 2602 2603 func TestContext2Validate_provisionerConfig_bad(t *testing.T) { 2604 m := testModule(t, "validate-bad-prov-conf") 2605 p := testProvider("aws") 2606 pr := testProvisioner() 2607 c := testContext2(t, &ContextOpts{ 2608 Module: m, 2609 Providers: map[string]ResourceProviderFactory{ 2610 "aws": testProviderFuncFixed(p), 2611 }, 2612 Provisioners: map[string]ResourceProvisionerFactory{ 2613 "shell": testProvisionerFuncFixed(pr), 2614 }, 2615 }) 2616 2617 pr.ValidateReturnErrors = []error{fmt.Errorf("bad")} 2618 2619 w, e := c.Validate() 2620 if len(w) > 0 { 2621 t.Fatalf("bad: %#v", w) 2622 } 2623 if len(e) == 0 { 2624 t.Fatalf("bad: %#v", e) 2625 } 2626 } 2627 2628 func TestContext2Validate_provisionerConfig_good(t *testing.T) { 2629 m := testModule(t, "validate-bad-prov-conf") 2630 p := testProvider("aws") 2631 pr := testProvisioner() 2632 pr.ValidateFn = func(c *ResourceConfig) ([]string, []error) { 2633 if c == nil { 2634 t.Fatalf("missing resource config for provisioner") 2635 } 2636 return nil, c.CheckSet([]string{"command"}) 2637 } 2638 c := testContext2(t, &ContextOpts{ 2639 Module: m, 2640 Providers: map[string]ResourceProviderFactory{ 2641 "aws": testProviderFuncFixed(p), 2642 }, 2643 Provisioners: map[string]ResourceProvisionerFactory{ 2644 "shell": testProvisionerFuncFixed(pr), 2645 }, 2646 }) 2647 2648 w, e := c.Validate() 2649 if len(w) > 0 { 2650 t.Fatalf("bad: %#v", w) 2651 } 2652 if len(e) > 0 { 2653 t.Fatalf("bad: %#v", e) 2654 } 2655 } 2656 2657 func TestContext2Validate_requiredVar(t *testing.T) { 2658 m := testModule(t, "validate-required-var") 2659 p := testProvider("aws") 2660 c := testContext2(t, &ContextOpts{ 2661 Module: m, 2662 Providers: map[string]ResourceProviderFactory{ 2663 "aws": testProviderFuncFixed(p), 2664 }, 2665 }) 2666 2667 w, e := c.Validate() 2668 if len(w) > 0 { 2669 t.Fatalf("bad: %#v", w) 2670 } 2671 if len(e) == 0 { 2672 t.Fatalf("bad: %s", e) 2673 } 2674 } 2675 2676 func TestContext2Validate_resourceConfig_bad(t *testing.T) { 2677 m := testModule(t, "validate-bad-rc") 2678 p := testProvider("aws") 2679 c := testContext2(t, &ContextOpts{ 2680 Module: m, 2681 Providers: map[string]ResourceProviderFactory{ 2682 "aws": testProviderFuncFixed(p), 2683 }, 2684 }) 2685 2686 p.ValidateResourceReturnErrors = []error{fmt.Errorf("bad")} 2687 2688 w, e := c.Validate() 2689 if len(w) > 0 { 2690 t.Fatalf("bad: %#v", w) 2691 } 2692 if len(e) == 0 { 2693 t.Fatalf("bad: %s", e) 2694 } 2695 } 2696 2697 func TestContext2Validate_resourceConfig_good(t *testing.T) { 2698 m := testModule(t, "validate-bad-rc") 2699 p := testProvider("aws") 2700 c := testContext2(t, &ContextOpts{ 2701 Module: m, 2702 Providers: map[string]ResourceProviderFactory{ 2703 "aws": testProviderFuncFixed(p), 2704 }, 2705 }) 2706 2707 w, e := c.Validate() 2708 if len(w) > 0 { 2709 t.Fatalf("bad: %#v", w) 2710 } 2711 if len(e) > 0 { 2712 t.Fatalf("bad: %#v", e) 2713 } 2714 } 2715 2716 func TestContext2Validate_resourceNameSymbol(t *testing.T) { 2717 p := testProvider("aws") 2718 m := testModule(t, "validate-resource-name-symbol") 2719 c := testContext2(t, &ContextOpts{ 2720 Module: m, 2721 Providers: map[string]ResourceProviderFactory{ 2722 "aws": testProviderFuncFixed(p), 2723 }, 2724 }) 2725 2726 w, e := c.Validate() 2727 if len(w) == 0 { 2728 t.Fatalf("bad: %#v", w) 2729 } 2730 if len(e) > 0 { 2731 t.Fatalf("bad: %s", e) 2732 } 2733 } 2734 2735 func TestContext2Validate_selfRef(t *testing.T) { 2736 p := testProvider("aws") 2737 m := testModule(t, "validate-self-ref") 2738 c := testContext2(t, &ContextOpts{ 2739 Module: m, 2740 Providers: map[string]ResourceProviderFactory{ 2741 "aws": testProviderFuncFixed(p), 2742 }, 2743 }) 2744 2745 w, e := c.Validate() 2746 if len(w) > 0 { 2747 t.Fatalf("bad: %#v", w) 2748 } 2749 if len(e) == 0 { 2750 t.Fatalf("bad: %s", e) 2751 } 2752 } 2753 2754 func TestContext2Validate_selfRefMulti(t *testing.T) { 2755 p := testProvider("aws") 2756 m := testModule(t, "validate-self-ref-multi") 2757 c := testContext2(t, &ContextOpts{ 2758 Module: m, 2759 Providers: map[string]ResourceProviderFactory{ 2760 "aws": testProviderFuncFixed(p), 2761 }, 2762 }) 2763 2764 w, e := c.Validate() 2765 if len(w) > 0 { 2766 t.Fatalf("bad: %#v", w) 2767 } 2768 if len(e) == 0 { 2769 t.Fatalf("bad: %#v", e) 2770 } 2771 } 2772 2773 func TestContext2Validate_selfRefMultiAll(t *testing.T) { 2774 p := testProvider("aws") 2775 m := testModule(t, "validate-self-ref-multi-all") 2776 c := testContext2(t, &ContextOpts{ 2777 Module: m, 2778 Providers: map[string]ResourceProviderFactory{ 2779 "aws": testProviderFuncFixed(p), 2780 }, 2781 }) 2782 2783 w, e := c.Validate() 2784 if len(w) > 0 { 2785 t.Fatalf("bad: %#v", w) 2786 } 2787 if len(e) == 0 { 2788 t.Fatalf("bad: %#v", e) 2789 } 2790 } 2791 2792 func TestContext2Validate_tainted(t *testing.T) { 2793 p := testProvider("aws") 2794 m := testModule(t, "validate-good") 2795 state := &State{ 2796 Modules: []*ModuleState{ 2797 &ModuleState{ 2798 Path: rootModulePath, 2799 Resources: map[string]*ResourceState{ 2800 "aws_instance.foo": &ResourceState{ 2801 Type: "aws_instance", 2802 Tainted: []*InstanceState{ 2803 &InstanceState{ 2804 ID: "bar", 2805 }, 2806 }, 2807 }, 2808 }, 2809 }, 2810 }, 2811 } 2812 c := testContext2(t, &ContextOpts{ 2813 Module: m, 2814 Providers: map[string]ResourceProviderFactory{ 2815 "aws": testProviderFuncFixed(p), 2816 }, 2817 State: state, 2818 }) 2819 2820 p.ValidateResourceFn = func( 2821 t string, c *ResourceConfig) ([]string, []error) { 2822 return nil, c.CheckSet([]string{"foo"}) 2823 } 2824 2825 w, e := c.Validate() 2826 if len(w) > 0 { 2827 t.Fatalf("bad: %#v", w) 2828 } 2829 if len(e) > 0 { 2830 t.Fatalf("bad: %#v", e) 2831 } 2832 } 2833 2834 func TestContext2Validate_varRef(t *testing.T) { 2835 m := testModule(t, "validate-variable-ref") 2836 p := testProvider("aws") 2837 c := testContext2(t, &ContextOpts{ 2838 Module: m, 2839 Providers: map[string]ResourceProviderFactory{ 2840 "aws": testProviderFuncFixed(p), 2841 }, 2842 }) 2843 2844 computed := false 2845 p.ValidateResourceFn = func(t string, c *ResourceConfig) ([]string, []error) { 2846 computed = c.IsComputed("foo") 2847 return nil, nil 2848 } 2849 2850 c.Validate() 2851 if !computed { 2852 t.Fatal("should be computed") 2853 } 2854 } 2855 2856 func TestContext2Validate_varRefFilled(t *testing.T) { 2857 m := testModule(t, "validate-variable-ref") 2858 p := testProvider("aws") 2859 c := testContext2(t, &ContextOpts{ 2860 Module: m, 2861 Providers: map[string]ResourceProviderFactory{ 2862 "aws": testProviderFuncFixed(p), 2863 }, 2864 Variables: map[string]string{ 2865 "foo": "bar", 2866 }, 2867 }) 2868 2869 var value interface{} 2870 p.ValidateResourceFn = func(t string, c *ResourceConfig) ([]string, []error) { 2871 value, _ = c.Get("foo") 2872 return nil, nil 2873 } 2874 2875 c.Validate() 2876 if value != "bar" { 2877 t.Fatalf("bad: %#v", value) 2878 } 2879 } 2880 2881 func TestContext2Input(t *testing.T) { 2882 input := new(MockUIInput) 2883 m := testModule(t, "input-vars") 2884 p := testProvider("aws") 2885 p.ApplyFn = testApplyFn 2886 p.DiffFn = testDiffFn 2887 ctx := testContext2(t, &ContextOpts{ 2888 Module: m, 2889 Providers: map[string]ResourceProviderFactory{ 2890 "aws": testProviderFuncFixed(p), 2891 }, 2892 Variables: map[string]string{ 2893 "foo": "us-west-2", 2894 "amis.us-east-1": "override", 2895 }, 2896 UIInput: input, 2897 }) 2898 2899 input.InputReturnMap = map[string]string{ 2900 "var.foo": "us-east-1", 2901 } 2902 2903 if err := ctx.Input(InputModeStd); err != nil { 2904 t.Fatalf("err: %s", err) 2905 } 2906 2907 if _, err := ctx.Plan(); err != nil { 2908 t.Fatalf("err: %s", err) 2909 } 2910 2911 state, err := ctx.Apply() 2912 if err != nil { 2913 t.Fatalf("err: %s", err) 2914 } 2915 2916 actual := strings.TrimSpace(state.String()) 2917 expected := strings.TrimSpace(testTerraformInputVarsStr) 2918 if actual != expected { 2919 t.Fatalf("bad: \n%s", actual) 2920 } 2921 } 2922 2923 func TestContext2Input_badVarDefault(t *testing.T) { 2924 m := testModule(t, "input-bad-var-default") 2925 p := testProvider("aws") 2926 p.ApplyFn = testApplyFn 2927 p.DiffFn = testDiffFn 2928 ctx := testContext2(t, &ContextOpts{ 2929 Module: m, 2930 Providers: map[string]ResourceProviderFactory{ 2931 "aws": testProviderFuncFixed(p), 2932 }, 2933 }) 2934 2935 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 2936 c.Config["foo"] = "bar" 2937 return c, nil 2938 } 2939 2940 if err := ctx.Input(InputModeStd); err != nil { 2941 t.Fatalf("err: %s", err) 2942 } 2943 } 2944 2945 func TestContext2Input_provider(t *testing.T) { 2946 m := testModule(t, "input-provider") 2947 p := testProvider("aws") 2948 p.ApplyFn = testApplyFn 2949 p.DiffFn = testDiffFn 2950 ctx := testContext2(t, &ContextOpts{ 2951 Module: m, 2952 Providers: map[string]ResourceProviderFactory{ 2953 "aws": testProviderFuncFixed(p), 2954 }, 2955 }) 2956 2957 var actual interface{} 2958 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 2959 c.Config["foo"] = "bar" 2960 return c, nil 2961 } 2962 p.ConfigureFn = func(c *ResourceConfig) error { 2963 actual = c.Config["foo"] 2964 return nil 2965 } 2966 p.ValidateFn = func(c *ResourceConfig) ([]string, []error) { 2967 return nil, c.CheckSet([]string{"foo"}) 2968 } 2969 2970 if err := ctx.Input(InputModeStd); err != nil { 2971 t.Fatalf("err: %s", err) 2972 } 2973 2974 if _, err := ctx.Plan(); err != nil { 2975 t.Fatalf("err: %s", err) 2976 } 2977 2978 if _, err := ctx.Apply(); err != nil { 2979 t.Fatalf("err: %s", err) 2980 } 2981 2982 if !reflect.DeepEqual(actual, "bar") { 2983 t.Fatalf("bad: %#v", actual) 2984 } 2985 } 2986 2987 func TestContext2Input_providerMulti(t *testing.T) { 2988 m := testModule(t, "input-provider-multi") 2989 p := testProvider("aws") 2990 p.ApplyFn = testApplyFn 2991 p.DiffFn = testDiffFn 2992 ctx := testContext2(t, &ContextOpts{ 2993 Module: m, 2994 Providers: map[string]ResourceProviderFactory{ 2995 "aws": testProviderFuncFixed(p), 2996 }, 2997 }) 2998 2999 var actual []interface{} 3000 var lock sync.Mutex 3001 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 3002 c.Config["foo"] = "bar" 3003 return c, nil 3004 } 3005 p.ConfigureFn = func(c *ResourceConfig) error { 3006 lock.Lock() 3007 defer lock.Unlock() 3008 actual = append(actual, c.Config["foo"]) 3009 return nil 3010 } 3011 p.ValidateFn = func(c *ResourceConfig) ([]string, []error) { 3012 return nil, c.CheckSet([]string{"foo"}) 3013 } 3014 3015 if err := ctx.Input(InputModeStd); err != nil { 3016 t.Fatalf("err: %s", err) 3017 } 3018 3019 if _, err := ctx.Plan(); err != nil { 3020 t.Fatalf("err: %s", err) 3021 } 3022 3023 if _, err := ctx.Apply(); err != nil { 3024 t.Fatalf("err: %s", err) 3025 } 3026 3027 expected := []interface{}{"bar", "bar"} 3028 if !reflect.DeepEqual(actual, expected) { 3029 t.Fatalf("bad: %#v", actual) 3030 } 3031 } 3032 3033 func TestContext2Input_providerOnce(t *testing.T) { 3034 m := testModule(t, "input-provider-once") 3035 p := testProvider("aws") 3036 p.ApplyFn = testApplyFn 3037 p.DiffFn = testDiffFn 3038 ctx := testContext2(t, &ContextOpts{ 3039 Module: m, 3040 Providers: map[string]ResourceProviderFactory{ 3041 "aws": testProviderFuncFixed(p), 3042 }, 3043 }) 3044 3045 count := 0 3046 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 3047 count++ 3048 return nil, nil 3049 } 3050 3051 if err := ctx.Input(InputModeStd); err != nil { 3052 t.Fatalf("err: %s", err) 3053 } 3054 3055 if count != 1 { 3056 t.Fatalf("should only be called once: %d", count) 3057 } 3058 } 3059 3060 func TestContext2Input_providerId(t *testing.T) { 3061 input := new(MockUIInput) 3062 m := testModule(t, "input-provider") 3063 p := testProvider("aws") 3064 p.ApplyFn = testApplyFn 3065 p.DiffFn = testDiffFn 3066 ctx := testContext2(t, &ContextOpts{ 3067 Module: m, 3068 Providers: map[string]ResourceProviderFactory{ 3069 "aws": testProviderFuncFixed(p), 3070 }, 3071 UIInput: input, 3072 }) 3073 3074 var actual interface{} 3075 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 3076 v, err := i.Input(&InputOpts{Id: "foo"}) 3077 if err != nil { 3078 return nil, err 3079 } 3080 3081 c.Config["foo"] = v 3082 return c, nil 3083 } 3084 p.ConfigureFn = func(c *ResourceConfig) error { 3085 actual = c.Config["foo"] 3086 return nil 3087 } 3088 3089 input.InputReturnMap = map[string]string{ 3090 "provider.aws.foo": "bar", 3091 } 3092 3093 if err := ctx.Input(InputModeStd); err != nil { 3094 t.Fatalf("err: %s", err) 3095 } 3096 3097 if _, err := ctx.Plan(); err != nil { 3098 t.Fatalf("err: %s", err) 3099 } 3100 3101 if _, err := ctx.Apply(); err != nil { 3102 t.Fatalf("err: %s", err) 3103 } 3104 3105 if !reflect.DeepEqual(actual, "bar") { 3106 t.Fatalf("bad: %#v", actual) 3107 } 3108 } 3109 3110 func TestContext2Input_providerOnly(t *testing.T) { 3111 input := new(MockUIInput) 3112 m := testModule(t, "input-provider-vars") 3113 p := testProvider("aws") 3114 p.ApplyFn = testApplyFn 3115 p.DiffFn = testDiffFn 3116 ctx := testContext2(t, &ContextOpts{ 3117 Module: m, 3118 Providers: map[string]ResourceProviderFactory{ 3119 "aws": testProviderFuncFixed(p), 3120 }, 3121 Variables: map[string]string{ 3122 "foo": "us-west-2", 3123 }, 3124 UIInput: input, 3125 }) 3126 3127 input.InputReturnMap = map[string]string{ 3128 "var.foo": "us-east-1", 3129 } 3130 3131 var actual interface{} 3132 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 3133 c.Config["foo"] = "bar" 3134 return c, nil 3135 } 3136 p.ConfigureFn = func(c *ResourceConfig) error { 3137 actual = c.Config["foo"] 3138 return nil 3139 } 3140 3141 if err := ctx.Input(InputModeProvider); err != nil { 3142 t.Fatalf("err: %s", err) 3143 } 3144 3145 if _, err := ctx.Plan(); err != nil { 3146 t.Fatalf("err: %s", err) 3147 } 3148 3149 state, err := ctx.Apply() 3150 if err != nil { 3151 t.Fatalf("err: %s", err) 3152 } 3153 3154 if !reflect.DeepEqual(actual, "bar") { 3155 t.Fatalf("bad: %#v", actual) 3156 } 3157 3158 actualStr := strings.TrimSpace(state.String()) 3159 expectedStr := strings.TrimSpace(testTerraformInputProviderOnlyStr) 3160 if actualStr != expectedStr { 3161 t.Fatalf("bad: \n%s", actualStr) 3162 } 3163 } 3164 3165 func TestContext2Input_providerVars(t *testing.T) { 3166 input := new(MockUIInput) 3167 m := testModule(t, "input-provider-with-vars") 3168 p := testProvider("aws") 3169 p.ApplyFn = testApplyFn 3170 p.DiffFn = testDiffFn 3171 ctx := testContext2(t, &ContextOpts{ 3172 Module: m, 3173 Providers: map[string]ResourceProviderFactory{ 3174 "aws": testProviderFuncFixed(p), 3175 }, 3176 Variables: map[string]string{ 3177 "foo": "bar", 3178 }, 3179 UIInput: input, 3180 }) 3181 3182 input.InputReturnMap = map[string]string{ 3183 "var.foo": "bar", 3184 } 3185 3186 var actual interface{} 3187 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 3188 c.Config["bar"] = "baz" 3189 return c, nil 3190 } 3191 p.ConfigureFn = func(c *ResourceConfig) error { 3192 actual, _ = c.Get("foo") 3193 return nil 3194 } 3195 3196 if err := ctx.Input(InputModeStd); err != nil { 3197 t.Fatalf("err: %s", err) 3198 } 3199 3200 if _, err := ctx.Plan(); err != nil { 3201 t.Fatalf("err: %s", err) 3202 } 3203 3204 if _, err := ctx.Apply(); err != nil { 3205 t.Fatalf("err: %s", err) 3206 } 3207 3208 if !reflect.DeepEqual(actual, "bar") { 3209 t.Fatalf("bad: %#v", actual) 3210 } 3211 } 3212 3213 func TestContext2Input_providerVarsModuleInherit(t *testing.T) { 3214 input := new(MockUIInput) 3215 m := testModule(t, "input-provider-with-vars-and-module") 3216 p := testProvider("aws") 3217 p.ApplyFn = testApplyFn 3218 p.DiffFn = testDiffFn 3219 ctx := testContext2(t, &ContextOpts{ 3220 Module: m, 3221 Providers: map[string]ResourceProviderFactory{ 3222 "aws": testProviderFuncFixed(p), 3223 }, 3224 UIInput: input, 3225 }) 3226 3227 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 3228 if errs := c.CheckSet([]string{"access_key"}); len(errs) > 0 { 3229 return c, errs[0] 3230 } 3231 return c, nil 3232 } 3233 p.ConfigureFn = func(c *ResourceConfig) error { 3234 return nil 3235 } 3236 3237 if err := ctx.Input(InputModeStd); err != nil { 3238 t.Fatalf("err: %s", err) 3239 } 3240 } 3241 3242 func TestContext2Input_varOnly(t *testing.T) { 3243 input := new(MockUIInput) 3244 m := testModule(t, "input-provider-vars") 3245 p := testProvider("aws") 3246 p.ApplyFn = testApplyFn 3247 p.DiffFn = testDiffFn 3248 ctx := testContext2(t, &ContextOpts{ 3249 Module: m, 3250 Providers: map[string]ResourceProviderFactory{ 3251 "aws": testProviderFuncFixed(p), 3252 }, 3253 Variables: map[string]string{ 3254 "foo": "us-west-2", 3255 }, 3256 UIInput: input, 3257 }) 3258 3259 input.InputReturnMap = map[string]string{ 3260 "var.foo": "us-east-1", 3261 } 3262 3263 var actual interface{} 3264 p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) { 3265 c.Raw["foo"] = "bar" 3266 return c, nil 3267 } 3268 p.ConfigureFn = func(c *ResourceConfig) error { 3269 actual = c.Raw["foo"] 3270 return nil 3271 } 3272 3273 if err := ctx.Input(InputModeVar); err != nil { 3274 t.Fatalf("err: %s", err) 3275 } 3276 3277 if _, err := ctx.Plan(); err != nil { 3278 t.Fatalf("err: %s", err) 3279 } 3280 3281 state, err := ctx.Apply() 3282 if err != nil { 3283 t.Fatalf("err: %s", err) 3284 } 3285 3286 if reflect.DeepEqual(actual, "bar") { 3287 t.Fatalf("bad: %#v", actual) 3288 } 3289 3290 actualStr := strings.TrimSpace(state.String()) 3291 expectedStr := strings.TrimSpace(testTerraformInputVarOnlyStr) 3292 if actualStr != expectedStr { 3293 t.Fatalf("bad: \n%s", actualStr) 3294 } 3295 } 3296 3297 func TestContext2Input_varOnlyUnset(t *testing.T) { 3298 input := new(MockUIInput) 3299 m := testModule(t, "input-vars-unset") 3300 p := testProvider("aws") 3301 p.ApplyFn = testApplyFn 3302 p.DiffFn = testDiffFn 3303 ctx := testContext2(t, &ContextOpts{ 3304 Module: m, 3305 Providers: map[string]ResourceProviderFactory{ 3306 "aws": testProviderFuncFixed(p), 3307 }, 3308 Variables: map[string]string{ 3309 "foo": "foovalue", 3310 }, 3311 UIInput: input, 3312 }) 3313 3314 input.InputReturnMap = map[string]string{ 3315 "var.foo": "nope", 3316 "var.bar": "baz", 3317 } 3318 3319 if err := ctx.Input(InputModeVar | InputModeVarUnset); err != nil { 3320 t.Fatalf("err: %s", err) 3321 } 3322 3323 if _, err := ctx.Plan(); err != nil { 3324 t.Fatalf("err: %s", err) 3325 } 3326 3327 state, err := ctx.Apply() 3328 if err != nil { 3329 t.Fatalf("err: %s", err) 3330 } 3331 3332 actualStr := strings.TrimSpace(state.String()) 3333 expectedStr := strings.TrimSpace(testTerraformInputVarOnlyUnsetStr) 3334 if actualStr != expectedStr { 3335 t.Fatalf("bad: \n%s", actualStr) 3336 } 3337 } 3338 3339 func TestContext2Apply(t *testing.T) { 3340 m := testModule(t, "apply-good") 3341 p := testProvider("aws") 3342 p.ApplyFn = testApplyFn 3343 p.DiffFn = testDiffFn 3344 ctx := testContext2(t, &ContextOpts{ 3345 Module: m, 3346 Providers: map[string]ResourceProviderFactory{ 3347 "aws": testProviderFuncFixed(p), 3348 }, 3349 }) 3350 3351 if _, err := ctx.Plan(); err != nil { 3352 t.Fatalf("err: %s", err) 3353 } 3354 3355 state, err := ctx.Apply() 3356 if err != nil { 3357 t.Fatalf("err: %s", err) 3358 } 3359 3360 mod := state.RootModule() 3361 if len(mod.Resources) < 2 { 3362 t.Fatalf("bad: %#v", mod.Resources) 3363 } 3364 3365 actual := strings.TrimSpace(state.String()) 3366 expected := strings.TrimSpace(testTerraformApplyStr) 3367 if actual != expected { 3368 t.Fatalf("bad: \n%s", actual) 3369 } 3370 } 3371 3372 func TestContext2Apply_providerAlias(t *testing.T) { 3373 m := testModule(t, "apply-provider-alias") 3374 p := testProvider("aws") 3375 p.ApplyFn = testApplyFn 3376 p.DiffFn = testDiffFn 3377 ctx := testContext2(t, &ContextOpts{ 3378 Module: m, 3379 Providers: map[string]ResourceProviderFactory{ 3380 "aws": testProviderFuncFixed(p), 3381 }, 3382 }) 3383 3384 if _, err := ctx.Plan(); err != nil { 3385 t.Fatalf("err: %s", err) 3386 } 3387 3388 state, err := ctx.Apply() 3389 if err != nil { 3390 t.Fatalf("err: %s", err) 3391 } 3392 3393 mod := state.RootModule() 3394 if len(mod.Resources) < 2 { 3395 t.Fatalf("bad: %#v", mod.Resources) 3396 } 3397 3398 actual := strings.TrimSpace(state.String()) 3399 expected := strings.TrimSpace(testTerraformApplyProviderAliasStr) 3400 if actual != expected { 3401 t.Fatalf("bad: \n%s", actual) 3402 } 3403 } 3404 3405 func TestContext2Apply_emptyModule(t *testing.T) { 3406 m := testModule(t, "apply-empty-module") 3407 p := testProvider("aws") 3408 p.ApplyFn = testApplyFn 3409 p.DiffFn = testDiffFn 3410 ctx := testContext2(t, &ContextOpts{ 3411 Module: m, 3412 Providers: map[string]ResourceProviderFactory{ 3413 "aws": testProviderFuncFixed(p), 3414 }, 3415 }) 3416 3417 if _, err := ctx.Plan(); err != nil { 3418 t.Fatalf("err: %s", err) 3419 } 3420 3421 state, err := ctx.Apply() 3422 if err != nil { 3423 t.Fatalf("err: %s", err) 3424 } 3425 3426 actual := strings.TrimSpace(state.String()) 3427 actual = strings.Replace(actual, " ", "", -1) 3428 expected := strings.TrimSpace(testTerraformApplyEmptyModuleStr) 3429 if actual != expected { 3430 t.Fatalf("bad: \n%s\nexpect:\n%s", actual, expected) 3431 } 3432 } 3433 3434 func TestContext2Apply_createBeforeDestroy(t *testing.T) { 3435 m := testModule(t, "apply-good-create-before") 3436 p := testProvider("aws") 3437 p.ApplyFn = testApplyFn 3438 p.DiffFn = testDiffFn 3439 state := &State{ 3440 Modules: []*ModuleState{ 3441 &ModuleState{ 3442 Path: rootModulePath, 3443 Resources: map[string]*ResourceState{ 3444 "aws_instance.bar": &ResourceState{ 3445 Type: "aws_instance", 3446 Primary: &InstanceState{ 3447 ID: "bar", 3448 Attributes: map[string]string{ 3449 "require_new": "abc", 3450 }, 3451 }, 3452 }, 3453 }, 3454 }, 3455 }, 3456 } 3457 ctx := testContext2(t, &ContextOpts{ 3458 Module: m, 3459 Providers: map[string]ResourceProviderFactory{ 3460 "aws": testProviderFuncFixed(p), 3461 }, 3462 State: state, 3463 }) 3464 3465 if p, err := ctx.Plan(); err != nil { 3466 t.Fatalf("err: %s", err) 3467 } else { 3468 t.Logf(p.String()) 3469 } 3470 3471 state, err := ctx.Apply() 3472 if err != nil { 3473 t.Fatalf("err: %s", err) 3474 } 3475 3476 mod := state.RootModule() 3477 if len(mod.Resources) != 1 { 3478 t.Fatalf("bad: %s", state) 3479 } 3480 3481 actual := strings.TrimSpace(state.String()) 3482 expected := strings.TrimSpace(testTerraformApplyCreateBeforeStr) 3483 if actual != expected { 3484 t.Fatalf("bad: \n%s", actual) 3485 } 3486 } 3487 3488 func TestContext2Apply_createBeforeDestroyUpdate(t *testing.T) { 3489 m := testModule(t, "apply-good-create-before-update") 3490 p := testProvider("aws") 3491 p.ApplyFn = testApplyFn 3492 p.DiffFn = testDiffFn 3493 state := &State{ 3494 Modules: []*ModuleState{ 3495 &ModuleState{ 3496 Path: rootModulePath, 3497 Resources: map[string]*ResourceState{ 3498 "aws_instance.bar": &ResourceState{ 3499 Type: "aws_instance", 3500 Primary: &InstanceState{ 3501 ID: "bar", 3502 Attributes: map[string]string{ 3503 "foo": "bar", 3504 }, 3505 }, 3506 }, 3507 }, 3508 }, 3509 }, 3510 } 3511 ctx := testContext2(t, &ContextOpts{ 3512 Module: m, 3513 Providers: map[string]ResourceProviderFactory{ 3514 "aws": testProviderFuncFixed(p), 3515 }, 3516 State: state, 3517 }) 3518 3519 if p, err := ctx.Plan(); err != nil { 3520 t.Fatalf("err: %s", err) 3521 } else { 3522 t.Logf(p.String()) 3523 } 3524 3525 state, err := ctx.Apply() 3526 if err != nil { 3527 t.Fatalf("err: %s", err) 3528 } 3529 3530 mod := state.RootModule() 3531 if len(mod.Resources) != 1 { 3532 t.Fatalf("bad: %s", state) 3533 } 3534 3535 actual := strings.TrimSpace(state.String()) 3536 expected := strings.TrimSpace(testTerraformApplyCreateBeforeUpdateStr) 3537 if actual != expected { 3538 t.Fatalf("bad: \n%s", actual) 3539 } 3540 } 3541 3542 func TestContext2Apply_minimal(t *testing.T) { 3543 m := testModule(t, "apply-minimal") 3544 p := testProvider("aws") 3545 p.ApplyFn = testApplyFn 3546 p.DiffFn = testDiffFn 3547 ctx := testContext2(t, &ContextOpts{ 3548 Module: m, 3549 Providers: map[string]ResourceProviderFactory{ 3550 "aws": testProviderFuncFixed(p), 3551 }, 3552 }) 3553 3554 if _, err := ctx.Plan(); err != nil { 3555 t.Fatalf("err: %s", err) 3556 } 3557 3558 state, err := ctx.Apply() 3559 if err != nil { 3560 t.Fatalf("err: %s", err) 3561 } 3562 3563 actual := strings.TrimSpace(state.String()) 3564 expected := strings.TrimSpace(testTerraformApplyMinimalStr) 3565 if actual != expected { 3566 t.Fatalf("bad: \n%s", actual) 3567 } 3568 } 3569 3570 func TestContext2Apply_badDiff(t *testing.T) { 3571 m := testModule(t, "apply-good") 3572 p := testProvider("aws") 3573 p.ApplyFn = testApplyFn 3574 p.DiffFn = testDiffFn 3575 ctx := testContext2(t, &ContextOpts{ 3576 Module: m, 3577 Providers: map[string]ResourceProviderFactory{ 3578 "aws": testProviderFuncFixed(p), 3579 }, 3580 }) 3581 3582 if _, err := ctx.Plan(); err != nil { 3583 t.Fatalf("err: %s", err) 3584 } 3585 3586 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 3587 return &InstanceDiff{ 3588 Attributes: map[string]*ResourceAttrDiff{ 3589 "newp": nil, 3590 }, 3591 }, nil 3592 } 3593 3594 if _, err := ctx.Apply(); err == nil { 3595 t.Fatal("should error") 3596 } 3597 } 3598 3599 func TestContext2Apply_cancel(t *testing.T) { 3600 stopped := false 3601 3602 m := testModule(t, "apply-cancel") 3603 p := testProvider("aws") 3604 ctx := testContext2(t, &ContextOpts{ 3605 Module: m, 3606 Providers: map[string]ResourceProviderFactory{ 3607 "aws": testProviderFuncFixed(p), 3608 }, 3609 }) 3610 3611 p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) { 3612 if !stopped { 3613 stopped = true 3614 go ctx.Stop() 3615 3616 for { 3617 if ctx.sh.Stopped() { 3618 break 3619 } 3620 } 3621 } 3622 3623 return &InstanceState{ 3624 ID: "foo", 3625 Attributes: map[string]string{ 3626 "num": "2", 3627 }, 3628 }, nil 3629 } 3630 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 3631 return &InstanceDiff{ 3632 Attributes: map[string]*ResourceAttrDiff{ 3633 "num": &ResourceAttrDiff{ 3634 New: "bar", 3635 }, 3636 }, 3637 }, nil 3638 } 3639 3640 if _, err := ctx.Plan(); err != nil { 3641 t.Fatalf("err: %s", err) 3642 } 3643 3644 // Start the Apply in a goroutine 3645 stateCh := make(chan *State) 3646 go func() { 3647 state, err := ctx.Apply() 3648 if err != nil { 3649 panic(err) 3650 } 3651 3652 stateCh <- state 3653 }() 3654 3655 state := <-stateCh 3656 3657 mod := state.RootModule() 3658 if len(mod.Resources) != 1 { 3659 t.Fatalf("bad: %s", state.String()) 3660 } 3661 3662 actual := strings.TrimSpace(state.String()) 3663 expected := strings.TrimSpace(testTerraformApplyCancelStr) 3664 if actual != expected { 3665 t.Fatalf("bad: \n%s", actual) 3666 } 3667 } 3668 3669 func TestContext2Apply_compute(t *testing.T) { 3670 m := testModule(t, "apply-compute") 3671 p := testProvider("aws") 3672 p.ApplyFn = testApplyFn 3673 p.DiffFn = testDiffFn 3674 ctx := testContext2(t, &ContextOpts{ 3675 Module: m, 3676 Providers: map[string]ResourceProviderFactory{ 3677 "aws": testProviderFuncFixed(p), 3678 }, 3679 }) 3680 3681 if _, err := ctx.Plan(); err != nil { 3682 t.Fatalf("err: %s", err) 3683 } 3684 3685 ctx.variables = map[string]string{"value": "1"} 3686 3687 state, err := ctx.Apply() 3688 if err != nil { 3689 t.Fatalf("err: %s", err) 3690 } 3691 3692 actual := strings.TrimSpace(state.String()) 3693 expected := strings.TrimSpace(testTerraformApplyComputeStr) 3694 if actual != expected { 3695 t.Fatalf("bad: \n%s", actual) 3696 } 3697 } 3698 3699 func TestContext2Apply_countDecrease(t *testing.T) { 3700 m := testModule(t, "apply-count-dec") 3701 p := testProvider("aws") 3702 p.DiffFn = testDiffFn 3703 s := &State{ 3704 Modules: []*ModuleState{ 3705 &ModuleState{ 3706 Path: rootModulePath, 3707 Resources: map[string]*ResourceState{ 3708 "aws_instance.foo.0": &ResourceState{ 3709 Type: "aws_instance", 3710 Primary: &InstanceState{ 3711 ID: "bar", 3712 Attributes: map[string]string{ 3713 "foo": "foo", 3714 "type": "aws_instance", 3715 }, 3716 }, 3717 }, 3718 "aws_instance.foo.1": &ResourceState{ 3719 Type: "aws_instance", 3720 Primary: &InstanceState{ 3721 ID: "bar", 3722 Attributes: map[string]string{ 3723 "foo": "foo", 3724 "type": "aws_instance", 3725 }, 3726 }, 3727 }, 3728 "aws_instance.foo.2": &ResourceState{ 3729 Type: "aws_instance", 3730 Primary: &InstanceState{ 3731 ID: "bar", 3732 Attributes: map[string]string{ 3733 "foo": "foo", 3734 "type": "aws_instance", 3735 }, 3736 }, 3737 }, 3738 }, 3739 }, 3740 }, 3741 } 3742 ctx := testContext2(t, &ContextOpts{ 3743 Module: m, 3744 Providers: map[string]ResourceProviderFactory{ 3745 "aws": testProviderFuncFixed(p), 3746 }, 3747 State: s, 3748 }) 3749 3750 if _, err := ctx.Plan(); err != nil { 3751 t.Fatalf("err: %s", err) 3752 } 3753 3754 state, err := ctx.Apply() 3755 if err != nil { 3756 t.Fatalf("err: %s", err) 3757 } 3758 3759 actual := strings.TrimSpace(state.String()) 3760 expected := strings.TrimSpace(testTerraformApplyCountDecStr) 3761 if actual != expected { 3762 t.Fatalf("bad: \n%s", actual) 3763 } 3764 } 3765 3766 func TestContext2Apply_countDecreaseToOne(t *testing.T) { 3767 m := testModule(t, "apply-count-dec-one") 3768 p := testProvider("aws") 3769 p.ApplyFn = testApplyFn 3770 p.DiffFn = testDiffFn 3771 s := &State{ 3772 Modules: []*ModuleState{ 3773 &ModuleState{ 3774 Path: rootModulePath, 3775 Resources: map[string]*ResourceState{ 3776 "aws_instance.foo.0": &ResourceState{ 3777 Type: "aws_instance", 3778 Primary: &InstanceState{ 3779 ID: "bar", 3780 Attributes: map[string]string{ 3781 "foo": "foo", 3782 "type": "aws_instance", 3783 }, 3784 }, 3785 }, 3786 "aws_instance.foo.1": &ResourceState{ 3787 Type: "aws_instance", 3788 Primary: &InstanceState{ 3789 ID: "bar", 3790 }, 3791 }, 3792 "aws_instance.foo.2": &ResourceState{ 3793 Type: "aws_instance", 3794 Primary: &InstanceState{ 3795 ID: "bar", 3796 }, 3797 }, 3798 }, 3799 }, 3800 }, 3801 } 3802 ctx := testContext2(t, &ContextOpts{ 3803 Module: m, 3804 Providers: map[string]ResourceProviderFactory{ 3805 "aws": testProviderFuncFixed(p), 3806 }, 3807 State: s, 3808 }) 3809 3810 if _, err := ctx.Plan(); err != nil { 3811 t.Fatalf("err: %s", err) 3812 } 3813 3814 state, err := ctx.Apply() 3815 if err != nil { 3816 t.Fatalf("err: %s", err) 3817 } 3818 3819 actual := strings.TrimSpace(state.String()) 3820 expected := strings.TrimSpace(testTerraformApplyCountDecToOneStr) 3821 if actual != expected { 3822 t.Fatalf("bad: \n%s", actual) 3823 } 3824 } 3825 3826 // https://github.com/PeoplePerHour/terraform/pull/11 3827 // 3828 // This tests a case where both a "resource" and "resource.0" are in 3829 // the state file, which apparently is a reasonable backwards compatibility 3830 // concern found in the above 3rd party repo. 3831 func TestContext2Apply_countDecreaseToOneCorrupted(t *testing.T) { 3832 m := testModule(t, "apply-count-dec-one") 3833 p := testProvider("aws") 3834 p.ApplyFn = testApplyFn 3835 p.DiffFn = testDiffFn 3836 s := &State{ 3837 Modules: []*ModuleState{ 3838 &ModuleState{ 3839 Path: rootModulePath, 3840 Resources: map[string]*ResourceState{ 3841 "aws_instance.foo": &ResourceState{ 3842 Type: "aws_instance", 3843 Primary: &InstanceState{ 3844 ID: "bar", 3845 Attributes: map[string]string{ 3846 "foo": "foo", 3847 "type": "aws_instance", 3848 }, 3849 }, 3850 }, 3851 "aws_instance.foo.0": &ResourceState{ 3852 Type: "aws_instance", 3853 Primary: &InstanceState{ 3854 ID: "baz", 3855 Attributes: map[string]string{ 3856 "type": "aws_instance", 3857 }, 3858 }, 3859 }, 3860 }, 3861 }, 3862 }, 3863 } 3864 ctx := testContext2(t, &ContextOpts{ 3865 Module: m, 3866 Providers: map[string]ResourceProviderFactory{ 3867 "aws": testProviderFuncFixed(p), 3868 }, 3869 State: s, 3870 }) 3871 3872 if p, err := ctx.Plan(); err != nil { 3873 t.Fatalf("err: %s", err) 3874 } else { 3875 testStringMatch(t, p, testTerraformApplyCountDecToOneCorruptedPlanStr) 3876 } 3877 3878 state, err := ctx.Apply() 3879 if err != nil { 3880 t.Fatalf("err: %s", err) 3881 } 3882 3883 actual := strings.TrimSpace(state.String()) 3884 expected := strings.TrimSpace(testTerraformApplyCountDecToOneCorruptedStr) 3885 if actual != expected { 3886 t.Fatalf("bad: \n%s", actual) 3887 } 3888 } 3889 3890 func TestContext2Apply_countTainted(t *testing.T) { 3891 m := testModule(t, "apply-count-tainted") 3892 p := testProvider("aws") 3893 p.DiffFn = testDiffFn 3894 s := &State{ 3895 Modules: []*ModuleState{ 3896 &ModuleState{ 3897 Path: rootModulePath, 3898 Resources: map[string]*ResourceState{ 3899 "aws_instance.foo.0": &ResourceState{ 3900 Type: "aws_instance", 3901 Tainted: []*InstanceState{ 3902 &InstanceState{ 3903 ID: "bar", 3904 Attributes: map[string]string{ 3905 "foo": "foo", 3906 "type": "aws_instance", 3907 }, 3908 }, 3909 }, 3910 }, 3911 }, 3912 }, 3913 }, 3914 } 3915 ctx := testContext2(t, &ContextOpts{ 3916 Module: m, 3917 Providers: map[string]ResourceProviderFactory{ 3918 "aws": testProviderFuncFixed(p), 3919 }, 3920 State: s, 3921 }) 3922 3923 if _, err := ctx.Plan(); err != nil { 3924 t.Fatalf("err: %s", err) 3925 } 3926 3927 state, err := ctx.Apply() 3928 if err != nil { 3929 t.Fatalf("err: %s", err) 3930 } 3931 3932 actual := strings.TrimSpace(state.String()) 3933 expected := strings.TrimSpace(testTerraformApplyCountTaintedStr) 3934 if actual != expected { 3935 t.Fatalf("bad: \n%s", actual) 3936 } 3937 } 3938 3939 func TestContext2Apply_countVariable(t *testing.T) { 3940 m := testModule(t, "apply-count-variable") 3941 p := testProvider("aws") 3942 p.ApplyFn = testApplyFn 3943 p.DiffFn = testDiffFn 3944 ctx := testContext2(t, &ContextOpts{ 3945 Module: m, 3946 Providers: map[string]ResourceProviderFactory{ 3947 "aws": testProviderFuncFixed(p), 3948 }, 3949 }) 3950 3951 if _, err := ctx.Plan(); err != nil { 3952 t.Fatalf("err: %s", err) 3953 } 3954 3955 state, err := ctx.Apply() 3956 if err != nil { 3957 t.Fatalf("err: %s", err) 3958 } 3959 3960 actual := strings.TrimSpace(state.String()) 3961 expected := strings.TrimSpace(testTerraformApplyCountVariableStr) 3962 if actual != expected { 3963 t.Fatalf("bad: \n%s", actual) 3964 } 3965 } 3966 3967 func TestContext2Apply_module(t *testing.T) { 3968 m := testModule(t, "apply-module") 3969 p := testProvider("aws") 3970 p.ApplyFn = testApplyFn 3971 p.DiffFn = testDiffFn 3972 ctx := testContext2(t, &ContextOpts{ 3973 Module: m, 3974 Providers: map[string]ResourceProviderFactory{ 3975 "aws": testProviderFuncFixed(p), 3976 }, 3977 }) 3978 3979 if _, err := ctx.Plan(); err != nil { 3980 t.Fatalf("err: %s", err) 3981 } 3982 3983 state, err := ctx.Apply() 3984 if err != nil { 3985 t.Fatalf("err: %s", err) 3986 } 3987 3988 actual := strings.TrimSpace(state.String()) 3989 expected := strings.TrimSpace(testTerraformApplyModuleStr) 3990 if actual != expected { 3991 t.Fatalf("bad: \n%s", actual) 3992 } 3993 } 3994 3995 func TestContext2Apply_moduleVarResourceCount(t *testing.T) { 3996 m := testModule(t, "apply-module-var-resource-count") 3997 p := testProvider("aws") 3998 p.ApplyFn = testApplyFn 3999 p.DiffFn = testDiffFn 4000 ctx := testContext2(t, &ContextOpts{ 4001 Module: m, 4002 Providers: map[string]ResourceProviderFactory{ 4003 "aws": testProviderFuncFixed(p), 4004 }, 4005 Variables: map[string]string{ 4006 "count": "2", 4007 }, 4008 Destroy: true, 4009 }) 4010 4011 if _, err := ctx.Plan(); err != nil { 4012 t.Fatalf("err: %s", err) 4013 } 4014 4015 if _, err := ctx.Apply(); err != nil { 4016 t.Fatalf("err: %s", err) 4017 } 4018 4019 ctx = testContext2(t, &ContextOpts{ 4020 Module: m, 4021 Providers: map[string]ResourceProviderFactory{ 4022 "aws": testProviderFuncFixed(p), 4023 }, 4024 Variables: map[string]string{ 4025 "count": "5", 4026 }, 4027 }) 4028 4029 if _, err := ctx.Plan(); err != nil { 4030 t.Fatalf("err: %s", err) 4031 } 4032 4033 if _, err := ctx.Apply(); err != nil { 4034 t.Fatalf("err: %s", err) 4035 } 4036 } 4037 4038 // GH-819 4039 func TestContext2Apply_moduleBool(t *testing.T) { 4040 m := testModule(t, "apply-module-bool") 4041 p := testProvider("aws") 4042 p.ApplyFn = testApplyFn 4043 p.DiffFn = testDiffFn 4044 ctx := testContext2(t, &ContextOpts{ 4045 Module: m, 4046 Providers: map[string]ResourceProviderFactory{ 4047 "aws": testProviderFuncFixed(p), 4048 }, 4049 }) 4050 4051 if _, err := ctx.Plan(); err != nil { 4052 t.Fatalf("err: %s", err) 4053 } 4054 4055 state, err := ctx.Apply() 4056 if err != nil { 4057 t.Fatalf("err: %s", err) 4058 } 4059 4060 actual := strings.TrimSpace(state.String()) 4061 expected := strings.TrimSpace(testTerraformApplyModuleBoolStr) 4062 if actual != expected { 4063 t.Fatalf("bad: \n%s", actual) 4064 } 4065 } 4066 4067 func TestContext2Apply_multiProvider(t *testing.T) { 4068 m := testModule(t, "apply-multi-provider") 4069 p := testProvider("aws") 4070 p.ApplyFn = testApplyFn 4071 p.DiffFn = testDiffFn 4072 4073 pDO := testProvider("do") 4074 pDO.ApplyFn = testApplyFn 4075 pDO.DiffFn = testDiffFn 4076 4077 ctx := testContext2(t, &ContextOpts{ 4078 Module: m, 4079 Providers: map[string]ResourceProviderFactory{ 4080 "aws": testProviderFuncFixed(p), 4081 "do": testProviderFuncFixed(pDO), 4082 }, 4083 }) 4084 4085 if _, err := ctx.Plan(); err != nil { 4086 t.Fatalf("err: %s", err) 4087 } 4088 4089 state, err := ctx.Apply() 4090 if err != nil { 4091 t.Fatalf("err: %s", err) 4092 } 4093 4094 mod := state.RootModule() 4095 if len(mod.Resources) < 2 { 4096 t.Fatalf("bad: %#v", mod.Resources) 4097 } 4098 4099 actual := strings.TrimSpace(state.String()) 4100 expected := strings.TrimSpace(testTerraformApplyMultiProviderStr) 4101 if actual != expected { 4102 t.Fatalf("bad: \n%s", actual) 4103 } 4104 } 4105 4106 func TestContext2Apply_nilDiff(t *testing.T) { 4107 m := testModule(t, "apply-good") 4108 p := testProvider("aws") 4109 p.ApplyFn = testApplyFn 4110 p.DiffFn = testDiffFn 4111 ctx := testContext2(t, &ContextOpts{ 4112 Module: m, 4113 Providers: map[string]ResourceProviderFactory{ 4114 "aws": testProviderFuncFixed(p), 4115 }, 4116 }) 4117 4118 if _, err := ctx.Plan(); err != nil { 4119 t.Fatalf("err: %s", err) 4120 } 4121 4122 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 4123 return nil, nil 4124 } 4125 4126 if _, err := ctx.Apply(); err == nil { 4127 t.Fatal("should error") 4128 } 4129 } 4130 4131 func TestContext2Apply_Provisioner_compute(t *testing.T) { 4132 m := testModule(t, "apply-provisioner-compute") 4133 p := testProvider("aws") 4134 pr := testProvisioner() 4135 p.ApplyFn = testApplyFn 4136 p.DiffFn = testDiffFn 4137 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4138 val, ok := c.Config["foo"] 4139 if !ok || val != "computed_dynamical" { 4140 t.Fatalf("bad value for foo: %v %#v", val, c) 4141 } 4142 4143 return nil 4144 } 4145 ctx := testContext2(t, &ContextOpts{ 4146 Module: m, 4147 Providers: map[string]ResourceProviderFactory{ 4148 "aws": testProviderFuncFixed(p), 4149 }, 4150 Provisioners: map[string]ResourceProvisionerFactory{ 4151 "shell": testProvisionerFuncFixed(pr), 4152 }, 4153 Variables: map[string]string{ 4154 "value": "1", 4155 }, 4156 }) 4157 4158 if _, err := ctx.Plan(); err != nil { 4159 t.Fatalf("err: %s", err) 4160 } 4161 4162 state, err := ctx.Apply() 4163 if err != nil { 4164 t.Fatalf("err: %s", err) 4165 } 4166 4167 actual := strings.TrimSpace(state.String()) 4168 expected := strings.TrimSpace(testTerraformApplyProvisionerStr) 4169 if actual != expected { 4170 t.Fatalf("bad: \n%s", actual) 4171 } 4172 4173 // Verify apply was invoked 4174 if !pr.ApplyCalled { 4175 t.Fatalf("provisioner not invoked") 4176 } 4177 } 4178 4179 func TestContext2Apply_provisionerCreateFail(t *testing.T) { 4180 m := testModule(t, "apply-provisioner-fail-create") 4181 p := testProvider("aws") 4182 pr := testProvisioner() 4183 p.DiffFn = testDiffFn 4184 4185 p.ApplyFn = func( 4186 info *InstanceInfo, 4187 is *InstanceState, 4188 id *InstanceDiff) (*InstanceState, error) { 4189 is.ID = "foo" 4190 return is, fmt.Errorf("error") 4191 } 4192 4193 ctx := testContext2(t, &ContextOpts{ 4194 Module: m, 4195 Providers: map[string]ResourceProviderFactory{ 4196 "aws": testProviderFuncFixed(p), 4197 }, 4198 Provisioners: map[string]ResourceProvisionerFactory{ 4199 "shell": testProvisionerFuncFixed(pr), 4200 }, 4201 }) 4202 4203 if _, err := ctx.Plan(); err != nil { 4204 t.Fatalf("err: %s", err) 4205 } 4206 4207 state, err := ctx.Apply() 4208 if err == nil { 4209 t.Fatal("should error") 4210 } 4211 4212 actual := strings.TrimSpace(state.String()) 4213 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateStr) 4214 if actual != expected { 4215 t.Fatalf("bad: \n%s", actual) 4216 } 4217 } 4218 4219 func TestContext2Apply_provisionerCreateFailNoId(t *testing.T) { 4220 m := testModule(t, "apply-provisioner-fail-create") 4221 p := testProvider("aws") 4222 pr := testProvisioner() 4223 p.DiffFn = testDiffFn 4224 4225 p.ApplyFn = func( 4226 info *InstanceInfo, 4227 is *InstanceState, 4228 id *InstanceDiff) (*InstanceState, error) { 4229 return nil, fmt.Errorf("error") 4230 } 4231 4232 ctx := testContext2(t, &ContextOpts{ 4233 Module: m, 4234 Providers: map[string]ResourceProviderFactory{ 4235 "aws": testProviderFuncFixed(p), 4236 }, 4237 Provisioners: map[string]ResourceProvisionerFactory{ 4238 "shell": testProvisionerFuncFixed(pr), 4239 }, 4240 }) 4241 4242 if _, err := ctx.Plan(); err != nil { 4243 t.Fatalf("err: %s", err) 4244 } 4245 4246 state, err := ctx.Apply() 4247 if err == nil { 4248 t.Fatal("should error") 4249 } 4250 4251 actual := strings.TrimSpace(state.String()) 4252 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateNoIdStr) 4253 if actual != expected { 4254 t.Fatalf("bad: \n%s", actual) 4255 } 4256 } 4257 4258 func TestContext2Apply_provisionerFail(t *testing.T) { 4259 m := testModule(t, "apply-provisioner-fail") 4260 p := testProvider("aws") 4261 pr := testProvisioner() 4262 p.ApplyFn = testApplyFn 4263 p.DiffFn = testDiffFn 4264 4265 pr.ApplyFn = func(*InstanceState, *ResourceConfig) error { 4266 return fmt.Errorf("EXPLOSION") 4267 } 4268 4269 ctx := testContext2(t, &ContextOpts{ 4270 Module: m, 4271 Providers: map[string]ResourceProviderFactory{ 4272 "aws": testProviderFuncFixed(p), 4273 }, 4274 Provisioners: map[string]ResourceProvisionerFactory{ 4275 "shell": testProvisionerFuncFixed(pr), 4276 }, 4277 Variables: map[string]string{ 4278 "value": "1", 4279 }, 4280 }) 4281 4282 if _, err := ctx.Plan(); err != nil { 4283 t.Fatalf("err: %s", err) 4284 } 4285 4286 state, err := ctx.Apply() 4287 if err == nil { 4288 t.Fatal("should error") 4289 } 4290 4291 actual := strings.TrimSpace(state.String()) 4292 expected := strings.TrimSpace(testTerraformApplyProvisionerFailStr) 4293 if actual != expected { 4294 t.Fatalf("bad: \n%s", actual) 4295 } 4296 } 4297 4298 func TestContext2Apply_provisionerFail_createBeforeDestroy(t *testing.T) { 4299 m := testModule(t, "apply-provisioner-fail-create-before") 4300 p := testProvider("aws") 4301 pr := testProvisioner() 4302 p.ApplyFn = testApplyFn 4303 p.DiffFn = testDiffFn 4304 pr.ApplyFn = func(*InstanceState, *ResourceConfig) error { 4305 return fmt.Errorf("EXPLOSION") 4306 } 4307 4308 state := &State{ 4309 Modules: []*ModuleState{ 4310 &ModuleState{ 4311 Path: rootModulePath, 4312 Resources: map[string]*ResourceState{ 4313 "aws_instance.bar": &ResourceState{ 4314 Type: "aws_instance", 4315 Primary: &InstanceState{ 4316 ID: "bar", 4317 Attributes: map[string]string{ 4318 "require_new": "abc", 4319 }, 4320 }, 4321 }, 4322 }, 4323 }, 4324 }, 4325 } 4326 ctx := testContext2(t, &ContextOpts{ 4327 Module: m, 4328 Providers: map[string]ResourceProviderFactory{ 4329 "aws": testProviderFuncFixed(p), 4330 }, 4331 Provisioners: map[string]ResourceProvisionerFactory{ 4332 "shell": testProvisionerFuncFixed(pr), 4333 }, 4334 State: state, 4335 }) 4336 4337 if _, err := ctx.Plan(); err != nil { 4338 t.Fatalf("err: %s", err) 4339 } 4340 4341 state, err := ctx.Apply() 4342 if err == nil { 4343 t.Fatal("should error") 4344 } 4345 4346 actual := strings.TrimSpace(state.String()) 4347 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateBeforeDestroyStr) 4348 if actual != expected { 4349 t.Fatalf("bad: \n%s", actual) 4350 } 4351 } 4352 4353 func TestContext2Apply_error_createBeforeDestroy(t *testing.T) { 4354 m := testModule(t, "apply-error-create-before") 4355 p := testProvider("aws") 4356 state := &State{ 4357 Modules: []*ModuleState{ 4358 &ModuleState{ 4359 Path: rootModulePath, 4360 Resources: map[string]*ResourceState{ 4361 "aws_instance.bar": &ResourceState{ 4362 Type: "aws_instance", 4363 Primary: &InstanceState{ 4364 ID: "bar", 4365 Attributes: map[string]string{ 4366 "require_new": "abc", 4367 }, 4368 }, 4369 }, 4370 }, 4371 }, 4372 }, 4373 } 4374 ctx := testContext2(t, &ContextOpts{ 4375 Module: m, 4376 Providers: map[string]ResourceProviderFactory{ 4377 "aws": testProviderFuncFixed(p), 4378 }, 4379 State: state, 4380 }) 4381 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 4382 return nil, fmt.Errorf("error") 4383 } 4384 p.DiffFn = testDiffFn 4385 4386 if _, err := ctx.Plan(); err != nil { 4387 t.Fatalf("err: %s", err) 4388 } 4389 4390 state, err := ctx.Apply() 4391 if err == nil { 4392 t.Fatal("should have error") 4393 } 4394 4395 actual := strings.TrimSpace(state.String()) 4396 expected := strings.TrimSpace(testTerraformApplyErrorCreateBeforeDestroyStr) 4397 if actual != expected { 4398 t.Fatalf("bad: \n%s\n\nExpected:\n\n%s", actual, expected) 4399 } 4400 } 4401 4402 func TestContext2Apply_errorDestroy_createBeforeDestroy(t *testing.T) { 4403 m := testModule(t, "apply-error-create-before") 4404 p := testProvider("aws") 4405 state := &State{ 4406 Modules: []*ModuleState{ 4407 &ModuleState{ 4408 Path: rootModulePath, 4409 Resources: map[string]*ResourceState{ 4410 "aws_instance.bar": &ResourceState{ 4411 Type: "aws_instance", 4412 Primary: &InstanceState{ 4413 ID: "bar", 4414 Attributes: map[string]string{ 4415 "require_new": "abc", 4416 }, 4417 }, 4418 }, 4419 }, 4420 }, 4421 }, 4422 } 4423 ctx := testContext2(t, &ContextOpts{ 4424 Module: m, 4425 Providers: map[string]ResourceProviderFactory{ 4426 "aws": testProviderFuncFixed(p), 4427 }, 4428 State: state, 4429 }) 4430 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 4431 // Fail the destroy! 4432 if id.Destroy { 4433 return is, fmt.Errorf("error") 4434 } 4435 4436 // Create should work 4437 is = &InstanceState{ 4438 ID: "foo", 4439 } 4440 return is, nil 4441 } 4442 p.DiffFn = testDiffFn 4443 4444 if _, err := ctx.Plan(); err != nil { 4445 t.Fatalf("err: %s", err) 4446 } 4447 4448 state, err := ctx.Apply() 4449 if err == nil { 4450 t.Fatal("should have error") 4451 } 4452 4453 actual := strings.TrimSpace(state.String()) 4454 expected := strings.TrimSpace(testTerraformApplyErrorDestroyCreateBeforeDestroyStr) 4455 if actual != expected { 4456 t.Fatalf("bad: actual:\n%s\n\nexpected:\n%s", actual, expected) 4457 } 4458 } 4459 4460 func TestContext2Apply_multiDepose_createBeforeDestroy(t *testing.T) { 4461 m := testModule(t, "apply-multi-depose-create-before-destroy") 4462 p := testProvider("aws") 4463 p.DiffFn = testDiffFn 4464 ps := map[string]ResourceProviderFactory{"aws": testProviderFuncFixed(p)} 4465 state := &State{ 4466 Modules: []*ModuleState{ 4467 &ModuleState{ 4468 Path: rootModulePath, 4469 Resources: map[string]*ResourceState{ 4470 "aws_instance.web": &ResourceState{ 4471 Type: "aws_instance", 4472 Primary: &InstanceState{ID: "foo"}, 4473 }, 4474 }, 4475 }, 4476 }, 4477 } 4478 4479 ctx := testContext2(t, &ContextOpts{ 4480 Module: m, 4481 Providers: ps, 4482 State: state, 4483 }) 4484 createdInstanceId := "bar" 4485 // Create works 4486 createFunc := func(is *InstanceState) (*InstanceState, error) { 4487 return &InstanceState{ID: createdInstanceId}, nil 4488 } 4489 // Destroy starts broken 4490 destroyFunc := func(is *InstanceState) (*InstanceState, error) { 4491 return is, fmt.Errorf("destroy failed") 4492 } 4493 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 4494 if id.Destroy { 4495 return destroyFunc(is) 4496 } else { 4497 return createFunc(is) 4498 } 4499 } 4500 4501 if _, err := ctx.Plan(); err != nil { 4502 t.Fatalf("err: %s", err) 4503 } 4504 4505 // Destroy is broken, so even though CBD successfully replaces the instance, 4506 // we'll have to save the Deposed instance to destroy later 4507 state, err := ctx.Apply() 4508 if err == nil { 4509 t.Fatal("should have error") 4510 } 4511 4512 checkStateString(t, state, ` 4513 aws_instance.web: (1 deposed) 4514 ID = bar 4515 Deposed ID 1 = foo 4516 `) 4517 4518 createdInstanceId = "baz" 4519 ctx = testContext2(t, &ContextOpts{ 4520 Module: m, 4521 Providers: ps, 4522 State: state, 4523 }) 4524 4525 if _, err := ctx.Plan(); err != nil { 4526 t.Fatalf("err: %s", err) 4527 } 4528 4529 // We're replacing the primary instance once again. Destroy is _still_ 4530 // broken, so the Deposed list gets longer 4531 state, err = ctx.Apply() 4532 if err == nil { 4533 t.Fatal("should have error") 4534 } 4535 4536 checkStateString(t, state, ` 4537 aws_instance.web: (2 deposed) 4538 ID = baz 4539 Deposed ID 1 = foo 4540 Deposed ID 2 = bar 4541 `) 4542 4543 // Destroy partially fixed! 4544 destroyFunc = func(is *InstanceState) (*InstanceState, error) { 4545 if is.ID == "foo" || is.ID == "baz" { 4546 return nil, nil 4547 } else { 4548 return is, fmt.Errorf("destroy partially failed") 4549 } 4550 } 4551 4552 createdInstanceId = "qux" 4553 if _, err := ctx.Plan(); err != nil { 4554 t.Fatalf("err: %s", err) 4555 } 4556 state, err = ctx.Apply() 4557 // Expect error because 1/2 of Deposed destroys failed 4558 if err == nil { 4559 t.Fatal("should have error") 4560 } 4561 4562 // foo and baz are now gone, bar sticks around 4563 checkStateString(t, state, ` 4564 aws_instance.web: (1 deposed) 4565 ID = qux 4566 Deposed ID 1 = bar 4567 `) 4568 4569 // Destroy working fully! 4570 destroyFunc = func(is *InstanceState) (*InstanceState, error) { 4571 return nil, nil 4572 } 4573 4574 createdInstanceId = "quux" 4575 if _, err := ctx.Plan(); err != nil { 4576 t.Fatalf("err: %s", err) 4577 } 4578 state, err = ctx.Apply() 4579 if err != nil { 4580 t.Fatal("should not have error:", err) 4581 } 4582 4583 // And finally the state is clean 4584 checkStateString(t, state, ` 4585 aws_instance.web: 4586 ID = quux 4587 `) 4588 } 4589 4590 func TestContext2Apply_provisionerResourceRef(t *testing.T) { 4591 m := testModule(t, "apply-provisioner-resource-ref") 4592 p := testProvider("aws") 4593 pr := testProvisioner() 4594 p.ApplyFn = testApplyFn 4595 p.DiffFn = testDiffFn 4596 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4597 val, ok := c.Config["foo"] 4598 if !ok || val != "2" { 4599 t.Fatalf("bad value for foo: %v %#v", val, c) 4600 } 4601 4602 return nil 4603 } 4604 4605 ctx := testContext2(t, &ContextOpts{ 4606 Module: m, 4607 Providers: map[string]ResourceProviderFactory{ 4608 "aws": testProviderFuncFixed(p), 4609 }, 4610 Provisioners: map[string]ResourceProvisionerFactory{ 4611 "shell": testProvisionerFuncFixed(pr), 4612 }, 4613 }) 4614 4615 if _, err := ctx.Plan(); err != nil { 4616 t.Fatalf("err: %s", err) 4617 } 4618 4619 state, err := ctx.Apply() 4620 if err != nil { 4621 t.Fatalf("err: %s", err) 4622 } 4623 4624 actual := strings.TrimSpace(state.String()) 4625 expected := strings.TrimSpace(testTerraformApplyProvisionerResourceRefStr) 4626 if actual != expected { 4627 t.Fatalf("bad: \n%s", actual) 4628 } 4629 4630 // Verify apply was invoked 4631 if !pr.ApplyCalled { 4632 t.Fatalf("provisioner not invoked") 4633 } 4634 } 4635 4636 func TestContext2Apply_provisionerSelfRef(t *testing.T) { 4637 m := testModule(t, "apply-provisioner-self-ref") 4638 p := testProvider("aws") 4639 pr := testProvisioner() 4640 p.ApplyFn = testApplyFn 4641 p.DiffFn = testDiffFn 4642 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4643 val, ok := c.Config["command"] 4644 if !ok || val != "bar" { 4645 t.Fatalf("bad value for command: %v %#v", val, c) 4646 } 4647 4648 return nil 4649 } 4650 4651 ctx := testContext2(t, &ContextOpts{ 4652 Module: m, 4653 Providers: map[string]ResourceProviderFactory{ 4654 "aws": testProviderFuncFixed(p), 4655 }, 4656 Provisioners: map[string]ResourceProvisionerFactory{ 4657 "shell": testProvisionerFuncFixed(pr), 4658 }, 4659 }) 4660 4661 if _, err := ctx.Plan(); err != nil { 4662 t.Fatalf("err: %s", err) 4663 } 4664 4665 state, err := ctx.Apply() 4666 if err != nil { 4667 t.Fatalf("err: %s", err) 4668 } 4669 4670 actual := strings.TrimSpace(state.String()) 4671 expected := strings.TrimSpace(testTerraformApplyProvisionerSelfRefStr) 4672 if actual != expected { 4673 t.Fatalf("bad: \n%s", actual) 4674 } 4675 4676 // Verify apply was invoked 4677 if !pr.ApplyCalled { 4678 t.Fatalf("provisioner not invoked") 4679 } 4680 } 4681 4682 func TestContext2Apply_provisionerMultiSelfRef(t *testing.T) { 4683 var lock sync.Mutex 4684 commands := make([]string, 0, 5) 4685 4686 m := testModule(t, "apply-provisioner-multi-self-ref") 4687 p := testProvider("aws") 4688 pr := testProvisioner() 4689 p.ApplyFn = testApplyFn 4690 p.DiffFn = testDiffFn 4691 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4692 lock.Lock() 4693 defer lock.Unlock() 4694 4695 val, ok := c.Config["command"] 4696 if !ok { 4697 t.Fatalf("bad value for command: %v %#v", val, c) 4698 } 4699 4700 commands = append(commands, val.(string)) 4701 return nil 4702 } 4703 4704 ctx := testContext2(t, &ContextOpts{ 4705 Module: m, 4706 Providers: map[string]ResourceProviderFactory{ 4707 "aws": testProviderFuncFixed(p), 4708 }, 4709 Provisioners: map[string]ResourceProvisionerFactory{ 4710 "shell": testProvisionerFuncFixed(pr), 4711 }, 4712 }) 4713 4714 if _, err := ctx.Plan(); err != nil { 4715 t.Fatalf("err: %s", err) 4716 } 4717 4718 state, err := ctx.Apply() 4719 if err != nil { 4720 t.Fatalf("err: %s", err) 4721 } 4722 4723 actual := strings.TrimSpace(state.String()) 4724 expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefStr) 4725 if actual != expected { 4726 t.Fatalf("bad: \n%s", actual) 4727 } 4728 4729 // Verify apply was invoked 4730 if !pr.ApplyCalled { 4731 t.Fatalf("provisioner not invoked") 4732 } 4733 4734 // Verify our result 4735 sort.Strings(commands) 4736 expectedCommands := []string{"number 0", "number 1", "number 2"} 4737 if !reflect.DeepEqual(commands, expectedCommands) { 4738 t.Fatalf("bad: %#v", commands) 4739 } 4740 } 4741 4742 // Provisioner should NOT run on a diff, only create 4743 func TestContext2Apply_Provisioner_Diff(t *testing.T) { 4744 m := testModule(t, "apply-provisioner-diff") 4745 p := testProvider("aws") 4746 pr := testProvisioner() 4747 p.ApplyFn = testApplyFn 4748 p.DiffFn = testDiffFn 4749 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4750 return nil 4751 } 4752 ctx := testContext2(t, &ContextOpts{ 4753 Module: m, 4754 Providers: map[string]ResourceProviderFactory{ 4755 "aws": testProviderFuncFixed(p), 4756 }, 4757 Provisioners: map[string]ResourceProvisionerFactory{ 4758 "shell": testProvisionerFuncFixed(pr), 4759 }, 4760 }) 4761 4762 if _, err := ctx.Plan(); err != nil { 4763 t.Fatalf("err: %s", err) 4764 } 4765 4766 state, err := ctx.Apply() 4767 if err != nil { 4768 t.Fatalf("err: %s", err) 4769 } 4770 4771 actual := strings.TrimSpace(state.String()) 4772 expected := strings.TrimSpace(testTerraformApplyProvisionerDiffStr) 4773 if actual != expected { 4774 t.Fatalf("bad: \n%s", actual) 4775 } 4776 4777 // Verify apply was invoked 4778 if !pr.ApplyCalled { 4779 t.Fatalf("provisioner not invoked") 4780 } 4781 pr.ApplyCalled = false 4782 4783 // Change the state to force a diff 4784 mod := state.RootModule() 4785 mod.Resources["aws_instance.bar"].Primary.Attributes["foo"] = "baz" 4786 4787 // Re-create context with state 4788 ctx = testContext2(t, &ContextOpts{ 4789 Module: m, 4790 Providers: map[string]ResourceProviderFactory{ 4791 "aws": testProviderFuncFixed(p), 4792 }, 4793 Provisioners: map[string]ResourceProvisionerFactory{ 4794 "shell": testProvisionerFuncFixed(pr), 4795 }, 4796 State: state, 4797 }) 4798 4799 if _, err := ctx.Plan(); err != nil { 4800 t.Fatalf("err: %s", err) 4801 } 4802 4803 state2, err := ctx.Apply() 4804 if err != nil { 4805 t.Fatalf("err: %s", err) 4806 } 4807 4808 actual = strings.TrimSpace(state2.String()) 4809 if actual != expected { 4810 t.Fatalf("bad: \n%s", actual) 4811 } 4812 4813 // Verify apply was NOT invoked 4814 if pr.ApplyCalled { 4815 t.Fatalf("provisioner invoked") 4816 } 4817 } 4818 4819 func TestContext2Apply_outputDiffVars(t *testing.T) { 4820 m := testModule(t, "apply-good") 4821 p := testProvider("aws") 4822 s := &State{ 4823 Modules: []*ModuleState{ 4824 &ModuleState{ 4825 Path: rootModulePath, 4826 Resources: map[string]*ResourceState{ 4827 "aws_instance.baz": &ResourceState{ 4828 Type: "aws_instance", 4829 Primary: &InstanceState{ 4830 ID: "bar", 4831 }, 4832 }, 4833 }, 4834 }, 4835 }, 4836 } 4837 ctx := testContext2(t, &ContextOpts{ 4838 Module: m, 4839 Providers: map[string]ResourceProviderFactory{ 4840 "aws": testProviderFuncFixed(p), 4841 }, 4842 State: s, 4843 }) 4844 4845 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 4846 for k, ad := range d.Attributes { 4847 if ad.NewComputed { 4848 return nil, fmt.Errorf("%s: computed", k) 4849 } 4850 } 4851 4852 result := s.MergeDiff(d) 4853 result.ID = "foo" 4854 return result, nil 4855 } 4856 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 4857 return &InstanceDiff{ 4858 Attributes: map[string]*ResourceAttrDiff{ 4859 "foo": &ResourceAttrDiff{ 4860 NewComputed: true, 4861 Type: DiffAttrOutput, 4862 }, 4863 "bar": &ResourceAttrDiff{ 4864 New: "baz", 4865 }, 4866 }, 4867 }, nil 4868 } 4869 4870 if _, err := ctx.Plan(); err != nil { 4871 t.Fatalf("err: %s", err) 4872 } 4873 if _, err := ctx.Apply(); err != nil { 4874 t.Fatalf("err: %s", err) 4875 } 4876 } 4877 4878 func TestContext2Apply_Provisioner_ConnInfo(t *testing.T) { 4879 m := testModule(t, "apply-provisioner-conninfo") 4880 p := testProvider("aws") 4881 pr := testProvisioner() 4882 4883 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 4884 if s.Ephemeral.ConnInfo == nil { 4885 t.Fatalf("ConnInfo not initialized") 4886 } 4887 4888 result, _ := testApplyFn(info, s, d) 4889 result.Ephemeral.ConnInfo = map[string]string{ 4890 "type": "ssh", 4891 "host": "127.0.0.1", 4892 "port": "22", 4893 } 4894 return result, nil 4895 } 4896 p.DiffFn = testDiffFn 4897 4898 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4899 conn := rs.Ephemeral.ConnInfo 4900 if conn["type"] != "telnet" { 4901 t.Fatalf("Bad: %#v", conn) 4902 } 4903 if conn["host"] != "127.0.0.1" { 4904 t.Fatalf("Bad: %#v", conn) 4905 } 4906 if conn["port"] != "2222" { 4907 t.Fatalf("Bad: %#v", conn) 4908 } 4909 if conn["user"] != "superuser" { 4910 t.Fatalf("Bad: %#v", conn) 4911 } 4912 if conn["pass"] != "test" { 4913 t.Fatalf("Bad: %#v", conn) 4914 } 4915 4916 return nil 4917 } 4918 4919 ctx := testContext2(t, &ContextOpts{ 4920 Module: m, 4921 Providers: map[string]ResourceProviderFactory{ 4922 "aws": testProviderFuncFixed(p), 4923 }, 4924 Provisioners: map[string]ResourceProvisionerFactory{ 4925 "shell": testProvisionerFuncFixed(pr), 4926 }, 4927 Variables: map[string]string{ 4928 "value": "1", 4929 "pass": "test", 4930 }, 4931 }) 4932 4933 if _, err := ctx.Plan(); err != nil { 4934 t.Fatalf("err: %s", err) 4935 } 4936 4937 state, err := ctx.Apply() 4938 if err != nil { 4939 t.Fatalf("err: %s", err) 4940 } 4941 4942 actual := strings.TrimSpace(state.String()) 4943 expected := strings.TrimSpace(testTerraformApplyProvisionerStr) 4944 if actual != expected { 4945 t.Fatalf("bad: \n%s", actual) 4946 } 4947 4948 // Verify apply was invoked 4949 if !pr.ApplyCalled { 4950 t.Fatalf("provisioner not invoked") 4951 } 4952 } 4953 4954 func TestContext2Apply_destroy(t *testing.T) { 4955 m := testModule(t, "apply-destroy") 4956 h := new(HookRecordApplyOrder) 4957 p := testProvider("aws") 4958 p.ApplyFn = testApplyFn 4959 p.DiffFn = testDiffFn 4960 ctx := testContext2(t, &ContextOpts{ 4961 Module: m, 4962 Hooks: []Hook{h}, 4963 Providers: map[string]ResourceProviderFactory{ 4964 "aws": testProviderFuncFixed(p), 4965 }, 4966 }) 4967 4968 // First plan and apply a create operation 4969 if _, err := ctx.Plan(); err != nil { 4970 t.Fatalf("err: %s", err) 4971 } 4972 4973 state, err := ctx.Apply() 4974 if err != nil { 4975 t.Fatalf("err: %s", err) 4976 } 4977 4978 // Next, plan and apply a destroy operation 4979 h.Active = true 4980 ctx = testContext2(t, &ContextOpts{ 4981 Destroy: true, 4982 State: state, 4983 Module: m, 4984 Hooks: []Hook{h}, 4985 Providers: map[string]ResourceProviderFactory{ 4986 "aws": testProviderFuncFixed(p), 4987 }, 4988 }) 4989 4990 if _, err := ctx.Plan(); err != nil { 4991 t.Fatalf("err: %s", err) 4992 } 4993 4994 state, err = ctx.Apply() 4995 if err != nil { 4996 t.Fatalf("err: %s", err) 4997 } 4998 4999 // Test that things were destroyed 5000 actual := strings.TrimSpace(state.String()) 5001 expected := strings.TrimSpace(testTerraformApplyDestroyStr) 5002 if actual != expected { 5003 t.Fatalf("bad: \n%s", actual) 5004 } 5005 5006 // Test that things were destroyed _in the right order_ 5007 expected2 := []string{"aws_instance.bar", "aws_instance.foo"} 5008 actual2 := h.IDs 5009 if !reflect.DeepEqual(actual2, expected2) { 5010 t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2) 5011 } 5012 } 5013 5014 func TestContext2Apply_destroyOutputs(t *testing.T) { 5015 m := testModule(t, "apply-destroy-outputs") 5016 h := new(HookRecordApplyOrder) 5017 p := testProvider("aws") 5018 p.ApplyFn = testApplyFn 5019 p.DiffFn = testDiffFn 5020 ctx := testContext2(t, &ContextOpts{ 5021 Module: m, 5022 Hooks: []Hook{h}, 5023 Providers: map[string]ResourceProviderFactory{ 5024 "aws": testProviderFuncFixed(p), 5025 }, 5026 }) 5027 5028 // First plan and apply a create operation 5029 if _, err := ctx.Plan(); err != nil { 5030 t.Fatalf("err: %s", err) 5031 } 5032 5033 state, err := ctx.Apply() 5034 5035 if err != nil { 5036 t.Fatalf("err: %s", err) 5037 } 5038 5039 // Next, plan and apply a destroy operation 5040 h.Active = true 5041 ctx = testContext2(t, &ContextOpts{ 5042 Destroy: true, 5043 State: state, 5044 Module: m, 5045 Hooks: []Hook{h}, 5046 Providers: map[string]ResourceProviderFactory{ 5047 "aws": testProviderFuncFixed(p), 5048 }, 5049 }) 5050 5051 if _, err := ctx.Plan(); err != nil { 5052 t.Fatalf("err: %s", err) 5053 } 5054 5055 state, err = ctx.Apply() 5056 if err != nil { 5057 t.Fatalf("err: %s", err) 5058 } 5059 5060 mod := state.RootModule() 5061 if len(mod.Resources) > 0 { 5062 t.Fatalf("bad: %#v", mod) 5063 } 5064 } 5065 5066 func TestContext2Apply_destroyOrphan(t *testing.T) { 5067 m := testModule(t, "apply-error") 5068 p := testProvider("aws") 5069 s := &State{ 5070 Modules: []*ModuleState{ 5071 &ModuleState{ 5072 Path: rootModulePath, 5073 Resources: map[string]*ResourceState{ 5074 "aws_instance.baz": &ResourceState{ 5075 Type: "aws_instance", 5076 Primary: &InstanceState{ 5077 ID: "bar", 5078 }, 5079 }, 5080 }, 5081 }, 5082 }, 5083 } 5084 ctx := testContext2(t, &ContextOpts{ 5085 Module: m, 5086 Providers: map[string]ResourceProviderFactory{ 5087 "aws": testProviderFuncFixed(p), 5088 }, 5089 State: s, 5090 }) 5091 5092 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 5093 if d.Destroy { 5094 return nil, nil 5095 } 5096 5097 result := s.MergeDiff(d) 5098 result.ID = "foo" 5099 return result, nil 5100 } 5101 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 5102 return &InstanceDiff{ 5103 Attributes: map[string]*ResourceAttrDiff{ 5104 "num": &ResourceAttrDiff{ 5105 New: "bar", 5106 }, 5107 }, 5108 }, nil 5109 } 5110 5111 if _, err := ctx.Plan(); err != nil { 5112 t.Fatalf("err: %s", err) 5113 } 5114 5115 state, err := ctx.Apply() 5116 if err != nil { 5117 t.Fatalf("err: %s", err) 5118 } 5119 5120 mod := state.RootModule() 5121 if _, ok := mod.Resources["aws_instance.baz"]; ok { 5122 t.Fatalf("bad: %#v", mod.Resources) 5123 } 5124 } 5125 5126 func TestContext2Apply_destroyTaintedProvisioner(t *testing.T) { 5127 m := testModule(t, "apply-destroy-provisioner") 5128 p := testProvider("aws") 5129 pr := testProvisioner() 5130 p.ApplyFn = testApplyFn 5131 p.DiffFn = testDiffFn 5132 5133 called := false 5134 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 5135 called = true 5136 return nil 5137 } 5138 5139 s := &State{ 5140 Modules: []*ModuleState{ 5141 &ModuleState{ 5142 Path: rootModulePath, 5143 Resources: map[string]*ResourceState{ 5144 "aws_instance.foo": &ResourceState{ 5145 Type: "aws_instance", 5146 Tainted: []*InstanceState{ 5147 &InstanceState{ 5148 ID: "bar", 5149 Attributes: map[string]string{ 5150 "id": "bar", 5151 }, 5152 }, 5153 }, 5154 }, 5155 }, 5156 }, 5157 }, 5158 } 5159 5160 ctx := testContext2(t, &ContextOpts{ 5161 Module: m, 5162 Providers: map[string]ResourceProviderFactory{ 5163 "aws": testProviderFuncFixed(p), 5164 }, 5165 Provisioners: map[string]ResourceProvisionerFactory{ 5166 "shell": testProvisionerFuncFixed(pr), 5167 }, 5168 State: s, 5169 Destroy: true, 5170 }) 5171 5172 if _, err := ctx.Plan(); err != nil { 5173 t.Fatalf("err: %s", err) 5174 } 5175 5176 state, err := ctx.Apply() 5177 if err != nil { 5178 t.Fatalf("err: %s", err) 5179 } 5180 5181 if called { 5182 t.Fatal("provisioner should not be called") 5183 } 5184 5185 actual := strings.TrimSpace(state.String()) 5186 expected := strings.TrimSpace("<no state>") 5187 if actual != expected { 5188 t.Fatalf("bad: \n%s", actual) 5189 } 5190 } 5191 5192 func TestContext2Apply_error(t *testing.T) { 5193 errored := false 5194 5195 m := testModule(t, "apply-error") 5196 p := testProvider("aws") 5197 ctx := testContext2(t, &ContextOpts{ 5198 Module: m, 5199 Providers: map[string]ResourceProviderFactory{ 5200 "aws": testProviderFuncFixed(p), 5201 }, 5202 }) 5203 5204 p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) { 5205 if errored { 5206 state := &InstanceState{ 5207 ID: "bar", 5208 } 5209 return state, fmt.Errorf("error") 5210 } 5211 errored = true 5212 5213 return &InstanceState{ 5214 ID: "foo", 5215 Attributes: map[string]string{ 5216 "num": "2", 5217 }, 5218 }, nil 5219 } 5220 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 5221 return &InstanceDiff{ 5222 Attributes: map[string]*ResourceAttrDiff{ 5223 "num": &ResourceAttrDiff{ 5224 New: "bar", 5225 }, 5226 }, 5227 }, nil 5228 } 5229 5230 if _, err := ctx.Plan(); err != nil { 5231 t.Fatalf("err: %s", err) 5232 } 5233 5234 state, err := ctx.Apply() 5235 if err == nil { 5236 t.Fatal("should have error") 5237 } 5238 5239 actual := strings.TrimSpace(state.String()) 5240 expected := strings.TrimSpace(testTerraformApplyErrorStr) 5241 if actual != expected { 5242 t.Fatalf("bad: \n%s", actual) 5243 } 5244 } 5245 5246 func TestContext2Apply_errorPartial(t *testing.T) { 5247 errored := false 5248 5249 m := testModule(t, "apply-error") 5250 p := testProvider("aws") 5251 s := &State{ 5252 Modules: []*ModuleState{ 5253 &ModuleState{ 5254 Path: rootModulePath, 5255 Resources: map[string]*ResourceState{ 5256 "aws_instance.bar": &ResourceState{ 5257 Type: "aws_instance", 5258 Primary: &InstanceState{ 5259 ID: "bar", 5260 }, 5261 }, 5262 }, 5263 }, 5264 }, 5265 } 5266 ctx := testContext2(t, &ContextOpts{ 5267 Module: m, 5268 Providers: map[string]ResourceProviderFactory{ 5269 "aws": testProviderFuncFixed(p), 5270 }, 5271 State: s, 5272 }) 5273 5274 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 5275 if errored { 5276 return s, fmt.Errorf("error") 5277 } 5278 errored = true 5279 5280 return &InstanceState{ 5281 ID: "foo", 5282 Attributes: map[string]string{ 5283 "num": "2", 5284 }, 5285 }, nil 5286 } 5287 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 5288 return &InstanceDiff{ 5289 Attributes: map[string]*ResourceAttrDiff{ 5290 "num": &ResourceAttrDiff{ 5291 New: "bar", 5292 }, 5293 }, 5294 }, nil 5295 } 5296 5297 if _, err := ctx.Plan(); err != nil { 5298 t.Fatalf("err: %s", err) 5299 } 5300 5301 state, err := ctx.Apply() 5302 if err == nil { 5303 t.Fatal("should have error") 5304 } 5305 5306 mod := state.RootModule() 5307 if len(mod.Resources) != 2 { 5308 t.Fatalf("bad: %#v", mod.Resources) 5309 } 5310 5311 actual := strings.TrimSpace(state.String()) 5312 expected := strings.TrimSpace(testTerraformApplyErrorPartialStr) 5313 if actual != expected { 5314 t.Fatalf("bad: \n%s", actual) 5315 } 5316 } 5317 5318 func TestContext2Apply_hook(t *testing.T) { 5319 m := testModule(t, "apply-good") 5320 h := new(MockHook) 5321 p := testProvider("aws") 5322 p.ApplyFn = testApplyFn 5323 p.DiffFn = testDiffFn 5324 ctx := testContext2(t, &ContextOpts{ 5325 Module: m, 5326 Hooks: []Hook{h}, 5327 Providers: map[string]ResourceProviderFactory{ 5328 "aws": testProviderFuncFixed(p), 5329 }, 5330 }) 5331 5332 if _, err := ctx.Plan(); err != nil { 5333 t.Fatalf("err: %s", err) 5334 } 5335 5336 if _, err := ctx.Apply(); err != nil { 5337 t.Fatalf("err: %s", err) 5338 } 5339 5340 if !h.PreApplyCalled { 5341 t.Fatal("should be called") 5342 } 5343 if !h.PostApplyCalled { 5344 t.Fatal("should be called") 5345 } 5346 if !h.PostStateUpdateCalled { 5347 t.Fatalf("should call post state update") 5348 } 5349 } 5350 5351 func TestContext2Apply_idAttr(t *testing.T) { 5352 m := testModule(t, "apply-idattr") 5353 p := testProvider("aws") 5354 ctx := testContext2(t, &ContextOpts{ 5355 Module: m, 5356 Providers: map[string]ResourceProviderFactory{ 5357 "aws": testProviderFuncFixed(p), 5358 }, 5359 }) 5360 5361 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 5362 result := s.MergeDiff(d) 5363 result.ID = "foo" 5364 result.Attributes = map[string]string{ 5365 "id": "bar", 5366 } 5367 5368 return result, nil 5369 } 5370 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 5371 return &InstanceDiff{ 5372 Attributes: map[string]*ResourceAttrDiff{ 5373 "num": &ResourceAttrDiff{ 5374 New: "bar", 5375 }, 5376 }, 5377 }, nil 5378 } 5379 5380 if _, err := ctx.Plan(); err != nil { 5381 t.Fatalf("err: %s", err) 5382 } 5383 5384 state, err := ctx.Apply() 5385 if err != nil { 5386 t.Fatalf("err: %s", err) 5387 } 5388 5389 mod := state.RootModule() 5390 rs, ok := mod.Resources["aws_instance.foo"] 5391 if !ok { 5392 t.Fatal("not in state") 5393 } 5394 if rs.Primary.ID != "foo" { 5395 t.Fatalf("bad: %#v", rs.Primary.ID) 5396 } 5397 if rs.Primary.Attributes["id"] != "foo" { 5398 t.Fatalf("bad: %#v", rs.Primary.Attributes) 5399 } 5400 } 5401 5402 func TestContext2Apply_output(t *testing.T) { 5403 m := testModule(t, "apply-output") 5404 p := testProvider("aws") 5405 p.ApplyFn = testApplyFn 5406 p.DiffFn = testDiffFn 5407 ctx := testContext2(t, &ContextOpts{ 5408 Module: m, 5409 Providers: map[string]ResourceProviderFactory{ 5410 "aws": testProviderFuncFixed(p), 5411 }, 5412 }) 5413 5414 if _, err := ctx.Plan(); err != nil { 5415 t.Fatalf("err: %s", err) 5416 } 5417 5418 state, err := ctx.Apply() 5419 if err != nil { 5420 t.Fatalf("err: %s", err) 5421 } 5422 5423 actual := strings.TrimSpace(state.String()) 5424 expected := strings.TrimSpace(testTerraformApplyOutputStr) 5425 if actual != expected { 5426 t.Fatalf("bad: \n%s", actual) 5427 } 5428 } 5429 5430 func TestContext2Apply_outputInvalid(t *testing.T) { 5431 m := testModule(t, "apply-output-invalid") 5432 p := testProvider("aws") 5433 p.ApplyFn = testApplyFn 5434 p.DiffFn = testDiffFn 5435 ctx := testContext2(t, &ContextOpts{ 5436 Module: m, 5437 Providers: map[string]ResourceProviderFactory{ 5438 "aws": testProviderFuncFixed(p), 5439 }, 5440 }) 5441 5442 _, err := ctx.Plan() 5443 if err == nil { 5444 t.Fatalf("err: %s", err) 5445 } 5446 if !strings.Contains(err.Error(), "is not a string") { 5447 t.Fatalf("err: %s", err) 5448 } 5449 } 5450 5451 func TestContext2Apply_outputList(t *testing.T) { 5452 m := testModule(t, "apply-output-list") 5453 p := testProvider("aws") 5454 p.ApplyFn = testApplyFn 5455 p.DiffFn = testDiffFn 5456 ctx := testContext2(t, &ContextOpts{ 5457 Module: m, 5458 Providers: map[string]ResourceProviderFactory{ 5459 "aws": testProviderFuncFixed(p), 5460 }, 5461 }) 5462 5463 if _, err := ctx.Plan(); err != nil { 5464 t.Fatalf("err: %s", err) 5465 } 5466 5467 state, err := ctx.Apply() 5468 if err != nil { 5469 t.Fatalf("err: %s", err) 5470 } 5471 5472 actual := strings.TrimSpace(state.String()) 5473 expected := strings.TrimSpace(testTerraformApplyOutputListStr) 5474 if actual != expected { 5475 t.Fatalf("bad: \n%s", actual) 5476 } 5477 } 5478 5479 func TestContext2Apply_outputMulti(t *testing.T) { 5480 m := testModule(t, "apply-output-multi") 5481 p := testProvider("aws") 5482 p.ApplyFn = testApplyFn 5483 p.DiffFn = testDiffFn 5484 ctx := testContext2(t, &ContextOpts{ 5485 Module: m, 5486 Providers: map[string]ResourceProviderFactory{ 5487 "aws": testProviderFuncFixed(p), 5488 }, 5489 }) 5490 5491 if _, err := ctx.Plan(); err != nil { 5492 t.Fatalf("err: %s", err) 5493 } 5494 5495 state, err := ctx.Apply() 5496 if err != nil { 5497 t.Fatalf("err: %s", err) 5498 } 5499 5500 actual := strings.TrimSpace(state.String()) 5501 expected := strings.TrimSpace(testTerraformApplyOutputMultiStr) 5502 if actual != expected { 5503 t.Fatalf("bad: \n%s", actual) 5504 } 5505 } 5506 5507 func TestContext2Apply_outputMultiIndex(t *testing.T) { 5508 m := testModule(t, "apply-output-multi-index") 5509 p := testProvider("aws") 5510 p.ApplyFn = testApplyFn 5511 p.DiffFn = testDiffFn 5512 ctx := testContext2(t, &ContextOpts{ 5513 Module: m, 5514 Providers: map[string]ResourceProviderFactory{ 5515 "aws": testProviderFuncFixed(p), 5516 }, 5517 }) 5518 5519 if _, err := ctx.Plan(); err != nil { 5520 t.Fatalf("err: %s", err) 5521 } 5522 5523 state, err := ctx.Apply() 5524 if err != nil { 5525 t.Fatalf("err: %s", err) 5526 } 5527 5528 actual := strings.TrimSpace(state.String()) 5529 expected := strings.TrimSpace(testTerraformApplyOutputMultiIndexStr) 5530 if actual != expected { 5531 t.Fatalf("bad: \n%s", actual) 5532 } 5533 } 5534 5535 func TestContext2Apply_taint(t *testing.T) { 5536 m := testModule(t, "apply-taint") 5537 p := testProvider("aws") 5538 5539 // destroyCount tests against regression of 5540 // https://github.com/hashicorp/terraform/issues/1056 5541 var destroyCount = int32(0) 5542 var once sync.Once 5543 simulateProviderDelay := func() { 5544 time.Sleep(10 * time.Millisecond) 5545 } 5546 5547 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 5548 once.Do(simulateProviderDelay) 5549 if d.Destroy { 5550 atomic.AddInt32(&destroyCount, 1) 5551 } 5552 return testApplyFn(info, s, d) 5553 } 5554 p.DiffFn = testDiffFn 5555 s := &State{ 5556 Modules: []*ModuleState{ 5557 &ModuleState{ 5558 Path: rootModulePath, 5559 Resources: map[string]*ResourceState{ 5560 "aws_instance.bar": &ResourceState{ 5561 Type: "aws_instance", 5562 Tainted: []*InstanceState{ 5563 &InstanceState{ 5564 ID: "baz", 5565 Attributes: map[string]string{ 5566 "num": "2", 5567 "type": "aws_instance", 5568 }, 5569 }, 5570 }, 5571 }, 5572 }, 5573 }, 5574 }, 5575 } 5576 ctx := testContext2(t, &ContextOpts{ 5577 Module: m, 5578 Providers: map[string]ResourceProviderFactory{ 5579 "aws": testProviderFuncFixed(p), 5580 }, 5581 State: s, 5582 }) 5583 5584 if _, err := ctx.Plan(); err != nil { 5585 t.Fatalf("err: %s", err) 5586 } 5587 5588 state, err := ctx.Apply() 5589 if err != nil { 5590 t.Fatalf("err: %s", err) 5591 } 5592 5593 actual := strings.TrimSpace(state.String()) 5594 expected := strings.TrimSpace(testTerraformApplyTaintStr) 5595 if actual != expected { 5596 t.Fatalf("bad:\n%s", actual) 5597 } 5598 5599 if destroyCount != 1 { 5600 t.Fatalf("Expected 1 destroy, got %d", destroyCount) 5601 } 5602 } 5603 5604 func TestContext2Apply_taintDep(t *testing.T) { 5605 m := testModule(t, "apply-taint-dep") 5606 p := testProvider("aws") 5607 p.ApplyFn = testApplyFn 5608 p.DiffFn = testDiffFn 5609 s := &State{ 5610 Modules: []*ModuleState{ 5611 &ModuleState{ 5612 Path: rootModulePath, 5613 Resources: map[string]*ResourceState{ 5614 "aws_instance.foo": &ResourceState{ 5615 Type: "aws_instance", 5616 Tainted: []*InstanceState{ 5617 &InstanceState{ 5618 ID: "baz", 5619 Attributes: map[string]string{ 5620 "num": "2", 5621 "type": "aws_instance", 5622 }, 5623 }, 5624 }, 5625 }, 5626 "aws_instance.bar": &ResourceState{ 5627 Type: "aws_instance", 5628 Primary: &InstanceState{ 5629 ID: "bar", 5630 Attributes: map[string]string{ 5631 "foo": "baz", 5632 "num": "2", 5633 "type": "aws_instance", 5634 }, 5635 }, 5636 }, 5637 }, 5638 }, 5639 }, 5640 } 5641 ctx := testContext2(t, &ContextOpts{ 5642 Module: m, 5643 Providers: map[string]ResourceProviderFactory{ 5644 "aws": testProviderFuncFixed(p), 5645 }, 5646 State: s, 5647 }) 5648 5649 if p, err := ctx.Plan(); err != nil { 5650 t.Fatalf("err: %s", err) 5651 } else { 5652 t.Logf("plan: %s", p) 5653 } 5654 5655 state, err := ctx.Apply() 5656 if err != nil { 5657 t.Fatalf("err: %s", err) 5658 } 5659 5660 actual := strings.TrimSpace(state.String()) 5661 expected := strings.TrimSpace(testTerraformApplyTaintDepStr) 5662 if actual != expected { 5663 t.Fatalf("bad:\n%s", actual) 5664 } 5665 } 5666 5667 func TestContext2Apply_taintDepRequiresNew(t *testing.T) { 5668 m := testModule(t, "apply-taint-dep-requires-new") 5669 p := testProvider("aws") 5670 p.ApplyFn = testApplyFn 5671 p.DiffFn = testDiffFn 5672 s := &State{ 5673 Modules: []*ModuleState{ 5674 &ModuleState{ 5675 Path: rootModulePath, 5676 Resources: map[string]*ResourceState{ 5677 "aws_instance.foo": &ResourceState{ 5678 Type: "aws_instance", 5679 Tainted: []*InstanceState{ 5680 &InstanceState{ 5681 ID: "baz", 5682 Attributes: map[string]string{ 5683 "num": "2", 5684 "type": "aws_instance", 5685 }, 5686 }, 5687 }, 5688 }, 5689 "aws_instance.bar": &ResourceState{ 5690 Type: "aws_instance", 5691 Primary: &InstanceState{ 5692 ID: "bar", 5693 Attributes: map[string]string{ 5694 "foo": "baz", 5695 "num": "2", 5696 "type": "aws_instance", 5697 }, 5698 }, 5699 }, 5700 }, 5701 }, 5702 }, 5703 } 5704 ctx := testContext2(t, &ContextOpts{ 5705 Module: m, 5706 Providers: map[string]ResourceProviderFactory{ 5707 "aws": testProviderFuncFixed(p), 5708 }, 5709 State: s, 5710 }) 5711 5712 if p, err := ctx.Plan(); err != nil { 5713 t.Fatalf("err: %s", err) 5714 } else { 5715 t.Logf("plan: %s", p) 5716 } 5717 5718 state, err := ctx.Apply() 5719 if err != nil { 5720 t.Fatalf("err: %s", err) 5721 } 5722 5723 actual := strings.TrimSpace(state.String()) 5724 expected := strings.TrimSpace(testTerraformApplyTaintDepRequireNewStr) 5725 if actual != expected { 5726 t.Fatalf("bad:\n%s", actual) 5727 } 5728 } 5729 5730 func TestContext2Apply_targeted(t *testing.T) { 5731 m := testModule(t, "apply-targeted") 5732 p := testProvider("aws") 5733 p.ApplyFn = testApplyFn 5734 p.DiffFn = testDiffFn 5735 ctx := testContext2(t, &ContextOpts{ 5736 Module: m, 5737 Providers: map[string]ResourceProviderFactory{ 5738 "aws": testProviderFuncFixed(p), 5739 }, 5740 Targets: []string{"aws_instance.foo"}, 5741 }) 5742 5743 if _, err := ctx.Plan(); err != nil { 5744 t.Fatalf("err: %s", err) 5745 } 5746 5747 state, err := ctx.Apply() 5748 if err != nil { 5749 t.Fatalf("err: %s", err) 5750 } 5751 5752 mod := state.RootModule() 5753 if len(mod.Resources) != 1 { 5754 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 5755 } 5756 5757 checkStateString(t, state, ` 5758 aws_instance.foo: 5759 ID = foo 5760 num = 2 5761 type = aws_instance 5762 `) 5763 } 5764 5765 func TestContext2Apply_targetedCount(t *testing.T) { 5766 m := testModule(t, "apply-targeted-count") 5767 p := testProvider("aws") 5768 p.ApplyFn = testApplyFn 5769 p.DiffFn = testDiffFn 5770 ctx := testContext2(t, &ContextOpts{ 5771 Module: m, 5772 Providers: map[string]ResourceProviderFactory{ 5773 "aws": testProviderFuncFixed(p), 5774 }, 5775 Targets: []string{"aws_instance.foo"}, 5776 }) 5777 5778 if _, err := ctx.Plan(); err != nil { 5779 t.Fatalf("err: %s", err) 5780 } 5781 5782 state, err := ctx.Apply() 5783 if err != nil { 5784 t.Fatalf("err: %s", err) 5785 } 5786 5787 checkStateString(t, state, ` 5788 aws_instance.foo.0: 5789 ID = foo 5790 aws_instance.foo.1: 5791 ID = foo 5792 aws_instance.foo.2: 5793 ID = foo 5794 `) 5795 } 5796 5797 func TestContext2Apply_targetedCountIndex(t *testing.T) { 5798 m := testModule(t, "apply-targeted-count") 5799 p := testProvider("aws") 5800 p.ApplyFn = testApplyFn 5801 p.DiffFn = testDiffFn 5802 ctx := testContext2(t, &ContextOpts{ 5803 Module: m, 5804 Providers: map[string]ResourceProviderFactory{ 5805 "aws": testProviderFuncFixed(p), 5806 }, 5807 Targets: []string{"aws_instance.foo[1]"}, 5808 }) 5809 5810 if _, err := ctx.Plan(); err != nil { 5811 t.Fatalf("err: %s", err) 5812 } 5813 5814 state, err := ctx.Apply() 5815 if err != nil { 5816 t.Fatalf("err: %s", err) 5817 } 5818 5819 checkStateString(t, state, ` 5820 aws_instance.foo.1: 5821 ID = foo 5822 `) 5823 } 5824 5825 func TestContext2Apply_targetedDestroy(t *testing.T) { 5826 m := testModule(t, "apply-targeted") 5827 p := testProvider("aws") 5828 p.ApplyFn = testApplyFn 5829 p.DiffFn = testDiffFn 5830 ctx := testContext2(t, &ContextOpts{ 5831 Module: m, 5832 Providers: map[string]ResourceProviderFactory{ 5833 "aws": testProviderFuncFixed(p), 5834 }, 5835 State: &State{ 5836 Modules: []*ModuleState{ 5837 &ModuleState{ 5838 Path: rootModulePath, 5839 Resources: map[string]*ResourceState{ 5840 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 5841 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 5842 }, 5843 }, 5844 }, 5845 }, 5846 Targets: []string{"aws_instance.foo"}, 5847 Destroy: true, 5848 }) 5849 5850 if _, err := ctx.Plan(); err != nil { 5851 t.Fatalf("err: %s", err) 5852 } 5853 5854 state, err := ctx.Apply() 5855 if err != nil { 5856 t.Fatalf("err: %s", err) 5857 } 5858 5859 mod := state.RootModule() 5860 if len(mod.Resources) != 1 { 5861 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 5862 } 5863 5864 checkStateString(t, state, ` 5865 aws_instance.bar: 5866 ID = i-abc123 5867 `) 5868 } 5869 5870 func TestContext2Apply_targetedDestroyCountIndex(t *testing.T) { 5871 m := testModule(t, "apply-targeted-count") 5872 p := testProvider("aws") 5873 p.ApplyFn = testApplyFn 5874 p.DiffFn = testDiffFn 5875 ctx := testContext2(t, &ContextOpts{ 5876 Module: m, 5877 Providers: map[string]ResourceProviderFactory{ 5878 "aws": testProviderFuncFixed(p), 5879 }, 5880 State: &State{ 5881 Modules: []*ModuleState{ 5882 &ModuleState{ 5883 Path: rootModulePath, 5884 Resources: map[string]*ResourceState{ 5885 "aws_instance.foo.0": resourceState("aws_instance", "i-bcd345"), 5886 "aws_instance.foo.1": resourceState("aws_instance", "i-bcd345"), 5887 "aws_instance.foo.2": resourceState("aws_instance", "i-bcd345"), 5888 "aws_instance.bar.0": resourceState("aws_instance", "i-abc123"), 5889 "aws_instance.bar.1": resourceState("aws_instance", "i-abc123"), 5890 "aws_instance.bar.2": resourceState("aws_instance", "i-abc123"), 5891 }, 5892 }, 5893 }, 5894 }, 5895 Targets: []string{ 5896 "aws_instance.foo[2]", 5897 "aws_instance.bar[1]", 5898 }, 5899 Destroy: true, 5900 }) 5901 5902 if _, err := ctx.Plan(); err != nil { 5903 t.Fatalf("err: %s", err) 5904 } 5905 5906 state, err := ctx.Apply() 5907 if err != nil { 5908 t.Fatalf("err: %s", err) 5909 } 5910 5911 checkStateString(t, state, ` 5912 aws_instance.bar.0: 5913 ID = i-abc123 5914 aws_instance.bar.2: 5915 ID = i-abc123 5916 aws_instance.foo.0: 5917 ID = i-bcd345 5918 aws_instance.foo.1: 5919 ID = i-bcd345 5920 `) 5921 } 5922 5923 func TestContext2Apply_unknownAttribute(t *testing.T) { 5924 m := testModule(t, "apply-unknown") 5925 p := testProvider("aws") 5926 p.ApplyFn = testApplyFn 5927 p.DiffFn = testDiffFn 5928 ctx := testContext2(t, &ContextOpts{ 5929 Module: m, 5930 Providers: map[string]ResourceProviderFactory{ 5931 "aws": testProviderFuncFixed(p), 5932 }, 5933 }) 5934 5935 if _, err := ctx.Plan(); err != nil { 5936 t.Fatalf("err: %s", err) 5937 } 5938 5939 state, err := ctx.Apply() 5940 if err == nil { 5941 t.Fatal("should error") 5942 } 5943 5944 actual := strings.TrimSpace(state.String()) 5945 expected := strings.TrimSpace(testTerraformApplyUnknownAttrStr) 5946 if actual != expected { 5947 t.Fatalf("bad: \n%s", actual) 5948 } 5949 } 5950 5951 func TestContext2Apply_vars(t *testing.T) { 5952 m := testModule(t, "apply-vars") 5953 p := testProvider("aws") 5954 p.ApplyFn = testApplyFn 5955 p.DiffFn = testDiffFn 5956 ctx := testContext2(t, &ContextOpts{ 5957 Module: m, 5958 Providers: map[string]ResourceProviderFactory{ 5959 "aws": testProviderFuncFixed(p), 5960 }, 5961 Variables: map[string]string{ 5962 "foo": "us-west-2", 5963 "amis.us-east-1": "override", 5964 }, 5965 }) 5966 5967 w, e := ctx.Validate() 5968 if len(w) > 0 { 5969 t.Fatalf("bad: %#v", w) 5970 } 5971 if len(e) > 0 { 5972 t.Fatalf("bad: %s", e) 5973 } 5974 5975 if _, err := ctx.Plan(); err != nil { 5976 t.Fatalf("err: %s", err) 5977 } 5978 5979 state, err := ctx.Apply() 5980 if err != nil { 5981 t.Fatalf("err: %s", err) 5982 } 5983 5984 actual := strings.TrimSpace(state.String()) 5985 expected := strings.TrimSpace(testTerraformApplyVarsStr) 5986 if actual != expected { 5987 t.Fatalf("bad: \n%s", actual) 5988 } 5989 } 5990 5991 func TestContext2Apply_varsEnv(t *testing.T) { 5992 m := testModule(t, "apply-vars-env") 5993 p := testProvider("aws") 5994 p.ApplyFn = testApplyFn 5995 p.DiffFn = testDiffFn 5996 ctx := testContext2(t, &ContextOpts{ 5997 Module: m, 5998 Providers: map[string]ResourceProviderFactory{ 5999 "aws": testProviderFuncFixed(p), 6000 }, 6001 }) 6002 6003 // Set the env var 6004 old := tempEnv(t, "TF_VAR_ami", "baz") 6005 defer os.Setenv("TF_VAR_ami", old) 6006 6007 w, e := ctx.Validate() 6008 if len(w) > 0 { 6009 t.Fatalf("bad: %#v", w) 6010 } 6011 if len(e) > 0 { 6012 t.Fatalf("bad: %s", e) 6013 } 6014 6015 if _, err := ctx.Plan(); err != nil { 6016 t.Fatalf("err: %s", err) 6017 } 6018 6019 state, err := ctx.Apply() 6020 if err != nil { 6021 t.Fatalf("err: %s", err) 6022 } 6023 6024 actual := strings.TrimSpace(state.String()) 6025 expected := strings.TrimSpace(testTerraformApplyVarsEnvStr) 6026 if actual != expected { 6027 t.Fatalf("bad: \n%s", actual) 6028 } 6029 } 6030 6031 func TestContext2Apply_createBefore_depends(t *testing.T) { 6032 m := testModule(t, "apply-depends-create-before") 6033 h := new(HookRecordApplyOrder) 6034 p := testProvider("aws") 6035 p.ApplyFn = testApplyFn 6036 p.DiffFn = testDiffFn 6037 state := &State{ 6038 Modules: []*ModuleState{ 6039 &ModuleState{ 6040 Path: rootModulePath, 6041 Resources: map[string]*ResourceState{ 6042 "aws_instance.web": &ResourceState{ 6043 Type: "aws_instance", 6044 Primary: &InstanceState{ 6045 ID: "bar", 6046 Attributes: map[string]string{ 6047 "require_new": "ami-old", 6048 }, 6049 }, 6050 }, 6051 "aws_instance.lb": &ResourceState{ 6052 Type: "aws_instance", 6053 Primary: &InstanceState{ 6054 ID: "baz", 6055 Attributes: map[string]string{ 6056 "instance": "bar", 6057 }, 6058 }, 6059 }, 6060 }, 6061 }, 6062 }, 6063 } 6064 ctx := testContext2(t, &ContextOpts{ 6065 Module: m, 6066 Hooks: []Hook{h}, 6067 Providers: map[string]ResourceProviderFactory{ 6068 "aws": testProviderFuncFixed(p), 6069 }, 6070 State: state, 6071 }) 6072 6073 if _, err := ctx.Plan(); err != nil { 6074 t.Fatalf("err: %s", err) 6075 } 6076 6077 h.Active = true 6078 state, err := ctx.Apply() 6079 if err != nil { 6080 t.Fatalf("err: %s", err) 6081 } 6082 6083 mod := state.RootModule() 6084 if len(mod.Resources) < 2 { 6085 t.Fatalf("bad: %#v", mod.Resources) 6086 } 6087 6088 actual := strings.TrimSpace(state.String()) 6089 expected := strings.TrimSpace(testTerraformApplyDependsCreateBeforeStr) 6090 if actual != expected { 6091 t.Fatalf("bad: \n%s\n%s", actual, expected) 6092 } 6093 6094 // Test that things were managed _in the right order_ 6095 order := h.States 6096 diffs := h.Diffs 6097 if order[0].ID != "" || diffs[0].Destroy { 6098 t.Fatalf("should create new instance first: %#v", order) 6099 } 6100 6101 if order[1].ID != "baz" { 6102 t.Fatalf("update must happen after create: %#v", order) 6103 } 6104 6105 if order[2].ID != "bar" || !diffs[2].Destroy { 6106 t.Fatalf("destroy must happen after update: %#v", order) 6107 } 6108 } 6109 6110 func TestContext2Apply_singleDestroy(t *testing.T) { 6111 m := testModule(t, "apply-depends-create-before") 6112 h := new(HookRecordApplyOrder) 6113 p := testProvider("aws") 6114 6115 invokeCount := 0 6116 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 6117 invokeCount++ 6118 switch invokeCount { 6119 case 1: 6120 if d.Destroy { 6121 t.Fatalf("should not destroy") 6122 } 6123 if s.ID != "" { 6124 t.Fatalf("should not have ID") 6125 } 6126 case 2: 6127 if d.Destroy { 6128 t.Fatalf("should not destroy") 6129 } 6130 if s.ID != "baz" { 6131 t.Fatalf("should have id") 6132 } 6133 case 3: 6134 if !d.Destroy { 6135 t.Fatalf("should destroy") 6136 } 6137 if s.ID == "" { 6138 t.Fatalf("should have ID") 6139 } 6140 default: 6141 t.Fatalf("bad invoke count %d", invokeCount) 6142 } 6143 return testApplyFn(info, s, d) 6144 } 6145 p.DiffFn = testDiffFn 6146 state := &State{ 6147 Modules: []*ModuleState{ 6148 &ModuleState{ 6149 Path: rootModulePath, 6150 Resources: map[string]*ResourceState{ 6151 "aws_instance.web": &ResourceState{ 6152 Type: "aws_instance", 6153 Primary: &InstanceState{ 6154 ID: "bar", 6155 Attributes: map[string]string{ 6156 "require_new": "ami-old", 6157 }, 6158 }, 6159 }, 6160 "aws_instance.lb": &ResourceState{ 6161 Type: "aws_instance", 6162 Primary: &InstanceState{ 6163 ID: "baz", 6164 Attributes: map[string]string{ 6165 "instance": "bar", 6166 }, 6167 }, 6168 }, 6169 }, 6170 }, 6171 }, 6172 } 6173 ctx := testContext2(t, &ContextOpts{ 6174 Module: m, 6175 Hooks: []Hook{h}, 6176 Providers: map[string]ResourceProviderFactory{ 6177 "aws": testProviderFuncFixed(p), 6178 }, 6179 State: state, 6180 }) 6181 6182 if _, err := ctx.Plan(); err != nil { 6183 t.Fatalf("err: %s", err) 6184 } 6185 6186 h.Active = true 6187 state, err := ctx.Apply() 6188 if err != nil { 6189 t.Fatalf("err: %s", err) 6190 } 6191 6192 if invokeCount != 3 { 6193 t.Fatalf("bad: %d", invokeCount) 6194 } 6195 } 6196 6197 func testContext2(t *testing.T, opts *ContextOpts) *Context { 6198 return NewContext(opts) 6199 } 6200 6201 func testApplyFn( 6202 info *InstanceInfo, 6203 s *InstanceState, 6204 d *InstanceDiff) (*InstanceState, error) { 6205 if d.Destroy { 6206 return nil, nil 6207 } 6208 6209 id := "foo" 6210 if idAttr, ok := d.Attributes["id"]; ok && !idAttr.NewComputed { 6211 id = idAttr.New 6212 } 6213 6214 result := &InstanceState{ 6215 ID: id, 6216 Attributes: make(map[string]string), 6217 } 6218 6219 // Copy all the prior attributes 6220 for k, v := range s.Attributes { 6221 result.Attributes[k] = v 6222 } 6223 6224 if d != nil { 6225 result = result.MergeDiff(d) 6226 } 6227 return result, nil 6228 } 6229 6230 func testDiffFn( 6231 info *InstanceInfo, 6232 s *InstanceState, 6233 c *ResourceConfig) (*InstanceDiff, error) { 6234 var diff InstanceDiff 6235 diff.Attributes = make(map[string]*ResourceAttrDiff) 6236 6237 for k, v := range c.Raw { 6238 if _, ok := v.(string); !ok { 6239 continue 6240 } 6241 6242 if k == "nil" { 6243 return nil, nil 6244 } 6245 6246 // This key is used for other purposes 6247 if k == "compute_value" { 6248 continue 6249 } 6250 6251 if k == "compute" { 6252 attrDiff := &ResourceAttrDiff{ 6253 Old: "", 6254 New: "", 6255 NewComputed: true, 6256 } 6257 6258 if cv, ok := c.Config["compute_value"]; ok { 6259 if cv.(string) == "1" { 6260 attrDiff.NewComputed = false 6261 attrDiff.New = fmt.Sprintf("computed_%s", v.(string)) 6262 } 6263 } 6264 6265 diff.Attributes[v.(string)] = attrDiff 6266 continue 6267 } 6268 6269 // If this key is not computed, then look it up in the 6270 // cleaned config. 6271 found := false 6272 for _, ck := range c.ComputedKeys { 6273 if ck == k { 6274 found = true 6275 break 6276 } 6277 } 6278 if !found { 6279 v = c.Config[k] 6280 } 6281 6282 attrDiff := &ResourceAttrDiff{ 6283 Old: "", 6284 New: v.(string), 6285 } 6286 6287 if k == "require_new" { 6288 attrDiff.RequiresNew = true 6289 } 6290 diff.Attributes[k] = attrDiff 6291 } 6292 6293 for _, k := range c.ComputedKeys { 6294 diff.Attributes[k] = &ResourceAttrDiff{ 6295 Old: "", 6296 NewComputed: true, 6297 } 6298 } 6299 6300 for k, v := range diff.Attributes { 6301 if v.NewComputed { 6302 continue 6303 } 6304 6305 old, ok := s.Attributes[k] 6306 if !ok { 6307 continue 6308 } 6309 if old == v.New { 6310 delete(diff.Attributes, k) 6311 } 6312 } 6313 6314 if !diff.Empty() { 6315 diff.Attributes["type"] = &ResourceAttrDiff{ 6316 Old: "", 6317 New: info.Type, 6318 } 6319 } 6320 6321 return &diff, nil 6322 } 6323 6324 func testProvider(prefix string) *MockResourceProvider { 6325 p := new(MockResourceProvider) 6326 p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) { 6327 return s, nil 6328 } 6329 p.ResourcesReturn = []ResourceType{ 6330 ResourceType{ 6331 Name: fmt.Sprintf("%s_instance", prefix), 6332 }, 6333 } 6334 6335 return p 6336 } 6337 6338 func testProvisioner() *MockResourceProvisioner { 6339 p := new(MockResourceProvisioner) 6340 return p 6341 } 6342 6343 func checkStateString(t *testing.T, state *State, expected string) { 6344 actual := strings.TrimSpace(state.String()) 6345 expected = strings.TrimSpace(expected) 6346 6347 if actual != expected { 6348 t.Fatalf("state does not match! actual:\n%s\n\nexpected:\n%s", actual, expected) 6349 } 6350 } 6351 6352 func resourceState(resourceType, resourceID string) *ResourceState { 6353 return &ResourceState{ 6354 Type: resourceType, 6355 Primary: &InstanceState{ 6356 ID: resourceID, 6357 }, 6358 } 6359 } 6360 6361 const testContextGraph = ` 6362 root: root 6363 aws_instance.bar 6364 aws_instance.bar -> provider.aws 6365 aws_instance.foo 6366 aws_instance.foo -> provider.aws 6367 provider.aws 6368 root 6369 root -> aws_instance.bar 6370 root -> aws_instance.foo 6371 ` 6372 6373 const testContextRefreshModuleStr = ` 6374 aws_instance.web: (1 tainted) 6375 ID = <not created> 6376 Tainted ID 1 = bar 6377 6378 module.child: 6379 aws_instance.web: 6380 ID = new 6381 ` 6382 6383 const testContextRefreshOutputStr = ` 6384 aws_instance.web: 6385 ID = foo 6386 foo = bar 6387 6388 Outputs: 6389 6390 foo = bar 6391 ` 6392 6393 const testContextRefreshOutputPartialStr = ` 6394 <no state> 6395 ` 6396 6397 const testContextRefreshTaintedStr = ` 6398 aws_instance.web: (1 tainted) 6399 ID = <not created> 6400 Tainted ID 1 = foo 6401 `