package terraform import ( "fmt" "testing" "github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/internal/configs" "github.com/hashicorp/terraform/internal/configs/configschema" "github.com/hashicorp/terraform/internal/states" "github.com/zclconf/go-cty/cty" ) func TestNodeAbstractResourceInstanceProvider(t *testing.T) { tests := []struct { Addr addrs.AbsResourceInstance Config *configs.Resource Want addrs.Provider }{ { Addr: addrs.Resource{ Mode: addrs.ManagedResourceMode, Type: "null_resource", Name: "baz", }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), Want: addrs.Provider{ Hostname: addrs.DefaultProviderRegistryHost, Namespace: "hashicorp", Type: "null", }, }, { Addr: addrs.Resource{ Mode: addrs.DataResourceMode, Type: "terraform_remote_state", Name: "baz", }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), Want: addrs.Provider{ // As a special case, the type prefix "terraform_" maps to // the builtin provider, not the default one. Hostname: addrs.BuiltInProviderHost, Namespace: addrs.BuiltInProviderNamespace, Type: "terraform", }, }, { Addr: addrs.Resource{ Mode: addrs.ManagedResourceMode, Type: "null_resource", Name: "baz", }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), Config: &configs.Resource{ // Just enough configs.Resource for the Provider method. Not // actually valid for general use. Provider: addrs.Provider{ Hostname: addrs.DefaultProviderRegistryHost, Namespace: "awesomecorp", Type: "happycloud", }, }, // The config overrides the default behavior. Want: addrs.Provider{ Hostname: addrs.DefaultProviderRegistryHost, Namespace: "awesomecorp", Type: "happycloud", }, }, { Addr: addrs.Resource{ Mode: addrs.DataResourceMode, Type: "terraform_remote_state", Name: "baz", }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), Config: &configs.Resource{ // Just enough configs.Resource for the Provider method. Not // actually valid for general use. Provider: addrs.Provider{ Hostname: addrs.DefaultProviderRegistryHost, Namespace: "awesomecorp", Type: "happycloud", }, }, // The config overrides the default behavior. Want: addrs.Provider{ Hostname: addrs.DefaultProviderRegistryHost, Namespace: "awesomecorp", Type: "happycloud", }, }, } for _, test := range tests { var name string if test.Config != nil { name = fmt.Sprintf("%s with configured %s", test.Addr, test.Config.Provider) } else { name = fmt.Sprintf("%s with no configuration", test.Addr) } t.Run(name, func(t *testing.T) { node := &NodeAbstractResourceInstance{ // Just enough NodeAbstractResourceInstance for the Provider // function. (This would not be valid for some other functions.) Addr: test.Addr, NodeAbstractResource: NodeAbstractResource{ Config: test.Config, }, } got := node.Provider() if got != test.Want { t.Errorf("wrong result\naddr: %s\nconfig: %#v\ngot: %s\nwant: %s", test.Addr, test.Config, got, test.Want) } }) } } func TestNodeAbstractResourceInstance_WriteResourceInstanceState(t *testing.T) { state := states.NewState() ctx := new(MockEvalContext) ctx.StateState = state.SyncWrapper() ctx.PathPath = addrs.RootModuleInstance mockProvider := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{ Attributes: map[string]*configschema.Attribute{ "id": { Type: cty.String, Optional: true, }, }, }) obj := &states.ResourceInstanceObject{ Value: cty.ObjectVal(map[string]cty.Value{ "id": cty.StringVal("i-abc123"), }), Status: states.ObjectReady, } node := &NodeAbstractResourceInstance{ Addr: mustResourceInstanceAddr("aws_instance.foo"), // instanceState: obj, NodeAbstractResource: NodeAbstractResource{ ResolvedProvider: mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), }, } ctx.ProviderProvider = mockProvider ctx.ProviderSchemaSchema = mockProvider.ProviderSchema() err := node.writeResourceInstanceState(ctx, obj, workingState) if err != nil { t.Fatalf("unexpected error: %s", err.Error()) } checkStateString(t, state, ` aws_instance.foo: ID = i-abc123 provider = provider["registry.terraform.io/hashicorp/aws"] `) }