github.com/lymingtonprecision/terraform@v0.9.9-0.20170613092852-62acef9611a9/terraform/context_refresh_test.go (about) 1 package terraform 2 3 import ( 4 "reflect" 5 "sort" 6 "strings" 7 "sync" 8 "testing" 9 ) 10 11 func TestContext2Refresh(t *testing.T) { 12 p := testProvider("aws") 13 m := testModule(t, "refresh-basic") 14 ctx := testContext2(t, &ContextOpts{ 15 Module: m, 16 ProviderResolver: ResourceProviderResolverFixed( 17 map[string]ResourceProviderFactory{ 18 "aws": testProviderFuncFixed(p), 19 }, 20 ), 21 State: &State{ 22 Modules: []*ModuleState{ 23 &ModuleState{ 24 Path: rootModulePath, 25 Resources: map[string]*ResourceState{ 26 "aws_instance.web": &ResourceState{ 27 Type: "aws_instance", 28 Primary: &InstanceState{ 29 ID: "foo", 30 }, 31 }, 32 }, 33 }, 34 }, 35 }, 36 }) 37 38 p.RefreshFn = nil 39 p.RefreshReturn = &InstanceState{ 40 ID: "foo", 41 } 42 43 s, err := ctx.Refresh() 44 mod := s.RootModule() 45 if err != nil { 46 t.Fatalf("err: %s", err) 47 } 48 if !p.RefreshCalled { 49 t.Fatal("refresh should be called") 50 } 51 if p.RefreshState.ID != "foo" { 52 t.Fatalf("bad: %#v", p.RefreshState) 53 } 54 if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) { 55 t.Fatalf("bad: %#v %#v", mod.Resources["aws_instance.web"], p.RefreshReturn) 56 } 57 58 for _, r := range mod.Resources { 59 if r.Type == "" { 60 t.Fatalf("no type: %#v", r) 61 } 62 } 63 } 64 65 func TestContext2Refresh_dataComputedModuleVar(t *testing.T) { 66 p := testProvider("aws") 67 m := testModule(t, "refresh-data-module-var") 68 ctx := testContext2(t, &ContextOpts{ 69 Module: m, 70 ProviderResolver: ResourceProviderResolverFixed( 71 map[string]ResourceProviderFactory{ 72 "aws": testProviderFuncFixed(p), 73 }, 74 ), 75 }) 76 77 p.RefreshFn = nil 78 p.RefreshReturn = &InstanceState{ 79 ID: "foo", 80 } 81 82 s, err := ctx.Refresh() 83 if err != nil { 84 t.Fatalf("err: %s", err) 85 } 86 87 checkStateString(t, s, ` 88 <no state> 89 module.child: 90 <no state>`) 91 } 92 93 func TestContext2Refresh_targeted(t *testing.T) { 94 p := testProvider("aws") 95 m := testModule(t, "refresh-targeted") 96 ctx := testContext2(t, &ContextOpts{ 97 Module: m, 98 ProviderResolver: ResourceProviderResolverFixed( 99 map[string]ResourceProviderFactory{ 100 "aws": testProviderFuncFixed(p), 101 }, 102 ), 103 State: &State{ 104 Modules: []*ModuleState{ 105 &ModuleState{ 106 Path: rootModulePath, 107 Resources: map[string]*ResourceState{ 108 "aws_vpc.metoo": resourceState("aws_vpc", "vpc-abc123"), 109 "aws_instance.notme": resourceState("aws_instance", "i-bcd345"), 110 "aws_instance.me": resourceState("aws_instance", "i-abc123"), 111 "aws_elb.meneither": resourceState("aws_elb", "lb-abc123"), 112 }, 113 }, 114 }, 115 }, 116 Targets: []string{"aws_instance.me"}, 117 }) 118 119 refreshedResources := make([]string, 0, 2) 120 p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) { 121 refreshedResources = append(refreshedResources, i.Id) 122 return is, nil 123 } 124 125 _, err := ctx.Refresh() 126 if err != nil { 127 t.Fatalf("err: %s", err) 128 } 129 130 expected := []string{"aws_vpc.metoo", "aws_instance.me"} 131 if !reflect.DeepEqual(refreshedResources, expected) { 132 t.Fatalf("expected: %#v, got: %#v", expected, refreshedResources) 133 } 134 } 135 136 func TestContext2Refresh_targetedCount(t *testing.T) { 137 p := testProvider("aws") 138 m := testModule(t, "refresh-targeted-count") 139 ctx := testContext2(t, &ContextOpts{ 140 Module: m, 141 ProviderResolver: ResourceProviderResolverFixed( 142 map[string]ResourceProviderFactory{ 143 "aws": testProviderFuncFixed(p), 144 }, 145 ), 146 State: &State{ 147 Modules: []*ModuleState{ 148 &ModuleState{ 149 Path: rootModulePath, 150 Resources: map[string]*ResourceState{ 151 "aws_vpc.metoo": resourceState("aws_vpc", "vpc-abc123"), 152 "aws_instance.notme": resourceState("aws_instance", "i-bcd345"), 153 "aws_instance.me.0": resourceState("aws_instance", "i-abc123"), 154 "aws_instance.me.1": resourceState("aws_instance", "i-cde567"), 155 "aws_instance.me.2": resourceState("aws_instance", "i-cde789"), 156 "aws_elb.meneither": resourceState("aws_elb", "lb-abc123"), 157 }, 158 }, 159 }, 160 }, 161 Targets: []string{"aws_instance.me"}, 162 }) 163 164 refreshedResources := make([]string, 0, 2) 165 p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) { 166 refreshedResources = append(refreshedResources, i.Id) 167 return is, nil 168 } 169 170 _, err := ctx.Refresh() 171 if err != nil { 172 t.Fatalf("err: %s", err) 173 } 174 175 // Target didn't specify index, so we should get all our instances 176 expected := []string{ 177 "aws_vpc.metoo", 178 "aws_instance.me.0", 179 "aws_instance.me.1", 180 "aws_instance.me.2", 181 } 182 sort.Strings(expected) 183 sort.Strings(refreshedResources) 184 if !reflect.DeepEqual(refreshedResources, expected) { 185 t.Fatalf("expected: %#v, got: %#v", expected, refreshedResources) 186 } 187 } 188 189 func TestContext2Refresh_targetedCountIndex(t *testing.T) { 190 p := testProvider("aws") 191 m := testModule(t, "refresh-targeted-count") 192 ctx := testContext2(t, &ContextOpts{ 193 Module: m, 194 ProviderResolver: ResourceProviderResolverFixed( 195 map[string]ResourceProviderFactory{ 196 "aws": testProviderFuncFixed(p), 197 }, 198 ), 199 State: &State{ 200 Modules: []*ModuleState{ 201 &ModuleState{ 202 Path: rootModulePath, 203 Resources: map[string]*ResourceState{ 204 "aws_vpc.metoo": resourceState("aws_vpc", "vpc-abc123"), 205 "aws_instance.notme": resourceState("aws_instance", "i-bcd345"), 206 "aws_instance.me.0": resourceState("aws_instance", "i-abc123"), 207 "aws_instance.me.1": resourceState("aws_instance", "i-cde567"), 208 "aws_instance.me.2": resourceState("aws_instance", "i-cde789"), 209 "aws_elb.meneither": resourceState("aws_elb", "lb-abc123"), 210 }, 211 }, 212 }, 213 }, 214 Targets: []string{"aws_instance.me[0]"}, 215 }) 216 217 refreshedResources := make([]string, 0, 2) 218 p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) { 219 refreshedResources = append(refreshedResources, i.Id) 220 return is, nil 221 } 222 223 _, err := ctx.Refresh() 224 if err != nil { 225 t.Fatalf("err: %s", err) 226 } 227 228 expected := []string{"aws_vpc.metoo", "aws_instance.me.0"} 229 if !reflect.DeepEqual(refreshedResources, expected) { 230 t.Fatalf("expected: %#v, got: %#v", expected, refreshedResources) 231 } 232 } 233 234 func TestContext2Refresh_moduleComputedVar(t *testing.T) { 235 p := testProvider("aws") 236 m := testModule(t, "refresh-module-computed-var") 237 ctx := testContext2(t, &ContextOpts{ 238 Module: m, 239 ProviderResolver: ResourceProviderResolverFixed( 240 map[string]ResourceProviderFactory{ 241 "aws": testProviderFuncFixed(p), 242 }, 243 ), 244 }) 245 246 // This was failing (see GH-2188) at some point, so this test just 247 // verifies that the failure goes away. 248 if _, err := ctx.Refresh(); err != nil { 249 t.Fatalf("err: %s", err) 250 } 251 } 252 253 func TestContext2Refresh_delete(t *testing.T) { 254 p := testProvider("aws") 255 m := testModule(t, "refresh-basic") 256 ctx := testContext2(t, &ContextOpts{ 257 Module: m, 258 ProviderResolver: ResourceProviderResolverFixed( 259 map[string]ResourceProviderFactory{ 260 "aws": testProviderFuncFixed(p), 261 }, 262 ), 263 State: &State{ 264 Modules: []*ModuleState{ 265 &ModuleState{ 266 Path: rootModulePath, 267 Resources: map[string]*ResourceState{ 268 "aws_instance.web": &ResourceState{ 269 Type: "aws_instance", 270 Primary: &InstanceState{ 271 ID: "foo", 272 }, 273 }, 274 }, 275 }, 276 }, 277 }, 278 }) 279 280 p.RefreshFn = nil 281 p.RefreshReturn = nil 282 283 s, err := ctx.Refresh() 284 if err != nil { 285 t.Fatalf("err: %s", err) 286 } 287 288 mod := s.RootModule() 289 if len(mod.Resources) > 0 { 290 t.Fatal("resources should be empty") 291 } 292 } 293 294 func TestContext2Refresh_ignoreUncreated(t *testing.T) { 295 p := testProvider("aws") 296 m := testModule(t, "refresh-basic") 297 ctx := testContext2(t, &ContextOpts{ 298 Module: m, 299 ProviderResolver: ResourceProviderResolverFixed( 300 map[string]ResourceProviderFactory{ 301 "aws": testProviderFuncFixed(p), 302 }, 303 ), 304 State: nil, 305 }) 306 307 p.RefreshFn = nil 308 p.RefreshReturn = &InstanceState{ 309 ID: "foo", 310 } 311 312 _, err := ctx.Refresh() 313 if err != nil { 314 t.Fatalf("err: %s", err) 315 } 316 if p.RefreshCalled { 317 t.Fatal("refresh should not be called") 318 } 319 } 320 321 func TestContext2Refresh_hook(t *testing.T) { 322 h := new(MockHook) 323 p := testProvider("aws") 324 m := testModule(t, "refresh-basic") 325 ctx := testContext2(t, &ContextOpts{ 326 Module: m, 327 Hooks: []Hook{h}, 328 ProviderResolver: ResourceProviderResolverFixed( 329 map[string]ResourceProviderFactory{ 330 "aws": testProviderFuncFixed(p), 331 }, 332 ), 333 State: &State{ 334 Modules: []*ModuleState{ 335 &ModuleState{ 336 Path: rootModulePath, 337 Resources: map[string]*ResourceState{ 338 "aws_instance.web": &ResourceState{ 339 Type: "aws_instance", 340 Primary: &InstanceState{ 341 ID: "foo", 342 }, 343 }, 344 }, 345 }, 346 }, 347 }, 348 }) 349 350 if _, err := ctx.Refresh(); err != nil { 351 t.Fatalf("err: %s", err) 352 } 353 if !h.PreRefreshCalled { 354 t.Fatal("should be called") 355 } 356 if !h.PostRefreshCalled { 357 t.Fatal("should be called") 358 } 359 } 360 361 func TestContext2Refresh_modules(t *testing.T) { 362 p := testProvider("aws") 363 m := testModule(t, "refresh-modules") 364 state := &State{ 365 Modules: []*ModuleState{ 366 &ModuleState{ 367 Path: rootModulePath, 368 Resources: map[string]*ResourceState{ 369 "aws_instance.web": &ResourceState{ 370 Type: "aws_instance", 371 Primary: &InstanceState{ 372 ID: "bar", 373 Tainted: true, 374 }, 375 }, 376 }, 377 }, 378 379 &ModuleState{ 380 Path: []string{"root", "child"}, 381 Resources: map[string]*ResourceState{ 382 "aws_instance.web": &ResourceState{ 383 Type: "aws_instance", 384 Primary: &InstanceState{ 385 ID: "baz", 386 }, 387 }, 388 }, 389 }, 390 }, 391 } 392 ctx := testContext2(t, &ContextOpts{ 393 Module: m, 394 ProviderResolver: ResourceProviderResolverFixed( 395 map[string]ResourceProviderFactory{ 396 "aws": testProviderFuncFixed(p), 397 }, 398 ), 399 State: state, 400 }) 401 402 p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) { 403 if s.ID != "baz" { 404 return s, nil 405 } 406 407 s.ID = "new" 408 return s, nil 409 } 410 411 s, err := ctx.Refresh() 412 if err != nil { 413 t.Fatalf("err: %s", err) 414 } 415 416 actual := strings.TrimSpace(s.String()) 417 expected := strings.TrimSpace(testContextRefreshModuleStr) 418 if actual != expected { 419 t.Fatalf("bad:\n\n%s\n\n%s", actual, expected) 420 } 421 } 422 423 func TestContext2Refresh_moduleInputComputedOutput(t *testing.T) { 424 m := testModule(t, "refresh-module-input-computed-output") 425 p := testProvider("aws") 426 p.DiffFn = testDiffFn 427 ctx := testContext2(t, &ContextOpts{ 428 Module: m, 429 ProviderResolver: ResourceProviderResolverFixed( 430 map[string]ResourceProviderFactory{ 431 "aws": testProviderFuncFixed(p), 432 }, 433 ), 434 }) 435 436 if _, err := ctx.Refresh(); err != nil { 437 t.Fatalf("err: %s", err) 438 } 439 } 440 441 func TestContext2Refresh_moduleVarModule(t *testing.T) { 442 m := testModule(t, "refresh-module-var-module") 443 p := testProvider("aws") 444 p.DiffFn = testDiffFn 445 ctx := testContext2(t, &ContextOpts{ 446 Module: m, 447 ProviderResolver: ResourceProviderResolverFixed( 448 map[string]ResourceProviderFactory{ 449 "aws": testProviderFuncFixed(p), 450 }, 451 ), 452 }) 453 454 if _, err := ctx.Refresh(); err != nil { 455 t.Fatalf("err: %s", err) 456 } 457 } 458 459 // GH-70 460 func TestContext2Refresh_noState(t *testing.T) { 461 p := testProvider("aws") 462 m := testModule(t, "refresh-no-state") 463 ctx := testContext2(t, &ContextOpts{ 464 Module: m, 465 ProviderResolver: ResourceProviderResolverFixed( 466 map[string]ResourceProviderFactory{ 467 "aws": testProviderFuncFixed(p), 468 }, 469 ), 470 }) 471 472 p.RefreshFn = nil 473 p.RefreshReturn = &InstanceState{ 474 ID: "foo", 475 } 476 477 if _, err := ctx.Refresh(); err != nil { 478 t.Fatalf("err: %s", err) 479 } 480 } 481 482 func TestContext2Refresh_output(t *testing.T) { 483 p := testProvider("aws") 484 m := testModule(t, "refresh-output") 485 ctx := testContext2(t, &ContextOpts{ 486 Module: m, 487 ProviderResolver: ResourceProviderResolverFixed( 488 map[string]ResourceProviderFactory{ 489 "aws": testProviderFuncFixed(p), 490 }, 491 ), 492 State: &State{ 493 Modules: []*ModuleState{ 494 &ModuleState{ 495 Path: rootModulePath, 496 Resources: map[string]*ResourceState{ 497 "aws_instance.web": &ResourceState{ 498 Type: "aws_instance", 499 Primary: &InstanceState{ 500 ID: "foo", 501 Attributes: map[string]string{ 502 "foo": "bar", 503 }, 504 }, 505 }, 506 }, 507 508 Outputs: map[string]*OutputState{ 509 "foo": &OutputState{ 510 Type: "string", 511 Sensitive: false, 512 Value: "foo", 513 }, 514 }, 515 }, 516 }, 517 }, 518 }) 519 520 p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) { 521 return s, nil 522 } 523 524 s, err := ctx.Refresh() 525 if err != nil { 526 t.Fatalf("err: %s", err) 527 } 528 529 actual := strings.TrimSpace(s.String()) 530 expected := strings.TrimSpace(testContextRefreshOutputStr) 531 if actual != expected { 532 t.Fatalf("bad:\n\n%s\n\n%s", actual, expected) 533 } 534 } 535 536 func TestContext2Refresh_outputPartial(t *testing.T) { 537 p := testProvider("aws") 538 m := testModule(t, "refresh-output-partial") 539 ctx := testContext2(t, &ContextOpts{ 540 Module: m, 541 ProviderResolver: ResourceProviderResolverFixed( 542 map[string]ResourceProviderFactory{ 543 "aws": testProviderFuncFixed(p), 544 }, 545 ), 546 State: &State{ 547 Modules: []*ModuleState{ 548 &ModuleState{ 549 Path: rootModulePath, 550 Resources: map[string]*ResourceState{ 551 "aws_instance.foo": &ResourceState{ 552 Type: "aws_instance", 553 Primary: &InstanceState{ 554 ID: "foo", 555 }, 556 }, 557 }, 558 Outputs: map[string]*OutputState{}, 559 }, 560 }, 561 }, 562 }) 563 564 p.RefreshFn = nil 565 p.RefreshReturn = nil 566 567 s, err := ctx.Refresh() 568 if err != nil { 569 t.Fatalf("err: %s", err) 570 } 571 572 actual := strings.TrimSpace(s.String()) 573 expected := strings.TrimSpace(testContextRefreshOutputPartialStr) 574 if actual != expected { 575 t.Fatalf("bad:\n\n%s\n\n%s", actual, expected) 576 } 577 } 578 579 func TestContext2Refresh_stateBasic(t *testing.T) { 580 p := testProvider("aws") 581 m := testModule(t, "refresh-basic") 582 state := &State{ 583 Modules: []*ModuleState{ 584 &ModuleState{ 585 Path: rootModulePath, 586 Resources: map[string]*ResourceState{ 587 "aws_instance.web": &ResourceState{ 588 Type: "aws_instance", 589 Primary: &InstanceState{ 590 ID: "bar", 591 }, 592 }, 593 }, 594 }, 595 }, 596 } 597 ctx := testContext2(t, &ContextOpts{ 598 Module: m, 599 ProviderResolver: ResourceProviderResolverFixed( 600 map[string]ResourceProviderFactory{ 601 "aws": testProviderFuncFixed(p), 602 }, 603 ), 604 State: state, 605 }) 606 607 p.RefreshFn = nil 608 p.RefreshReturn = &InstanceState{ 609 ID: "foo", 610 } 611 612 s, err := ctx.Refresh() 613 if err != nil { 614 t.Fatalf("err: %s", err) 615 } 616 originalMod := state.RootModule() 617 mod := s.RootModule() 618 if !p.RefreshCalled { 619 t.Fatal("refresh should be called") 620 } 621 if !reflect.DeepEqual(p.RefreshState, originalMod.Resources["aws_instance.web"].Primary) { 622 t.Fatalf( 623 "bad:\n\n%#v\n\n%#v", 624 p.RefreshState, 625 originalMod.Resources["aws_instance.web"].Primary) 626 } 627 if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) { 628 t.Fatalf("bad: %#v", mod.Resources) 629 } 630 } 631 632 func TestContext2Refresh_dataOrphan(t *testing.T) { 633 p := testProvider("null") 634 state := &State{ 635 Modules: []*ModuleState{ 636 &ModuleState{ 637 Path: rootModulePath, 638 Resources: map[string]*ResourceState{ 639 "data.null_data_source.bar": &ResourceState{ 640 Type: "null_data_source", 641 Primary: &InstanceState{ 642 ID: "foo", 643 }, 644 }, 645 }, 646 }, 647 }, 648 } 649 ctx := testContext2(t, &ContextOpts{ 650 ProviderResolver: ResourceProviderResolverFixed( 651 map[string]ResourceProviderFactory{ 652 "null": testProviderFuncFixed(p), 653 }, 654 ), 655 State: state, 656 }) 657 658 s, err := ctx.Refresh() 659 if err != nil { 660 t.Fatalf("err: %s", err) 661 } 662 663 checkStateString(t, s, `<no state>`) 664 } 665 666 func TestContext2Refresh_dataState(t *testing.T) { 667 p := testProvider("null") 668 m := testModule(t, "refresh-data-resource-basic") 669 state := &State{ 670 Modules: []*ModuleState{ 671 &ModuleState{ 672 Path: rootModulePath, 673 // Intentionally no resources since data resources are 674 // supposed to refresh themselves even if they didn't 675 // already exist. 676 Resources: map[string]*ResourceState{}, 677 }, 678 }, 679 } 680 ctx := testContext2(t, &ContextOpts{ 681 Module: m, 682 ProviderResolver: ResourceProviderResolverFixed( 683 map[string]ResourceProviderFactory{ 684 "null": testProviderFuncFixed(p), 685 }, 686 ), 687 State: state, 688 }) 689 690 p.ReadDataDiffFn = nil 691 p.ReadDataDiffReturn = &InstanceDiff{ 692 Attributes: map[string]*ResourceAttrDiff{ 693 "inputs.#": { 694 Old: "0", 695 New: "1", 696 Type: DiffAttrInput, 697 }, 698 "inputs.test": { 699 Old: "", 700 New: "yes", 701 Type: DiffAttrInput, 702 }, 703 "outputs.#": { 704 Old: "", 705 New: "", 706 NewComputed: true, 707 Type: DiffAttrOutput, 708 }, 709 }, 710 } 711 712 p.ReadDataApplyFn = nil 713 p.ReadDataApplyReturn = &InstanceState{ 714 ID: "-", 715 } 716 717 s, err := ctx.Refresh() 718 if err != nil { 719 t.Fatalf("err: %s", err) 720 } 721 722 if !p.ReadDataDiffCalled { 723 t.Fatal("ReadDataDiff should have been called") 724 } 725 if !p.ReadDataApplyCalled { 726 t.Fatal("ReadDataApply should have been called") 727 } 728 729 mod := s.RootModule() 730 if got := mod.Resources["data.null_data_source.testing"].Primary.ID; got != "-" { 731 t.Fatalf("resource id is %q; want %s", got, "-") 732 } 733 if !reflect.DeepEqual(mod.Resources["data.null_data_source.testing"].Primary, p.ReadDataApplyReturn) { 734 t.Fatalf("bad: %#v", mod.Resources) 735 } 736 } 737 738 func TestContext2Refresh_dataStateRefData(t *testing.T) { 739 p := testProvider("null") 740 m := testModule(t, "refresh-data-ref-data") 741 state := &State{ 742 Modules: []*ModuleState{ 743 &ModuleState{ 744 Path: rootModulePath, 745 // Intentionally no resources since data resources are 746 // supposed to refresh themselves even if they didn't 747 // already exist. 748 Resources: map[string]*ResourceState{}, 749 }, 750 }, 751 } 752 ctx := testContext2(t, &ContextOpts{ 753 Module: m, 754 ProviderResolver: ResourceProviderResolverFixed( 755 map[string]ResourceProviderFactory{ 756 "null": testProviderFuncFixed(p), 757 }, 758 ), 759 State: state, 760 }) 761 762 p.ReadDataDiffFn = testDataDiffFn 763 p.ReadDataApplyFn = testDataApplyFn 764 765 s, err := ctx.Refresh() 766 if err != nil { 767 t.Fatalf("err: %s", err) 768 } 769 770 actual := strings.TrimSpace(s.String()) 771 expected := strings.TrimSpace(testTerraformRefreshDataRefDataStr) 772 if actual != expected { 773 t.Fatalf("bad:\n\n%s\n\n%s", actual, expected) 774 } 775 } 776 777 func TestContext2Refresh_tainted(t *testing.T) { 778 p := testProvider("aws") 779 m := testModule(t, "refresh-basic") 780 state := &State{ 781 Modules: []*ModuleState{ 782 &ModuleState{ 783 Path: rootModulePath, 784 Resources: map[string]*ResourceState{ 785 "aws_instance.web": &ResourceState{ 786 Type: "aws_instance", 787 Primary: &InstanceState{ 788 ID: "bar", 789 Tainted: true, 790 }, 791 }, 792 }, 793 }, 794 }, 795 } 796 ctx := testContext2(t, &ContextOpts{ 797 Module: m, 798 ProviderResolver: ResourceProviderResolverFixed( 799 map[string]ResourceProviderFactory{ 800 "aws": testProviderFuncFixed(p), 801 }, 802 ), 803 State: state, 804 }) 805 806 p.RefreshFn = nil 807 p.RefreshReturn = &InstanceState{ 808 ID: "foo", 809 Tainted: true, 810 } 811 812 s, err := ctx.Refresh() 813 if err != nil { 814 t.Fatalf("err: %s", err) 815 } 816 if !p.RefreshCalled { 817 t.Fatal("refresh should be called") 818 } 819 820 actual := strings.TrimSpace(s.String()) 821 expected := strings.TrimSpace(testContextRefreshTaintedStr) 822 if actual != expected { 823 t.Fatalf("bad:\n\n%s\n\n%s", actual, expected) 824 } 825 } 826 827 // Doing a Refresh (or any operation really, but Refresh usually 828 // happens first) with a config with an unknown provider should result in 829 // an error. The key bug this found was that this wasn't happening if 830 // Providers was _empty_. 831 func TestContext2Refresh_unknownProvider(t *testing.T) { 832 m := testModule(t, "refresh-unknown-provider") 833 p := testProvider("aws") 834 p.ApplyFn = testApplyFn 835 p.DiffFn = testDiffFn 836 837 _, err := NewContext(&ContextOpts{ 838 Module: m, 839 ProviderResolver: ResourceProviderResolverFixed( 840 map[string]ResourceProviderFactory{}, 841 ), 842 Shadow: true, 843 State: &State{ 844 Modules: []*ModuleState{ 845 &ModuleState{ 846 Path: rootModulePath, 847 Resources: map[string]*ResourceState{ 848 "aws_instance.web": &ResourceState{ 849 Type: "aws_instance", 850 Primary: &InstanceState{ 851 ID: "foo", 852 }, 853 }, 854 }, 855 }, 856 }, 857 }, 858 }) 859 860 if err == nil { 861 t.Fatal("successfully created context; want error") 862 } 863 864 if !strings.Contains(err.Error(), "Can't satisfy provider requirements") { 865 t.Fatalf("wrong error: %s", err) 866 } 867 } 868 869 func TestContext2Refresh_vars(t *testing.T) { 870 p := testProvider("aws") 871 m := testModule(t, "refresh-vars") 872 ctx := testContext2(t, &ContextOpts{ 873 Module: m, 874 ProviderResolver: ResourceProviderResolverFixed( 875 map[string]ResourceProviderFactory{ 876 "aws": testProviderFuncFixed(p), 877 }, 878 ), 879 State: &State{ 880 881 Modules: []*ModuleState{ 882 &ModuleState{ 883 Path: rootModulePath, 884 Resources: map[string]*ResourceState{ 885 "aws_instance.web": &ResourceState{ 886 Type: "aws_instance", 887 Primary: &InstanceState{ 888 ID: "foo", 889 }, 890 }, 891 }, 892 }, 893 }, 894 }, 895 }) 896 897 p.RefreshFn = nil 898 p.RefreshReturn = &InstanceState{ 899 ID: "foo", 900 } 901 902 s, err := ctx.Refresh() 903 if err != nil { 904 t.Fatalf("err: %s", err) 905 } 906 mod := s.RootModule() 907 if !p.RefreshCalled { 908 t.Fatal("refresh should be called") 909 } 910 if p.RefreshState.ID != "foo" { 911 t.Fatalf("bad: %#v", p.RefreshState) 912 } 913 if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) { 914 t.Fatalf("bad: %#v", mod.Resources["aws_instance.web"]) 915 } 916 917 for _, r := range mod.Resources { 918 if r.Type == "" { 919 t.Fatalf("no type: %#v", r) 920 } 921 } 922 } 923 924 func TestContext2Refresh_orphanModule(t *testing.T) { 925 p := testProvider("aws") 926 m := testModule(t, "refresh-module-orphan") 927 928 // Create a custom refresh function to track the order they were visited 929 var order []string 930 var orderLock sync.Mutex 931 p.RefreshFn = func( 932 info *InstanceInfo, 933 is *InstanceState) (*InstanceState, error) { 934 orderLock.Lock() 935 defer orderLock.Unlock() 936 937 order = append(order, is.ID) 938 return is, nil 939 } 940 941 state := &State{ 942 Modules: []*ModuleState{ 943 &ModuleState{ 944 Path: rootModulePath, 945 Resources: map[string]*ResourceState{ 946 "aws_instance.foo": &ResourceState{ 947 Type: "aws_instance", 948 Primary: &InstanceState{ 949 ID: "i-abc123", 950 Attributes: map[string]string{ 951 "childid": "i-bcd234", 952 "grandchildid": "i-cde345", 953 }, 954 }, 955 Dependencies: []string{ 956 "module.child", 957 "module.child", 958 }, 959 }, 960 }, 961 }, 962 &ModuleState{ 963 Path: append(rootModulePath, "child"), 964 Resources: map[string]*ResourceState{ 965 "aws_instance.bar": &ResourceState{ 966 Type: "aws_instance", 967 Primary: &InstanceState{ 968 ID: "i-bcd234", 969 Attributes: map[string]string{ 970 "grandchildid": "i-cde345", 971 }, 972 }, 973 Dependencies: []string{ 974 "module.grandchild", 975 }, 976 }, 977 }, 978 Outputs: map[string]*OutputState{ 979 "id": &OutputState{ 980 Value: "i-bcd234", 981 Type: "string", 982 }, 983 "grandchild_id": &OutputState{ 984 Value: "i-cde345", 985 Type: "string", 986 }, 987 }, 988 }, 989 &ModuleState{ 990 Path: append(rootModulePath, "child", "grandchild"), 991 Resources: map[string]*ResourceState{ 992 "aws_instance.baz": &ResourceState{ 993 Type: "aws_instance", 994 Primary: &InstanceState{ 995 ID: "i-cde345", 996 }, 997 }, 998 }, 999 Outputs: map[string]*OutputState{ 1000 "id": &OutputState{ 1001 Value: "i-cde345", 1002 Type: "string", 1003 }, 1004 }, 1005 }, 1006 }, 1007 } 1008 ctx := testContext2(t, &ContextOpts{ 1009 Module: m, 1010 ProviderResolver: ResourceProviderResolverFixed( 1011 map[string]ResourceProviderFactory{ 1012 "aws": testProviderFuncFixed(p), 1013 }, 1014 ), 1015 State: state, 1016 }) 1017 1018 testCheckDeadlock(t, func() { 1019 _, err := ctx.Refresh() 1020 if err != nil { 1021 t.Fatalf("err: %s", err) 1022 } 1023 1024 // TODO: handle order properly for orphaned modules / resources 1025 // expected := []string{"i-abc123", "i-bcd234", "i-cde345"} 1026 // if !reflect.DeepEqual(order, expected) { 1027 // t.Fatalf("expected: %#v, got: %#v", expected, order) 1028 // } 1029 }) 1030 } 1031 1032 func TestContext2Validate(t *testing.T) { 1033 p := testProvider("aws") 1034 m := testModule(t, "validate-good") 1035 c := testContext2(t, &ContextOpts{ 1036 Module: m, 1037 ProviderResolver: ResourceProviderResolverFixed( 1038 map[string]ResourceProviderFactory{ 1039 "aws": testProviderFuncFixed(p), 1040 }, 1041 ), 1042 }) 1043 1044 w, e := c.Validate() 1045 if len(w) > 0 { 1046 t.Fatalf("bad: %#v", w) 1047 } 1048 if len(e) > 0 { 1049 t.Fatalf("bad: %s", e) 1050 } 1051 }