mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-24 16:10:46 -06:00
testing framework: add validation for provider blocks in test files (#33542)
* testing framework: add validation for provider blocks in test files * .tftest -> .tftest.hcl
This commit is contained in:
parent
dff447bc9f
commit
222676390c
@ -594,7 +594,7 @@ func (c *Config) addProviderRequirementsFromProviderBlock(reqs getproviders.Requ
|
|||||||
// resolveProviderTypes walks through the providers in the module and ensures
|
// resolveProviderTypes walks through the providers in the module and ensures
|
||||||
// the true types are assigned based on the provider requirements for the
|
// the true types are assigned based on the provider requirements for the
|
||||||
// module.
|
// module.
|
||||||
func (c *Config) resolveProviderTypes() {
|
func (c *Config) resolveProviderTypes() map[string]addrs.Provider {
|
||||||
for _, child := range c.Children {
|
for _, child := range c.Children {
|
||||||
child.resolveProviderTypes()
|
child.resolveProviderTypes()
|
||||||
}
|
}
|
||||||
@ -636,6 +636,147 @@ func (c *Config) resolveProviderTypes() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return providers
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolveProviderTypesForTests matches resolveProviderTypes except it uses
|
||||||
|
// the information from resolveProviderTypes to resolve the provider types for
|
||||||
|
// providers defined within the configs test files.
|
||||||
|
func (c *Config) resolveProviderTypesForTests(providers map[string]addrs.Provider) {
|
||||||
|
|
||||||
|
for _, test := range c.Module.Tests {
|
||||||
|
|
||||||
|
// testProviders contains the configuration blocks for all the providers
|
||||||
|
// defined by this test file. It is keyed by the name of the provider
|
||||||
|
// and the values are a slice of provider configurations which contains
|
||||||
|
// all the definitions of a named provider of which there can be
|
||||||
|
// multiple because of aliases.
|
||||||
|
testProviders := make(map[string][]*Provider)
|
||||||
|
for _, provider := range test.Providers {
|
||||||
|
testProviders[provider.Name] = append(testProviders[provider.Name], provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
// matchedProviders maps the names of providers from testProviders to
|
||||||
|
// the provider type we have identified for them so far. If during the
|
||||||
|
// course of resolving the types we find a run block is attempting to
|
||||||
|
// reuse a provider that has already been assigned a different type,
|
||||||
|
// then this is an error that we can raise now.
|
||||||
|
matchedProviders := make(map[string]addrs.Provider)
|
||||||
|
|
||||||
|
// First, we primarily draw our provider types from the main
|
||||||
|
// configuration under test. The providers for the main configuration
|
||||||
|
// are provided to us in the argument.
|
||||||
|
|
||||||
|
// We've now set provider types for all the providers required by the
|
||||||
|
// main configuration. But we can have modules with their own required
|
||||||
|
// providers referenced by the run blocks. We also have passed provider
|
||||||
|
// configs that can affect the types of providers when the names don't
|
||||||
|
// match, so we'll do that here.
|
||||||
|
|
||||||
|
for _, run := range test.Runs {
|
||||||
|
|
||||||
|
// If this run block is executing against our main configuration, we
|
||||||
|
// want to use the external providers passed in. If we are executing
|
||||||
|
// against a different module then we need to resolve the provider
|
||||||
|
// types for that first, and then use those providers.
|
||||||
|
providers := providers
|
||||||
|
if run.ConfigUnderTest != nil {
|
||||||
|
providers = run.ConfigUnderTest.resolveProviderTypes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// We now check to see what providers this run block is actually
|
||||||
|
// using, and we can then assign types back to the
|
||||||
|
|
||||||
|
if len(run.Providers) > 0 {
|
||||||
|
// This provider is only using the subset of providers specified
|
||||||
|
// within the provider block.
|
||||||
|
|
||||||
|
for _, p := range run.Providers {
|
||||||
|
addr, exists := providers[p.InChild.Name]
|
||||||
|
if !exists {
|
||||||
|
// If this provider wasn't explicitly defined in the
|
||||||
|
// target module, then we'll set it to the default.
|
||||||
|
addr = addrs.NewDefaultProvider(p.InChild.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The child type is always just derived from the providers
|
||||||
|
// within the config this run block is using.
|
||||||
|
p.InChild.providerType = addr
|
||||||
|
|
||||||
|
// If we have previously assigned a type to the provider
|
||||||
|
// for the parent reference, then we use that for the
|
||||||
|
// parent type.
|
||||||
|
if addr, exists := matchedProviders[p.InParent.Name]; exists {
|
||||||
|
p.InParent.providerType = addr
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, we'll define the parent type based on the
|
||||||
|
// child and reference that backwards.
|
||||||
|
p.InParent.providerType = p.InChild.providerType
|
||||||
|
|
||||||
|
if aliases, exists := testProviders[p.InParent.Name]; exists {
|
||||||
|
matchedProviders[p.InParent.Name] = p.InParent.providerType
|
||||||
|
for _, alias := range aliases {
|
||||||
|
alias.providerType = p.InParent.providerType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// This provider is going to load all the providers it can using
|
||||||
|
// simple name matching.
|
||||||
|
|
||||||
|
for name, addr := range providers {
|
||||||
|
|
||||||
|
if _, exists := matchedProviders[name]; exists {
|
||||||
|
// Then we've already handled providers of this type
|
||||||
|
// previously.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if aliases, exists := testProviders[name]; exists {
|
||||||
|
// Then this provider has been defined within our test
|
||||||
|
// config. Let's give it the appropriate type.
|
||||||
|
matchedProviders[name] = addr
|
||||||
|
for _, alias := range aliases {
|
||||||
|
alias.providerType = addr
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we get here then it means we don't actually have a
|
||||||
|
// provider block for this provider name within our test
|
||||||
|
// file. This is fine, it just means we don't have to do
|
||||||
|
// anything and the test will use the default provider for
|
||||||
|
// that name.
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, we've analysed all the test runs for this file. If any providers
|
||||||
|
// have not been claimed then we'll just give them the default provider
|
||||||
|
// for their name.
|
||||||
|
for name, aliases := range testProviders {
|
||||||
|
if _, exists := matchedProviders[name]; exists {
|
||||||
|
// Then this provider has a type already.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
addr := addrs.NewDefaultProvider(name)
|
||||||
|
matchedProviders[name] = addr
|
||||||
|
|
||||||
|
for _, alias := range aliases {
|
||||||
|
alias.providerType = addr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProviderTypes returns the FQNs of each distinct provider type referenced
|
// ProviderTypes returns the FQNs of each distinct provider type referenced
|
||||||
|
@ -36,10 +36,12 @@ func BuildConfig(root *Module, walker ModuleWalker) (*Config, hcl.Diagnostics) {
|
|||||||
if !diags.HasErrors() {
|
if !diags.HasErrors() {
|
||||||
// Now that the config is built, we can connect the provider names to all
|
// Now that the config is built, we can connect the provider names to all
|
||||||
// the known types for validation.
|
// the known types for validation.
|
||||||
cfg.resolveProviderTypes()
|
providers := cfg.resolveProviderTypes()
|
||||||
|
cfg.resolveProviderTypesForTests(providers)
|
||||||
}
|
}
|
||||||
|
|
||||||
diags = append(diags, validateProviderConfigs(nil, cfg, nil)...)
|
diags = append(diags, validateProviderConfigs(nil, cfg, nil)...)
|
||||||
|
diags = append(diags, validateProviderConfigsForTests(cfg)...)
|
||||||
|
|
||||||
return cfg, diags
|
return cfg, diags
|
||||||
}
|
}
|
||||||
|
@ -172,7 +172,7 @@ func TestBuildConfigInvalidModules(t *testing.T) {
|
|||||||
parser := NewParser(nil)
|
parser := NewParser(nil)
|
||||||
path := filepath.Join(testDir, name)
|
path := filepath.Join(testDir, name)
|
||||||
|
|
||||||
mod, diags := parser.LoadConfigDir(path)
|
mod, diags := parser.LoadConfigDirWithTests(path, "tests")
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
// these tests should only trigger errors that are caught in
|
// these tests should only trigger errors that are caught in
|
||||||
// the config loader.
|
// the config loader.
|
||||||
|
@ -9,9 +9,268 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/hcl/v2"
|
"github.com/hashicorp/hcl/v2"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/internal/addrs"
|
"github.com/hashicorp/terraform/internal/addrs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// validateProviderConfigsForTests performs the same role as
|
||||||
|
// validateProviderConfigs except it validates the providers configured within
|
||||||
|
// test files.
|
||||||
|
//
|
||||||
|
// To do this is calls out to validateProviderConfigs for each run block that
|
||||||
|
// has ConfigUnderTest set.
|
||||||
|
//
|
||||||
|
// In addition, for each run block that executes against the main config it
|
||||||
|
// validates the providers the run block wants to use match the providers
|
||||||
|
// specified in the main configuration. It does this without reaching out to
|
||||||
|
// validateProviderConfigs because the main configuration has already been
|
||||||
|
// validated, and we don't want to redo all the work that happens in that
|
||||||
|
// function. So, we only validate the providers our test files define match
|
||||||
|
// the providers required by the main configuration.
|
||||||
|
//
|
||||||
|
// This function does some fairly controversial conversions into structures
|
||||||
|
// expected by validateProviderConfigs but since we're just using it for
|
||||||
|
// validation we'll still get the correct error messages, and we can make the
|
||||||
|
// declaration ranges line up sensibly so we'll even get good diagnostics.
|
||||||
|
func validateProviderConfigsForTests(cfg *Config) (diags hcl.Diagnostics) {
|
||||||
|
|
||||||
|
for name, test := range cfg.Module.Tests {
|
||||||
|
for _, run := range test.Runs {
|
||||||
|
|
||||||
|
if run.ConfigUnderTest == nil {
|
||||||
|
// Then we're calling out to the main configuration under test.
|
||||||
|
//
|
||||||
|
// We just need to make sure that the providers we are setting
|
||||||
|
// actually match the providers in the configuration. The main
|
||||||
|
// configuration has already been validated, so we don't need to
|
||||||
|
// do the whole thing again.
|
||||||
|
|
||||||
|
if len(run.Providers) > 0 {
|
||||||
|
// This is the easy case, we can just validate that the
|
||||||
|
// provider types match.
|
||||||
|
for _, provider := range run.Providers {
|
||||||
|
|
||||||
|
parentType, childType := provider.InParent.providerType, provider.InChild.providerType
|
||||||
|
if parentType.IsZero() {
|
||||||
|
parentType = addrs.NewDefaultProvider(provider.InParent.Name)
|
||||||
|
}
|
||||||
|
if childType.IsZero() {
|
||||||
|
childType = addrs.NewDefaultProvider(provider.InChild.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !childType.Equals(parentType) {
|
||||||
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
|
Severity: hcl.DiagError,
|
||||||
|
Summary: "Provider type mismatch",
|
||||||
|
Detail: fmt.Sprintf(
|
||||||
|
"The local name %q in %s represents provider %q, but %q in the root module represents %q.\n\nThis means the provider definition for %q within %s, or other provider definitions with the same name, have been referenced by multiple run blocks and assigned to different provider types.",
|
||||||
|
provider.InParent.Name, name, parentType, provider.InChild.Name, childType, provider.InParent.Name, name),
|
||||||
|
Subject: provider.InParent.NameRange.Ptr(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip to the next file, we only need to verify the types
|
||||||
|
// specified here.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, we need to verify that the providers required by
|
||||||
|
// the configuration match the types defined by our test file.
|
||||||
|
|
||||||
|
for _, requirement := range cfg.Module.ProviderRequirements.RequiredProviders {
|
||||||
|
if provider, exists := test.Providers[requirement.Name]; exists {
|
||||||
|
|
||||||
|
providerType := provider.providerType
|
||||||
|
if providerType.IsZero() {
|
||||||
|
providerType = addrs.NewDefaultProvider(provider.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !providerType.Equals(requirement.Type) {
|
||||||
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
|
Severity: hcl.DiagError,
|
||||||
|
Summary: "Provider type mismatch",
|
||||||
|
Detail: fmt.Sprintf(
|
||||||
|
"The provider %q in %s represents provider %q, but %q in the root module represents %q.\n\nThis means the provider definition for %q within %s, or other provider definitions with the same name, have been referenced by multiple run blocks and assigned to different provider types.",
|
||||||
|
provider.moduleUniqueKey(), name, providerType, requirement.Name, requirement.Type, provider.moduleUniqueKey(), name),
|
||||||
|
Subject: provider.DeclRange.Ptr(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, alias := range requirement.Aliases {
|
||||||
|
if provider, exists := test.Providers[alias.StringCompact()]; exists {
|
||||||
|
|
||||||
|
providerType := provider.providerType
|
||||||
|
if providerType.IsZero() {
|
||||||
|
providerType = addrs.NewDefaultProvider(provider.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !providerType.Equals(requirement.Type) {
|
||||||
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
|
Severity: hcl.DiagError,
|
||||||
|
Summary: "Provider type mismatch",
|
||||||
|
Detail: fmt.Sprintf(
|
||||||
|
"The provider %q in %s represents provider %q, but %q in the root module represents %q.\n\nThis means the provider definition for %q within %s, or other provider definitions with the same name, have been referenced by multiple run blocks and assigned to different provider types.",
|
||||||
|
provider.moduleUniqueKey(), name, providerType, alias.StringCompact(), requirement.Type, provider.moduleUniqueKey(), name),
|
||||||
|
Subject: provider.DeclRange.Ptr(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, provider := range cfg.Module.ProviderConfigs {
|
||||||
|
|
||||||
|
providerType := provider.providerType
|
||||||
|
if providerType.IsZero() {
|
||||||
|
providerType = addrs.NewDefaultProvider(provider.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if testProvider, exists := test.Providers[provider.moduleUniqueKey()]; exists {
|
||||||
|
|
||||||
|
testProviderType := testProvider.providerType
|
||||||
|
if testProviderType.IsZero() {
|
||||||
|
testProviderType = addrs.NewDefaultProvider(testProvider.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !providerType.Equals(testProviderType) {
|
||||||
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
|
Severity: hcl.DiagError,
|
||||||
|
Summary: "Provider type mismatch",
|
||||||
|
Detail: fmt.Sprintf(
|
||||||
|
"The provider %q in %s represents provider %q, but %q in the root module represents %q.\n\nThis means the provider definition for %q within %s has been referenced by multiple run blocks and assigned to different provider types.",
|
||||||
|
testProvider.moduleUniqueKey(), name, testProviderType, provider.moduleUniqueKey(), providerType, testProvider.moduleUniqueKey(), name),
|
||||||
|
Subject: testProvider.DeclRange.Ptr(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Then we're executing another module. We'll just call out to
|
||||||
|
// validateProviderConfigs and let it do the whole thing.
|
||||||
|
|
||||||
|
providers := run.Providers
|
||||||
|
if len(providers) == 0 {
|
||||||
|
// If the test run didn't provide us a subset of providers
|
||||||
|
// to use, we'll build our own. This is so that we can fit
|
||||||
|
// into the schema expected by validateProviderConfigs.
|
||||||
|
|
||||||
|
matchedProviders := make(map[string]PassedProviderConfig)
|
||||||
|
|
||||||
|
// We'll go over all the requirements in the module first
|
||||||
|
// and see if we have defined any providers for that
|
||||||
|
// requirement. If we have, then we'll take not of that.
|
||||||
|
|
||||||
|
for _, requirement := range cfg.Module.ProviderRequirements.RequiredProviders {
|
||||||
|
|
||||||
|
if provider, exists := test.Providers[requirement.Name]; exists {
|
||||||
|
matchedProviders[requirement.Name] = PassedProviderConfig{
|
||||||
|
InChild: &ProviderConfigRef{
|
||||||
|
Name: requirement.Name,
|
||||||
|
NameRange: requirement.DeclRange,
|
||||||
|
providerType: requirement.Type,
|
||||||
|
},
|
||||||
|
InParent: &ProviderConfigRef{
|
||||||
|
Name: provider.Name,
|
||||||
|
NameRange: provider.NameRange,
|
||||||
|
Alias: provider.Alias,
|
||||||
|
AliasRange: provider.AliasRange,
|
||||||
|
providerType: provider.providerType,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also, remember to check for any aliases the module
|
||||||
|
// expects.
|
||||||
|
|
||||||
|
for _, alias := range requirement.Aliases {
|
||||||
|
key := alias.StringCompact()
|
||||||
|
|
||||||
|
if provider, exists := test.Providers[key]; exists {
|
||||||
|
matchedProviders[key] = PassedProviderConfig{
|
||||||
|
InChild: &ProviderConfigRef{
|
||||||
|
Name: requirement.Name,
|
||||||
|
NameRange: requirement.DeclRange,
|
||||||
|
Alias: alias.Alias,
|
||||||
|
AliasRange: requirement.DeclRange.Ptr(),
|
||||||
|
providerType: requirement.Type,
|
||||||
|
},
|
||||||
|
InParent: &ProviderConfigRef{
|
||||||
|
Name: provider.Name,
|
||||||
|
NameRange: provider.NameRange,
|
||||||
|
Alias: provider.Alias,
|
||||||
|
AliasRange: provider.AliasRange,
|
||||||
|
providerType: provider.providerType,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, we'll look at any providers the module has defined
|
||||||
|
// directly. If we have an equivalent provider in the test
|
||||||
|
// file then we'll add that in to override it. If the module
|
||||||
|
// has both built a required providers block and a provider
|
||||||
|
// block for the same provider, we'll overwrite the one we
|
||||||
|
// made for the requirement provider. We get more precise
|
||||||
|
// DeclRange objects from provider blocks so it makes for
|
||||||
|
// better error messages to use these.
|
||||||
|
|
||||||
|
for _, provider := range cfg.Module.ProviderConfigs {
|
||||||
|
key := provider.moduleUniqueKey()
|
||||||
|
|
||||||
|
if testProvider, exists := test.Providers[key]; exists {
|
||||||
|
matchedProviders[key] = PassedProviderConfig{
|
||||||
|
InChild: &ProviderConfigRef{
|
||||||
|
Name: provider.Name,
|
||||||
|
NameRange: provider.DeclRange,
|
||||||
|
Alias: provider.Alias,
|
||||||
|
AliasRange: provider.DeclRange.Ptr(),
|
||||||
|
providerType: provider.providerType,
|
||||||
|
},
|
||||||
|
InParent: &ProviderConfigRef{
|
||||||
|
Name: testProvider.Name,
|
||||||
|
NameRange: testProvider.NameRange,
|
||||||
|
Alias: testProvider.Alias,
|
||||||
|
AliasRange: testProvider.AliasRange,
|
||||||
|
providerType: testProvider.providerType,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last thing to do here is add them into the actual
|
||||||
|
// providers list that is going into the module call below.
|
||||||
|
for _, provider := range matchedProviders {
|
||||||
|
providers = append(providers, provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let's make a little fake module call that we can use to call
|
||||||
|
// into validateProviderConfigs.
|
||||||
|
mc := &ModuleCall{
|
||||||
|
Name: run.Name,
|
||||||
|
SourceAddr: run.Module.Source,
|
||||||
|
SourceAddrRange: run.Module.SourceDeclRange,
|
||||||
|
SourceSet: true,
|
||||||
|
Version: run.Module.Version,
|
||||||
|
Providers: providers,
|
||||||
|
DeclRange: run.Module.DeclRange,
|
||||||
|
}
|
||||||
|
|
||||||
|
diags = append(diags, validateProviderConfigs(mc, run.ConfigUnderTest, nil)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return diags
|
||||||
|
}
|
||||||
|
|
||||||
// validateProviderConfigs walks the full configuration tree from the root
|
// validateProviderConfigs walks the full configuration tree from the root
|
||||||
// module outward, static validation rules to the various combinations of
|
// module outward, static validation rules to the various combinations of
|
||||||
// provider configuration, required_providers values, and module call providers
|
// provider configuration, required_providers values, and module call providers
|
||||||
|
3
internal/configs/testdata/config-diagnostics/tests-provider-mismatch-with-module/errors
vendored
Normal file
3
internal/configs/testdata/config-diagnostics/tests-provider-mismatch-with-module/errors
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
testdata/config-diagnostics/tests-provider-mismatch-with-module/main.tftest.hcl:2,1-15: Provider type mismatch; The provider "foo" in main.tftest.hcl represents provider "registry.terraform.io/hashicorp/bar", but "foo" in the root module represents "registry.terraform.io/hashicorp/foo".\n\nThis means the provider definition for "foo" within main.tftest.hcl, or other provider definitions with the same name, have been referenced by multiple run blocks and assigned to different provider types.
|
||||||
|
testdata/config-diagnostics/tests-provider-mismatch-with-module/main.tftest.hcl:4,1-15: Provider type mismatch; The provider "foo.bar" in main.tftest.hcl represents provider "registry.terraform.io/hashicorp/bar", but "foo.bar" in the root module represents "registry.terraform.io/hashicorp/foo".\n\nThis means the provider definition for "foo.bar" within main.tftest.hcl, or other provider definitions with the same name, have been referenced by multiple run blocks and assigned to different provider types.
|
||||||
|
testdata/config-diagnostics/tests-provider-mismatch-with-module/main.tftest.hcl:8,1-15: Provider type mismatch; The provider "bar" in main.tftest.hcl represents provider "registry.terraform.io/hashicorp/foo", but "bar" in the root module represents "registry.terraform.io/hashicorp/bar".\n\nThis means the provider definition for "bar" within main.tftest.hcl has been referenced by multiple run blocks and assigned to different provider types.
|
14
internal/configs/testdata/config-diagnostics/tests-provider-mismatch-with-module/main.tf
vendored
Normal file
14
internal/configs/testdata/config-diagnostics/tests-provider-mismatch-with-module/main.tf
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
foo = {
|
||||||
|
source = "hashicorp/foo"
|
||||||
|
configuration_aliases = [foo.bar]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "bar" {}
|
||||||
|
|
||||||
|
resource "foo_resource" "resource" {}
|
||||||
|
|
||||||
|
resource "bar_resource" "resource" {}
|
18
internal/configs/testdata/config-diagnostics/tests-provider-mismatch-with-module/main.tftest.hcl
vendored
Normal file
18
internal/configs/testdata/config-diagnostics/tests-provider-mismatch-with-module/main.tftest.hcl
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
provider "foo" {}
|
||||||
|
|
||||||
|
provider "foo" {
|
||||||
|
alias = "bar"
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "bar" {}
|
||||||
|
|
||||||
|
run "setup_module" {
|
||||||
|
|
||||||
|
module {
|
||||||
|
source = "./setup"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
run "main_module" {}
|
15
internal/configs/testdata/config-diagnostics/tests-provider-mismatch-with-module/setup/main.tf
vendored
Normal file
15
internal/configs/testdata/config-diagnostics/tests-provider-mismatch-with-module/setup/main.tf
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
foo = {
|
||||||
|
source = "hashicorp/bar"
|
||||||
|
configuration_aliases = [ foo.bar ]
|
||||||
|
}
|
||||||
|
bar = {
|
||||||
|
source = "hashicorp/foo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "foo_resource" "resource" {}
|
||||||
|
|
||||||
|
resource "bar_resource" "resource" {}
|
1
internal/configs/testdata/config-diagnostics/tests-provider-mismatch/errors
vendored
Normal file
1
internal/configs/testdata/config-diagnostics/tests-provider-mismatch/errors
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
testdata/config-diagnostics/tests-provider-mismatch/main.tftest.hcl:27,11-14: Provider type mismatch; The local name "bar" in main.tftest.hcl represents provider "registry.terraform.io/hashicorp/bar", but "foo" in the root module represents "registry.terraform.io/hashicorp/foo".\n\nThis means the provider definition for "bar" within main.tftest.hcl, or other provider definitions with the same name, have been referenced by multiple run blocks and assigned to different provider types.
|
14
internal/configs/testdata/config-diagnostics/tests-provider-mismatch/main.tf
vendored
Normal file
14
internal/configs/testdata/config-diagnostics/tests-provider-mismatch/main.tf
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
foo = {
|
||||||
|
source = "hashicorp/foo"
|
||||||
|
configuration_aliases = [foo.bar]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "bar" {}
|
||||||
|
|
||||||
|
resource "foo_resource" "resource" {}
|
||||||
|
|
||||||
|
resource "bar_resource" "resource" {}
|
32
internal/configs/testdata/config-diagnostics/tests-provider-mismatch/main.tftest.hcl
vendored
Normal file
32
internal/configs/testdata/config-diagnostics/tests-provider-mismatch/main.tftest.hcl
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
provider "foo" {}
|
||||||
|
|
||||||
|
provider "foo" {
|
||||||
|
alias = "bar"
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "bar" {
|
||||||
|
alias = "foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
run "default_should_be_fine" {}
|
||||||
|
|
||||||
|
run "bit_complicated_still_okay "{
|
||||||
|
|
||||||
|
providers = {
|
||||||
|
foo = foo
|
||||||
|
foo.bar = foo.bar
|
||||||
|
bar = bar.foo
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
run "mismatched_foo_direct" {
|
||||||
|
|
||||||
|
providers = {
|
||||||
|
foo = bar // bad!
|
||||||
|
foo.bar = foo.bar
|
||||||
|
bar = bar.foo
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user