github.com/cgmcandrews/terraform@v0.11.12-beta1/command/plan_test.go (about) 1 package command 2 3 import ( 4 "bytes" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "reflect" 9 "strings" 10 "sync" 11 "testing" 12 "time" 13 14 "github.com/hashicorp/terraform/helper/copy" 15 "github.com/hashicorp/terraform/terraform" 16 "github.com/mitchellh/cli" 17 ) 18 19 func TestPlan(t *testing.T) { 20 cwd, err := os.Getwd() 21 if err != nil { 22 t.Fatalf("err: %s", err) 23 } 24 if err := os.Chdir(testFixturePath("plan")); err != nil { 25 t.Fatalf("err: %s", err) 26 } 27 defer os.Chdir(cwd) 28 29 p := testProvider() 30 ui := new(cli.MockUi) 31 c := &PlanCommand{ 32 Meta: Meta{ 33 testingOverrides: metaOverridesForProvider(p), 34 Ui: ui, 35 }, 36 } 37 38 args := []string{} 39 if code := c.Run(args); code != 0 { 40 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 41 } 42 } 43 44 func TestPlan_lockedState(t *testing.T) { 45 cwd, err := os.Getwd() 46 if err != nil { 47 t.Fatalf("err: %s", err) 48 } 49 50 testPath := testFixturePath("plan") 51 unlock, err := testLockState("./testdata", filepath.Join(testPath, DefaultStateFilename)) 52 if err != nil { 53 t.Fatal(err) 54 } 55 defer unlock() 56 57 if err := os.Chdir(testPath); err != nil { 58 t.Fatalf("err: %s", err) 59 } 60 defer os.Chdir(cwd) 61 62 p := testProvider() 63 ui := new(cli.MockUi) 64 c := &PlanCommand{ 65 Meta: Meta{ 66 testingOverrides: metaOverridesForProvider(p), 67 Ui: ui, 68 }, 69 } 70 71 args := []string{} 72 if code := c.Run(args); code == 0 { 73 t.Fatal("expected error") 74 } 75 76 output := ui.ErrorWriter.String() 77 if !strings.Contains(output, "lock") { 78 t.Fatal("command output does not look like a lock error:", output) 79 } 80 } 81 82 func TestPlan_plan(t *testing.T) { 83 tmp, cwd := testCwd(t) 84 defer testFixCwd(t, tmp, cwd) 85 86 planPath := testPlanFile(t, &terraform.Plan{ 87 Module: testModule(t, "apply"), 88 }) 89 90 p := testProvider() 91 ui := new(cli.MockUi) 92 c := &PlanCommand{ 93 Meta: Meta{ 94 testingOverrides: metaOverridesForProvider(p), 95 Ui: ui, 96 }, 97 } 98 99 args := []string{planPath} 100 if code := c.Run(args); code != 0 { 101 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 102 } 103 104 if p.RefreshCalled { 105 t.Fatal("refresh should not be called") 106 } 107 } 108 109 func TestPlan_destroy(t *testing.T) { 110 originalState := &terraform.State{ 111 Modules: []*terraform.ModuleState{ 112 &terraform.ModuleState{ 113 Path: []string{"root"}, 114 Resources: map[string]*terraform.ResourceState{ 115 "test_instance.foo": &terraform.ResourceState{ 116 Type: "test_instance", 117 Primary: &terraform.InstanceState{ 118 ID: "bar", 119 }, 120 }, 121 }, 122 }, 123 }, 124 } 125 126 outPath := testTempFile(t) 127 statePath := testStateFile(t, originalState) 128 129 p := testProvider() 130 ui := new(cli.MockUi) 131 c := &PlanCommand{ 132 Meta: Meta{ 133 testingOverrides: metaOverridesForProvider(p), 134 Ui: ui, 135 }, 136 } 137 138 args := []string{ 139 "-destroy", 140 "-out", outPath, 141 "-state", statePath, 142 testFixturePath("plan"), 143 } 144 if code := c.Run(args); code != 0 { 145 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 146 } 147 148 if !p.RefreshCalled { 149 t.Fatal("refresh should be called") 150 } 151 152 plan := testReadPlan(t, outPath) 153 for _, m := range plan.Diff.Modules { 154 for _, r := range m.Resources { 155 if !r.Destroy { 156 t.Fatalf("bad: %#v", r) 157 } 158 } 159 } 160 } 161 162 func TestPlan_noState(t *testing.T) { 163 tmp, cwd := testCwd(t) 164 defer testFixCwd(t, tmp, cwd) 165 166 p := testProvider() 167 ui := new(cli.MockUi) 168 c := &PlanCommand{ 169 Meta: Meta{ 170 testingOverrides: metaOverridesForProvider(p), 171 Ui: ui, 172 }, 173 } 174 175 args := []string{ 176 testFixturePath("plan"), 177 } 178 if code := c.Run(args); code != 0 { 179 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 180 } 181 182 // Verify that refresh was called 183 if p.RefreshCalled { 184 t.Fatal("refresh should not be called") 185 } 186 187 // Verify that the provider was called with the existing state 188 actual := strings.TrimSpace(p.DiffState.String()) 189 expected := strings.TrimSpace(testPlanNoStateStr) 190 if actual != expected { 191 t.Fatalf("bad:\n\n%s", actual) 192 } 193 } 194 195 func TestPlan_outPath(t *testing.T) { 196 tmp, cwd := testCwd(t) 197 defer testFixCwd(t, tmp, cwd) 198 199 td := testTempDir(t) 200 outPath := filepath.Join(td, "test.plan") 201 202 p := testProvider() 203 ui := new(cli.MockUi) 204 c := &PlanCommand{ 205 Meta: Meta{ 206 testingOverrides: metaOverridesForProvider(p), 207 Ui: ui, 208 }, 209 } 210 211 p.DiffReturn = &terraform.InstanceDiff{ 212 Destroy: true, 213 } 214 215 args := []string{ 216 "-out", outPath, 217 testFixturePath("plan"), 218 } 219 if code := c.Run(args); code != 0 { 220 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 221 } 222 223 f, err := os.Open(outPath) 224 if err != nil { 225 t.Fatalf("err: %s", err) 226 } 227 defer f.Close() 228 229 if _, err := terraform.ReadPlan(f); err != nil { 230 t.Fatalf("err: %s", err) 231 } 232 } 233 234 func TestPlan_outPathNoChange(t *testing.T) { 235 originalState := &terraform.State{ 236 Modules: []*terraform.ModuleState{ 237 &terraform.ModuleState{ 238 Path: []string{"root"}, 239 Resources: map[string]*terraform.ResourceState{ 240 "test_instance.foo": &terraform.ResourceState{ 241 Type: "test_instance", 242 Primary: &terraform.InstanceState{ 243 ID: "bar", 244 }, 245 }, 246 }, 247 }, 248 }, 249 } 250 statePath := testStateFile(t, originalState) 251 252 td := testTempDir(t) 253 outPath := filepath.Join(td, "test.plan") 254 255 p := testProvider() 256 ui := new(cli.MockUi) 257 c := &PlanCommand{ 258 Meta: Meta{ 259 testingOverrides: metaOverridesForProvider(p), 260 Ui: ui, 261 }, 262 } 263 264 args := []string{ 265 "-out", outPath, 266 "-state", statePath, 267 testFixturePath("plan"), 268 } 269 if code := c.Run(args); code != 0 { 270 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 271 } 272 273 plan := testReadPlan(t, outPath) 274 if !plan.Diff.Empty() { 275 t.Fatalf("Expected empty plan to be written to plan file, got: %s", plan) 276 } 277 } 278 279 // When using "-out" with a backend, the plan should encode the backend config 280 func TestPlan_outBackend(t *testing.T) { 281 // Create a temporary working directory that is empty 282 td := tempDir(t) 283 copy.CopyDir(testFixturePath("plan-out-backend"), td) 284 defer os.RemoveAll(td) 285 defer testChdir(t, td)() 286 287 // Our state 288 originalState := &terraform.State{ 289 Modules: []*terraform.ModuleState{ 290 &terraform.ModuleState{ 291 Path: []string{"root"}, 292 Resources: map[string]*terraform.ResourceState{ 293 "test_instance.foo": &terraform.ResourceState{ 294 Type: "test_instance", 295 Primary: &terraform.InstanceState{ 296 ID: "bar", 297 }, 298 }, 299 }, 300 }, 301 }, 302 } 303 originalState.Init() 304 305 // Setup our backend state 306 dataState, srv := testBackendState(t, originalState, 200) 307 defer srv.Close() 308 testStateFileRemote(t, dataState) 309 310 outPath := "foo" 311 p := testProvider() 312 ui := new(cli.MockUi) 313 c := &PlanCommand{ 314 Meta: Meta{ 315 testingOverrides: metaOverridesForProvider(p), 316 Ui: ui, 317 }, 318 } 319 320 args := []string{ 321 "-out", outPath, 322 } 323 if code := c.Run(args); code != 0 { 324 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 325 } 326 327 plan := testReadPlan(t, outPath) 328 if !plan.Diff.Empty() { 329 t.Fatalf("Expected empty plan to be written to plan file, got: %s", plan) 330 } 331 332 if plan.Backend.Empty() { 333 t.Fatal("should have backend info") 334 } 335 if !reflect.DeepEqual(plan.Backend, dataState.Backend) { 336 t.Fatalf("bad: %#v", plan.Backend) 337 } 338 } 339 340 // When using "-out" with a legacy remote state, the plan should encode 341 // the backend config 342 func TestPlan_outBackendLegacy(t *testing.T) { 343 // Create a temporary working directory that is empty 344 td := tempDir(t) 345 copy.CopyDir(testFixturePath("plan-out-backend-legacy"), td) 346 defer os.RemoveAll(td) 347 defer testChdir(t, td)() 348 349 // Our state 350 originalState := &terraform.State{ 351 Modules: []*terraform.ModuleState{ 352 &terraform.ModuleState{ 353 Path: []string{"root"}, 354 Resources: map[string]*terraform.ResourceState{ 355 "test_instance.foo": &terraform.ResourceState{ 356 Type: "test_instance", 357 Primary: &terraform.InstanceState{ 358 ID: "bar", 359 }, 360 }, 361 }, 362 }, 363 }, 364 } 365 originalState.Init() 366 367 // Setup our legacy state 368 remoteState, srv := testRemoteState(t, originalState, 200) 369 defer srv.Close() 370 dataState := terraform.NewState() 371 dataState.Remote = remoteState 372 testStateFileRemote(t, dataState) 373 374 outPath := "foo" 375 p := testProvider() 376 ui := new(cli.MockUi) 377 c := &PlanCommand{ 378 Meta: Meta{ 379 testingOverrides: metaOverridesForProvider(p), 380 Ui: ui, 381 }, 382 } 383 384 args := []string{ 385 "-out", outPath, 386 } 387 if code := c.Run(args); code != 0 { 388 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 389 } 390 391 plan := testReadPlan(t, outPath) 392 if !plan.Diff.Empty() { 393 t.Fatalf("Expected empty plan to be written to plan file, got: %s", plan) 394 } 395 396 if plan.State.Remote.Empty() { 397 t.Fatal("should have remote info") 398 } 399 } 400 401 func TestPlan_refresh(t *testing.T) { 402 tmp, cwd := testCwd(t) 403 defer testFixCwd(t, tmp, cwd) 404 405 p := testProvider() 406 ui := new(cli.MockUi) 407 c := &PlanCommand{ 408 Meta: Meta{ 409 testingOverrides: metaOverridesForProvider(p), 410 Ui: ui, 411 }, 412 } 413 414 args := []string{ 415 "-refresh=false", 416 testFixturePath("plan"), 417 } 418 if code := c.Run(args); code != 0 { 419 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 420 } 421 422 if p.RefreshCalled { 423 t.Fatal("refresh should not be called") 424 } 425 } 426 427 func TestPlan_state(t *testing.T) { 428 originalState := testState() 429 statePath := testStateFile(t, originalState) 430 431 p := testProvider() 432 ui := new(cli.MockUi) 433 c := &PlanCommand{ 434 Meta: Meta{ 435 testingOverrides: metaOverridesForProvider(p), 436 Ui: ui, 437 }, 438 } 439 440 args := []string{ 441 "-state", statePath, 442 testFixturePath("plan"), 443 } 444 if code := c.Run(args); code != 0 { 445 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 446 } 447 448 // Verify that the provider was called with the existing state 449 actual := strings.TrimSpace(p.DiffState.String()) 450 expected := strings.TrimSpace(testPlanStateStr) 451 if actual != expected { 452 t.Fatalf("bad:\n\n%s", actual) 453 } 454 } 455 456 func TestPlan_stateDefault(t *testing.T) { 457 originalState := testState() 458 statePath := testStateFile(t, originalState) 459 460 // Change to that directory 461 cwd, err := os.Getwd() 462 if err != nil { 463 t.Fatalf("err: %s", err) 464 } 465 if err := os.Chdir(filepath.Dir(statePath)); err != nil { 466 t.Fatalf("err: %s", err) 467 } 468 defer os.Chdir(cwd) 469 470 p := testProvider() 471 ui := new(cli.MockUi) 472 c := &PlanCommand{ 473 Meta: Meta{ 474 testingOverrides: metaOverridesForProvider(p), 475 Ui: ui, 476 }, 477 } 478 479 args := []string{ 480 "-state", statePath, 481 testFixturePath("plan"), 482 } 483 if code := c.Run(args); code != 0 { 484 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 485 } 486 487 // Verify that the provider was called with the existing state 488 actual := strings.TrimSpace(p.DiffState.String()) 489 expected := strings.TrimSpace(testPlanStateDefaultStr) 490 if actual != expected { 491 t.Fatalf("bad:\n\n%s", actual) 492 } 493 } 494 495 func TestPlan_stateFuture(t *testing.T) { 496 originalState := testState() 497 originalState.TFVersion = "99.99.99" 498 statePath := testStateFile(t, originalState) 499 500 p := testProvider() 501 ui := new(cli.MockUi) 502 c := &PlanCommand{ 503 Meta: Meta{ 504 testingOverrides: metaOverridesForProvider(p), 505 Ui: ui, 506 }, 507 } 508 509 args := []string{ 510 "-state", statePath, 511 testFixturePath("plan"), 512 } 513 if code := c.Run(args); code == 0 { 514 t.Fatal("should fail") 515 } 516 517 f, err := os.Open(statePath) 518 if err != nil { 519 t.Fatalf("err: %s", err) 520 } 521 522 newState, err := terraform.ReadState(f) 523 f.Close() 524 if err != nil { 525 t.Fatalf("err: %s", err) 526 } 527 528 if !newState.Equal(originalState) { 529 t.Fatalf("bad: %#v", newState) 530 } 531 if newState.TFVersion != originalState.TFVersion { 532 t.Fatalf("bad: %#v", newState) 533 } 534 } 535 536 func TestPlan_statePast(t *testing.T) { 537 originalState := testState() 538 originalState.TFVersion = "0.1.0" 539 statePath := testStateFile(t, originalState) 540 541 p := testProvider() 542 ui := new(cli.MockUi) 543 c := &PlanCommand{ 544 Meta: Meta{ 545 testingOverrides: metaOverridesForProvider(p), 546 Ui: ui, 547 }, 548 } 549 550 args := []string{ 551 "-state", statePath, 552 testFixturePath("plan"), 553 } 554 if code := c.Run(args); code != 0 { 555 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 556 } 557 } 558 559 func TestPlan_validate(t *testing.T) { 560 // This is triggered by not asking for input so we have to set this to false 561 test = false 562 defer func() { test = true }() 563 564 cwd, err := os.Getwd() 565 if err != nil { 566 t.Fatalf("err: %s", err) 567 } 568 if err := os.Chdir(testFixturePath("plan-invalid")); err != nil { 569 t.Fatalf("err: %s", err) 570 } 571 defer os.Chdir(cwd) 572 573 p := testProvider() 574 ui := new(cli.MockUi) 575 c := &PlanCommand{ 576 Meta: Meta{ 577 testingOverrides: metaOverridesForProvider(p), 578 Ui: ui, 579 }, 580 } 581 582 args := []string{} 583 if code := c.Run(args); code != 1 { 584 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 585 } 586 587 actual := ui.ErrorWriter.String() 588 if !strings.Contains(actual, "cannot be computed") { 589 t.Fatalf("bad: %s", actual) 590 } 591 } 592 593 func TestPlan_vars(t *testing.T) { 594 tmp, cwd := testCwd(t) 595 defer testFixCwd(t, tmp, cwd) 596 597 p := testProvider() 598 ui := new(cli.MockUi) 599 c := &PlanCommand{ 600 Meta: Meta{ 601 testingOverrides: metaOverridesForProvider(p), 602 Ui: ui, 603 }, 604 } 605 606 actual := "" 607 p.DiffFn = func( 608 info *terraform.InstanceInfo, 609 s *terraform.InstanceState, 610 c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { 611 if v, ok := c.Config["value"]; ok { 612 actual = v.(string) 613 } 614 615 return nil, nil 616 } 617 618 args := []string{ 619 "-var", "foo=bar", 620 testFixturePath("plan-vars"), 621 } 622 if code := c.Run(args); code != 0 { 623 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 624 } 625 626 if actual != "bar" { 627 t.Fatal("didn't work") 628 } 629 } 630 631 func TestPlan_varsUnset(t *testing.T) { 632 tmp, cwd := testCwd(t) 633 defer testFixCwd(t, tmp, cwd) 634 635 // Disable test mode so input would be asked 636 test = false 637 defer func() { test = true }() 638 639 defaultInputReader = bytes.NewBufferString("bar\n") 640 641 p := testProvider() 642 ui := new(cli.MockUi) 643 c := &PlanCommand{ 644 Meta: Meta{ 645 testingOverrides: metaOverridesForProvider(p), 646 Ui: ui, 647 }, 648 } 649 650 args := []string{ 651 testFixturePath("plan-vars"), 652 } 653 if code := c.Run(args); code != 0 { 654 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 655 } 656 } 657 658 func TestPlan_varFile(t *testing.T) { 659 tmp, cwd := testCwd(t) 660 defer testFixCwd(t, tmp, cwd) 661 662 varFilePath := testTempFile(t) 663 if err := ioutil.WriteFile(varFilePath, []byte(planVarFile), 0644); err != nil { 664 t.Fatalf("err: %s", err) 665 } 666 667 p := testProvider() 668 ui := new(cli.MockUi) 669 c := &PlanCommand{ 670 Meta: Meta{ 671 testingOverrides: metaOverridesForProvider(p), 672 Ui: ui, 673 }, 674 } 675 676 actual := "" 677 p.DiffFn = func( 678 info *terraform.InstanceInfo, 679 s *terraform.InstanceState, 680 c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { 681 if v, ok := c.Config["value"]; ok { 682 actual = v.(string) 683 } 684 685 return nil, nil 686 } 687 688 args := []string{ 689 "-var-file", varFilePath, 690 testFixturePath("plan-vars"), 691 } 692 if code := c.Run(args); code != 0 { 693 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 694 } 695 696 if actual != "bar" { 697 t.Fatal("didn't work") 698 } 699 } 700 701 func TestPlan_varFileDefault(t *testing.T) { 702 varFileDir := testTempDir(t) 703 varFilePath := filepath.Join(varFileDir, "terraform.tfvars") 704 if err := ioutil.WriteFile(varFilePath, []byte(planVarFile), 0644); err != nil { 705 t.Fatalf("err: %s", err) 706 } 707 708 cwd, err := os.Getwd() 709 if err != nil { 710 t.Fatalf("err: %s", err) 711 } 712 if err := os.Chdir(varFileDir); err != nil { 713 t.Fatalf("err: %s", err) 714 } 715 defer os.Chdir(cwd) 716 717 p := testProvider() 718 ui := new(cli.MockUi) 719 c := &PlanCommand{ 720 Meta: Meta{ 721 testingOverrides: metaOverridesForProvider(p), 722 Ui: ui, 723 }, 724 } 725 726 actual := "" 727 p.DiffFn = func( 728 info *terraform.InstanceInfo, 729 s *terraform.InstanceState, 730 c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { 731 if v, ok := c.Config["value"]; ok { 732 actual = v.(string) 733 } 734 735 return nil, nil 736 } 737 738 args := []string{ 739 testFixturePath("plan-vars"), 740 } 741 if code := c.Run(args); code != 0 { 742 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 743 } 744 745 if actual != "bar" { 746 t.Fatal("didn't work") 747 } 748 } 749 750 func TestPlan_detailedExitcode(t *testing.T) { 751 cwd, err := os.Getwd() 752 if err != nil { 753 t.Fatalf("err: %s", err) 754 } 755 if err := os.Chdir(testFixturePath("plan")); err != nil { 756 t.Fatalf("err: %s", err) 757 } 758 defer os.Chdir(cwd) 759 760 p := testProvider() 761 ui := new(cli.MockUi) 762 c := &PlanCommand{ 763 Meta: Meta{ 764 testingOverrides: metaOverridesForProvider(p), 765 Ui: ui, 766 }, 767 } 768 769 args := []string{"-detailed-exitcode"} 770 if code := c.Run(args); code != 2 { 771 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 772 } 773 } 774 775 func TestPlan_detailedExitcode_emptyDiff(t *testing.T) { 776 cwd, err := os.Getwd() 777 if err != nil { 778 t.Fatalf("err: %s", err) 779 } 780 if err := os.Chdir(testFixturePath("plan-emptydiff")); err != nil { 781 t.Fatalf("err: %s", err) 782 } 783 defer os.Chdir(cwd) 784 785 p := testProvider() 786 ui := new(cli.MockUi) 787 c := &PlanCommand{ 788 Meta: Meta{ 789 testingOverrides: metaOverridesForProvider(p), 790 Ui: ui, 791 }, 792 } 793 794 args := []string{"-detailed-exitcode"} 795 if code := c.Run(args); code != 0 { 796 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 797 } 798 } 799 800 func TestPlan_shutdown(t *testing.T) { 801 cancelled := make(chan struct{}) 802 shutdownCh := make(chan struct{}) 803 804 p := testProvider() 805 ui := new(cli.MockUi) 806 c := &PlanCommand{ 807 Meta: Meta{ 808 testingOverrides: metaOverridesForProvider(p), 809 Ui: ui, 810 ShutdownCh: shutdownCh, 811 }, 812 } 813 814 p.StopFn = func() error { 815 close(cancelled) 816 return nil 817 } 818 819 var once sync.Once 820 821 p.DiffFn = func( 822 *terraform.InstanceInfo, 823 *terraform.InstanceState, 824 *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { 825 826 once.Do(func() { 827 shutdownCh <- struct{}{} 828 }) 829 830 // Because of the internal lock in the MockProvider, we can't 831 // coordiante directly with the calling of Stop, and making the 832 // MockProvider concurrent is disruptive to a lot of existing tests. 833 // Wait here a moment to help make sure the main goroutine gets to the 834 // Stop call before we exit, or the plan may finish before it can be 835 // canceled. 836 time.Sleep(200 * time.Millisecond) 837 838 return &terraform.InstanceDiff{ 839 Attributes: map[string]*terraform.ResourceAttrDiff{ 840 "ami": &terraform.ResourceAttrDiff{ 841 New: "bar", 842 }, 843 }, 844 }, nil 845 } 846 847 if code := c.Run([]string{testFixturePath("apply-shutdown")}); code != 1 { 848 // FIXME: we should be able to avoid the error during evaluation 849 // the early exit isn't caught before the interpolation is evaluated 850 t.Fatal(ui.OutputWriter.String()) 851 } 852 853 select { 854 case <-cancelled: 855 default: 856 t.Fatal("command not cancelled") 857 } 858 } 859 860 const planVarFile = ` 861 foo = "bar" 862 ` 863 864 const testPlanNoStateStr = ` 865 <not created> 866 ` 867 868 const testPlanStateStr = ` 869 ID = bar 870 Tainted = false 871 ` 872 873 const testPlanStateDefaultStr = ` 874 ID = bar 875 Tainted = false 876 `