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