opentofu/terraform/module_dependencies_test.go
Kristin Laemmert b4f21b6044 terraform: fix issue merging provider version constraints
A bug in ConfigTreeDependencies, where a pointer was being updated
instead of the map value, meant that only the first provider config
version constraing to be processes was being stored. This fixes that
bug, so now the returned moduledeps.Providers could have multiple
version constraints.

The responsibility for resolving provider version selection continues to
lie in the command package's ProviderResolver (under plugins.go).
2020-02-06 11:28:48 -05:00

260 lines
6.7 KiB
Go

package terraform
import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/configs"
"github.com/hashicorp/terraform/moduledeps"
"github.com/hashicorp/terraform/plugin/discovery"
)
func TestModuleTreeDependencies(t *testing.T) {
tests := map[string]struct {
ConfigDir string // directory name from testdata dir
State *State
Want *moduledeps.Module
}{
"no config or state": {
"",
nil,
&moduledeps.Module{
Name: "root",
Providers: moduledeps.Providers{},
Children: nil,
},
},
"empty config no state": {
"empty",
nil,
&moduledeps.Module{
Name: "root",
Providers: moduledeps.Providers{},
Children: nil,
},
},
"explicit provider": {
"module-deps-explicit-provider",
nil,
&moduledeps.Module{
Name: "root",
Providers: moduledeps.Providers{
addrs.NewLegacyProvider("foo"): moduledeps.ProviderDependency{
Constraints: discovery.ConstraintStr(">=1.0.0,>=2.0.0").MustParse(),
Reason: moduledeps.ProviderDependencyExplicit,
},
},
Children: nil,
},
},
"required_providers block": {
"module-deps-required-providers",
nil,
&moduledeps.Module{
Name: "root",
Providers: moduledeps.Providers{
addrs.NewLegacyProvider("foo"): moduledeps.ProviderDependency{
Constraints: discovery.ConstraintStr(">=1.0.0").MustParse(),
Reason: moduledeps.ProviderDependencyExplicit,
},
},
Children: nil,
},
},
"explicit provider unconstrained": {
"module-deps-explicit-provider-unconstrained",
nil,
&moduledeps.Module{
Name: "root",
Providers: moduledeps.Providers{
addrs.NewLegacyProvider("foo"): moduledeps.ProviderDependency{
Constraints: discovery.AllVersions,
Reason: moduledeps.ProviderDependencyExplicit,
},
},
Children: nil,
},
},
"implicit provider": {
"module-deps-implicit-provider",
nil,
&moduledeps.Module{
Name: "root",
Providers: moduledeps.Providers{
addrs.NewLegacyProvider("foo"): moduledeps.ProviderDependency{
Constraints: discovery.AllVersions,
Reason: moduledeps.ProviderDependencyImplicit,
},
},
Children: nil,
},
},
"explicit provider with resource": {
"module-deps-explicit-provider-resource",
nil,
&moduledeps.Module{
Name: "root",
Providers: moduledeps.Providers{
addrs.NewLegacyProvider("foo"): moduledeps.ProviderDependency{
Constraints: discovery.ConstraintStr(">=1.0.0").MustParse(),
Reason: moduledeps.ProviderDependencyExplicit,
},
},
Children: nil,
},
},
"inheritance of providers": {
"module-deps-inherit-provider",
nil,
&moduledeps.Module{
Name: "root",
Providers: moduledeps.Providers{
addrs.NewLegacyProvider("foo"): moduledeps.ProviderDependency{
Constraints: discovery.AllVersions,
Reason: moduledeps.ProviderDependencyExplicit,
},
addrs.NewLegacyProvider("bar"): moduledeps.ProviderDependency{
Constraints: discovery.AllVersions,
Reason: moduledeps.ProviderDependencyExplicit,
},
},
Children: []*moduledeps.Module{
{
Name: "child",
Providers: moduledeps.Providers{
addrs.NewLegacyProvider("foo"): moduledeps.ProviderDependency{
Constraints: discovery.AllVersions,
Reason: moduledeps.ProviderDependencyInherited,
},
addrs.NewLegacyProvider("baz"): moduledeps.ProviderDependency{
Constraints: discovery.AllVersions,
Reason: moduledeps.ProviderDependencyImplicit,
},
},
Children: []*moduledeps.Module{
{
Name: "grandchild",
Providers: moduledeps.Providers{
addrs.NewLegacyProvider("bar"): moduledeps.ProviderDependency{
Constraints: discovery.AllVersions,
Reason: moduledeps.ProviderDependencyInherited,
},
addrs.NewLegacyProvider("foo"): moduledeps.ProviderDependency{
Constraints: discovery.AllVersions,
Reason: moduledeps.ProviderDependencyExplicit,
},
},
},
},
},
},
},
},
"provider from state": {
"empty",
&State{
Modules: []*ModuleState{
{
Path: []string{"root"},
Resources: map[string]*ResourceState{
"foo_bar.baz": {
Type: "foo_bar",
Provider: "",
},
},
},
},
},
&moduledeps.Module{
Name: "root",
Providers: moduledeps.Providers{
addrs.NewLegacyProvider("foo"): moduledeps.ProviderDependency{
Constraints: discovery.AllVersions,
Reason: moduledeps.ProviderDependencyFromState,
},
},
Children: nil,
},
},
"providers in both config and state": {
"module-deps-explicit-provider",
&State{
Modules: []*ModuleState{
{
Path: []string{"root"},
Resources: map[string]*ResourceState{
"foo_bar.test1": {
Type: "foo_bar",
Provider: "",
},
"baz_bar.test": {
Type: "baz_bar",
Provider: "",
},
},
},
// note that we've skipped root.child intentionally here,
// to verify that we'll infer it based on the following
// module rather than crashing.
{
Path: []string{"root", "child", "grandchild"},
Resources: map[string]*ResourceState{
"banana_skin.test": {
Type: "banana_skin",
Provider: "",
},
},
},
},
},
&moduledeps.Module{
Name: "root",
Providers: moduledeps.Providers{
addrs.NewLegacyProvider("foo"): moduledeps.ProviderDependency{
Constraints: discovery.ConstraintStr(">=1.0.0,>=2.0.0").MustParse(),
Reason: moduledeps.ProviderDependencyExplicit,
},
addrs.NewLegacyProvider("baz"): moduledeps.ProviderDependency{
Constraints: discovery.AllVersions,
Reason: moduledeps.ProviderDependencyFromState,
},
},
Children: []*moduledeps.Module{
{
Name: "child",
Providers: make(moduledeps.Providers),
Children: []*moduledeps.Module{
{
Name: "grandchild",
Providers: moduledeps.Providers{
addrs.NewLegacyProvider("banana"): moduledeps.ProviderDependency{
Constraints: discovery.AllVersions,
Reason: moduledeps.ProviderDependencyFromState,
},
},
},
},
},
},
},
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
var root *configs.Config
if test.ConfigDir != "" {
root = testModule(t, test.ConfigDir)
}
got := ConfigTreeDependencies(root, MustShimLegacyState(test.State))
if !cmp.Equal(got, test.Want) {
t.Error(cmp.Diff(got, test.Want))
}
})
}
}