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