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