github.com/danrjohnson/terraform@v0.7.0-rc2.0.20160627135212-d0fc1fa086ff/terraform/context_apply_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 "github.com/hashicorp/terraform/config/module" 16 ) 17 18 func TestContext2Apply(t *testing.T) { 19 m := testModule(t, "apply-good") 20 p := testProvider("aws") 21 p.ApplyFn = testApplyFn 22 p.DiffFn = testDiffFn 23 ctx := testContext2(t, &ContextOpts{ 24 Module: m, 25 Providers: map[string]ResourceProviderFactory{ 26 "aws": testProviderFuncFixed(p), 27 }, 28 }) 29 30 if _, err := ctx.Plan(); err != nil { 31 t.Fatalf("err: %s", err) 32 } 33 34 state, err := ctx.Apply() 35 if err != nil { 36 t.Fatalf("err: %s", err) 37 } 38 39 mod := state.RootModule() 40 if len(mod.Resources) < 2 { 41 t.Fatalf("bad: %#v", mod.Resources) 42 } 43 44 actual := strings.TrimSpace(state.String()) 45 expected := strings.TrimSpace(testTerraformApplyStr) 46 if actual != expected { 47 t.Fatalf("bad: \n%s", actual) 48 } 49 } 50 51 func TestContext2Apply_resourceCountOneList(t *testing.T) { 52 m := testModule(t, "apply-resource-count-one-list") 53 p := testProvider("null") 54 p.ApplyFn = testApplyFn 55 p.DiffFn = testDiffFn 56 ctx := testContext2(t, &ContextOpts{ 57 Module: m, 58 Providers: map[string]ResourceProviderFactory{ 59 "null": testProviderFuncFixed(p), 60 }, 61 }) 62 63 if _, err := ctx.Plan(); err != nil { 64 t.Fatalf("err: %s", err) 65 } 66 67 state, err := ctx.Apply() 68 if err != nil { 69 t.Fatalf("err: %s", err) 70 } 71 72 actual := strings.TrimSpace(state.String()) 73 expected := strings.TrimSpace(`null_resource.foo: 74 ID = foo 75 76 Outputs: 77 78 test = [foo]`) 79 if actual != expected { 80 t.Fatalf("expected: \n%s\n\ngot: \n%s\n", expected, actual) 81 } 82 } 83 func TestContext2Apply_resourceCountZeroList(t *testing.T) { 84 m := testModule(t, "apply-resource-count-zero-list") 85 p := testProvider("null") 86 p.ApplyFn = testApplyFn 87 p.DiffFn = testDiffFn 88 ctx := testContext2(t, &ContextOpts{ 89 Module: m, 90 Providers: map[string]ResourceProviderFactory{ 91 "null": testProviderFuncFixed(p), 92 }, 93 }) 94 95 if _, err := ctx.Plan(); err != nil { 96 t.Fatalf("err: %s", err) 97 } 98 99 state, err := ctx.Apply() 100 if err != nil { 101 t.Fatalf("err: %s", err) 102 } 103 104 actual := strings.TrimSpace(state.String()) 105 expected := strings.TrimSpace(`<no state> 106 Outputs: 107 108 test = []`) 109 if actual != expected { 110 t.Fatalf("expected: \n%s\n\ngot: \n%s\n", expected, actual) 111 } 112 } 113 114 func TestContext2Apply_mapVarBetweenModules(t *testing.T) { 115 m := testModule(t, "apply-map-var-through-module") 116 p := testProvider("null") 117 p.ApplyFn = testApplyFn 118 p.DiffFn = testDiffFn 119 ctx := testContext2(t, &ContextOpts{ 120 Module: m, 121 Providers: map[string]ResourceProviderFactory{ 122 "null": testProviderFuncFixed(p), 123 }, 124 }) 125 126 if _, err := ctx.Plan(); err != nil { 127 t.Fatalf("err: %s", err) 128 } 129 130 state, err := ctx.Apply() 131 if err != nil { 132 t.Fatalf("err: %s", err) 133 } 134 135 actual := strings.TrimSpace(state.String()) 136 expected := strings.TrimSpace(`<no state> 137 Outputs: 138 139 amis_from_module = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-123456 us-west-2:ami-456789 } 140 141 module.test: 142 null_resource.noop: 143 ID = foo 144 145 Outputs: 146 147 amis_out = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-123456 us-west-2:ami-456789 }`) 148 if actual != expected { 149 t.Fatalf("expected: \n%s\n\ngot: \n%s\n", expected, actual) 150 } 151 } 152 153 func TestContext2Apply_providerAlias(t *testing.T) { 154 m := testModule(t, "apply-provider-alias") 155 p := testProvider("aws") 156 p.ApplyFn = testApplyFn 157 p.DiffFn = testDiffFn 158 ctx := testContext2(t, &ContextOpts{ 159 Module: m, 160 Providers: map[string]ResourceProviderFactory{ 161 "aws": testProviderFuncFixed(p), 162 }, 163 }) 164 165 if _, err := ctx.Plan(); err != nil { 166 t.Fatalf("err: %s", err) 167 } 168 169 state, err := ctx.Apply() 170 if err != nil { 171 t.Fatalf("err: %s", err) 172 } 173 174 mod := state.RootModule() 175 if len(mod.Resources) < 2 { 176 t.Fatalf("bad: %#v", mod.Resources) 177 } 178 179 actual := strings.TrimSpace(state.String()) 180 expected := strings.TrimSpace(testTerraformApplyProviderAliasStr) 181 if actual != expected { 182 t.Fatalf("bad: \n%s", actual) 183 } 184 } 185 186 // GH-2870 187 func TestContext2Apply_providerWarning(t *testing.T) { 188 m := testModule(t, "apply-provider-warning") 189 p := testProvider("aws") 190 p.ApplyFn = testApplyFn 191 p.DiffFn = testDiffFn 192 p.ValidateFn = func(c *ResourceConfig) (ws []string, es []error) { 193 ws = append(ws, "Just a warning") 194 return 195 } 196 ctx := testContext2(t, &ContextOpts{ 197 Module: m, 198 Providers: map[string]ResourceProviderFactory{ 199 "aws": testProviderFuncFixed(p), 200 }, 201 }) 202 203 if _, err := ctx.Plan(); err != nil { 204 t.Fatalf("err: %s", err) 205 } 206 207 state, err := ctx.Apply() 208 if err != nil { 209 t.Fatalf("err: %s", err) 210 } 211 212 actual := strings.TrimSpace(state.String()) 213 expected := strings.TrimSpace(` 214 aws_instance.foo: 215 ID = foo 216 `) 217 if actual != expected { 218 t.Fatalf("got: \n%s\n\nexpected:\n%s", actual, expected) 219 } 220 221 if !p.ConfigureCalled { 222 t.Fatalf("provider Configure() was never called!") 223 } 224 } 225 226 func TestContext2Apply_emptyModule(t *testing.T) { 227 m := testModule(t, "apply-empty-module") 228 p := testProvider("aws") 229 p.ApplyFn = testApplyFn 230 p.DiffFn = testDiffFn 231 ctx := testContext2(t, &ContextOpts{ 232 Module: m, 233 Providers: map[string]ResourceProviderFactory{ 234 "aws": testProviderFuncFixed(p), 235 }, 236 }) 237 238 if _, err := ctx.Plan(); err != nil { 239 t.Fatalf("err: %s", err) 240 } 241 242 state, err := ctx.Apply() 243 if err != nil { 244 t.Fatalf("err: %s", err) 245 } 246 247 actual := strings.TrimSpace(state.String()) 248 actual = strings.Replace(actual, " ", "", -1) 249 expected := strings.TrimSpace(testTerraformApplyEmptyModuleStr) 250 if actual != expected { 251 t.Fatalf("bad: \n%s\nexpect:\n%s", actual, expected) 252 } 253 } 254 255 func TestContext2Apply_createBeforeDestroy(t *testing.T) { 256 m := testModule(t, "apply-good-create-before") 257 p := testProvider("aws") 258 p.ApplyFn = testApplyFn 259 p.DiffFn = testDiffFn 260 state := &State{ 261 Modules: []*ModuleState{ 262 &ModuleState{ 263 Path: rootModulePath, 264 Resources: map[string]*ResourceState{ 265 "aws_instance.bar": &ResourceState{ 266 Type: "aws_instance", 267 Primary: &InstanceState{ 268 ID: "bar", 269 Attributes: map[string]string{ 270 "require_new": "abc", 271 }, 272 }, 273 }, 274 }, 275 }, 276 }, 277 } 278 ctx := testContext2(t, &ContextOpts{ 279 Module: m, 280 Providers: map[string]ResourceProviderFactory{ 281 "aws": testProviderFuncFixed(p), 282 }, 283 State: state, 284 }) 285 286 if p, err := ctx.Plan(); err != nil { 287 t.Fatalf("err: %s", err) 288 } else { 289 t.Logf(p.String()) 290 } 291 292 state, err := ctx.Apply() 293 if err != nil { 294 t.Fatalf("err: %s", err) 295 } 296 297 mod := state.RootModule() 298 if len(mod.Resources) != 1 { 299 t.Fatalf("bad: %s", state) 300 } 301 302 actual := strings.TrimSpace(state.String()) 303 expected := strings.TrimSpace(testTerraformApplyCreateBeforeStr) 304 if actual != expected { 305 t.Fatalf("bad: \n%s", actual) 306 } 307 } 308 309 func TestContext2Apply_createBeforeDestroyUpdate(t *testing.T) { 310 m := testModule(t, "apply-good-create-before-update") 311 p := testProvider("aws") 312 p.ApplyFn = testApplyFn 313 p.DiffFn = testDiffFn 314 state := &State{ 315 Modules: []*ModuleState{ 316 &ModuleState{ 317 Path: rootModulePath, 318 Resources: map[string]*ResourceState{ 319 "aws_instance.bar": &ResourceState{ 320 Type: "aws_instance", 321 Primary: &InstanceState{ 322 ID: "bar", 323 Attributes: map[string]string{ 324 "foo": "bar", 325 }, 326 }, 327 }, 328 }, 329 }, 330 }, 331 } 332 ctx := testContext2(t, &ContextOpts{ 333 Module: m, 334 Providers: map[string]ResourceProviderFactory{ 335 "aws": testProviderFuncFixed(p), 336 }, 337 State: state, 338 }) 339 340 if p, err := ctx.Plan(); err != nil { 341 t.Fatalf("err: %s", err) 342 } else { 343 t.Logf(p.String()) 344 } 345 346 state, err := ctx.Apply() 347 if err != nil { 348 t.Fatalf("err: %s", err) 349 } 350 351 mod := state.RootModule() 352 if len(mod.Resources) != 1 { 353 t.Fatalf("bad: %s", state) 354 } 355 356 actual := strings.TrimSpace(state.String()) 357 expected := strings.TrimSpace(testTerraformApplyCreateBeforeUpdateStr) 358 if actual != expected { 359 t.Fatalf("bad: \n%s", actual) 360 } 361 } 362 363 func TestContext2Apply_destroyComputed(t *testing.T) { 364 m := testModule(t, "apply-destroy-computed") 365 p := testProvider("aws") 366 p.ApplyFn = testApplyFn 367 p.DiffFn = testDiffFn 368 state := &State{ 369 Modules: []*ModuleState{ 370 &ModuleState{ 371 Path: rootModulePath, 372 Resources: map[string]*ResourceState{ 373 "aws_instance.foo": &ResourceState{ 374 Type: "aws_instance", 375 Primary: &InstanceState{ 376 ID: "foo", 377 Attributes: map[string]string{ 378 "output": "value", 379 }, 380 }, 381 }, 382 }, 383 }, 384 }, 385 } 386 ctx := testContext2(t, &ContextOpts{ 387 Module: m, 388 Providers: map[string]ResourceProviderFactory{ 389 "aws": testProviderFuncFixed(p), 390 }, 391 State: state, 392 Destroy: true, 393 }) 394 395 if p, err := ctx.Plan(); err != nil { 396 t.Fatalf("err: %s", err) 397 } else { 398 t.Logf(p.String()) 399 } 400 401 if _, err := ctx.Apply(); err != nil { 402 t.Fatalf("err: %s", err) 403 } 404 } 405 406 func TestContext2Apply_destroyData(t *testing.T) { 407 m := testModule(t, "apply-destroy-data-resource") 408 p := testProvider("null") 409 p.ApplyFn = testApplyFn 410 p.DiffFn = testDiffFn 411 state := &State{ 412 Modules: []*ModuleState{ 413 &ModuleState{ 414 Path: rootModulePath, 415 Resources: map[string]*ResourceState{ 416 "data.null_data_source.testing": &ResourceState{ 417 Type: "aws_instance", 418 Primary: &InstanceState{ 419 ID: "-", 420 Attributes: map[string]string{ 421 "inputs.#": "1", 422 "inputs.test": "yes", 423 }, 424 }, 425 }, 426 }, 427 }, 428 }, 429 } 430 ctx := testContext2(t, &ContextOpts{ 431 Module: m, 432 Providers: map[string]ResourceProviderFactory{ 433 "null": testProviderFuncFixed(p), 434 }, 435 State: state, 436 Destroy: true, 437 }) 438 439 if p, err := ctx.Plan(); err != nil { 440 t.Fatalf("err: %s", err) 441 } else { 442 t.Logf(p.String()) 443 } 444 445 newState, err := ctx.Apply() 446 if err != nil { 447 t.Fatalf("err: %s", err) 448 } 449 450 if got := len(newState.Modules); got != 1 { 451 t.Fatalf("state has %d modules after destroy; want 1", got) 452 } 453 454 if got := len(newState.Modules[0].Resources); got != 0 { 455 t.Fatalf("state has %d resources after destroy; want 0", got) 456 } 457 } 458 459 // https://github.com/hashicorp/terraform/pull/5096 460 func TestContext2Apply_destroySkipsCBD(t *testing.T) { 461 // Config contains CBD resource depending on non-CBD resource, which triggers 462 // a cycle if they are both replaced, but should _not_ trigger a cycle when 463 // just doing a `terraform destroy`. 464 m := testModule(t, "apply-destroy-cbd") 465 p := testProvider("aws") 466 p.ApplyFn = testApplyFn 467 p.DiffFn = testDiffFn 468 state := &State{ 469 Modules: []*ModuleState{ 470 &ModuleState{ 471 Path: rootModulePath, 472 Resources: map[string]*ResourceState{ 473 "aws_instance.foo": &ResourceState{ 474 Type: "aws_instance", 475 Primary: &InstanceState{ 476 ID: "foo", 477 }, 478 }, 479 "aws_instance.bar": &ResourceState{ 480 Type: "aws_instance", 481 Primary: &InstanceState{ 482 ID: "foo", 483 }, 484 }, 485 }, 486 }, 487 }, 488 } 489 ctx := testContext2(t, &ContextOpts{ 490 Module: m, 491 Providers: map[string]ResourceProviderFactory{ 492 "aws": testProviderFuncFixed(p), 493 }, 494 State: state, 495 Destroy: true, 496 }) 497 498 if p, err := ctx.Plan(); err != nil { 499 t.Fatalf("err: %s", err) 500 } else { 501 t.Logf(p.String()) 502 } 503 504 if _, err := ctx.Apply(); err != nil { 505 t.Fatalf("err: %s", err) 506 } 507 } 508 509 func TestContext2Apply_destroyModuleVarProviderConfig(t *testing.T) { 510 m := testModule(t, "apply-destroy-mod-var-provider-config") 511 p := testProvider("aws") 512 p.ApplyFn = testApplyFn 513 p.DiffFn = testDiffFn 514 state := &State{ 515 Modules: []*ModuleState{ 516 &ModuleState{ 517 Path: []string{"root", "child"}, 518 Resources: map[string]*ResourceState{ 519 "aws_instance.foo": &ResourceState{ 520 Type: "aws_instance", 521 Primary: &InstanceState{ 522 ID: "foo", 523 }, 524 }, 525 }, 526 }, 527 }, 528 } 529 ctx := testContext2(t, &ContextOpts{ 530 Module: m, 531 Providers: map[string]ResourceProviderFactory{ 532 "aws": testProviderFuncFixed(p), 533 }, 534 State: state, 535 Destroy: true, 536 }) 537 538 if _, err := ctx.Plan(); err != nil { 539 t.Fatalf("err: %s", err) 540 } 541 542 _, err := ctx.Apply() 543 if err != nil { 544 t.Fatalf("err: %s", err) 545 } 546 } 547 548 // https://github.com/hashicorp/terraform/issues/2892 549 func TestContext2Apply_destroyCrossProviders(t *testing.T) { 550 m := testModule(t, "apply-destroy-cross-providers") 551 552 p_aws := testProvider("aws") 553 p_aws.ApplyFn = testApplyFn 554 p_aws.DiffFn = testDiffFn 555 556 p_tf := testProvider("terraform") 557 p_tf.ApplyFn = testApplyFn 558 p_tf.DiffFn = testDiffFn 559 560 providers := map[string]ResourceProviderFactory{ 561 "aws": testProviderFuncFixed(p_aws), 562 "terraform": testProviderFuncFixed(p_tf), 563 } 564 565 // Bug only appears from time to time, 566 // so we run this test multiple times 567 // to check for the race-condition 568 for i := 0; i <= 10; i++ { 569 ctx := getContextForApply_destroyCrossProviders( 570 t, m, providers) 571 572 if p, err := ctx.Plan(); err != nil { 573 t.Fatalf("err: %s", err) 574 } else { 575 t.Logf(p.String()) 576 } 577 578 if _, err := ctx.Apply(); err != nil { 579 t.Fatalf("err: %s", err) 580 } 581 } 582 } 583 584 func getContextForApply_destroyCrossProviders( 585 t *testing.T, 586 m *module.Tree, 587 providers map[string]ResourceProviderFactory) *Context { 588 state := &State{ 589 Modules: []*ModuleState{ 590 &ModuleState{ 591 Path: rootModulePath, 592 Resources: map[string]*ResourceState{ 593 "terraform_remote_state.shared": &ResourceState{ 594 Type: "terraform_remote_state", 595 Primary: &InstanceState{ 596 ID: "remote-2652591293", 597 Attributes: map[string]string{ 598 "output.env_name": "test", 599 }, 600 }, 601 }, 602 }, 603 }, 604 &ModuleState{ 605 Path: []string{"root", "example"}, 606 Resources: map[string]*ResourceState{ 607 "aws_vpc.bar": &ResourceState{ 608 Type: "aws_vpc", 609 Primary: &InstanceState{ 610 ID: "vpc-aaabbb12", 611 Attributes: map[string]string{ 612 "value": "test", 613 }, 614 }, 615 }, 616 }, 617 }, 618 }, 619 } 620 ctx := testContext2(t, &ContextOpts{ 621 Module: m, 622 Providers: providers, 623 State: state, 624 Destroy: true, 625 }) 626 627 return ctx 628 } 629 630 func TestContext2Apply_minimal(t *testing.T) { 631 m := testModule(t, "apply-minimal") 632 p := testProvider("aws") 633 p.ApplyFn = testApplyFn 634 p.DiffFn = testDiffFn 635 ctx := testContext2(t, &ContextOpts{ 636 Module: m, 637 Providers: map[string]ResourceProviderFactory{ 638 "aws": testProviderFuncFixed(p), 639 }, 640 }) 641 642 if _, err := ctx.Plan(); err != nil { 643 t.Fatalf("err: %s", err) 644 } 645 646 state, err := ctx.Apply() 647 if err != nil { 648 t.Fatalf("err: %s", err) 649 } 650 651 actual := strings.TrimSpace(state.String()) 652 expected := strings.TrimSpace(testTerraformApplyMinimalStr) 653 if actual != expected { 654 t.Fatalf("bad: \n%s", actual) 655 } 656 } 657 658 func TestContext2Apply_badDiff(t *testing.T) { 659 m := testModule(t, "apply-good") 660 p := testProvider("aws") 661 p.ApplyFn = testApplyFn 662 p.DiffFn = testDiffFn 663 ctx := testContext2(t, &ContextOpts{ 664 Module: m, 665 Providers: map[string]ResourceProviderFactory{ 666 "aws": testProviderFuncFixed(p), 667 }, 668 }) 669 670 if _, err := ctx.Plan(); err != nil { 671 t.Fatalf("err: %s", err) 672 } 673 674 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 675 return &InstanceDiff{ 676 Attributes: map[string]*ResourceAttrDiff{ 677 "newp": nil, 678 }, 679 }, nil 680 } 681 682 if _, err := ctx.Apply(); err == nil { 683 t.Fatal("should error") 684 } 685 } 686 687 func TestContext2Apply_cancel(t *testing.T) { 688 stopped := false 689 690 m := testModule(t, "apply-cancel") 691 p := testProvider("aws") 692 ctx := testContext2(t, &ContextOpts{ 693 Module: m, 694 Providers: map[string]ResourceProviderFactory{ 695 "aws": testProviderFuncFixed(p), 696 }, 697 }) 698 699 p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) { 700 if !stopped { 701 stopped = true 702 go ctx.Stop() 703 704 for { 705 if ctx.sh.Stopped() { 706 break 707 } 708 } 709 } 710 711 return &InstanceState{ 712 ID: "foo", 713 Attributes: map[string]string{ 714 "num": "2", 715 }, 716 }, nil 717 } 718 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 719 return &InstanceDiff{ 720 Attributes: map[string]*ResourceAttrDiff{ 721 "num": &ResourceAttrDiff{ 722 New: "bar", 723 }, 724 }, 725 }, nil 726 } 727 728 if _, err := ctx.Plan(); err != nil { 729 t.Fatalf("err: %s", err) 730 } 731 732 // Start the Apply in a goroutine 733 stateCh := make(chan *State) 734 go func() { 735 state, err := ctx.Apply() 736 if err != nil { 737 panic(err) 738 } 739 740 stateCh <- state 741 }() 742 743 state := <-stateCh 744 745 mod := state.RootModule() 746 if len(mod.Resources) != 1 { 747 t.Fatalf("bad: %s", state.String()) 748 } 749 750 actual := strings.TrimSpace(state.String()) 751 expected := strings.TrimSpace(testTerraformApplyCancelStr) 752 if actual != expected { 753 t.Fatalf("bad: \n%s", actual) 754 } 755 } 756 757 func TestContext2Apply_compute(t *testing.T) { 758 m := testModule(t, "apply-compute") 759 p := testProvider("aws") 760 p.ApplyFn = testApplyFn 761 p.DiffFn = testDiffFn 762 ctx := testContext2(t, &ContextOpts{ 763 Module: m, 764 Providers: map[string]ResourceProviderFactory{ 765 "aws": testProviderFuncFixed(p), 766 }, 767 }) 768 769 if _, err := ctx.Plan(); err != nil { 770 t.Fatalf("err: %s", err) 771 } 772 773 ctx.variables = map[string]string{"value": "1"} 774 775 state, err := ctx.Apply() 776 if err != nil { 777 t.Fatalf("err: %s", err) 778 } 779 780 actual := strings.TrimSpace(state.String()) 781 expected := strings.TrimSpace(testTerraformApplyComputeStr) 782 if actual != expected { 783 t.Fatalf("bad: \n%s", actual) 784 } 785 } 786 787 func TestContext2Apply_countDecrease(t *testing.T) { 788 m := testModule(t, "apply-count-dec") 789 p := testProvider("aws") 790 p.DiffFn = testDiffFn 791 s := &State{ 792 Modules: []*ModuleState{ 793 &ModuleState{ 794 Path: rootModulePath, 795 Resources: map[string]*ResourceState{ 796 "aws_instance.foo.0": &ResourceState{ 797 Type: "aws_instance", 798 Primary: &InstanceState{ 799 ID: "bar", 800 Attributes: map[string]string{ 801 "foo": "foo", 802 "type": "aws_instance", 803 }, 804 }, 805 }, 806 "aws_instance.foo.1": &ResourceState{ 807 Type: "aws_instance", 808 Primary: &InstanceState{ 809 ID: "bar", 810 Attributes: map[string]string{ 811 "foo": "foo", 812 "type": "aws_instance", 813 }, 814 }, 815 }, 816 "aws_instance.foo.2": &ResourceState{ 817 Type: "aws_instance", 818 Primary: &InstanceState{ 819 ID: "bar", 820 Attributes: map[string]string{ 821 "foo": "foo", 822 "type": "aws_instance", 823 }, 824 }, 825 }, 826 }, 827 }, 828 }, 829 } 830 ctx := testContext2(t, &ContextOpts{ 831 Module: m, 832 Providers: map[string]ResourceProviderFactory{ 833 "aws": testProviderFuncFixed(p), 834 }, 835 State: s, 836 }) 837 838 if _, err := ctx.Plan(); err != nil { 839 t.Fatalf("err: %s", err) 840 } 841 842 state, err := ctx.Apply() 843 if err != nil { 844 t.Fatalf("err: %s", err) 845 } 846 847 actual := strings.TrimSpace(state.String()) 848 expected := strings.TrimSpace(testTerraformApplyCountDecStr) 849 if actual != expected { 850 t.Fatalf("bad: \n%s", actual) 851 } 852 } 853 854 func TestContext2Apply_countDecreaseToOne(t *testing.T) { 855 m := testModule(t, "apply-count-dec-one") 856 p := testProvider("aws") 857 p.ApplyFn = testApplyFn 858 p.DiffFn = testDiffFn 859 s := &State{ 860 Modules: []*ModuleState{ 861 &ModuleState{ 862 Path: rootModulePath, 863 Resources: map[string]*ResourceState{ 864 "aws_instance.foo.0": &ResourceState{ 865 Type: "aws_instance", 866 Primary: &InstanceState{ 867 ID: "bar", 868 Attributes: map[string]string{ 869 "foo": "foo", 870 "type": "aws_instance", 871 }, 872 }, 873 }, 874 "aws_instance.foo.1": &ResourceState{ 875 Type: "aws_instance", 876 Primary: &InstanceState{ 877 ID: "bar", 878 }, 879 }, 880 "aws_instance.foo.2": &ResourceState{ 881 Type: "aws_instance", 882 Primary: &InstanceState{ 883 ID: "bar", 884 }, 885 }, 886 }, 887 }, 888 }, 889 } 890 ctx := testContext2(t, &ContextOpts{ 891 Module: m, 892 Providers: map[string]ResourceProviderFactory{ 893 "aws": testProviderFuncFixed(p), 894 }, 895 State: s, 896 }) 897 898 if _, err := ctx.Plan(); err != nil { 899 t.Fatalf("err: %s", err) 900 } 901 902 state, err := ctx.Apply() 903 if err != nil { 904 t.Fatalf("err: %s", err) 905 } 906 907 actual := strings.TrimSpace(state.String()) 908 expected := strings.TrimSpace(testTerraformApplyCountDecToOneStr) 909 if actual != expected { 910 t.Fatalf("bad: \n%s", actual) 911 } 912 } 913 914 // https://github.com/PeoplePerHour/terraform/pull/11 915 // 916 // This tests a case where both a "resource" and "resource.0" are in 917 // the state file, which apparently is a reasonable backwards compatibility 918 // concern found in the above 3rd party repo. 919 func TestContext2Apply_countDecreaseToOneCorrupted(t *testing.T) { 920 m := testModule(t, "apply-count-dec-one") 921 p := testProvider("aws") 922 p.ApplyFn = testApplyFn 923 p.DiffFn = testDiffFn 924 s := &State{ 925 Modules: []*ModuleState{ 926 &ModuleState{ 927 Path: rootModulePath, 928 Resources: map[string]*ResourceState{ 929 "aws_instance.foo": &ResourceState{ 930 Type: "aws_instance", 931 Primary: &InstanceState{ 932 ID: "bar", 933 Attributes: map[string]string{ 934 "foo": "foo", 935 "type": "aws_instance", 936 }, 937 }, 938 }, 939 "aws_instance.foo.0": &ResourceState{ 940 Type: "aws_instance", 941 Primary: &InstanceState{ 942 ID: "baz", 943 Attributes: map[string]string{ 944 "type": "aws_instance", 945 }, 946 }, 947 }, 948 }, 949 }, 950 }, 951 } 952 ctx := testContext2(t, &ContextOpts{ 953 Module: m, 954 Providers: map[string]ResourceProviderFactory{ 955 "aws": testProviderFuncFixed(p), 956 }, 957 State: s, 958 }) 959 960 if p, err := ctx.Plan(); err != nil { 961 t.Fatalf("err: %s", err) 962 } else { 963 testStringMatch(t, p, testTerraformApplyCountDecToOneCorruptedPlanStr) 964 } 965 966 state, err := ctx.Apply() 967 if err != nil { 968 t.Fatalf("err: %s", err) 969 } 970 971 actual := strings.TrimSpace(state.String()) 972 expected := strings.TrimSpace(testTerraformApplyCountDecToOneCorruptedStr) 973 if actual != expected { 974 t.Fatalf("bad: \n%s", actual) 975 } 976 } 977 978 func TestContext2Apply_countTainted(t *testing.T) { 979 m := testModule(t, "apply-count-tainted") 980 p := testProvider("aws") 981 p.DiffFn = testDiffFn 982 s := &State{ 983 Modules: []*ModuleState{ 984 &ModuleState{ 985 Path: rootModulePath, 986 Resources: map[string]*ResourceState{ 987 "aws_instance.foo.0": &ResourceState{ 988 Type: "aws_instance", 989 Primary: &InstanceState{ 990 ID: "bar", 991 Attributes: map[string]string{ 992 "foo": "foo", 993 "type": "aws_instance", 994 }, 995 Tainted: true, 996 }, 997 }, 998 }, 999 }, 1000 }, 1001 } 1002 ctx := testContext2(t, &ContextOpts{ 1003 Module: m, 1004 Providers: map[string]ResourceProviderFactory{ 1005 "aws": testProviderFuncFixed(p), 1006 }, 1007 State: s, 1008 }) 1009 1010 if _, err := ctx.Plan(); err != nil { 1011 t.Fatalf("err: %s", err) 1012 } 1013 1014 state, err := ctx.Apply() 1015 if err != nil { 1016 t.Fatalf("err: %s", err) 1017 } 1018 1019 actual := strings.TrimSpace(state.String()) 1020 expected := strings.TrimSpace(testTerraformApplyCountTaintedStr) 1021 if actual != expected { 1022 t.Fatalf("bad: \n%s", actual) 1023 } 1024 } 1025 1026 func TestContext2Apply_countVariable(t *testing.T) { 1027 m := testModule(t, "apply-count-variable") 1028 p := testProvider("aws") 1029 p.ApplyFn = testApplyFn 1030 p.DiffFn = testDiffFn 1031 ctx := testContext2(t, &ContextOpts{ 1032 Module: m, 1033 Providers: map[string]ResourceProviderFactory{ 1034 "aws": testProviderFuncFixed(p), 1035 }, 1036 }) 1037 1038 if _, err := ctx.Plan(); err != nil { 1039 t.Fatalf("err: %s", err) 1040 } 1041 1042 state, err := ctx.Apply() 1043 if err != nil { 1044 t.Fatalf("err: %s", err) 1045 } 1046 1047 actual := strings.TrimSpace(state.String()) 1048 expected := strings.TrimSpace(testTerraformApplyCountVariableStr) 1049 if actual != expected { 1050 t.Fatalf("bad: \n%s", actual) 1051 } 1052 } 1053 1054 func TestContext2Apply_mapVariableOverride(t *testing.T) { 1055 m := testModule(t, "apply-map-var-override") 1056 p := testProvider("aws") 1057 p.ApplyFn = testApplyFn 1058 p.DiffFn = testDiffFn 1059 ctx := testContext2(t, &ContextOpts{ 1060 Module: m, 1061 Providers: map[string]ResourceProviderFactory{ 1062 "aws": testProviderFuncFixed(p), 1063 }, 1064 Variables: map[string]string{ 1065 "images.us-west-2": "overridden", 1066 }, 1067 }) 1068 1069 if _, err := ctx.Plan(); err != nil { 1070 t.Fatalf("err: %s", err) 1071 } 1072 1073 state, err := ctx.Apply() 1074 if err != nil { 1075 t.Fatalf("err: %s", err) 1076 } 1077 1078 actual := strings.TrimSpace(state.String()) 1079 expected := strings.TrimSpace(` 1080 aws_instance.bar: 1081 ID = foo 1082 ami = overridden 1083 type = aws_instance 1084 aws_instance.foo: 1085 ID = foo 1086 ami = image-1234 1087 type = aws_instance 1088 `) 1089 if actual != expected { 1090 t.Fatalf("got: \n%s\nexpected: \n%s", actual, expected) 1091 } 1092 } 1093 1094 func TestContext2Apply_module(t *testing.T) { 1095 m := testModule(t, "apply-module") 1096 p := testProvider("aws") 1097 p.ApplyFn = testApplyFn 1098 p.DiffFn = testDiffFn 1099 ctx := testContext2(t, &ContextOpts{ 1100 Module: m, 1101 Providers: map[string]ResourceProviderFactory{ 1102 "aws": testProviderFuncFixed(p), 1103 }, 1104 }) 1105 1106 if _, err := ctx.Plan(); err != nil { 1107 t.Fatalf("err: %s", err) 1108 } 1109 1110 state, err := ctx.Apply() 1111 if err != nil { 1112 t.Fatalf("err: %s", err) 1113 } 1114 1115 actual := strings.TrimSpace(state.String()) 1116 expected := strings.TrimSpace(testTerraformApplyModuleStr) 1117 if actual != expected { 1118 t.Fatalf("bad: \n%s", actual) 1119 } 1120 } 1121 1122 func TestContext2Apply_moduleDestroyOrder(t *testing.T) { 1123 m := testModule(t, "apply-module-destroy-order") 1124 p := testProvider("aws") 1125 p.DiffFn = testDiffFn 1126 1127 // Create a custom apply function to track the order they were destroyed 1128 var order []string 1129 var orderLock sync.Mutex 1130 p.ApplyFn = func( 1131 info *InstanceInfo, 1132 is *InstanceState, 1133 id *InstanceDiff) (*InstanceState, error) { 1134 orderLock.Lock() 1135 defer orderLock.Unlock() 1136 1137 order = append(order, is.ID) 1138 return nil, nil 1139 } 1140 1141 state := &State{ 1142 Modules: []*ModuleState{ 1143 &ModuleState{ 1144 Path: rootModulePath, 1145 Resources: map[string]*ResourceState{ 1146 "aws_instance.b": &ResourceState{ 1147 Type: "aws_instance", 1148 Primary: &InstanceState{ 1149 ID: "b", 1150 }, 1151 }, 1152 }, 1153 }, 1154 1155 &ModuleState{ 1156 Path: []string{"root", "child"}, 1157 Resources: map[string]*ResourceState{ 1158 "aws_instance.a": &ResourceState{ 1159 Type: "aws_instance", 1160 Primary: &InstanceState{ 1161 ID: "a", 1162 }, 1163 }, 1164 }, 1165 Outputs: map[string]*OutputState{ 1166 "a_output": &OutputState{ 1167 Type: "string", 1168 Sensitive: false, 1169 Value: "a", 1170 }, 1171 }, 1172 }, 1173 }, 1174 } 1175 1176 ctx := testContext2(t, &ContextOpts{ 1177 Module: m, 1178 Providers: map[string]ResourceProviderFactory{ 1179 "aws": testProviderFuncFixed(p), 1180 }, 1181 State: state, 1182 Destroy: true, 1183 }) 1184 1185 if _, err := ctx.Plan(); err != nil { 1186 t.Fatalf("err: %s", err) 1187 } 1188 1189 state, err := ctx.Apply() 1190 if err != nil { 1191 t.Fatalf("err: %s", err) 1192 } 1193 1194 expected := []string{"b", "a"} 1195 if !reflect.DeepEqual(order, expected) { 1196 t.Fatalf("bad: %#v", order) 1197 } 1198 1199 { 1200 actual := strings.TrimSpace(state.String()) 1201 expected := strings.TrimSpace(testTerraformApplyModuleDestroyOrderStr) 1202 if actual != expected { 1203 t.Fatalf("bad: \n%s", actual) 1204 } 1205 } 1206 } 1207 1208 func TestContext2Apply_moduleOrphanProvider(t *testing.T) { 1209 m := testModule(t, "apply-module-orphan-provider-inherit") 1210 p := testProvider("aws") 1211 p.ApplyFn = testApplyFn 1212 p.DiffFn = testDiffFn 1213 1214 p.ConfigureFn = func(c *ResourceConfig) error { 1215 if _, ok := c.Get("value"); !ok { 1216 return fmt.Errorf("value is not found") 1217 } 1218 1219 return nil 1220 } 1221 1222 // Create a state with an orphan module 1223 state := &State{ 1224 Modules: []*ModuleState{ 1225 &ModuleState{ 1226 Path: []string{"root", "child"}, 1227 Resources: map[string]*ResourceState{ 1228 "aws_instance.bar": &ResourceState{ 1229 Type: "aws_instance", 1230 Primary: &InstanceState{ 1231 ID: "bar", 1232 }, 1233 }, 1234 }, 1235 }, 1236 }, 1237 } 1238 1239 ctx := testContext2(t, &ContextOpts{ 1240 Module: m, 1241 State: state, 1242 Providers: map[string]ResourceProviderFactory{ 1243 "aws": testProviderFuncFixed(p), 1244 }, 1245 }) 1246 1247 if _, err := ctx.Plan(); err != nil { 1248 t.Fatalf("err: %s", err) 1249 } 1250 1251 if _, err := ctx.Apply(); err != nil { 1252 t.Fatalf("err: %s", err) 1253 } 1254 } 1255 1256 func TestContext2Apply_moduleGrandchildProvider(t *testing.T) { 1257 m := testModule(t, "apply-module-grandchild-provider-inherit") 1258 p := testProvider("aws") 1259 p.ApplyFn = testApplyFn 1260 p.DiffFn = testDiffFn 1261 1262 var callLock sync.Mutex 1263 called := false 1264 p.ConfigureFn = func(c *ResourceConfig) error { 1265 if _, ok := c.Get("value"); !ok { 1266 return fmt.Errorf("value is not found") 1267 } 1268 callLock.Lock() 1269 called = true 1270 callLock.Unlock() 1271 1272 return nil 1273 } 1274 1275 ctx := testContext2(t, &ContextOpts{ 1276 Module: m, 1277 Providers: map[string]ResourceProviderFactory{ 1278 "aws": testProviderFuncFixed(p), 1279 }, 1280 }) 1281 1282 if _, err := ctx.Plan(); err != nil { 1283 t.Fatalf("err: %s", err) 1284 } 1285 1286 if _, err := ctx.Apply(); err != nil { 1287 t.Fatalf("err: %s", err) 1288 } 1289 1290 callLock.Lock() 1291 defer callLock.Unlock() 1292 if called != true { 1293 t.Fatalf("err: configure never called") 1294 } 1295 } 1296 1297 // This tests an issue where all the providers in a module but not 1298 // in the root weren't being added to the root properly. In this test 1299 // case: aws is explicitly added to root, but "test" should be added to. 1300 // With the bug, it wasn't. 1301 func TestContext2Apply_moduleOnlyProvider(t *testing.T) { 1302 m := testModule(t, "apply-module-only-provider") 1303 p := testProvider("aws") 1304 p.ApplyFn = testApplyFn 1305 p.DiffFn = testDiffFn 1306 pTest := testProvider("test") 1307 pTest.ApplyFn = testApplyFn 1308 pTest.DiffFn = testDiffFn 1309 1310 ctx := testContext2(t, &ContextOpts{ 1311 Module: m, 1312 Providers: map[string]ResourceProviderFactory{ 1313 "aws": testProviderFuncFixed(p), 1314 "test": testProviderFuncFixed(pTest), 1315 }, 1316 }) 1317 1318 if _, err := ctx.Plan(); err != nil { 1319 t.Fatalf("err: %s", err) 1320 } 1321 1322 state, err := ctx.Apply() 1323 if err != nil { 1324 t.Fatalf("err: %s", err) 1325 } 1326 1327 actual := strings.TrimSpace(state.String()) 1328 expected := strings.TrimSpace(testTerraformApplyModuleOnlyProviderStr) 1329 if actual != expected { 1330 t.Fatalf("bad: \n%s", actual) 1331 } 1332 } 1333 1334 func TestContext2Apply_moduleProviderAlias(t *testing.T) { 1335 m := testModule(t, "apply-module-provider-alias") 1336 p := testProvider("aws") 1337 p.ApplyFn = testApplyFn 1338 p.DiffFn = testDiffFn 1339 ctx := testContext2(t, &ContextOpts{ 1340 Module: m, 1341 Providers: map[string]ResourceProviderFactory{ 1342 "aws": testProviderFuncFixed(p), 1343 }, 1344 }) 1345 1346 if _, err := ctx.Plan(); err != nil { 1347 t.Fatalf("err: %s", err) 1348 } 1349 1350 state, err := ctx.Apply() 1351 if err != nil { 1352 t.Fatalf("err: %s", err) 1353 } 1354 1355 actual := strings.TrimSpace(state.String()) 1356 expected := strings.TrimSpace(testTerraformApplyModuleProviderAliasStr) 1357 if actual != expected { 1358 t.Fatalf("bad: \n%s", actual) 1359 } 1360 } 1361 1362 func TestContext2Apply_moduleProviderAliasTargets(t *testing.T) { 1363 m := testModule(t, "apply-module-provider-alias") 1364 p := testProvider("aws") 1365 p.ApplyFn = testApplyFn 1366 p.DiffFn = testDiffFn 1367 ctx := testContext2(t, &ContextOpts{ 1368 Module: m, 1369 Providers: map[string]ResourceProviderFactory{ 1370 "aws": testProviderFuncFixed(p), 1371 }, 1372 Targets: []string{"no.thing"}, 1373 }) 1374 1375 if _, err := ctx.Plan(); err != nil { 1376 t.Fatalf("err: %s", err) 1377 } 1378 1379 state, err := ctx.Apply() 1380 if err != nil { 1381 t.Fatalf("err: %s", err) 1382 } 1383 1384 actual := strings.TrimSpace(state.String()) 1385 expected := strings.TrimSpace(` 1386 <no state> 1387 `) 1388 if actual != expected { 1389 t.Fatalf("bad: \n%s", actual) 1390 } 1391 } 1392 1393 func TestContext2Apply_moduleProviderCloseNested(t *testing.T) { 1394 m := testModule(t, "apply-module-provider-close-nested") 1395 p := testProvider("aws") 1396 p.ApplyFn = testApplyFn 1397 p.DiffFn = testDiffFn 1398 ctx := testContext2(t, &ContextOpts{ 1399 Module: m, 1400 Providers: map[string]ResourceProviderFactory{ 1401 "aws": testProviderFuncFixed(p), 1402 }, 1403 State: &State{ 1404 Modules: []*ModuleState{ 1405 &ModuleState{ 1406 Path: []string{"root", "child", "subchild"}, 1407 Resources: map[string]*ResourceState{ 1408 "aws_instance.foo": &ResourceState{ 1409 Type: "aws_instance", 1410 Primary: &InstanceState{ 1411 ID: "bar", 1412 }, 1413 }, 1414 }, 1415 }, 1416 }, 1417 }, 1418 Destroy: true, 1419 }) 1420 1421 if _, err := ctx.Plan(); err != nil { 1422 t.Fatalf("err: %s", err) 1423 } 1424 1425 if _, err := ctx.Apply(); err != nil { 1426 t.Fatalf("err: %s", err) 1427 } 1428 } 1429 1430 func TestContext2Apply_moduleVarResourceCount(t *testing.T) { 1431 m := testModule(t, "apply-module-var-resource-count") 1432 p := testProvider("aws") 1433 p.ApplyFn = testApplyFn 1434 p.DiffFn = testDiffFn 1435 ctx := testContext2(t, &ContextOpts{ 1436 Module: m, 1437 Providers: map[string]ResourceProviderFactory{ 1438 "aws": testProviderFuncFixed(p), 1439 }, 1440 Variables: map[string]string{ 1441 "count": "2", 1442 }, 1443 Destroy: true, 1444 }) 1445 1446 if _, err := ctx.Plan(); err != nil { 1447 t.Fatalf("err: %s", err) 1448 } 1449 1450 if _, err := ctx.Apply(); err != nil { 1451 t.Fatalf("err: %s", err) 1452 } 1453 1454 ctx = testContext2(t, &ContextOpts{ 1455 Module: m, 1456 Providers: map[string]ResourceProviderFactory{ 1457 "aws": testProviderFuncFixed(p), 1458 }, 1459 Variables: map[string]string{ 1460 "count": "5", 1461 }, 1462 }) 1463 1464 if _, err := ctx.Plan(); err != nil { 1465 t.Fatalf("err: %s", err) 1466 } 1467 1468 if _, err := ctx.Apply(); err != nil { 1469 t.Fatalf("err: %s", err) 1470 } 1471 } 1472 1473 // GH-819 1474 func TestContext2Apply_moduleBool(t *testing.T) { 1475 m := testModule(t, "apply-module-bool") 1476 p := testProvider("aws") 1477 p.ApplyFn = testApplyFn 1478 p.DiffFn = testDiffFn 1479 ctx := testContext2(t, &ContextOpts{ 1480 Module: m, 1481 Providers: map[string]ResourceProviderFactory{ 1482 "aws": testProviderFuncFixed(p), 1483 }, 1484 }) 1485 1486 if _, err := ctx.Plan(); err != nil { 1487 t.Fatalf("err: %s", err) 1488 } 1489 1490 state, err := ctx.Apply() 1491 if err != nil { 1492 t.Fatalf("err: %s", err) 1493 } 1494 1495 actual := strings.TrimSpace(state.String()) 1496 expected := strings.TrimSpace(testTerraformApplyModuleBoolStr) 1497 if actual != expected { 1498 t.Fatalf("bad: \n%s", actual) 1499 } 1500 } 1501 1502 func TestContext2Apply_multiProvider(t *testing.T) { 1503 m := testModule(t, "apply-multi-provider") 1504 p := testProvider("aws") 1505 p.ApplyFn = testApplyFn 1506 p.DiffFn = testDiffFn 1507 1508 pDO := testProvider("do") 1509 pDO.ApplyFn = testApplyFn 1510 pDO.DiffFn = testDiffFn 1511 1512 ctx := testContext2(t, &ContextOpts{ 1513 Module: m, 1514 Providers: map[string]ResourceProviderFactory{ 1515 "aws": testProviderFuncFixed(p), 1516 "do": testProviderFuncFixed(pDO), 1517 }, 1518 }) 1519 1520 if _, err := ctx.Plan(); err != nil { 1521 t.Fatalf("err: %s", err) 1522 } 1523 1524 state, err := ctx.Apply() 1525 if err != nil { 1526 t.Fatalf("err: %s", err) 1527 } 1528 1529 mod := state.RootModule() 1530 if len(mod.Resources) < 2 { 1531 t.Fatalf("bad: %#v", mod.Resources) 1532 } 1533 1534 actual := strings.TrimSpace(state.String()) 1535 expected := strings.TrimSpace(testTerraformApplyMultiProviderStr) 1536 if actual != expected { 1537 t.Fatalf("bad: \n%s", actual) 1538 } 1539 } 1540 1541 func TestContext2Apply_multiVar(t *testing.T) { 1542 m := testModule(t, "apply-multi-var") 1543 p := testProvider("aws") 1544 p.ApplyFn = testApplyFn 1545 p.DiffFn = testDiffFn 1546 1547 // First, apply with a count of 3 1548 ctx := testContext2(t, &ContextOpts{ 1549 Module: m, 1550 Providers: map[string]ResourceProviderFactory{ 1551 "aws": testProviderFuncFixed(p), 1552 }, 1553 Variables: map[string]string{ 1554 "count": "3", 1555 }, 1556 }) 1557 1558 if _, err := ctx.Plan(); err != nil { 1559 t.Fatalf("err: %s", err) 1560 } 1561 1562 state, err := ctx.Apply() 1563 if err != nil { 1564 t.Fatalf("err: %s", err) 1565 } 1566 1567 actual := state.RootModule().Outputs["output"] 1568 expected := "bar0,bar1,bar2" 1569 if actual.Value != expected { 1570 t.Fatalf("bad: \n%s", actual) 1571 } 1572 1573 // Apply again, reduce the count to 1 1574 { 1575 ctx := testContext2(t, &ContextOpts{ 1576 Module: m, 1577 State: state, 1578 Providers: map[string]ResourceProviderFactory{ 1579 "aws": testProviderFuncFixed(p), 1580 }, 1581 Variables: map[string]string{ 1582 "count": "1", 1583 }, 1584 }) 1585 1586 if _, err := ctx.Plan(); err != nil { 1587 t.Fatalf("err: %s", err) 1588 } 1589 1590 state, err := ctx.Apply() 1591 if err != nil { 1592 t.Fatalf("err: %s", err) 1593 } 1594 1595 actual := state.RootModule().Outputs["output"] 1596 expected := "bar0" 1597 if actual.Value != expected { 1598 t.Fatalf("bad: \n%s", actual) 1599 } 1600 } 1601 } 1602 1603 func TestContext2Apply_nilDiff(t *testing.T) { 1604 m := testModule(t, "apply-good") 1605 p := testProvider("aws") 1606 p.ApplyFn = testApplyFn 1607 p.DiffFn = testDiffFn 1608 ctx := testContext2(t, &ContextOpts{ 1609 Module: m, 1610 Providers: map[string]ResourceProviderFactory{ 1611 "aws": testProviderFuncFixed(p), 1612 }, 1613 }) 1614 1615 if _, err := ctx.Plan(); err != nil { 1616 t.Fatalf("err: %s", err) 1617 } 1618 1619 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 1620 return nil, nil 1621 } 1622 1623 if _, err := ctx.Apply(); err == nil { 1624 t.Fatal("should error") 1625 } 1626 } 1627 1628 func TestContext2Apply_outputOrphan(t *testing.T) { 1629 m := testModule(t, "apply-output-orphan") 1630 p := testProvider("aws") 1631 p.ApplyFn = testApplyFn 1632 p.DiffFn = testDiffFn 1633 1634 state := &State{ 1635 Modules: []*ModuleState{ 1636 &ModuleState{ 1637 Path: rootModulePath, 1638 Outputs: map[string]*OutputState{ 1639 "foo": &OutputState{ 1640 Type: "string", 1641 Sensitive: false, 1642 Value: "bar", 1643 }, 1644 "bar": &OutputState{ 1645 Type: "string", 1646 Sensitive: false, 1647 Value: "baz", 1648 }, 1649 }, 1650 }, 1651 }, 1652 } 1653 1654 ctx := testContext2(t, &ContextOpts{ 1655 Module: m, 1656 Providers: map[string]ResourceProviderFactory{ 1657 "aws": testProviderFuncFixed(p), 1658 }, 1659 State: state, 1660 }) 1661 1662 if _, err := ctx.Plan(); err != nil { 1663 t.Fatalf("err: %s", err) 1664 } 1665 1666 state, err := ctx.Apply() 1667 if err != nil { 1668 t.Fatalf("err: %s", err) 1669 } 1670 1671 actual := strings.TrimSpace(state.String()) 1672 expected := strings.TrimSpace(testTerraformApplyOutputOrphanStr) 1673 if actual != expected { 1674 t.Fatalf("bad: \n%s", actual) 1675 } 1676 } 1677 1678 func TestContext2Apply_providerComputedVar(t *testing.T) { 1679 m := testModule(t, "apply-provider-computed") 1680 p := testProvider("aws") 1681 p.ApplyFn = testApplyFn 1682 p.DiffFn = testDiffFn 1683 1684 pTest := testProvider("test") 1685 pTest.ApplyFn = testApplyFn 1686 pTest.DiffFn = testDiffFn 1687 1688 ctx := testContext2(t, &ContextOpts{ 1689 Module: m, 1690 Providers: map[string]ResourceProviderFactory{ 1691 "aws": testProviderFuncFixed(p), 1692 "test": testProviderFuncFixed(pTest), 1693 }, 1694 }) 1695 1696 p.ConfigureFn = func(c *ResourceConfig) error { 1697 if c.IsComputed("value") { 1698 return fmt.Errorf("value is computed") 1699 } 1700 1701 v, ok := c.Get("value") 1702 if !ok { 1703 return fmt.Errorf("value is not found") 1704 } 1705 if v != "yes" { 1706 return fmt.Errorf("value is not 'yes': %v", v) 1707 } 1708 1709 return nil 1710 } 1711 1712 if _, err := ctx.Plan(); err != nil { 1713 t.Fatalf("err: %s", err) 1714 } 1715 1716 if _, err := ctx.Apply(); err != nil { 1717 t.Fatalf("err: %s", err) 1718 } 1719 } 1720 1721 func TestContext2Apply_Provisioner_compute(t *testing.T) { 1722 m := testModule(t, "apply-provisioner-compute") 1723 p := testProvider("aws") 1724 pr := testProvisioner() 1725 p.ApplyFn = testApplyFn 1726 p.DiffFn = testDiffFn 1727 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 1728 val, ok := c.Config["foo"] 1729 if !ok || val != "computed_dynamical" { 1730 t.Fatalf("bad value for foo: %v %#v", val, c) 1731 } 1732 1733 return nil 1734 } 1735 ctx := testContext2(t, &ContextOpts{ 1736 Module: m, 1737 Providers: map[string]ResourceProviderFactory{ 1738 "aws": testProviderFuncFixed(p), 1739 }, 1740 Provisioners: map[string]ResourceProvisionerFactory{ 1741 "shell": testProvisionerFuncFixed(pr), 1742 }, 1743 Variables: map[string]string{ 1744 "value": "1", 1745 }, 1746 }) 1747 1748 if _, err := ctx.Plan(); err != nil { 1749 t.Fatalf("err: %s", err) 1750 } 1751 1752 state, err := ctx.Apply() 1753 if err != nil { 1754 t.Fatalf("err: %s", err) 1755 } 1756 1757 actual := strings.TrimSpace(state.String()) 1758 expected := strings.TrimSpace(testTerraformApplyProvisionerStr) 1759 if actual != expected { 1760 t.Fatalf("bad: \n%s", actual) 1761 } 1762 1763 // Verify apply was invoked 1764 if !pr.ApplyCalled { 1765 t.Fatalf("provisioner not invoked") 1766 } 1767 } 1768 1769 func TestContext2Apply_provisionerCreateFail(t *testing.T) { 1770 m := testModule(t, "apply-provisioner-fail-create") 1771 p := testProvider("aws") 1772 pr := testProvisioner() 1773 p.DiffFn = testDiffFn 1774 1775 p.ApplyFn = func( 1776 info *InstanceInfo, 1777 is *InstanceState, 1778 id *InstanceDiff) (*InstanceState, error) { 1779 is.ID = "foo" 1780 return is, fmt.Errorf("error") 1781 } 1782 1783 ctx := testContext2(t, &ContextOpts{ 1784 Module: m, 1785 Providers: map[string]ResourceProviderFactory{ 1786 "aws": testProviderFuncFixed(p), 1787 }, 1788 Provisioners: map[string]ResourceProvisionerFactory{ 1789 "shell": testProvisionerFuncFixed(pr), 1790 }, 1791 }) 1792 1793 if _, err := ctx.Plan(); err != nil { 1794 t.Fatalf("err: %s", err) 1795 } 1796 1797 state, err := ctx.Apply() 1798 if err == nil { 1799 t.Fatal("should error") 1800 } 1801 1802 actual := strings.TrimSpace(state.String()) 1803 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateStr) 1804 if actual != expected { 1805 t.Fatalf("bad: \n%s", actual) 1806 } 1807 } 1808 1809 func TestContext2Apply_provisionerCreateFailNoId(t *testing.T) { 1810 m := testModule(t, "apply-provisioner-fail-create") 1811 p := testProvider("aws") 1812 pr := testProvisioner() 1813 p.DiffFn = testDiffFn 1814 1815 p.ApplyFn = func( 1816 info *InstanceInfo, 1817 is *InstanceState, 1818 id *InstanceDiff) (*InstanceState, error) { 1819 return nil, fmt.Errorf("error") 1820 } 1821 1822 ctx := testContext2(t, &ContextOpts{ 1823 Module: m, 1824 Providers: map[string]ResourceProviderFactory{ 1825 "aws": testProviderFuncFixed(p), 1826 }, 1827 Provisioners: map[string]ResourceProvisionerFactory{ 1828 "shell": testProvisionerFuncFixed(pr), 1829 }, 1830 }) 1831 1832 if _, err := ctx.Plan(); err != nil { 1833 t.Fatalf("err: %s", err) 1834 } 1835 1836 state, err := ctx.Apply() 1837 if err == nil { 1838 t.Fatal("should error") 1839 } 1840 1841 actual := strings.TrimSpace(state.String()) 1842 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateNoIdStr) 1843 if actual != expected { 1844 t.Fatalf("bad: \n%s", actual) 1845 } 1846 } 1847 1848 func TestContext2Apply_provisionerFail(t *testing.T) { 1849 m := testModule(t, "apply-provisioner-fail") 1850 p := testProvider("aws") 1851 pr := testProvisioner() 1852 p.ApplyFn = testApplyFn 1853 p.DiffFn = testDiffFn 1854 1855 pr.ApplyFn = func(*InstanceState, *ResourceConfig) error { 1856 return fmt.Errorf("EXPLOSION") 1857 } 1858 1859 ctx := testContext2(t, &ContextOpts{ 1860 Module: m, 1861 Providers: map[string]ResourceProviderFactory{ 1862 "aws": testProviderFuncFixed(p), 1863 }, 1864 Provisioners: map[string]ResourceProvisionerFactory{ 1865 "shell": testProvisionerFuncFixed(pr), 1866 }, 1867 Variables: map[string]string{ 1868 "value": "1", 1869 }, 1870 }) 1871 1872 if _, err := ctx.Plan(); err != nil { 1873 t.Fatalf("err: %s", err) 1874 } 1875 1876 state, err := ctx.Apply() 1877 if err == nil { 1878 t.Fatal("should error") 1879 } 1880 1881 actual := strings.TrimSpace(state.String()) 1882 expected := strings.TrimSpace(testTerraformApplyProvisionerFailStr) 1883 if actual != expected { 1884 t.Fatalf("bad: \n%s", actual) 1885 } 1886 } 1887 1888 func TestContext2Apply_provisionerFail_createBeforeDestroy(t *testing.T) { 1889 m := testModule(t, "apply-provisioner-fail-create-before") 1890 p := testProvider("aws") 1891 pr := testProvisioner() 1892 p.ApplyFn = testApplyFn 1893 p.DiffFn = testDiffFn 1894 pr.ApplyFn = func(*InstanceState, *ResourceConfig) error { 1895 return fmt.Errorf("EXPLOSION") 1896 } 1897 1898 state := &State{ 1899 Modules: []*ModuleState{ 1900 &ModuleState{ 1901 Path: rootModulePath, 1902 Resources: map[string]*ResourceState{ 1903 "aws_instance.bar": &ResourceState{ 1904 Type: "aws_instance", 1905 Primary: &InstanceState{ 1906 ID: "bar", 1907 Attributes: map[string]string{ 1908 "require_new": "abc", 1909 }, 1910 }, 1911 }, 1912 }, 1913 }, 1914 }, 1915 } 1916 ctx := testContext2(t, &ContextOpts{ 1917 Module: m, 1918 Providers: map[string]ResourceProviderFactory{ 1919 "aws": testProviderFuncFixed(p), 1920 }, 1921 Provisioners: map[string]ResourceProvisionerFactory{ 1922 "shell": testProvisionerFuncFixed(pr), 1923 }, 1924 State: state, 1925 }) 1926 1927 if _, err := ctx.Plan(); err != nil { 1928 t.Fatalf("err: %s", err) 1929 } 1930 1931 state, err := ctx.Apply() 1932 if err == nil { 1933 t.Fatal("should error") 1934 } 1935 1936 actual := strings.TrimSpace(state.String()) 1937 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateBeforeDestroyStr) 1938 if actual != expected { 1939 t.Fatalf("bad: \n%s", actual) 1940 } 1941 } 1942 1943 func TestContext2Apply_error_createBeforeDestroy(t *testing.T) { 1944 m := testModule(t, "apply-error-create-before") 1945 p := testProvider("aws") 1946 state := &State{ 1947 Modules: []*ModuleState{ 1948 &ModuleState{ 1949 Path: rootModulePath, 1950 Resources: map[string]*ResourceState{ 1951 "aws_instance.bar": &ResourceState{ 1952 Type: "aws_instance", 1953 Primary: &InstanceState{ 1954 ID: "bar", 1955 Attributes: map[string]string{ 1956 "require_new": "abc", 1957 }, 1958 }, 1959 }, 1960 }, 1961 }, 1962 }, 1963 } 1964 ctx := testContext2(t, &ContextOpts{ 1965 Module: m, 1966 Providers: map[string]ResourceProviderFactory{ 1967 "aws": testProviderFuncFixed(p), 1968 }, 1969 State: state, 1970 }) 1971 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 1972 return nil, fmt.Errorf("error") 1973 } 1974 p.DiffFn = testDiffFn 1975 1976 if _, err := ctx.Plan(); err != nil { 1977 t.Fatalf("err: %s", err) 1978 } 1979 1980 state, err := ctx.Apply() 1981 if err == nil { 1982 t.Fatal("should have error") 1983 } 1984 1985 actual := strings.TrimSpace(state.String()) 1986 expected := strings.TrimSpace(testTerraformApplyErrorCreateBeforeDestroyStr) 1987 if actual != expected { 1988 t.Fatalf("bad: \n%s\n\nExpected:\n\n%s", actual, expected) 1989 } 1990 } 1991 1992 func TestContext2Apply_errorDestroy_createBeforeDestroy(t *testing.T) { 1993 m := testModule(t, "apply-error-create-before") 1994 p := testProvider("aws") 1995 state := &State{ 1996 Modules: []*ModuleState{ 1997 &ModuleState{ 1998 Path: rootModulePath, 1999 Resources: map[string]*ResourceState{ 2000 "aws_instance.bar": &ResourceState{ 2001 Type: "aws_instance", 2002 Primary: &InstanceState{ 2003 ID: "bar", 2004 Attributes: map[string]string{ 2005 "require_new": "abc", 2006 }, 2007 }, 2008 }, 2009 }, 2010 }, 2011 }, 2012 } 2013 ctx := testContext2(t, &ContextOpts{ 2014 Module: m, 2015 Providers: map[string]ResourceProviderFactory{ 2016 "aws": testProviderFuncFixed(p), 2017 }, 2018 State: state, 2019 }) 2020 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 2021 // Fail the destroy! 2022 if id.Destroy { 2023 return is, fmt.Errorf("error") 2024 } 2025 2026 // Create should work 2027 is = &InstanceState{ 2028 ID: "foo", 2029 } 2030 return is, nil 2031 } 2032 p.DiffFn = testDiffFn 2033 2034 if _, err := ctx.Plan(); err != nil { 2035 t.Fatalf("err: %s", err) 2036 } 2037 2038 state, err := ctx.Apply() 2039 if err == nil { 2040 t.Fatal("should have error") 2041 } 2042 2043 actual := strings.TrimSpace(state.String()) 2044 expected := strings.TrimSpace(testTerraformApplyErrorDestroyCreateBeforeDestroyStr) 2045 if actual != expected { 2046 t.Fatalf("bad: actual:\n%s\n\nexpected:\n%s", actual, expected) 2047 } 2048 } 2049 2050 func TestContext2Apply_multiDepose_createBeforeDestroy(t *testing.T) { 2051 m := testModule(t, "apply-multi-depose-create-before-destroy") 2052 p := testProvider("aws") 2053 p.DiffFn = testDiffFn 2054 ps := map[string]ResourceProviderFactory{"aws": testProviderFuncFixed(p)} 2055 state := &State{ 2056 Modules: []*ModuleState{ 2057 &ModuleState{ 2058 Path: rootModulePath, 2059 Resources: map[string]*ResourceState{ 2060 "aws_instance.web": &ResourceState{ 2061 Type: "aws_instance", 2062 Primary: &InstanceState{ID: "foo"}, 2063 }, 2064 }, 2065 }, 2066 }, 2067 } 2068 2069 ctx := testContext2(t, &ContextOpts{ 2070 Module: m, 2071 Providers: ps, 2072 State: state, 2073 }) 2074 createdInstanceId := "bar" 2075 // Create works 2076 createFunc := func(is *InstanceState) (*InstanceState, error) { 2077 return &InstanceState{ID: createdInstanceId}, nil 2078 } 2079 // Destroy starts broken 2080 destroyFunc := func(is *InstanceState) (*InstanceState, error) { 2081 return is, fmt.Errorf("destroy failed") 2082 } 2083 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 2084 if id.Destroy { 2085 return destroyFunc(is) 2086 } else { 2087 return createFunc(is) 2088 } 2089 } 2090 2091 if _, err := ctx.Plan(); err != nil { 2092 t.Fatalf("err: %s", err) 2093 } 2094 2095 // Destroy is broken, so even though CBD successfully replaces the instance, 2096 // we'll have to save the Deposed instance to destroy later 2097 state, err := ctx.Apply() 2098 if err == nil { 2099 t.Fatal("should have error") 2100 } 2101 2102 checkStateString(t, state, ` 2103 aws_instance.web: (1 deposed) 2104 ID = bar 2105 Deposed ID 1 = foo 2106 `) 2107 2108 createdInstanceId = "baz" 2109 ctx = testContext2(t, &ContextOpts{ 2110 Module: m, 2111 Providers: ps, 2112 State: state, 2113 }) 2114 2115 if _, err := ctx.Plan(); err != nil { 2116 t.Fatalf("err: %s", err) 2117 } 2118 2119 // We're replacing the primary instance once again. Destroy is _still_ 2120 // broken, so the Deposed list gets longer 2121 state, err = ctx.Apply() 2122 if err == nil { 2123 t.Fatal("should have error") 2124 } 2125 2126 checkStateString(t, state, ` 2127 aws_instance.web: (2 deposed) 2128 ID = baz 2129 Deposed ID 1 = foo 2130 Deposed ID 2 = bar 2131 `) 2132 2133 // Destroy partially fixed! 2134 destroyFunc = func(is *InstanceState) (*InstanceState, error) { 2135 if is.ID == "foo" || is.ID == "baz" { 2136 return nil, nil 2137 } else { 2138 return is, fmt.Errorf("destroy partially failed") 2139 } 2140 } 2141 2142 createdInstanceId = "qux" 2143 if _, err := ctx.Plan(); err != nil { 2144 t.Fatalf("err: %s", err) 2145 } 2146 state, err = ctx.Apply() 2147 // Expect error because 1/2 of Deposed destroys failed 2148 if err == nil { 2149 t.Fatal("should have error") 2150 } 2151 2152 // foo and baz are now gone, bar sticks around 2153 checkStateString(t, state, ` 2154 aws_instance.web: (1 deposed) 2155 ID = qux 2156 Deposed ID 1 = bar 2157 `) 2158 2159 // Destroy working fully! 2160 destroyFunc = func(is *InstanceState) (*InstanceState, error) { 2161 return nil, nil 2162 } 2163 2164 createdInstanceId = "quux" 2165 if _, err := ctx.Plan(); err != nil { 2166 t.Fatalf("err: %s", err) 2167 } 2168 state, err = ctx.Apply() 2169 if err != nil { 2170 t.Fatal("should not have error:", err) 2171 } 2172 2173 // And finally the state is clean 2174 checkStateString(t, state, ` 2175 aws_instance.web: 2176 ID = quux 2177 `) 2178 } 2179 2180 func TestContext2Apply_provisionerResourceRef(t *testing.T) { 2181 m := testModule(t, "apply-provisioner-resource-ref") 2182 p := testProvider("aws") 2183 pr := testProvisioner() 2184 p.ApplyFn = testApplyFn 2185 p.DiffFn = testDiffFn 2186 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 2187 val, ok := c.Config["foo"] 2188 if !ok || val != "2" { 2189 t.Fatalf("bad value for foo: %v %#v", val, c) 2190 } 2191 2192 return nil 2193 } 2194 2195 ctx := testContext2(t, &ContextOpts{ 2196 Module: m, 2197 Providers: map[string]ResourceProviderFactory{ 2198 "aws": testProviderFuncFixed(p), 2199 }, 2200 Provisioners: map[string]ResourceProvisionerFactory{ 2201 "shell": testProvisionerFuncFixed(pr), 2202 }, 2203 }) 2204 2205 if _, err := ctx.Plan(); err != nil { 2206 t.Fatalf("err: %s", err) 2207 } 2208 2209 state, err := ctx.Apply() 2210 if err != nil { 2211 t.Fatalf("err: %s", err) 2212 } 2213 2214 actual := strings.TrimSpace(state.String()) 2215 expected := strings.TrimSpace(testTerraformApplyProvisionerResourceRefStr) 2216 if actual != expected { 2217 t.Fatalf("bad: \n%s", actual) 2218 } 2219 2220 // Verify apply was invoked 2221 if !pr.ApplyCalled { 2222 t.Fatalf("provisioner not invoked") 2223 } 2224 } 2225 2226 func TestContext2Apply_provisionerSelfRef(t *testing.T) { 2227 m := testModule(t, "apply-provisioner-self-ref") 2228 p := testProvider("aws") 2229 pr := testProvisioner() 2230 p.ApplyFn = testApplyFn 2231 p.DiffFn = testDiffFn 2232 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 2233 val, ok := c.Config["command"] 2234 if !ok || val != "bar" { 2235 t.Fatalf("bad value for command: %v %#v", val, c) 2236 } 2237 2238 return nil 2239 } 2240 2241 ctx := testContext2(t, &ContextOpts{ 2242 Module: m, 2243 Providers: map[string]ResourceProviderFactory{ 2244 "aws": testProviderFuncFixed(p), 2245 }, 2246 Provisioners: map[string]ResourceProvisionerFactory{ 2247 "shell": testProvisionerFuncFixed(pr), 2248 }, 2249 }) 2250 2251 if _, err := ctx.Plan(); err != nil { 2252 t.Fatalf("err: %s", err) 2253 } 2254 2255 state, err := ctx.Apply() 2256 if err != nil { 2257 t.Fatalf("err: %s", err) 2258 } 2259 2260 actual := strings.TrimSpace(state.String()) 2261 expected := strings.TrimSpace(testTerraformApplyProvisionerSelfRefStr) 2262 if actual != expected { 2263 t.Fatalf("bad: \n%s", actual) 2264 } 2265 2266 // Verify apply was invoked 2267 if !pr.ApplyCalled { 2268 t.Fatalf("provisioner not invoked") 2269 } 2270 } 2271 2272 func TestContext2Apply_provisionerMultiSelfRef(t *testing.T) { 2273 var lock sync.Mutex 2274 commands := make([]string, 0, 5) 2275 2276 m := testModule(t, "apply-provisioner-multi-self-ref") 2277 p := testProvider("aws") 2278 pr := testProvisioner() 2279 p.ApplyFn = testApplyFn 2280 p.DiffFn = testDiffFn 2281 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 2282 lock.Lock() 2283 defer lock.Unlock() 2284 2285 val, ok := c.Config["command"] 2286 if !ok { 2287 t.Fatalf("bad value for command: %v %#v", val, c) 2288 } 2289 2290 commands = append(commands, val.(string)) 2291 return nil 2292 } 2293 2294 ctx := testContext2(t, &ContextOpts{ 2295 Module: m, 2296 Providers: map[string]ResourceProviderFactory{ 2297 "aws": testProviderFuncFixed(p), 2298 }, 2299 Provisioners: map[string]ResourceProvisionerFactory{ 2300 "shell": testProvisionerFuncFixed(pr), 2301 }, 2302 }) 2303 2304 if _, err := ctx.Plan(); err != nil { 2305 t.Fatalf("err: %s", err) 2306 } 2307 2308 state, err := ctx.Apply() 2309 if err != nil { 2310 t.Fatalf("err: %s", err) 2311 } 2312 2313 actual := strings.TrimSpace(state.String()) 2314 expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefStr) 2315 if actual != expected { 2316 t.Fatalf("bad: \n%s", actual) 2317 } 2318 2319 // Verify apply was invoked 2320 if !pr.ApplyCalled { 2321 t.Fatalf("provisioner not invoked") 2322 } 2323 2324 // Verify our result 2325 sort.Strings(commands) 2326 expectedCommands := []string{"number 0", "number 1", "number 2"} 2327 if !reflect.DeepEqual(commands, expectedCommands) { 2328 t.Fatalf("bad: %#v", commands) 2329 } 2330 } 2331 2332 // Provisioner should NOT run on a diff, only create 2333 func TestContext2Apply_Provisioner_Diff(t *testing.T) { 2334 m := testModule(t, "apply-provisioner-diff") 2335 p := testProvider("aws") 2336 pr := testProvisioner() 2337 p.ApplyFn = testApplyFn 2338 p.DiffFn = testDiffFn 2339 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 2340 return nil 2341 } 2342 ctx := testContext2(t, &ContextOpts{ 2343 Module: m, 2344 Providers: map[string]ResourceProviderFactory{ 2345 "aws": testProviderFuncFixed(p), 2346 }, 2347 Provisioners: map[string]ResourceProvisionerFactory{ 2348 "shell": testProvisionerFuncFixed(pr), 2349 }, 2350 }) 2351 2352 if _, err := ctx.Plan(); err != nil { 2353 t.Fatalf("err: %s", err) 2354 } 2355 2356 state, err := ctx.Apply() 2357 if err != nil { 2358 t.Fatalf("err: %s", err) 2359 } 2360 2361 actual := strings.TrimSpace(state.String()) 2362 expected := strings.TrimSpace(testTerraformApplyProvisionerDiffStr) 2363 if actual != expected { 2364 t.Fatalf("bad: \n%s", actual) 2365 } 2366 2367 // Verify apply was invoked 2368 if !pr.ApplyCalled { 2369 t.Fatalf("provisioner not invoked") 2370 } 2371 pr.ApplyCalled = false 2372 2373 // Change the state to force a diff 2374 mod := state.RootModule() 2375 mod.Resources["aws_instance.bar"].Primary.Attributes["foo"] = "baz" 2376 2377 // Re-create context with state 2378 ctx = testContext2(t, &ContextOpts{ 2379 Module: m, 2380 Providers: map[string]ResourceProviderFactory{ 2381 "aws": testProviderFuncFixed(p), 2382 }, 2383 Provisioners: map[string]ResourceProvisionerFactory{ 2384 "shell": testProvisionerFuncFixed(pr), 2385 }, 2386 State: state, 2387 }) 2388 2389 if _, err := ctx.Plan(); err != nil { 2390 t.Fatalf("err: %s", err) 2391 } 2392 2393 state2, err := ctx.Apply() 2394 if err != nil { 2395 t.Fatalf("err: %s", err) 2396 } 2397 2398 actual = strings.TrimSpace(state2.String()) 2399 if actual != expected { 2400 t.Fatalf("bad: \n%s", actual) 2401 } 2402 2403 // Verify apply was NOT invoked 2404 if pr.ApplyCalled { 2405 t.Fatalf("provisioner invoked") 2406 } 2407 } 2408 2409 func TestContext2Apply_outputDiffVars(t *testing.T) { 2410 m := testModule(t, "apply-good") 2411 p := testProvider("aws") 2412 s := &State{ 2413 Modules: []*ModuleState{ 2414 &ModuleState{ 2415 Path: rootModulePath, 2416 Resources: map[string]*ResourceState{ 2417 "aws_instance.baz": &ResourceState{ 2418 Type: "aws_instance", 2419 Primary: &InstanceState{ 2420 ID: "bar", 2421 }, 2422 }, 2423 }, 2424 }, 2425 }, 2426 } 2427 ctx := testContext2(t, &ContextOpts{ 2428 Module: m, 2429 Providers: map[string]ResourceProviderFactory{ 2430 "aws": testProviderFuncFixed(p), 2431 }, 2432 State: s, 2433 }) 2434 2435 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 2436 for k, ad := range d.Attributes { 2437 if ad.NewComputed { 2438 return nil, fmt.Errorf("%s: computed", k) 2439 } 2440 } 2441 2442 result := s.MergeDiff(d) 2443 result.ID = "foo" 2444 return result, nil 2445 } 2446 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 2447 return &InstanceDiff{ 2448 Attributes: map[string]*ResourceAttrDiff{ 2449 "foo": &ResourceAttrDiff{ 2450 NewComputed: true, 2451 Type: DiffAttrOutput, 2452 }, 2453 "bar": &ResourceAttrDiff{ 2454 New: "baz", 2455 }, 2456 }, 2457 }, nil 2458 } 2459 2460 if _, err := ctx.Plan(); err != nil { 2461 t.Fatalf("err: %s", err) 2462 } 2463 if _, err := ctx.Apply(); err != nil { 2464 t.Fatalf("err: %s", err) 2465 } 2466 } 2467 2468 func TestContext2Apply_Provisioner_ConnInfo(t *testing.T) { 2469 m := testModule(t, "apply-provisioner-conninfo") 2470 p := testProvider("aws") 2471 pr := testProvisioner() 2472 2473 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 2474 if s.Ephemeral.ConnInfo == nil { 2475 t.Fatalf("ConnInfo not initialized") 2476 } 2477 2478 result, _ := testApplyFn(info, s, d) 2479 result.Ephemeral.ConnInfo = map[string]string{ 2480 "type": "ssh", 2481 "host": "127.0.0.1", 2482 "port": "22", 2483 } 2484 return result, nil 2485 } 2486 p.DiffFn = testDiffFn 2487 2488 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 2489 conn := rs.Ephemeral.ConnInfo 2490 if conn["type"] != "telnet" { 2491 t.Fatalf("Bad: %#v", conn) 2492 } 2493 if conn["host"] != "127.0.0.1" { 2494 t.Fatalf("Bad: %#v", conn) 2495 } 2496 if conn["port"] != "2222" { 2497 t.Fatalf("Bad: %#v", conn) 2498 } 2499 if conn["user"] != "superuser" { 2500 t.Fatalf("Bad: %#v", conn) 2501 } 2502 if conn["pass"] != "test" { 2503 t.Fatalf("Bad: %#v", conn) 2504 } 2505 2506 return nil 2507 } 2508 2509 ctx := testContext2(t, &ContextOpts{ 2510 Module: m, 2511 Providers: map[string]ResourceProviderFactory{ 2512 "aws": testProviderFuncFixed(p), 2513 }, 2514 Provisioners: map[string]ResourceProvisionerFactory{ 2515 "shell": testProvisionerFuncFixed(pr), 2516 }, 2517 Variables: map[string]string{ 2518 "value": "1", 2519 "pass": "test", 2520 }, 2521 }) 2522 2523 if _, err := ctx.Plan(); err != nil { 2524 t.Fatalf("err: %s", err) 2525 } 2526 2527 state, err := ctx.Apply() 2528 if err != nil { 2529 t.Fatalf("err: %s", err) 2530 } 2531 2532 actual := strings.TrimSpace(state.String()) 2533 expected := strings.TrimSpace(testTerraformApplyProvisionerStr) 2534 if actual != expected { 2535 t.Fatalf("bad: \n%s", actual) 2536 } 2537 2538 // Verify apply was invoked 2539 if !pr.ApplyCalled { 2540 t.Fatalf("provisioner not invoked") 2541 } 2542 } 2543 2544 func TestContext2Apply_destroy(t *testing.T) { 2545 m := testModule(t, "apply-destroy") 2546 h := new(HookRecordApplyOrder) 2547 p := testProvider("aws") 2548 p.ApplyFn = testApplyFn 2549 p.DiffFn = testDiffFn 2550 ctx := testContext2(t, &ContextOpts{ 2551 Module: m, 2552 Hooks: []Hook{h}, 2553 Providers: map[string]ResourceProviderFactory{ 2554 "aws": testProviderFuncFixed(p), 2555 }, 2556 }) 2557 2558 // First plan and apply a create operation 2559 if _, err := ctx.Plan(); err != nil { 2560 t.Fatalf("err: %s", err) 2561 } 2562 2563 state, err := ctx.Apply() 2564 if err != nil { 2565 t.Fatalf("err: %s", err) 2566 } 2567 2568 // Next, plan and apply a destroy operation 2569 h.Active = true 2570 ctx = testContext2(t, &ContextOpts{ 2571 Destroy: true, 2572 State: state, 2573 Module: m, 2574 Hooks: []Hook{h}, 2575 Providers: map[string]ResourceProviderFactory{ 2576 "aws": testProviderFuncFixed(p), 2577 }, 2578 }) 2579 2580 if _, err := ctx.Plan(); err != nil { 2581 t.Fatalf("err: %s", err) 2582 } 2583 2584 state, err = ctx.Apply() 2585 if err != nil { 2586 t.Fatalf("err: %s", err) 2587 } 2588 2589 // Test that things were destroyed 2590 actual := strings.TrimSpace(state.String()) 2591 expected := strings.TrimSpace(testTerraformApplyDestroyStr) 2592 if actual != expected { 2593 t.Fatalf("bad: \n%s", actual) 2594 } 2595 2596 // Test that things were destroyed _in the right order_ 2597 expected2 := []string{"aws_instance.bar", "aws_instance.foo"} 2598 actual2 := h.IDs 2599 if !reflect.DeepEqual(actual2, expected2) { 2600 t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2) 2601 } 2602 } 2603 2604 func TestContext2Apply_destroyNestedModule(t *testing.T) { 2605 m := testModule(t, "apply-destroy-nested-module") 2606 p := testProvider("aws") 2607 p.ApplyFn = testApplyFn 2608 p.DiffFn = testDiffFn 2609 2610 s := &State{ 2611 Modules: []*ModuleState{ 2612 &ModuleState{ 2613 Path: []string{"root", "child", "subchild"}, 2614 Resources: map[string]*ResourceState{ 2615 "aws_instance.bar": &ResourceState{ 2616 Type: "aws_instance", 2617 Primary: &InstanceState{ 2618 ID: "bar", 2619 }, 2620 }, 2621 }, 2622 }, 2623 }, 2624 } 2625 2626 ctx := testContext2(t, &ContextOpts{ 2627 Module: m, 2628 Providers: map[string]ResourceProviderFactory{ 2629 "aws": testProviderFuncFixed(p), 2630 }, 2631 State: s, 2632 }) 2633 2634 // First plan and apply a create operation 2635 if _, err := ctx.Plan(); err != nil { 2636 t.Fatalf("err: %s", err) 2637 } 2638 2639 state, err := ctx.Apply() 2640 if err != nil { 2641 t.Fatalf("err: %s", err) 2642 } 2643 2644 // Test that things were destroyed 2645 actual := strings.TrimSpace(state.String()) 2646 expected := strings.TrimSpace(testTerraformApplyDestroyNestedModuleStr) 2647 if actual != expected { 2648 t.Fatalf("bad: \n%s", actual) 2649 } 2650 } 2651 2652 func TestContext2Apply_destroyDeeplyNestedModule(t *testing.T) { 2653 m := testModule(t, "apply-destroy-deeply-nested-module") 2654 p := testProvider("aws") 2655 p.ApplyFn = testApplyFn 2656 p.DiffFn = testDiffFn 2657 2658 s := &State{ 2659 Modules: []*ModuleState{ 2660 &ModuleState{ 2661 Path: []string{"root", "child", "subchild", "subsubchild"}, 2662 Resources: map[string]*ResourceState{ 2663 "aws_instance.bar": &ResourceState{ 2664 Type: "aws_instance", 2665 Primary: &InstanceState{ 2666 ID: "bar", 2667 }, 2668 }, 2669 }, 2670 }, 2671 }, 2672 } 2673 2674 ctx := testContext2(t, &ContextOpts{ 2675 Module: m, 2676 Providers: map[string]ResourceProviderFactory{ 2677 "aws": testProviderFuncFixed(p), 2678 }, 2679 State: s, 2680 }) 2681 2682 // First plan and apply a create operation 2683 if _, err := ctx.Plan(); err != nil { 2684 t.Fatalf("err: %s", err) 2685 } 2686 2687 state, err := ctx.Apply() 2688 if err != nil { 2689 t.Fatalf("err: %s", err) 2690 } 2691 2692 // Test that things were destroyed 2693 actual := strings.TrimSpace(state.String()) 2694 expected := strings.TrimSpace(` 2695 module.child.subchild.subsubchild: 2696 <no state> 2697 `) 2698 if actual != expected { 2699 t.Fatalf("bad: \n%s", actual) 2700 } 2701 } 2702 2703 // https://github.com/hashicorp/terraform/issues/5440 2704 func TestContext2Apply_destroyModuleWithAttrsReferencingResource(t *testing.T) { 2705 m := testModule(t, "apply-destroy-module-with-attrs") 2706 p := testProvider("aws") 2707 p.ApplyFn = testApplyFn 2708 p.DiffFn = testDiffFn 2709 2710 var state *State 2711 var err error 2712 { 2713 ctx := testContext2(t, &ContextOpts{ 2714 Module: m, 2715 Providers: map[string]ResourceProviderFactory{ 2716 "aws": testProviderFuncFixed(p), 2717 }, 2718 }) 2719 2720 // First plan and apply a create operation 2721 if _, err := ctx.Plan(); err != nil { 2722 t.Fatalf("plan err: %s", err) 2723 } 2724 2725 state, err = ctx.Apply() 2726 if err != nil { 2727 t.Fatalf("apply err: %s", err) 2728 } 2729 } 2730 2731 h := new(HookRecordApplyOrder) 2732 h.Active = true 2733 2734 { 2735 ctx := testContext2(t, &ContextOpts{ 2736 Destroy: true, 2737 Module: m, 2738 State: state, 2739 Hooks: []Hook{h}, 2740 Providers: map[string]ResourceProviderFactory{ 2741 "aws": testProviderFuncFixed(p), 2742 }, 2743 Variables: map[string]string{ 2744 "key_name": "foobarkey", 2745 }, 2746 }) 2747 2748 // First plan and apply a create operation 2749 plan, err := ctx.Plan() 2750 if err != nil { 2751 t.Fatalf("destroy plan err: %s", err) 2752 } 2753 2754 var buf bytes.Buffer 2755 if err := WritePlan(plan, &buf); err != nil { 2756 t.Fatalf("plan write err: %s", err) 2757 } 2758 2759 planFromFile, err := ReadPlan(&buf) 2760 if err != nil { 2761 t.Fatalf("plan read err: %s", err) 2762 } 2763 2764 ctx, err = planFromFile.Context(&ContextOpts{ 2765 Providers: map[string]ResourceProviderFactory{ 2766 "aws": testProviderFuncFixed(p), 2767 }, 2768 }) 2769 if err != nil { 2770 t.Fatalf("err: %s", err) 2771 } 2772 2773 state, err = ctx.Apply() 2774 if err != nil { 2775 t.Fatalf("destroy apply err: %s", err) 2776 } 2777 } 2778 2779 //Test that things were destroyed 2780 actual := strings.TrimSpace(state.String()) 2781 expected := strings.TrimSpace(` 2782 <no state> 2783 module.child: 2784 <no state> 2785 `) 2786 if actual != expected { 2787 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 2788 } 2789 } 2790 2791 func TestContext2Apply_destroyWithModuleVariableAndCount(t *testing.T) { 2792 m := testModule(t, "apply-destroy-mod-var-and-count") 2793 p := testProvider("aws") 2794 p.ApplyFn = testApplyFn 2795 p.DiffFn = testDiffFn 2796 2797 var state *State 2798 var err error 2799 { 2800 ctx := testContext2(t, &ContextOpts{ 2801 Module: m, 2802 Providers: map[string]ResourceProviderFactory{ 2803 "aws": testProviderFuncFixed(p), 2804 }, 2805 }) 2806 2807 // First plan and apply a create operation 2808 if _, err := ctx.Plan(); err != nil { 2809 t.Fatalf("plan err: %s", err) 2810 } 2811 2812 state, err = ctx.Apply() 2813 if err != nil { 2814 t.Fatalf("apply err: %s", err) 2815 } 2816 } 2817 2818 h := new(HookRecordApplyOrder) 2819 h.Active = true 2820 2821 { 2822 ctx := testContext2(t, &ContextOpts{ 2823 Destroy: true, 2824 Module: m, 2825 State: state, 2826 Hooks: []Hook{h}, 2827 Providers: map[string]ResourceProviderFactory{ 2828 "aws": testProviderFuncFixed(p), 2829 }, 2830 }) 2831 2832 // First plan and apply a create operation 2833 plan, err := ctx.Plan() 2834 if err != nil { 2835 t.Fatalf("destroy plan err: %s", err) 2836 } 2837 2838 var buf bytes.Buffer 2839 if err := WritePlan(plan, &buf); err != nil { 2840 t.Fatalf("plan write err: %s", err) 2841 } 2842 2843 planFromFile, err := ReadPlan(&buf) 2844 if err != nil { 2845 t.Fatalf("plan read err: %s", err) 2846 } 2847 2848 ctx, err = planFromFile.Context(&ContextOpts{ 2849 Providers: map[string]ResourceProviderFactory{ 2850 "aws": testProviderFuncFixed(p), 2851 }, 2852 }) 2853 if err != nil { 2854 t.Fatalf("err: %s", err) 2855 } 2856 2857 state, err = ctx.Apply() 2858 if err != nil { 2859 t.Fatalf("destroy apply err: %s", err) 2860 } 2861 } 2862 2863 //Test that things were destroyed 2864 actual := strings.TrimSpace(state.String()) 2865 expected := strings.TrimSpace(` 2866 <no state> 2867 module.child: 2868 <no state> 2869 `) 2870 if actual != expected { 2871 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 2872 } 2873 } 2874 2875 func TestContext2Apply_destroyWithModuleVariableAndCountNested(t *testing.T) { 2876 m := testModule(t, "apply-destroy-mod-var-and-count-nested") 2877 p := testProvider("aws") 2878 p.ApplyFn = testApplyFn 2879 p.DiffFn = testDiffFn 2880 2881 var state *State 2882 var err error 2883 { 2884 ctx := testContext2(t, &ContextOpts{ 2885 Module: m, 2886 Providers: map[string]ResourceProviderFactory{ 2887 "aws": testProviderFuncFixed(p), 2888 }, 2889 }) 2890 2891 // First plan and apply a create operation 2892 if _, err := ctx.Plan(); err != nil { 2893 t.Fatalf("plan err: %s", err) 2894 } 2895 2896 state, err = ctx.Apply() 2897 if err != nil { 2898 t.Fatalf("apply err: %s", err) 2899 } 2900 } 2901 2902 h := new(HookRecordApplyOrder) 2903 h.Active = true 2904 2905 { 2906 ctx := testContext2(t, &ContextOpts{ 2907 Destroy: true, 2908 Module: m, 2909 State: state, 2910 Hooks: []Hook{h}, 2911 Providers: map[string]ResourceProviderFactory{ 2912 "aws": testProviderFuncFixed(p), 2913 }, 2914 }) 2915 2916 // First plan and apply a create operation 2917 plan, err := ctx.Plan() 2918 if err != nil { 2919 t.Fatalf("destroy plan err: %s", err) 2920 } 2921 2922 var buf bytes.Buffer 2923 if err := WritePlan(plan, &buf); err != nil { 2924 t.Fatalf("plan write err: %s", err) 2925 } 2926 2927 planFromFile, err := ReadPlan(&buf) 2928 if err != nil { 2929 t.Fatalf("plan read err: %s", err) 2930 } 2931 2932 ctx, err = planFromFile.Context(&ContextOpts{ 2933 Providers: map[string]ResourceProviderFactory{ 2934 "aws": testProviderFuncFixed(p), 2935 }, 2936 }) 2937 if err != nil { 2938 t.Fatalf("err: %s", err) 2939 } 2940 2941 state, err = ctx.Apply() 2942 if err != nil { 2943 t.Fatalf("destroy apply err: %s", err) 2944 } 2945 } 2946 2947 //Test that things were destroyed 2948 actual := strings.TrimSpace(state.String()) 2949 expected := strings.TrimSpace(` 2950 <no state> 2951 module.child: 2952 <no state> 2953 module.child.child2: 2954 <no state> 2955 `) 2956 if actual != expected { 2957 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 2958 } 2959 } 2960 2961 func TestContext2Apply_destroyOutputs(t *testing.T) { 2962 m := testModule(t, "apply-destroy-outputs") 2963 h := new(HookRecordApplyOrder) 2964 p := testProvider("aws") 2965 p.ApplyFn = testApplyFn 2966 p.DiffFn = testDiffFn 2967 ctx := testContext2(t, &ContextOpts{ 2968 Module: m, 2969 Hooks: []Hook{h}, 2970 Providers: map[string]ResourceProviderFactory{ 2971 "aws": testProviderFuncFixed(p), 2972 }, 2973 }) 2974 2975 // First plan and apply a create operation 2976 if _, err := ctx.Plan(); err != nil { 2977 t.Fatalf("err: %s", err) 2978 } 2979 2980 state, err := ctx.Apply() 2981 2982 if err != nil { 2983 t.Fatalf("err: %s", err) 2984 } 2985 2986 // Next, plan and apply a destroy operation 2987 h.Active = true 2988 ctx = testContext2(t, &ContextOpts{ 2989 Destroy: true, 2990 State: state, 2991 Module: m, 2992 Hooks: []Hook{h}, 2993 Providers: map[string]ResourceProviderFactory{ 2994 "aws": testProviderFuncFixed(p), 2995 }, 2996 }) 2997 2998 if _, err := ctx.Plan(); err != nil { 2999 t.Fatalf("err: %s", err) 3000 } 3001 3002 state, err = ctx.Apply() 3003 if err != nil { 3004 t.Fatalf("err: %s", err) 3005 } 3006 3007 mod := state.RootModule() 3008 if len(mod.Resources) > 0 { 3009 t.Fatalf("bad: %#v", mod) 3010 } 3011 } 3012 3013 func TestContext2Apply_destroyOrphan(t *testing.T) { 3014 m := testModule(t, "apply-error") 3015 p := testProvider("aws") 3016 s := &State{ 3017 Modules: []*ModuleState{ 3018 &ModuleState{ 3019 Path: rootModulePath, 3020 Resources: map[string]*ResourceState{ 3021 "aws_instance.baz": &ResourceState{ 3022 Type: "aws_instance", 3023 Primary: &InstanceState{ 3024 ID: "bar", 3025 }, 3026 }, 3027 }, 3028 }, 3029 }, 3030 } 3031 ctx := testContext2(t, &ContextOpts{ 3032 Module: m, 3033 Providers: map[string]ResourceProviderFactory{ 3034 "aws": testProviderFuncFixed(p), 3035 }, 3036 State: s, 3037 }) 3038 3039 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 3040 if d.Destroy { 3041 return nil, nil 3042 } 3043 3044 result := s.MergeDiff(d) 3045 result.ID = "foo" 3046 return result, nil 3047 } 3048 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 3049 return &InstanceDiff{ 3050 Attributes: map[string]*ResourceAttrDiff{ 3051 "num": &ResourceAttrDiff{ 3052 New: "bar", 3053 }, 3054 }, 3055 }, nil 3056 } 3057 3058 if _, err := ctx.Plan(); err != nil { 3059 t.Fatalf("err: %s", err) 3060 } 3061 3062 state, err := ctx.Apply() 3063 if err != nil { 3064 t.Fatalf("err: %s", err) 3065 } 3066 3067 mod := state.RootModule() 3068 if _, ok := mod.Resources["aws_instance.baz"]; ok { 3069 t.Fatalf("bad: %#v", mod.Resources) 3070 } 3071 } 3072 3073 func TestContext2Apply_destroyTaintedProvisioner(t *testing.T) { 3074 m := testModule(t, "apply-destroy-provisioner") 3075 p := testProvider("aws") 3076 pr := testProvisioner() 3077 p.ApplyFn = testApplyFn 3078 p.DiffFn = testDiffFn 3079 3080 called := false 3081 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 3082 called = true 3083 return nil 3084 } 3085 3086 s := &State{ 3087 Modules: []*ModuleState{ 3088 &ModuleState{ 3089 Path: rootModulePath, 3090 Resources: map[string]*ResourceState{ 3091 "aws_instance.foo": &ResourceState{ 3092 Type: "aws_instance", 3093 Primary: &InstanceState{ 3094 ID: "bar", 3095 Attributes: map[string]string{ 3096 "id": "bar", 3097 }, 3098 Tainted: true, 3099 }, 3100 }, 3101 }, 3102 }, 3103 }, 3104 } 3105 3106 ctx := testContext2(t, &ContextOpts{ 3107 Module: m, 3108 Providers: map[string]ResourceProviderFactory{ 3109 "aws": testProviderFuncFixed(p), 3110 }, 3111 Provisioners: map[string]ResourceProvisionerFactory{ 3112 "shell": testProvisionerFuncFixed(pr), 3113 }, 3114 State: s, 3115 Destroy: true, 3116 }) 3117 3118 if _, err := ctx.Plan(); err != nil { 3119 t.Fatalf("err: %s", err) 3120 } 3121 3122 state, err := ctx.Apply() 3123 if err != nil { 3124 t.Fatalf("err: %s", err) 3125 } 3126 3127 if called { 3128 t.Fatal("provisioner should not be called") 3129 } 3130 3131 actual := strings.TrimSpace(state.String()) 3132 expected := strings.TrimSpace("<no state>") 3133 if actual != expected { 3134 t.Fatalf("bad: \n%s", actual) 3135 } 3136 } 3137 3138 func TestContext2Apply_error(t *testing.T) { 3139 errored := false 3140 3141 m := testModule(t, "apply-error") 3142 p := testProvider("aws") 3143 ctx := testContext2(t, &ContextOpts{ 3144 Module: m, 3145 Providers: map[string]ResourceProviderFactory{ 3146 "aws": testProviderFuncFixed(p), 3147 }, 3148 }) 3149 3150 p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) { 3151 if errored { 3152 state := &InstanceState{ 3153 ID: "bar", 3154 } 3155 return state, fmt.Errorf("error") 3156 } 3157 errored = true 3158 3159 return &InstanceState{ 3160 ID: "foo", 3161 Attributes: map[string]string{ 3162 "num": "2", 3163 }, 3164 }, nil 3165 } 3166 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 3167 return &InstanceDiff{ 3168 Attributes: map[string]*ResourceAttrDiff{ 3169 "num": &ResourceAttrDiff{ 3170 New: "bar", 3171 }, 3172 }, 3173 }, nil 3174 } 3175 3176 if _, err := ctx.Plan(); err != nil { 3177 t.Fatalf("err: %s", err) 3178 } 3179 3180 state, err := ctx.Apply() 3181 if err == nil { 3182 t.Fatal("should have error") 3183 } 3184 3185 actual := strings.TrimSpace(state.String()) 3186 expected := strings.TrimSpace(testTerraformApplyErrorStr) 3187 if actual != expected { 3188 t.Fatalf("bad: \n%s", actual) 3189 } 3190 } 3191 3192 func TestContext2Apply_errorPartial(t *testing.T) { 3193 errored := false 3194 3195 m := testModule(t, "apply-error") 3196 p := testProvider("aws") 3197 s := &State{ 3198 Modules: []*ModuleState{ 3199 &ModuleState{ 3200 Path: rootModulePath, 3201 Resources: map[string]*ResourceState{ 3202 "aws_instance.bar": &ResourceState{ 3203 Type: "aws_instance", 3204 Primary: &InstanceState{ 3205 ID: "bar", 3206 }, 3207 }, 3208 }, 3209 }, 3210 }, 3211 } 3212 ctx := testContext2(t, &ContextOpts{ 3213 Module: m, 3214 Providers: map[string]ResourceProviderFactory{ 3215 "aws": testProviderFuncFixed(p), 3216 }, 3217 State: s, 3218 }) 3219 3220 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 3221 if errored { 3222 return s, fmt.Errorf("error") 3223 } 3224 errored = true 3225 3226 return &InstanceState{ 3227 ID: "foo", 3228 Attributes: map[string]string{ 3229 "num": "2", 3230 }, 3231 }, nil 3232 } 3233 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 3234 return &InstanceDiff{ 3235 Attributes: map[string]*ResourceAttrDiff{ 3236 "num": &ResourceAttrDiff{ 3237 New: "bar", 3238 }, 3239 }, 3240 }, nil 3241 } 3242 3243 if _, err := ctx.Plan(); err != nil { 3244 t.Fatalf("err: %s", err) 3245 } 3246 3247 state, err := ctx.Apply() 3248 if err == nil { 3249 t.Fatal("should have error") 3250 } 3251 3252 mod := state.RootModule() 3253 if len(mod.Resources) != 2 { 3254 t.Fatalf("bad: %#v", mod.Resources) 3255 } 3256 3257 actual := strings.TrimSpace(state.String()) 3258 expected := strings.TrimSpace(testTerraformApplyErrorPartialStr) 3259 if actual != expected { 3260 t.Fatalf("bad: \n%s", actual) 3261 } 3262 } 3263 3264 func TestContext2Apply_hook(t *testing.T) { 3265 m := testModule(t, "apply-good") 3266 h := new(MockHook) 3267 p := testProvider("aws") 3268 p.ApplyFn = testApplyFn 3269 p.DiffFn = testDiffFn 3270 ctx := testContext2(t, &ContextOpts{ 3271 Module: m, 3272 Hooks: []Hook{h}, 3273 Providers: map[string]ResourceProviderFactory{ 3274 "aws": testProviderFuncFixed(p), 3275 }, 3276 }) 3277 3278 if _, err := ctx.Plan(); err != nil { 3279 t.Fatalf("err: %s", err) 3280 } 3281 3282 if _, err := ctx.Apply(); err != nil { 3283 t.Fatalf("err: %s", err) 3284 } 3285 3286 if !h.PreApplyCalled { 3287 t.Fatal("should be called") 3288 } 3289 if !h.PostApplyCalled { 3290 t.Fatal("should be called") 3291 } 3292 if !h.PostStateUpdateCalled { 3293 t.Fatalf("should call post state update") 3294 } 3295 } 3296 3297 func TestContext2Apply_hookOrphan(t *testing.T) { 3298 m := testModule(t, "apply-blank") 3299 h := new(MockHook) 3300 p := testProvider("aws") 3301 p.ApplyFn = testApplyFn 3302 p.DiffFn = testDiffFn 3303 3304 state := &State{ 3305 Modules: []*ModuleState{ 3306 &ModuleState{ 3307 Path: rootModulePath, 3308 Resources: map[string]*ResourceState{ 3309 "aws_instance.bar": &ResourceState{ 3310 Type: "aws_instance", 3311 Primary: &InstanceState{ 3312 ID: "bar", 3313 }, 3314 }, 3315 }, 3316 }, 3317 }, 3318 } 3319 3320 ctx := testContext2(t, &ContextOpts{ 3321 Module: m, 3322 State: state, 3323 Hooks: []Hook{h}, 3324 Providers: map[string]ResourceProviderFactory{ 3325 "aws": testProviderFuncFixed(p), 3326 }, 3327 }) 3328 3329 if _, err := ctx.Plan(); err != nil { 3330 t.Fatalf("err: %s", err) 3331 } 3332 3333 if _, err := ctx.Apply(); err != nil { 3334 t.Fatalf("err: %s", err) 3335 } 3336 3337 if !h.PreApplyCalled { 3338 t.Fatal("should be called") 3339 } 3340 if !h.PostApplyCalled { 3341 t.Fatal("should be called") 3342 } 3343 if !h.PostStateUpdateCalled { 3344 t.Fatalf("should call post state update") 3345 } 3346 } 3347 3348 func TestContext2Apply_idAttr(t *testing.T) { 3349 m := testModule(t, "apply-idattr") 3350 p := testProvider("aws") 3351 ctx := testContext2(t, &ContextOpts{ 3352 Module: m, 3353 Providers: map[string]ResourceProviderFactory{ 3354 "aws": testProviderFuncFixed(p), 3355 }, 3356 }) 3357 3358 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 3359 result := s.MergeDiff(d) 3360 result.ID = "foo" 3361 result.Attributes = map[string]string{ 3362 "id": "bar", 3363 } 3364 3365 return result, nil 3366 } 3367 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 3368 return &InstanceDiff{ 3369 Attributes: map[string]*ResourceAttrDiff{ 3370 "num": &ResourceAttrDiff{ 3371 New: "bar", 3372 }, 3373 }, 3374 }, nil 3375 } 3376 3377 if _, err := ctx.Plan(); err != nil { 3378 t.Fatalf("err: %s", err) 3379 } 3380 3381 state, err := ctx.Apply() 3382 if err != nil { 3383 t.Fatalf("err: %s", err) 3384 } 3385 3386 mod := state.RootModule() 3387 rs, ok := mod.Resources["aws_instance.foo"] 3388 if !ok { 3389 t.Fatal("not in state") 3390 } 3391 if rs.Primary.ID != "foo" { 3392 t.Fatalf("bad: %#v", rs.Primary.ID) 3393 } 3394 if rs.Primary.Attributes["id"] != "foo" { 3395 t.Fatalf("bad: %#v", rs.Primary.Attributes) 3396 } 3397 } 3398 3399 func TestContext2Apply_output(t *testing.T) { 3400 m := testModule(t, "apply-output") 3401 p := testProvider("aws") 3402 p.ApplyFn = testApplyFn 3403 p.DiffFn = testDiffFn 3404 ctx := testContext2(t, &ContextOpts{ 3405 Module: m, 3406 Providers: map[string]ResourceProviderFactory{ 3407 "aws": testProviderFuncFixed(p), 3408 }, 3409 }) 3410 3411 if _, err := ctx.Plan(); err != nil { 3412 t.Fatalf("err: %s", err) 3413 } 3414 3415 state, err := ctx.Apply() 3416 if err != nil { 3417 t.Fatalf("err: %s", err) 3418 } 3419 3420 actual := strings.TrimSpace(state.String()) 3421 expected := strings.TrimSpace(testTerraformApplyOutputStr) 3422 if actual != expected { 3423 t.Fatalf("bad: \n%s", actual) 3424 } 3425 } 3426 3427 func TestContext2Apply_outputInvalid(t *testing.T) { 3428 m := testModule(t, "apply-output-invalid") 3429 p := testProvider("aws") 3430 p.ApplyFn = testApplyFn 3431 p.DiffFn = testDiffFn 3432 ctx := testContext2(t, &ContextOpts{ 3433 Module: m, 3434 Providers: map[string]ResourceProviderFactory{ 3435 "aws": testProviderFuncFixed(p), 3436 }, 3437 }) 3438 3439 _, err := ctx.Plan() 3440 if err == nil { 3441 t.Fatalf("err: %s", err) 3442 } 3443 if !strings.Contains(err.Error(), "is not a valid type") { 3444 t.Fatalf("err: %s", err) 3445 } 3446 } 3447 3448 func TestContext2Apply_outputAdd(t *testing.T) { 3449 m1 := testModule(t, "apply-output-add-before") 3450 p1 := testProvider("aws") 3451 p1.ApplyFn = testApplyFn 3452 p1.DiffFn = testDiffFn 3453 ctx1 := testContext2(t, &ContextOpts{ 3454 Module: m1, 3455 Providers: map[string]ResourceProviderFactory{ 3456 "aws": testProviderFuncFixed(p1), 3457 }, 3458 }) 3459 3460 if _, err := ctx1.Plan(); err != nil { 3461 t.Fatalf("err: %s", err) 3462 } 3463 3464 state1, err := ctx1.Apply() 3465 if err != nil { 3466 t.Fatalf("err: %s", err) 3467 } 3468 3469 m2 := testModule(t, "apply-output-add-after") 3470 p2 := testProvider("aws") 3471 p2.ApplyFn = testApplyFn 3472 p2.DiffFn = testDiffFn 3473 ctx2 := testContext2(t, &ContextOpts{ 3474 Module: m2, 3475 Providers: map[string]ResourceProviderFactory{ 3476 "aws": testProviderFuncFixed(p2), 3477 }, 3478 State: state1, 3479 }) 3480 3481 if _, err := ctx2.Plan(); err != nil { 3482 t.Fatalf("err: %s", err) 3483 } 3484 3485 state2, err := ctx2.Apply() 3486 if err != nil { 3487 t.Fatalf("err: %s", err) 3488 } 3489 3490 actual := strings.TrimSpace(state2.String()) 3491 expected := strings.TrimSpace(testTerraformApplyOutputAddStr) 3492 if actual != expected { 3493 t.Fatalf("bad: \n%s", actual) 3494 } 3495 } 3496 3497 func TestContext2Apply_outputList(t *testing.T) { 3498 m := testModule(t, "apply-output-list") 3499 p := testProvider("aws") 3500 p.ApplyFn = testApplyFn 3501 p.DiffFn = testDiffFn 3502 ctx := testContext2(t, &ContextOpts{ 3503 Module: m, 3504 Providers: map[string]ResourceProviderFactory{ 3505 "aws": testProviderFuncFixed(p), 3506 }, 3507 }) 3508 3509 if _, err := ctx.Plan(); err != nil { 3510 t.Fatalf("err: %s", err) 3511 } 3512 3513 state, err := ctx.Apply() 3514 if err != nil { 3515 t.Fatalf("err: %s", err) 3516 } 3517 3518 actual := strings.TrimSpace(state.String()) 3519 expected := strings.TrimSpace(testTerraformApplyOutputListStr) 3520 if actual != expected { 3521 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 3522 } 3523 } 3524 3525 func TestContext2Apply_outputMulti(t *testing.T) { 3526 m := testModule(t, "apply-output-multi") 3527 p := testProvider("aws") 3528 p.ApplyFn = testApplyFn 3529 p.DiffFn = testDiffFn 3530 ctx := testContext2(t, &ContextOpts{ 3531 Module: m, 3532 Providers: map[string]ResourceProviderFactory{ 3533 "aws": testProviderFuncFixed(p), 3534 }, 3535 }) 3536 3537 if _, err := ctx.Plan(); err != nil { 3538 t.Fatalf("err: %s", err) 3539 } 3540 3541 state, err := ctx.Apply() 3542 if err != nil { 3543 t.Fatalf("err: %s", err) 3544 } 3545 3546 actual := strings.TrimSpace(state.String()) 3547 expected := strings.TrimSpace(testTerraformApplyOutputMultiStr) 3548 if actual != expected { 3549 t.Fatalf("bad: \n%s", actual) 3550 } 3551 } 3552 3553 func TestContext2Apply_outputMultiIndex(t *testing.T) { 3554 m := testModule(t, "apply-output-multi-index") 3555 p := testProvider("aws") 3556 p.ApplyFn = testApplyFn 3557 p.DiffFn = testDiffFn 3558 ctx := testContext2(t, &ContextOpts{ 3559 Module: m, 3560 Providers: map[string]ResourceProviderFactory{ 3561 "aws": testProviderFuncFixed(p), 3562 }, 3563 }) 3564 3565 if _, err := ctx.Plan(); err != nil { 3566 t.Fatalf("err: %s", err) 3567 } 3568 3569 state, err := ctx.Apply() 3570 if err != nil { 3571 t.Fatalf("err: %s", err) 3572 } 3573 3574 actual := strings.TrimSpace(state.String()) 3575 expected := strings.TrimSpace(testTerraformApplyOutputMultiIndexStr) 3576 if actual != expected { 3577 t.Fatalf("bad: \n%s", actual) 3578 } 3579 } 3580 3581 func TestContext2Apply_taint(t *testing.T) { 3582 m := testModule(t, "apply-taint") 3583 p := testProvider("aws") 3584 3585 // destroyCount tests against regression of 3586 // https://github.com/hashicorp/terraform/issues/1056 3587 var destroyCount = int32(0) 3588 var once sync.Once 3589 simulateProviderDelay := func() { 3590 time.Sleep(10 * time.Millisecond) 3591 } 3592 3593 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 3594 once.Do(simulateProviderDelay) 3595 if d.Destroy { 3596 atomic.AddInt32(&destroyCount, 1) 3597 } 3598 return testApplyFn(info, s, d) 3599 } 3600 p.DiffFn = testDiffFn 3601 s := &State{ 3602 Modules: []*ModuleState{ 3603 &ModuleState{ 3604 Path: rootModulePath, 3605 Resources: map[string]*ResourceState{ 3606 "aws_instance.bar": &ResourceState{ 3607 Type: "aws_instance", 3608 Primary: &InstanceState{ 3609 ID: "baz", 3610 Attributes: map[string]string{ 3611 "num": "2", 3612 "type": "aws_instance", 3613 }, 3614 Tainted: true, 3615 }, 3616 }, 3617 }, 3618 }, 3619 }, 3620 } 3621 ctx := testContext2(t, &ContextOpts{ 3622 Module: m, 3623 Providers: map[string]ResourceProviderFactory{ 3624 "aws": testProviderFuncFixed(p), 3625 }, 3626 State: s, 3627 }) 3628 3629 if _, err := ctx.Plan(); err != nil { 3630 t.Fatalf("err: %s", err) 3631 } 3632 3633 state, err := ctx.Apply() 3634 if err != nil { 3635 t.Fatalf("err: %s", err) 3636 } 3637 3638 actual := strings.TrimSpace(state.String()) 3639 expected := strings.TrimSpace(testTerraformApplyTaintStr) 3640 if actual != expected { 3641 t.Fatalf("bad:\n%s", actual) 3642 } 3643 3644 if destroyCount != 1 { 3645 t.Fatalf("Expected 1 destroy, got %d", destroyCount) 3646 } 3647 } 3648 3649 func TestContext2Apply_taintDep(t *testing.T) { 3650 m := testModule(t, "apply-taint-dep") 3651 p := testProvider("aws") 3652 p.ApplyFn = testApplyFn 3653 p.DiffFn = testDiffFn 3654 s := &State{ 3655 Modules: []*ModuleState{ 3656 &ModuleState{ 3657 Path: rootModulePath, 3658 Resources: map[string]*ResourceState{ 3659 "aws_instance.foo": &ResourceState{ 3660 Type: "aws_instance", 3661 Primary: &InstanceState{ 3662 ID: "baz", 3663 Attributes: map[string]string{ 3664 "num": "2", 3665 "type": "aws_instance", 3666 }, 3667 Tainted: true, 3668 }, 3669 }, 3670 "aws_instance.bar": &ResourceState{ 3671 Type: "aws_instance", 3672 Primary: &InstanceState{ 3673 ID: "bar", 3674 Attributes: map[string]string{ 3675 "foo": "baz", 3676 "num": "2", 3677 "type": "aws_instance", 3678 }, 3679 }, 3680 }, 3681 }, 3682 }, 3683 }, 3684 } 3685 ctx := testContext2(t, &ContextOpts{ 3686 Module: m, 3687 Providers: map[string]ResourceProviderFactory{ 3688 "aws": testProviderFuncFixed(p), 3689 }, 3690 State: s, 3691 }) 3692 3693 if p, err := ctx.Plan(); err != nil { 3694 t.Fatalf("err: %s", err) 3695 } else { 3696 t.Logf("plan: %s", p) 3697 } 3698 3699 state, err := ctx.Apply() 3700 if err != nil { 3701 t.Fatalf("err: %s", err) 3702 } 3703 3704 actual := strings.TrimSpace(state.String()) 3705 expected := strings.TrimSpace(testTerraformApplyTaintDepStr) 3706 if actual != expected { 3707 t.Fatalf("bad:\n%s", actual) 3708 } 3709 } 3710 3711 func TestContext2Apply_taintDepRequiresNew(t *testing.T) { 3712 m := testModule(t, "apply-taint-dep-requires-new") 3713 p := testProvider("aws") 3714 p.ApplyFn = testApplyFn 3715 p.DiffFn = testDiffFn 3716 s := &State{ 3717 Modules: []*ModuleState{ 3718 &ModuleState{ 3719 Path: rootModulePath, 3720 Resources: map[string]*ResourceState{ 3721 "aws_instance.foo": &ResourceState{ 3722 Type: "aws_instance", 3723 Primary: &InstanceState{ 3724 ID: "baz", 3725 Attributes: map[string]string{ 3726 "num": "2", 3727 "type": "aws_instance", 3728 }, 3729 Tainted: true, 3730 }, 3731 }, 3732 "aws_instance.bar": &ResourceState{ 3733 Type: "aws_instance", 3734 Primary: &InstanceState{ 3735 ID: "bar", 3736 Attributes: map[string]string{ 3737 "foo": "baz", 3738 "num": "2", 3739 "type": "aws_instance", 3740 }, 3741 }, 3742 }, 3743 }, 3744 }, 3745 }, 3746 } 3747 ctx := testContext2(t, &ContextOpts{ 3748 Module: m, 3749 Providers: map[string]ResourceProviderFactory{ 3750 "aws": testProviderFuncFixed(p), 3751 }, 3752 State: s, 3753 }) 3754 3755 if p, err := ctx.Plan(); err != nil { 3756 t.Fatalf("err: %s", err) 3757 } else { 3758 t.Logf("plan: %s", p) 3759 } 3760 3761 state, err := ctx.Apply() 3762 if err != nil { 3763 t.Fatalf("err: %s", err) 3764 } 3765 3766 actual := strings.TrimSpace(state.String()) 3767 expected := strings.TrimSpace(testTerraformApplyTaintDepRequireNewStr) 3768 if actual != expected { 3769 t.Fatalf("bad:\n%s", actual) 3770 } 3771 } 3772 3773 func TestContext2Apply_targeted(t *testing.T) { 3774 m := testModule(t, "apply-targeted") 3775 p := testProvider("aws") 3776 p.ApplyFn = testApplyFn 3777 p.DiffFn = testDiffFn 3778 ctx := testContext2(t, &ContextOpts{ 3779 Module: m, 3780 Providers: map[string]ResourceProviderFactory{ 3781 "aws": testProviderFuncFixed(p), 3782 }, 3783 Targets: []string{"aws_instance.foo"}, 3784 }) 3785 3786 if _, err := ctx.Plan(); err != nil { 3787 t.Fatalf("err: %s", err) 3788 } 3789 3790 state, err := ctx.Apply() 3791 if err != nil { 3792 t.Fatalf("err: %s", err) 3793 } 3794 3795 mod := state.RootModule() 3796 if len(mod.Resources) != 1 { 3797 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 3798 } 3799 3800 checkStateString(t, state, ` 3801 aws_instance.foo: 3802 ID = foo 3803 num = 2 3804 type = aws_instance 3805 `) 3806 } 3807 3808 func TestContext2Apply_targetedCount(t *testing.T) { 3809 m := testModule(t, "apply-targeted-count") 3810 p := testProvider("aws") 3811 p.ApplyFn = testApplyFn 3812 p.DiffFn = testDiffFn 3813 ctx := testContext2(t, &ContextOpts{ 3814 Module: m, 3815 Providers: map[string]ResourceProviderFactory{ 3816 "aws": testProviderFuncFixed(p), 3817 }, 3818 Targets: []string{"aws_instance.foo"}, 3819 }) 3820 3821 if _, err := ctx.Plan(); err != nil { 3822 t.Fatalf("err: %s", err) 3823 } 3824 3825 state, err := ctx.Apply() 3826 if err != nil { 3827 t.Fatalf("err: %s", err) 3828 } 3829 3830 checkStateString(t, state, ` 3831 aws_instance.foo.0: 3832 ID = foo 3833 aws_instance.foo.1: 3834 ID = foo 3835 aws_instance.foo.2: 3836 ID = foo 3837 `) 3838 } 3839 3840 func TestContext2Apply_targetedCountIndex(t *testing.T) { 3841 m := testModule(t, "apply-targeted-count") 3842 p := testProvider("aws") 3843 p.ApplyFn = testApplyFn 3844 p.DiffFn = testDiffFn 3845 ctx := testContext2(t, &ContextOpts{ 3846 Module: m, 3847 Providers: map[string]ResourceProviderFactory{ 3848 "aws": testProviderFuncFixed(p), 3849 }, 3850 Targets: []string{"aws_instance.foo[1]"}, 3851 }) 3852 3853 if _, err := ctx.Plan(); err != nil { 3854 t.Fatalf("err: %s", err) 3855 } 3856 3857 state, err := ctx.Apply() 3858 if err != nil { 3859 t.Fatalf("err: %s", err) 3860 } 3861 3862 checkStateString(t, state, ` 3863 aws_instance.foo.1: 3864 ID = foo 3865 `) 3866 } 3867 3868 func TestContext2Apply_targetedDestroy(t *testing.T) { 3869 m := testModule(t, "apply-targeted") 3870 p := testProvider("aws") 3871 p.ApplyFn = testApplyFn 3872 p.DiffFn = testDiffFn 3873 ctx := testContext2(t, &ContextOpts{ 3874 Module: m, 3875 Providers: map[string]ResourceProviderFactory{ 3876 "aws": testProviderFuncFixed(p), 3877 }, 3878 State: &State{ 3879 Modules: []*ModuleState{ 3880 &ModuleState{ 3881 Path: rootModulePath, 3882 Resources: map[string]*ResourceState{ 3883 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 3884 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 3885 }, 3886 }, 3887 }, 3888 }, 3889 Targets: []string{"aws_instance.foo"}, 3890 Destroy: true, 3891 }) 3892 3893 if _, err := ctx.Plan(); err != nil { 3894 t.Fatalf("err: %s", err) 3895 } 3896 3897 state, err := ctx.Apply() 3898 if err != nil { 3899 t.Fatalf("err: %s", err) 3900 } 3901 3902 mod := state.RootModule() 3903 if len(mod.Resources) != 1 { 3904 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 3905 } 3906 3907 checkStateString(t, state, ` 3908 aws_instance.bar: 3909 ID = i-abc123 3910 `) 3911 } 3912 3913 // https://github.com/hashicorp/terraform/issues/4462 3914 func TestContext2Apply_targetedDestroyModule(t *testing.T) { 3915 m := testModule(t, "apply-targeted-module") 3916 p := testProvider("aws") 3917 p.ApplyFn = testApplyFn 3918 p.DiffFn = testDiffFn 3919 ctx := testContext2(t, &ContextOpts{ 3920 Module: m, 3921 Providers: map[string]ResourceProviderFactory{ 3922 "aws": testProviderFuncFixed(p), 3923 }, 3924 State: &State{ 3925 Modules: []*ModuleState{ 3926 &ModuleState{ 3927 Path: rootModulePath, 3928 Resources: map[string]*ResourceState{ 3929 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 3930 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 3931 }, 3932 }, 3933 &ModuleState{ 3934 Path: []string{"root", "child"}, 3935 Resources: map[string]*ResourceState{ 3936 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 3937 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 3938 }, 3939 }, 3940 }, 3941 }, 3942 Targets: []string{"module.child.aws_instance.foo"}, 3943 Destroy: true, 3944 }) 3945 3946 if _, err := ctx.Plan(); err != nil { 3947 t.Fatalf("err: %s", err) 3948 } 3949 3950 state, err := ctx.Apply() 3951 if err != nil { 3952 t.Fatalf("err: %s", err) 3953 } 3954 3955 checkStateString(t, state, ` 3956 aws_instance.bar: 3957 ID = i-abc123 3958 aws_instance.foo: 3959 ID = i-bcd345 3960 3961 module.child: 3962 aws_instance.bar: 3963 ID = i-abc123 3964 `) 3965 } 3966 3967 func TestContext2Apply_targetedDestroyCountIndex(t *testing.T) { 3968 m := testModule(t, "apply-targeted-count") 3969 p := testProvider("aws") 3970 p.ApplyFn = testApplyFn 3971 p.DiffFn = testDiffFn 3972 ctx := testContext2(t, &ContextOpts{ 3973 Module: m, 3974 Providers: map[string]ResourceProviderFactory{ 3975 "aws": testProviderFuncFixed(p), 3976 }, 3977 State: &State{ 3978 Modules: []*ModuleState{ 3979 &ModuleState{ 3980 Path: rootModulePath, 3981 Resources: map[string]*ResourceState{ 3982 "aws_instance.foo.0": resourceState("aws_instance", "i-bcd345"), 3983 "aws_instance.foo.1": resourceState("aws_instance", "i-bcd345"), 3984 "aws_instance.foo.2": resourceState("aws_instance", "i-bcd345"), 3985 "aws_instance.bar.0": resourceState("aws_instance", "i-abc123"), 3986 "aws_instance.bar.1": resourceState("aws_instance", "i-abc123"), 3987 "aws_instance.bar.2": resourceState("aws_instance", "i-abc123"), 3988 }, 3989 }, 3990 }, 3991 }, 3992 Targets: []string{ 3993 "aws_instance.foo[2]", 3994 "aws_instance.bar[1]", 3995 }, 3996 Destroy: true, 3997 }) 3998 3999 if _, err := ctx.Plan(); err != nil { 4000 t.Fatalf("err: %s", err) 4001 } 4002 4003 state, err := ctx.Apply() 4004 if err != nil { 4005 t.Fatalf("err: %s", err) 4006 } 4007 4008 checkStateString(t, state, ` 4009 aws_instance.bar.0: 4010 ID = i-abc123 4011 aws_instance.bar.2: 4012 ID = i-abc123 4013 aws_instance.foo.0: 4014 ID = i-bcd345 4015 aws_instance.foo.1: 4016 ID = i-bcd345 4017 `) 4018 } 4019 4020 func TestContext2Apply_targetedModule(t *testing.T) { 4021 m := testModule(t, "apply-targeted-module") 4022 p := testProvider("aws") 4023 p.ApplyFn = testApplyFn 4024 p.DiffFn = testDiffFn 4025 ctx := testContext2(t, &ContextOpts{ 4026 Module: m, 4027 Providers: map[string]ResourceProviderFactory{ 4028 "aws": testProviderFuncFixed(p), 4029 }, 4030 Targets: []string{"module.child"}, 4031 }) 4032 4033 if _, err := ctx.Plan(); err != nil { 4034 t.Fatalf("err: %s", err) 4035 } 4036 4037 state, err := ctx.Apply() 4038 if err != nil { 4039 t.Fatalf("err: %s", err) 4040 } 4041 4042 mod := state.ModuleByPath([]string{"root", "child"}) 4043 if mod == nil { 4044 t.Fatalf("no child module found in the state!\n\n%#v", state) 4045 } 4046 if len(mod.Resources) != 2 { 4047 t.Fatalf("expected 2 resources, got: %#v", mod.Resources) 4048 } 4049 4050 checkStateString(t, state, ` 4051 <no state> 4052 module.child: 4053 aws_instance.bar: 4054 ID = foo 4055 num = 2 4056 type = aws_instance 4057 aws_instance.foo: 4058 ID = foo 4059 num = 2 4060 type = aws_instance 4061 `) 4062 } 4063 4064 // GH-1858 4065 func TestContext2Apply_targetedModuleDep(t *testing.T) { 4066 m := testModule(t, "apply-targeted-module-dep") 4067 p := testProvider("aws") 4068 p.ApplyFn = testApplyFn 4069 p.DiffFn = testDiffFn 4070 ctx := testContext2(t, &ContextOpts{ 4071 Module: m, 4072 Providers: map[string]ResourceProviderFactory{ 4073 "aws": testProviderFuncFixed(p), 4074 }, 4075 Targets: []string{"aws_instance.foo"}, 4076 }) 4077 4078 if _, err := ctx.Plan(); err != nil { 4079 t.Fatalf("err: %s", err) 4080 } 4081 4082 state, err := ctx.Apply() 4083 if err != nil { 4084 t.Fatalf("err: %s", err) 4085 } 4086 4087 checkStateString(t, state, ` 4088 aws_instance.foo: 4089 ID = foo 4090 foo = foo 4091 type = aws_instance 4092 4093 Dependencies: 4094 module.child 4095 4096 module.child: 4097 aws_instance.mod: 4098 ID = foo 4099 4100 Outputs: 4101 4102 output = foo 4103 `) 4104 } 4105 4106 func TestContext2Apply_targetedModuleResource(t *testing.T) { 4107 m := testModule(t, "apply-targeted-module-resource") 4108 p := testProvider("aws") 4109 p.ApplyFn = testApplyFn 4110 p.DiffFn = testDiffFn 4111 ctx := testContext2(t, &ContextOpts{ 4112 Module: m, 4113 Providers: map[string]ResourceProviderFactory{ 4114 "aws": testProviderFuncFixed(p), 4115 }, 4116 Targets: []string{"module.child.aws_instance.foo"}, 4117 }) 4118 4119 if _, err := ctx.Plan(); err != nil { 4120 t.Fatalf("err: %s", err) 4121 } 4122 4123 state, err := ctx.Apply() 4124 if err != nil { 4125 t.Fatalf("err: %s", err) 4126 } 4127 4128 mod := state.ModuleByPath([]string{"root", "child"}) 4129 if len(mod.Resources) != 1 { 4130 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 4131 } 4132 4133 checkStateString(t, state, ` 4134 <no state> 4135 module.child: 4136 aws_instance.foo: 4137 ID = foo 4138 num = 2 4139 type = aws_instance 4140 `) 4141 } 4142 4143 func TestContext2Apply_unknownAttribute(t *testing.T) { 4144 m := testModule(t, "apply-unknown") 4145 p := testProvider("aws") 4146 p.ApplyFn = testApplyFn 4147 p.DiffFn = testDiffFn 4148 ctx := testContext2(t, &ContextOpts{ 4149 Module: m, 4150 Providers: map[string]ResourceProviderFactory{ 4151 "aws": testProviderFuncFixed(p), 4152 }, 4153 }) 4154 4155 if _, err := ctx.Plan(); err != nil { 4156 t.Fatalf("err: %s", err) 4157 } 4158 4159 state, err := ctx.Apply() 4160 if err == nil { 4161 t.Fatal("should error") 4162 } 4163 4164 actual := strings.TrimSpace(state.String()) 4165 expected := strings.TrimSpace(testTerraformApplyUnknownAttrStr) 4166 if actual != expected { 4167 t.Fatalf("bad: \n%s", actual) 4168 } 4169 } 4170 4171 func TestContext2Apply_unknownAttributeInterpolate(t *testing.T) { 4172 m := testModule(t, "apply-unknown-interpolate") 4173 p := testProvider("aws") 4174 p.ApplyFn = testApplyFn 4175 p.DiffFn = testDiffFn 4176 ctx := testContext2(t, &ContextOpts{ 4177 Module: m, 4178 Providers: map[string]ResourceProviderFactory{ 4179 "aws": testProviderFuncFixed(p), 4180 }, 4181 }) 4182 4183 if _, err := ctx.Plan(); err == nil { 4184 t.Fatal("should error") 4185 } 4186 } 4187 4188 func TestContext2Apply_vars(t *testing.T) { 4189 m := testModule(t, "apply-vars") 4190 p := testProvider("aws") 4191 p.ApplyFn = testApplyFn 4192 p.DiffFn = testDiffFn 4193 ctx := testContext2(t, &ContextOpts{ 4194 Module: m, 4195 Providers: map[string]ResourceProviderFactory{ 4196 "aws": testProviderFuncFixed(p), 4197 }, 4198 Variables: map[string]string{ 4199 "foo": "us-west-2", 4200 "amis.us-east-1": "override", 4201 }, 4202 }) 4203 4204 w, e := ctx.Validate() 4205 if len(w) > 0 { 4206 t.Fatalf("bad: %#v", w) 4207 } 4208 if len(e) > 0 { 4209 t.Fatalf("bad: %s", e) 4210 } 4211 4212 if _, err := ctx.Plan(); err != nil { 4213 t.Fatalf("err: %s", err) 4214 } 4215 4216 state, err := ctx.Apply() 4217 if err != nil { 4218 t.Fatalf("err: %s", err) 4219 } 4220 4221 actual := strings.TrimSpace(state.String()) 4222 expected := strings.TrimSpace(testTerraformApplyVarsStr) 4223 if actual != expected { 4224 t.Fatalf("expected: %s\n got:\n%s", expected, actual) 4225 } 4226 } 4227 4228 func TestContext2Apply_varsEnv(t *testing.T) { 4229 // Set the env var 4230 old := tempEnv(t, "TF_VAR_ami", "baz") 4231 defer os.Setenv("TF_VAR_ami", old) 4232 4233 m := testModule(t, "apply-vars-env") 4234 p := testProvider("aws") 4235 p.ApplyFn = testApplyFn 4236 p.DiffFn = testDiffFn 4237 ctx := testContext2(t, &ContextOpts{ 4238 Module: m, 4239 Providers: map[string]ResourceProviderFactory{ 4240 "aws": testProviderFuncFixed(p), 4241 }, 4242 }) 4243 4244 w, e := ctx.Validate() 4245 if len(w) > 0 { 4246 t.Fatalf("bad: %#v", w) 4247 } 4248 if len(e) > 0 { 4249 t.Fatalf("bad: %s", e) 4250 } 4251 4252 if _, err := ctx.Plan(); err != nil { 4253 t.Fatalf("err: %s", err) 4254 } 4255 4256 state, err := ctx.Apply() 4257 if err != nil { 4258 t.Fatalf("err: %s", err) 4259 } 4260 4261 actual := strings.TrimSpace(state.String()) 4262 expected := strings.TrimSpace(testTerraformApplyVarsEnvStr) 4263 if actual != expected { 4264 t.Fatalf("bad: \n%s", actual) 4265 } 4266 } 4267 4268 func TestContext2Apply_createBefore_depends(t *testing.T) { 4269 m := testModule(t, "apply-depends-create-before") 4270 h := new(HookRecordApplyOrder) 4271 p := testProvider("aws") 4272 p.ApplyFn = testApplyFn 4273 p.DiffFn = testDiffFn 4274 state := &State{ 4275 Modules: []*ModuleState{ 4276 &ModuleState{ 4277 Path: rootModulePath, 4278 Resources: map[string]*ResourceState{ 4279 "aws_instance.web": &ResourceState{ 4280 Type: "aws_instance", 4281 Primary: &InstanceState{ 4282 ID: "bar", 4283 Attributes: map[string]string{ 4284 "require_new": "ami-old", 4285 }, 4286 }, 4287 }, 4288 "aws_instance.lb": &ResourceState{ 4289 Type: "aws_instance", 4290 Primary: &InstanceState{ 4291 ID: "baz", 4292 Attributes: map[string]string{ 4293 "instance": "bar", 4294 }, 4295 }, 4296 }, 4297 }, 4298 }, 4299 }, 4300 } 4301 ctx := testContext2(t, &ContextOpts{ 4302 Module: m, 4303 Hooks: []Hook{h}, 4304 Providers: map[string]ResourceProviderFactory{ 4305 "aws": testProviderFuncFixed(p), 4306 }, 4307 State: state, 4308 }) 4309 4310 if _, err := ctx.Plan(); err != nil { 4311 t.Fatalf("err: %s", err) 4312 } 4313 4314 h.Active = true 4315 state, err := ctx.Apply() 4316 if err != nil { 4317 t.Fatalf("err: %s", err) 4318 } 4319 4320 mod := state.RootModule() 4321 if len(mod.Resources) < 2 { 4322 t.Fatalf("bad: %#v", mod.Resources) 4323 } 4324 4325 actual := strings.TrimSpace(state.String()) 4326 expected := strings.TrimSpace(testTerraformApplyDependsCreateBeforeStr) 4327 if actual != expected { 4328 t.Fatalf("bad: \n%s\n%s", actual, expected) 4329 } 4330 4331 // Test that things were managed _in the right order_ 4332 order := h.States 4333 diffs := h.Diffs 4334 if order[0].ID != "" || diffs[0].Destroy { 4335 t.Fatalf("should create new instance first: %#v", order) 4336 } 4337 4338 if order[1].ID != "baz" { 4339 t.Fatalf("update must happen after create: %#v", order) 4340 } 4341 4342 if order[2].ID != "bar" || !diffs[2].Destroy { 4343 t.Fatalf("destroy must happen after update: %#v", order) 4344 } 4345 } 4346 4347 func TestContext2Apply_singleDestroy(t *testing.T) { 4348 m := testModule(t, "apply-depends-create-before") 4349 h := new(HookRecordApplyOrder) 4350 p := testProvider("aws") 4351 4352 invokeCount := 0 4353 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 4354 invokeCount++ 4355 switch invokeCount { 4356 case 1: 4357 if d.Destroy { 4358 t.Fatalf("should not destroy") 4359 } 4360 if s.ID != "" { 4361 t.Fatalf("should not have ID") 4362 } 4363 case 2: 4364 if d.Destroy { 4365 t.Fatalf("should not destroy") 4366 } 4367 if s.ID != "baz" { 4368 t.Fatalf("should have id") 4369 } 4370 case 3: 4371 if !d.Destroy { 4372 t.Fatalf("should destroy") 4373 } 4374 if s.ID == "" { 4375 t.Fatalf("should have ID") 4376 } 4377 default: 4378 t.Fatalf("bad invoke count %d", invokeCount) 4379 } 4380 return testApplyFn(info, s, d) 4381 } 4382 p.DiffFn = testDiffFn 4383 state := &State{ 4384 Modules: []*ModuleState{ 4385 &ModuleState{ 4386 Path: rootModulePath, 4387 Resources: map[string]*ResourceState{ 4388 "aws_instance.web": &ResourceState{ 4389 Type: "aws_instance", 4390 Primary: &InstanceState{ 4391 ID: "bar", 4392 Attributes: map[string]string{ 4393 "require_new": "ami-old", 4394 }, 4395 }, 4396 }, 4397 "aws_instance.lb": &ResourceState{ 4398 Type: "aws_instance", 4399 Primary: &InstanceState{ 4400 ID: "baz", 4401 Attributes: map[string]string{ 4402 "instance": "bar", 4403 }, 4404 }, 4405 }, 4406 }, 4407 }, 4408 }, 4409 } 4410 ctx := testContext2(t, &ContextOpts{ 4411 Module: m, 4412 Hooks: []Hook{h}, 4413 Providers: map[string]ResourceProviderFactory{ 4414 "aws": testProviderFuncFixed(p), 4415 }, 4416 State: state, 4417 }) 4418 4419 if _, err := ctx.Plan(); err != nil { 4420 t.Fatalf("err: %s", err) 4421 } 4422 4423 h.Active = true 4424 state, err := ctx.Apply() 4425 if err != nil { 4426 t.Fatalf("err: %s", err) 4427 } 4428 4429 if invokeCount != 3 { 4430 t.Fatalf("bad: %d", invokeCount) 4431 } 4432 } 4433 4434 // GH-5254 4435 func TestContext2Apply_issue5254(t *testing.T) { 4436 // Create a provider. We use "template" here just to match the repro 4437 // we got from the issue itself. 4438 p := testProvider("template") 4439 p.ResourcesReturn = append(p.ResourcesReturn, ResourceType{ 4440 Name: "template_file", 4441 }) 4442 4443 p.ApplyFn = testApplyFn 4444 p.DiffFn = testDiffFn 4445 4446 // Apply cleanly step 0 4447 ctx := testContext2(t, &ContextOpts{ 4448 Module: testModule(t, "issue-5254/step-0"), 4449 Providers: map[string]ResourceProviderFactory{ 4450 "template": testProviderFuncFixed(p), 4451 }, 4452 }) 4453 4454 plan, err := ctx.Plan() 4455 if err != nil { 4456 t.Fatalf("err: %s", err) 4457 } 4458 4459 state, err := ctx.Apply() 4460 if err != nil { 4461 t.Fatalf("err: %s", err) 4462 } 4463 4464 // Application success. Now make the modification and store a plan 4465 ctx = testContext2(t, &ContextOpts{ 4466 Module: testModule(t, "issue-5254/step-1"), 4467 State: state, 4468 Providers: map[string]ResourceProviderFactory{ 4469 "template": testProviderFuncFixed(p), 4470 }, 4471 }) 4472 4473 plan, err = ctx.Plan() 4474 if err != nil { 4475 t.Fatalf("err: %s", err) 4476 } 4477 4478 // Write / Read plan to simulate running it through a Plan file 4479 var buf bytes.Buffer 4480 if err := WritePlan(plan, &buf); err != nil { 4481 t.Fatalf("err: %s", err) 4482 } 4483 4484 planFromFile, err := ReadPlan(&buf) 4485 if err != nil { 4486 t.Fatalf("err: %s", err) 4487 } 4488 4489 ctx, err = planFromFile.Context(&ContextOpts{ 4490 Providers: map[string]ResourceProviderFactory{ 4491 "template": testProviderFuncFixed(p), 4492 }, 4493 }) 4494 if err != nil { 4495 t.Fatalf("err: %s", err) 4496 } 4497 4498 state, err = ctx.Apply() 4499 if err != nil { 4500 t.Fatalf("err: %s", err) 4501 } 4502 4503 actual := strings.TrimSpace(state.String()) 4504 expected := strings.TrimSpace(` 4505 template_file.child: 4506 ID = foo 4507 template = Hi 4508 type = template_file 4509 4510 Dependencies: 4511 template_file.parent 4512 template_file.parent: 4513 ID = foo 4514 template = Hi 4515 type = template_file 4516 `) 4517 if actual != expected { 4518 t.Fatalf("expected state: \n%s\ngot: \n%s", expected, actual) 4519 } 4520 } 4521 4522 func TestContext2Apply_targetedWithTaintedInState(t *testing.T) { 4523 p := testProvider("aws") 4524 p.DiffFn = testDiffFn 4525 p.ApplyFn = testApplyFn 4526 ctx := testContext2(t, &ContextOpts{ 4527 Module: testModule(t, "apply-tainted-targets"), 4528 Providers: map[string]ResourceProviderFactory{ 4529 "aws": testProviderFuncFixed(p), 4530 }, 4531 Targets: []string{"aws_instance.iambeingadded"}, 4532 State: &State{ 4533 Modules: []*ModuleState{ 4534 &ModuleState{ 4535 Path: rootModulePath, 4536 Resources: map[string]*ResourceState{ 4537 "aws_instance.ifailedprovisioners": &ResourceState{ 4538 Primary: &InstanceState{ 4539 ID: "ifailedprovisioners", 4540 Tainted: true, 4541 }, 4542 }, 4543 }, 4544 }, 4545 }, 4546 }, 4547 }) 4548 4549 plan, err := ctx.Plan() 4550 if err != nil { 4551 t.Fatalf("err: %s", err) 4552 } 4553 4554 // Write / Read plan to simulate running it through a Plan file 4555 var buf bytes.Buffer 4556 if err := WritePlan(plan, &buf); err != nil { 4557 t.Fatalf("err: %s", err) 4558 } 4559 4560 planFromFile, err := ReadPlan(&buf) 4561 if err != nil { 4562 t.Fatalf("err: %s", err) 4563 } 4564 4565 ctx, err = planFromFile.Context(&ContextOpts{ 4566 Module: testModule(t, "apply-tainted-targets"), 4567 Providers: map[string]ResourceProviderFactory{ 4568 "aws": testProviderFuncFixed(p), 4569 }, 4570 }) 4571 if err != nil { 4572 t.Fatalf("err: %s", err) 4573 } 4574 4575 state, err := ctx.Apply() 4576 if err != nil { 4577 t.Fatalf("err: %s", err) 4578 } 4579 4580 actual := strings.TrimSpace(state.String()) 4581 expected := strings.TrimSpace(` 4582 aws_instance.iambeingadded: 4583 ID = foo 4584 aws_instance.ifailedprovisioners: (tainted) 4585 ID = ifailedprovisioners 4586 `) 4587 if actual != expected { 4588 t.Fatalf("expected state: \n%s\ngot: \n%s", expected, actual) 4589 } 4590 } 4591 4592 // Higher level test exposing the bug this covers in 4593 // TestResource_ignoreChangesRequired 4594 func TestContext2Apply_ignoreChangesCreate(t *testing.T) { 4595 m := testModule(t, "apply-ignore-changes-create") 4596 p := testProvider("aws") 4597 p.ApplyFn = testApplyFn 4598 p.DiffFn = testDiffFn 4599 ctx := testContext2(t, &ContextOpts{ 4600 Module: m, 4601 Providers: map[string]ResourceProviderFactory{ 4602 "aws": testProviderFuncFixed(p), 4603 }, 4604 }) 4605 4606 if p, err := ctx.Plan(); err != nil { 4607 t.Fatalf("err: %s", err) 4608 } else { 4609 t.Logf(p.String()) 4610 } 4611 4612 state, err := ctx.Apply() 4613 if err != nil { 4614 t.Fatalf("err: %s", err) 4615 } 4616 4617 mod := state.RootModule() 4618 if len(mod.Resources) != 1 { 4619 t.Fatalf("bad: %s", state) 4620 } 4621 4622 actual := strings.TrimSpace(state.String()) 4623 // Expect no changes from original state 4624 expected := strings.TrimSpace(` 4625 aws_instance.foo: 4626 ID = foo 4627 required_field = set 4628 type = aws_instance 4629 `) 4630 if actual != expected { 4631 t.Fatalf("bad: \n%s", actual) 4632 } 4633 }