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