mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-30 10:47:14 -06:00
e5f52e56f8
As the comment notes, this hostname is the default for provide source addresses. We'll shortly be adding some address types to represent module source addresses too, and so we'll also have DefaultModuleRegistryHost for that situation. (They'll actually both contain the the same hostname, but that's a coincidence rather than a requirement.)
312 lines
10 KiB
Go
312 lines
10 KiB
Go
package configs
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/terraform/internal/addrs"
|
|
)
|
|
|
|
// TestNewModule_provider_fqns exercises module.gatherProviderLocalNames()
|
|
func TestNewModule_provider_local_name(t *testing.T) {
|
|
mod, diags := testModuleFromDir("testdata/providers-explicit-fqn")
|
|
if diags.HasErrors() {
|
|
t.Fatal(diags.Error())
|
|
}
|
|
|
|
p := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "foo", "test")
|
|
if name, exists := mod.ProviderLocalNames[p]; !exists {
|
|
t.Fatal("provider FQN foo/test not found")
|
|
} else {
|
|
if name != "foo-test" {
|
|
t.Fatalf("provider localname mismatch: got %s, want foo-test", name)
|
|
}
|
|
}
|
|
|
|
// ensure the reverse lookup (fqn to local name) works as well
|
|
localName := mod.LocalNameForProvider(p)
|
|
if localName != "foo-test" {
|
|
t.Fatal("provider local name not found")
|
|
}
|
|
|
|
// if there is not a local name for a provider, it should return the type name
|
|
localName = mod.LocalNameForProvider(addrs.NewDefaultProvider("nonexist"))
|
|
if localName != "nonexist" {
|
|
t.Error("wrong local name returned for a non-local provider")
|
|
}
|
|
|
|
// can also look up the "terraform" provider and see that it sources is
|
|
// allowed to be overridden, even though there is a builtin provider
|
|
// called "terraform".
|
|
p = addrs.NewProvider(addrs.DefaultProviderRegistryHost, "not-builtin", "not-terraform")
|
|
if name, exists := mod.ProviderLocalNames[p]; !exists {
|
|
t.Fatal("provider FQN not-builtin/not-terraform not found")
|
|
} else {
|
|
if name != "terraform" {
|
|
t.Fatalf("provider localname mismatch: got %s, want terraform", name)
|
|
}
|
|
}
|
|
}
|
|
|
|
// This test validates the provider FQNs set in each Resource
|
|
func TestNewModule_resource_providers(t *testing.T) {
|
|
cfg, diags := testNestedModuleConfigFromDir(t, "testdata/valid-modules/nested-providers-fqns")
|
|
if diags.HasErrors() {
|
|
t.Fatal(diags.Error())
|
|
}
|
|
|
|
// both the root and child module have two resources, one which should use
|
|
// the default implied provider and one explicitly using a provider set in
|
|
// required_providers
|
|
wantImplicit := addrs.NewDefaultProvider("test")
|
|
wantFoo := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "foo", "test")
|
|
wantBar := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "bar", "test")
|
|
|
|
// root module
|
|
if !cfg.Module.ManagedResources["test_instance.explicit"].Provider.Equals(wantFoo) {
|
|
t.Fatalf("wrong provider for \"test_instance.explicit\"\ngot: %s\nwant: %s",
|
|
cfg.Module.ManagedResources["test_instance.explicit"].Provider,
|
|
wantFoo,
|
|
)
|
|
}
|
|
if !cfg.Module.ManagedResources["test_instance.implicit"].Provider.Equals(wantImplicit) {
|
|
t.Fatalf("wrong provider for \"test_instance.implicit\"\ngot: %s\nwant: %s",
|
|
cfg.Module.ManagedResources["test_instance.implicit"].Provider,
|
|
wantImplicit,
|
|
)
|
|
}
|
|
|
|
// a data source
|
|
if !cfg.Module.DataResources["data.test_resource.explicit"].Provider.Equals(wantFoo) {
|
|
t.Fatalf("wrong provider for \"module.child.test_instance.explicit\"\ngot: %s\nwant: %s",
|
|
cfg.Module.ManagedResources["test_instance.explicit"].Provider,
|
|
wantBar,
|
|
)
|
|
}
|
|
|
|
// child module
|
|
cm := cfg.Children["child"].Module
|
|
if !cm.ManagedResources["test_instance.explicit"].Provider.Equals(wantBar) {
|
|
t.Fatalf("wrong provider for \"module.child.test_instance.explicit\"\ngot: %s\nwant: %s",
|
|
cfg.Module.ManagedResources["test_instance.explicit"].Provider,
|
|
wantBar,
|
|
)
|
|
}
|
|
if !cm.ManagedResources["test_instance.implicit"].Provider.Equals(wantImplicit) {
|
|
t.Fatalf("wrong provider for \"module.child.test_instance.implicit\"\ngot: %s\nwant: %s",
|
|
cfg.Module.ManagedResources["test_instance.implicit"].Provider,
|
|
wantImplicit,
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestProviderForLocalConfig(t *testing.T) {
|
|
mod, diags := testModuleFromDir("testdata/providers-explicit-fqn")
|
|
if diags.HasErrors() {
|
|
t.Fatal(diags.Error())
|
|
}
|
|
lc := addrs.LocalProviderConfig{LocalName: "foo-test"}
|
|
got := mod.ProviderForLocalConfig(lc)
|
|
want := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "foo", "test")
|
|
if !got.Equals(want) {
|
|
t.Fatalf("wrong result! got %#v, want %#v\n", got, want)
|
|
}
|
|
}
|
|
|
|
// At most one required_providers block per module is permitted.
|
|
func TestModule_required_providers_multiple(t *testing.T) {
|
|
_, diags := testModuleFromDir("testdata/invalid-modules/multiple-required-providers")
|
|
if !diags.HasErrors() {
|
|
t.Fatal("module should have error diags, but does not")
|
|
}
|
|
|
|
want := `Duplicate required providers configuration`
|
|
if got := diags.Error(); !strings.Contains(got, want) {
|
|
t.Fatalf("expected error to contain %q\nerror was:\n%s", want, got)
|
|
}
|
|
}
|
|
|
|
// A module may have required_providers configured in files loaded later than
|
|
// resources. These provider settings should still be reflected in the
|
|
// resources' configuration.
|
|
func TestModule_required_providers_after_resource(t *testing.T) {
|
|
mod, diags := testModuleFromDir("testdata/valid-modules/required-providers-after-resource")
|
|
if diags.HasErrors() {
|
|
t.Fatal(diags.Error())
|
|
}
|
|
|
|
want := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "foo", "test")
|
|
|
|
req, exists := mod.ProviderRequirements.RequiredProviders["test"]
|
|
if !exists {
|
|
t.Fatal("no provider requirements found for \"test\"")
|
|
}
|
|
if req.Type != want {
|
|
t.Errorf("wrong provider addr for \"test\"\ngot: %s\nwant: %s",
|
|
req.Type, want,
|
|
)
|
|
}
|
|
|
|
if got := mod.ManagedResources["test_instance.my-instance"].Provider; !got.Equals(want) {
|
|
t.Errorf("wrong provider addr for \"test_instance.my-instance\"\ngot: %s\nwant: %s",
|
|
got, want,
|
|
)
|
|
}
|
|
}
|
|
|
|
// We support overrides for required_providers blocks, which should replace the
|
|
// entire block for each provider localname, leaving other blocks unaffected.
|
|
// This should also be reflected in any resources in the module using this
|
|
// provider.
|
|
func TestModule_required_provider_overrides(t *testing.T) {
|
|
mod, diags := testModuleFromDir("testdata/valid-modules/required-providers-overrides")
|
|
if diags.HasErrors() {
|
|
t.Fatal(diags.Error())
|
|
}
|
|
|
|
// The foo provider and resource should be unaffected
|
|
want := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "acme", "foo")
|
|
req, exists := mod.ProviderRequirements.RequiredProviders["foo"]
|
|
if !exists {
|
|
t.Fatal("no provider requirements found for \"foo\"")
|
|
}
|
|
if req.Type != want {
|
|
t.Errorf("wrong provider addr for \"foo\"\ngot: %s\nwant: %s",
|
|
req.Type, want,
|
|
)
|
|
}
|
|
if got := mod.ManagedResources["foo_thing.ft"].Provider; !got.Equals(want) {
|
|
t.Errorf("wrong provider addr for \"foo_thing.ft\"\ngot: %s\nwant: %s",
|
|
got, want,
|
|
)
|
|
}
|
|
|
|
// The bar provider and resource should be using the override config
|
|
want = addrs.NewProvider(addrs.DefaultProviderRegistryHost, "blorp", "bar")
|
|
req, exists = mod.ProviderRequirements.RequiredProviders["bar"]
|
|
if !exists {
|
|
t.Fatal("no provider requirements found for \"bar\"")
|
|
}
|
|
if req.Type != want {
|
|
t.Errorf("wrong provider addr for \"bar\"\ngot: %s\nwant: %s",
|
|
req.Type, want,
|
|
)
|
|
}
|
|
if gotVer, wantVer := req.Requirement.Required.String(), "~>2.0.0"; gotVer != wantVer {
|
|
t.Errorf("wrong provider version constraint for \"bar\"\ngot: %s\nwant: %s",
|
|
gotVer, wantVer,
|
|
)
|
|
}
|
|
if got := mod.ManagedResources["bar_thing.bt"].Provider; !got.Equals(want) {
|
|
t.Errorf("wrong provider addr for \"bar_thing.bt\"\ngot: %s\nwant: %s",
|
|
got, want,
|
|
)
|
|
}
|
|
}
|
|
|
|
// Resources without explicit provider configuration are assigned a provider
|
|
// implied based on the resource type. For example, this resource:
|
|
//
|
|
// resource foo_instance "test" { }
|
|
//
|
|
// is assigned a provider with type "foo".
|
|
//
|
|
// To find the correct provider, we first look in the module's provider
|
|
// requirements map for a local name matching the resource type, and fall back
|
|
// to a default provider if none is found. This applies to both managed and
|
|
// data resources.
|
|
func TestModule_implied_provider(t *testing.T) {
|
|
mod, diags := testModuleFromDir("testdata/valid-modules/implied-providers")
|
|
if diags.HasErrors() {
|
|
t.Fatal(diags.Error())
|
|
}
|
|
|
|
// The three providers used in the config resources
|
|
foo := addrs.NewProvider("registry.acme.corp", "acme", "foo")
|
|
whatever := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "acme", "something")
|
|
bar := addrs.NewDefaultProvider("bar")
|
|
|
|
// Verify that the registry.acme.corp/acme/foo provider is defined in the
|
|
// module provider requirements with local name "foo"
|
|
req, exists := mod.ProviderRequirements.RequiredProviders["foo"]
|
|
if !exists {
|
|
t.Fatal("no provider requirements found for \"foo\"")
|
|
}
|
|
if req.Type != foo {
|
|
t.Errorf("wrong provider addr for \"foo\"\ngot: %s\nwant: %s",
|
|
req.Type, foo,
|
|
)
|
|
}
|
|
|
|
// Verify that the acme/something provider is defined in the
|
|
// module provider requirements with local name "whatever"
|
|
req, exists = mod.ProviderRequirements.RequiredProviders["whatever"]
|
|
if !exists {
|
|
t.Fatal("no provider requirements found for \"foo\"")
|
|
}
|
|
if req.Type != whatever {
|
|
t.Errorf("wrong provider addr for \"whatever\"\ngot: %s\nwant: %s",
|
|
req.Type, whatever,
|
|
)
|
|
}
|
|
|
|
// Check that resources are assigned the correct providers: foo_* resources
|
|
// should have the custom foo provider, bar_* resources the default bar
|
|
// provider.
|
|
tests := []struct {
|
|
Address string
|
|
Provider addrs.Provider
|
|
}{
|
|
{"foo_resource.a", foo},
|
|
{"data.foo_resource.b", foo},
|
|
{"bar_resource.c", bar},
|
|
{"data.bar_resource.d", bar},
|
|
{"whatever_resource.e", whatever},
|
|
{"data.whatever_resource.f", whatever},
|
|
}
|
|
for _, test := range tests {
|
|
resources := mod.ManagedResources
|
|
if strings.HasPrefix(test.Address, "data.") {
|
|
resources = mod.DataResources
|
|
}
|
|
resource, exists := resources[test.Address]
|
|
if !exists {
|
|
t.Errorf("could not find resource %q in %#v", test.Address, resources)
|
|
continue
|
|
}
|
|
if got := resource.Provider; !got.Equals(test.Provider) {
|
|
t.Errorf("wrong provider addr for %q\ngot: %s\nwant: %s",
|
|
test.Address, got, test.Provider,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestImpliedProviderForUnqualifiedType(t *testing.T) {
|
|
mod, diags := testModuleFromDir("testdata/valid-modules/implied-providers")
|
|
if diags.HasErrors() {
|
|
t.Fatal(diags.Error())
|
|
}
|
|
|
|
foo := addrs.NewProvider("registry.acme.corp", "acme", "foo")
|
|
whatever := addrs.NewProvider(addrs.DefaultProviderRegistryHost, "acme", "something")
|
|
bar := addrs.NewDefaultProvider("bar")
|
|
tf := addrs.NewBuiltInProvider("terraform")
|
|
|
|
tests := []struct {
|
|
Type string
|
|
Provider addrs.Provider
|
|
}{
|
|
{"foo", foo},
|
|
{"whatever", whatever},
|
|
{"bar", bar},
|
|
{"terraform", tf},
|
|
}
|
|
for _, test := range tests {
|
|
got := mod.ImpliedProviderForUnqualifiedType(test.Type)
|
|
if !got.Equals(test.Provider) {
|
|
t.Errorf("wrong result for %q: got %#v, want %#v\n", test.Type, got, test.Provider)
|
|
}
|
|
}
|
|
}
|