opentofu/internal/terraform/node_resource_abstract_instance_test.go
Alisdair McDiarmid 5ddf5e1f7d core: Fix schema loading for deleted resources
Resource instances removed from the configuration would previously use
the implied provider address. This is correct for default providers, but
incorrect for those from other namespaces or hosts. The fix here is to
use the stored provider config if it is present.
2021-11-24 15:23:20 -05:00

183 lines
5.1 KiB
Go

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
StoredProviderConfig addrs.AbsProviderConfig
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",
},
},
{
Addr: addrs.Resource{
Mode: addrs.DataResourceMode,
Type: "null_resource",
Name: "baz",
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
Config: nil,
StoredProviderConfig: addrs.AbsProviderConfig{
Module: addrs.RootModule,
Provider: addrs.Provider{
Hostname: addrs.DefaultProviderRegistryHost,
Namespace: "awesomecorp",
Type: "null",
},
},
// The stored provider config overrides the default behavior.
Want: addrs.Provider{
Hostname: addrs.DefaultProviderRegistryHost,
Namespace: "awesomecorp",
Type: "null",
},
},
}
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,
},
storedProviderConfig: test.StoredProviderConfig,
}
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"]
`)
}