terraform: provider source test (#24342)
* configs: parse provider source string during module merge This was the smallest unit of work needed to start writing provider source tests! * Update configs/parser_test.go Co-Authored-By: Alisdair McDiarmid <alisdair@users.noreply.github.com>
This commit is contained in:
parent
33464568e8
commit
1c78b26012
|
@ -126,6 +126,11 @@ func (pt Provider) LessThan(other Provider) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Equals returns true if the receiver and other provider have the same attributes.
|
||||||
|
func (pt Provider) Equals(other Provider) bool {
|
||||||
|
return pt == other
|
||||||
|
}
|
||||||
|
|
||||||
// ParseProviderSourceString parses the source attribute and returns a provider.
|
// ParseProviderSourceString parses the source attribute and returns a provider.
|
||||||
// This is intended primarily to parse the FQN-like strings returned by
|
// This is intended primarily to parse the FQN-like strings returned by
|
||||||
// terraform-config-inspect.
|
// terraform-config-inspect.
|
||||||
|
|
|
@ -101,6 +101,10 @@ func TestParseProviderSourceStr(t *testing.T) {
|
||||||
Provider{},
|
Provider{},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
|
"/ / /": { // empty strings
|
||||||
|
Provider{},
|
||||||
|
true,
|
||||||
|
},
|
||||||
"badhost!/hashicorp/aws": {
|
"badhost!/hashicorp/aws": {
|
||||||
Provider{},
|
Provider{},
|
||||||
true,
|
true,
|
||||||
|
@ -241,5 +245,41 @@ func TestParseProviderPart(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProviderEquals(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
InputP Provider
|
||||||
|
OtherP Provider
|
||||||
|
Want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
NewProvider(DefaultRegistryHost, "foo", "test"),
|
||||||
|
NewProvider(DefaultRegistryHost, "foo", "test"),
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NewProvider(DefaultRegistryHost, "foo", "test"),
|
||||||
|
NewProvider(DefaultRegistryHost, "bar", "test"),
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NewProvider(DefaultRegistryHost, "foo", "test"),
|
||||||
|
NewProvider(DefaultRegistryHost, "foo", "my-test"),
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NewProvider(DefaultRegistryHost, "foo", "test"),
|
||||||
|
NewProvider("example.com", "foo", "test"),
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.InputP.String(), func(t *testing.T) {
|
||||||
|
got := test.InputP.Equals(test.OtherP)
|
||||||
|
if got != test.Want {
|
||||||
|
t.Errorf("wrong result\ngot: %v\nwant: %v", got, test.Want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConfigProviderTypes(t *testing.T) {
|
func TestConfigProviderTypes(t *testing.T) {
|
||||||
mod, diags := testModuleFromFile("testdata/valid-files/providers-explicit-implied.tf")
|
cfg, diags := testModuleConfigFromFile("testdata/valid-files/providers-explicit-implied.tf")
|
||||||
if diags.HasErrors() {
|
|
||||||
t.Fatal(diags.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg, diags := BuildConfig(mod, nil)
|
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
t.Fatal(diags.Error())
|
t.Fatal(diags.Error())
|
||||||
}
|
}
|
||||||
|
@ -30,13 +25,33 @@ func TestConfigProviderTypes(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigResolveAbsProviderAddr(t *testing.T) {
|
func TestConfigProviderTypes_nested(t *testing.T) {
|
||||||
mod, diags := testModuleFromDir("testdata/providers-explicit-fqn")
|
// basic test with a nil config
|
||||||
|
c := NewEmptyConfig()
|
||||||
|
got := c.ProviderTypes()
|
||||||
|
if len(got) != 0 {
|
||||||
|
t.Fatalf("wrong result!\ngot: %#v\nwant: nil\n", got)
|
||||||
|
}
|
||||||
|
|
||||||
|
// config with two provider sources
|
||||||
|
cfg, diags := testNestedModuleConfigFromDir(t, "testdata/valid-modules/nested-providers-fqns")
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
t.Fatal(diags.Error())
|
t.Fatal(diags.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, diags := BuildConfig(mod, nil)
|
got = cfg.ProviderTypes()
|
||||||
|
want := []addrs.Provider{
|
||||||
|
addrs.NewProvider(addrs.DefaultRegistryHost, "bar", "test"),
|
||||||
|
addrs.NewProvider(addrs.DefaultRegistryHost, "foo", "test"),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, problem := range deep.Equal(got, want) {
|
||||||
|
t.Error(problem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigResolveAbsProviderAddr(t *testing.T) {
|
||||||
|
cfg, diags := testModuleConfigFromDir("testdata/providers-explicit-fqn")
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
t.Fatal(diags.Error())
|
t.Fatal(diags.Error())
|
||||||
}
|
}
|
||||||
|
@ -89,3 +104,21 @@ func TestConfigResolveAbsProviderAddr(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProviderForConfigAddr(t *testing.T) {
|
||||||
|
cfg, diags := testModuleConfigFromDir("testdata/valid-modules/providers-fqns")
|
||||||
|
assertNoDiagnostics(t, diags)
|
||||||
|
|
||||||
|
got := cfg.ProviderForConfigAddr(addrs.NewDefaultLocalProviderConfig("foo-test"))
|
||||||
|
want := addrs.NewProvider(addrs.DefaultRegistryHost, "foo", "test")
|
||||||
|
if !got.Equals(want) {
|
||||||
|
t.Errorf("wrong result\ngot: %s\nwant: %s", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
// now check a provider that isn't in the configuration. It should return a NewLegacyProvider.
|
||||||
|
got = cfg.ProviderForConfigAddr(addrs.NewDefaultLocalProviderConfig("bar-test"))
|
||||||
|
want = addrs.NewLegacyProvider("bar-test")
|
||||||
|
if !got.Equals(want) {
|
||||||
|
t.Errorf("wrong result\ngot: %s\nwant: %s", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/addrs"
|
"github.com/hashicorp/terraform/addrs"
|
||||||
"github.com/hashicorp/terraform/experiments"
|
"github.com/hashicorp/terraform/experiments"
|
||||||
|
"github.com/hashicorp/terraform/tfdiags"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Module is a container for a set of configuration constructs that are
|
// Module is a container for a set of configuration constructs that are
|
||||||
|
@ -179,9 +180,21 @@ func (m *Module) appendFile(file *File) hcl.Diagnostics {
|
||||||
|
|
||||||
for _, reqd := range file.RequiredProviders {
|
for _, reqd := range file.RequiredProviders {
|
||||||
var fqn addrs.Provider
|
var fqn addrs.Provider
|
||||||
if reqd.Source != "" {
|
if reqd.Source.SourceStr != "" {
|
||||||
// FIXME: capture errors
|
var sourceDiags tfdiags.Diagnostics
|
||||||
fqn, _ = addrs.ParseProviderSourceString(reqd.Source)
|
fqn, sourceDiags = addrs.ParseProviderSourceString(reqd.Source.SourceStr)
|
||||||
|
if sourceDiags.HasErrors() {
|
||||||
|
for i := range sourceDiags {
|
||||||
|
if sourceDiags[i].Severity() == tfdiags.Error {
|
||||||
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
|
Severity: hcl.DiagError,
|
||||||
|
Summary: "Invalid provider source string",
|
||||||
|
Detail: sourceDiags[i].Description().Detail,
|
||||||
|
Subject: &reqd.Source.DeclRange,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fqn = addrs.NewLegacyProvider(reqd.Name)
|
fqn = addrs.NewLegacyProvider(reqd.Name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,13 @@ func mergeProviderVersionConstraints(recv map[string]ProviderRequirements, ovrd
|
||||||
delete(recv, reqd.Name)
|
delete(recv, reqd.Name)
|
||||||
}
|
}
|
||||||
for _, reqd := range ovrd {
|
for _, reqd := range ovrd {
|
||||||
fqn := addrs.NewLegacyProvider(reqd.Name)
|
var fqn addrs.Provider
|
||||||
|
if reqd.Source.SourceStr != "" {
|
||||||
|
// any errors parsing the source string will have already been captured.
|
||||||
|
fqn, _ = addrs.ParseProviderSourceString(reqd.Source.SourceStr)
|
||||||
|
} else {
|
||||||
|
fqn = addrs.NewLegacyProvider(reqd.Name)
|
||||||
|
}
|
||||||
recv[reqd.Name] = ProviderRequirements{Type: fqn, VersionConstraints: []VersionConstraint{reqd.Requirement}}
|
recv[reqd.Name] = ProviderRequirements{Type: fqn, VersionConstraints: []VersionConstraint{reqd.Requirement}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,3 +28,17 @@ func TestNewModule_provider_local_name(t *testing.T) {
|
||||||
t.Fatal("provider local name not found")
|
t.Fatal("provider local name not found")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.DefaultRegistryHost, "foo", "test")
|
||||||
|
if !got.Equals(want) {
|
||||||
|
t.Fatalf("wrong result! got %#v, want %#v\n", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
package configs
|
package configs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
|
||||||
|
version "github.com/hashicorp/go-version"
|
||||||
"github.com/hashicorp/hcl/v2"
|
"github.com/hashicorp/hcl/v2"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
|
@ -45,6 +48,17 @@ func testModuleFromFile(filename string) (*Module, hcl.Diagnostics) {
|
||||||
return mod, modDiags
|
return mod, modDiags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// testModuleConfigFrom File reads a single file from the given path as a
|
||||||
|
// module and returns its configuration. This is a helper for use in unit tests.
|
||||||
|
func testModuleConfigFromFile(filename string) (*Config, hcl.Diagnostics) {
|
||||||
|
parser := NewParser(nil)
|
||||||
|
f, diags := parser.LoadConfigFile(filename)
|
||||||
|
mod, modDiags := NewModule([]*File{f}, nil)
|
||||||
|
diags = append(diags, modDiags...)
|
||||||
|
cfg, moreDiags := BuildConfig(mod, nil)
|
||||||
|
return cfg, append(diags, moreDiags...)
|
||||||
|
}
|
||||||
|
|
||||||
// testModuleFromDir reads configuration from the given directory path as
|
// testModuleFromDir reads configuration from the given directory path as
|
||||||
// a module and returns it. This is a helper for use in unit tests.
|
// a module and returns it. This is a helper for use in unit tests.
|
||||||
func testModuleFromDir(path string) (*Module, hcl.Diagnostics) {
|
func testModuleFromDir(path string) (*Module, hcl.Diagnostics) {
|
||||||
|
@ -52,6 +66,46 @@ func testModuleFromDir(path string) (*Module, hcl.Diagnostics) {
|
||||||
return parser.LoadConfigDir(path)
|
return parser.LoadConfigDir(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// testModuleFromDir reads configuration from the given directory path as a
|
||||||
|
// module and returns its configuration. This is a helper for use in unit tests.
|
||||||
|
func testModuleConfigFromDir(path string) (*Config, hcl.Diagnostics) {
|
||||||
|
parser := NewParser(nil)
|
||||||
|
mod, diags := parser.LoadConfigDir(path)
|
||||||
|
cfg, moreDiags := BuildConfig(mod, nil)
|
||||||
|
return cfg, append(diags, moreDiags...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// testNestedModuleConfigFromDir reads configuration from the given directory path as
|
||||||
|
// a module with (optional) submodules and returns its configuration. This is a
|
||||||
|
// helper for use in unit tests.
|
||||||
|
func testNestedModuleConfigFromDir(t *testing.T, path string) (*Config, hcl.Diagnostics) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
parser := NewParser(nil)
|
||||||
|
mod, diags := parser.LoadConfigDir(path)
|
||||||
|
assertNoDiagnostics(t, diags)
|
||||||
|
if mod == nil {
|
||||||
|
t.Fatal("got nil root module; want non-nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
versionI := 0
|
||||||
|
cfg, diags := BuildConfig(mod, ModuleWalkerFunc(
|
||||||
|
func(req *ModuleRequest) (*Module, *version.Version, hcl.Diagnostics) {
|
||||||
|
// For the sake of this test we're going to just treat our
|
||||||
|
// SourceAddr as a path relative to our fixture directory.
|
||||||
|
// A "real" implementation of ModuleWalker should accept the
|
||||||
|
// various different source address syntaxes Terraform supports.
|
||||||
|
sourcePath := filepath.Join(path, req.SourceAddr)
|
||||||
|
|
||||||
|
mod, diags := parser.LoadConfigDir(sourcePath)
|
||||||
|
version, _ := version.NewVersion(fmt.Sprintf("1.0.%d", versionI))
|
||||||
|
versionI++
|
||||||
|
return mod, version, diags
|
||||||
|
},
|
||||||
|
))
|
||||||
|
return cfg, diags
|
||||||
|
}
|
||||||
|
|
||||||
func assertNoDiagnostics(t *testing.T, diags hcl.Diagnostics) bool {
|
func assertNoDiagnostics(t *testing.T, diags hcl.Diagnostics) bool {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
return assertDiagnosticCount(t, diags, 0)
|
return assertDiagnosticCount(t, diags, 0)
|
||||||
|
@ -59,7 +113,7 @@ func assertNoDiagnostics(t *testing.T, diags hcl.Diagnostics) bool {
|
||||||
|
|
||||||
func assertDiagnosticCount(t *testing.T, diags hcl.Diagnostics, want int) bool {
|
func assertDiagnosticCount(t *testing.T, diags hcl.Diagnostics, want int) bool {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
if len(diags) != 0 {
|
if len(diags) != want {
|
||||||
t.Errorf("wrong number of diagnostics %d; want %d", len(diags), want)
|
t.Errorf("wrong number of diagnostics %d; want %d", len(diags), want)
|
||||||
for _, diag := range diags {
|
for _, diag := range diags {
|
||||||
t.Logf("- %s", diag)
|
t.Logf("- %s", diag)
|
||||||
|
|
|
@ -7,14 +7,20 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// RequiredProvider represents a declaration of a dependency on a particular
|
// RequiredProvider represents a declaration of a dependency on a particular
|
||||||
// provider version without actually configuring that provider. This is used in
|
// provider version or source without actually configuring that provider. This
|
||||||
// child modules that expect a provider to be passed in from their parent.
|
// is used in child modules that expect a provider to be passed in from their
|
||||||
|
// parent.
|
||||||
type RequiredProvider struct {
|
type RequiredProvider struct {
|
||||||
Name string
|
Name string
|
||||||
Source string // TODO
|
Source Source
|
||||||
Requirement VersionConstraint
|
Requirement VersionConstraint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Source struct {
|
||||||
|
SourceStr string
|
||||||
|
DeclRange hcl.Range
|
||||||
|
}
|
||||||
|
|
||||||
// ProviderRequirements represents merged provider version constraints.
|
// ProviderRequirements represents merged provider version constraints.
|
||||||
// VersionConstraints come from terraform.require_providers blocks and provider
|
// VersionConstraints come from terraform.require_providers blocks and provider
|
||||||
// blocks.
|
// blocks.
|
||||||
|
@ -63,7 +69,8 @@ func decodeRequiredProvidersBlock(block *hcl.Block) ([]*RequiredProvider, hcl.Di
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if expr.Type().HasAttribute("source") {
|
if expr.Type().HasAttribute("source") {
|
||||||
ret.Source = expr.GetAttr("source").AsString()
|
ret.Source.SourceStr = expr.GetAttr("source").AsString()
|
||||||
|
ret.Source.DeclRange = attr.Range
|
||||||
}
|
}
|
||||||
reqs = append(reqs, ret)
|
reqs = append(reqs, ret)
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -60,6 +60,12 @@ func TestDecodeRequiredProvidersBlock_legacy(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDecodeRequiredProvidersBlock_provider_source(t *testing.T) {
|
func TestDecodeRequiredProvidersBlock_provider_source(t *testing.T) {
|
||||||
|
mockRange := hcl.Range{
|
||||||
|
Filename: "mock.tf",
|
||||||
|
Start: hcl.Pos{Line: 3, Column: 12, Byte: 27},
|
||||||
|
End: hcl.Pos{Line: 3, Column: 19, Byte: 34},
|
||||||
|
}
|
||||||
|
|
||||||
block := &hcl.Block{
|
block := &hcl.Block{
|
||||||
Type: "required_providers",
|
Type: "required_providers",
|
||||||
Body: hcltest.MockBody(&hcl.BodyContent{
|
Body: hcltest.MockBody(&hcl.BodyContent{
|
||||||
|
@ -70,6 +76,7 @@ func TestDecodeRequiredProvidersBlock_provider_source(t *testing.T) {
|
||||||
"source": cty.StringVal("mycloud/test"),
|
"source": cty.StringVal("mycloud/test"),
|
||||||
"version": cty.StringVal("2.0.0"),
|
"version": cty.StringVal("2.0.0"),
|
||||||
})),
|
})),
|
||||||
|
Range: mockRange,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
@ -77,7 +84,7 @@ func TestDecodeRequiredProvidersBlock_provider_source(t *testing.T) {
|
||||||
|
|
||||||
want := &RequiredProvider{
|
want := &RequiredProvider{
|
||||||
Name: "my_test",
|
Name: "my_test",
|
||||||
Source: "mycloud/test",
|
Source: Source{SourceStr: "mycloud/test", DeclRange: mockRange},
|
||||||
Requirement: testVC("2.0.0"),
|
Requirement: testVC("2.0.0"),
|
||||||
}
|
}
|
||||||
got, diags := decodeRequiredProvidersBlock(block)
|
got, diags := decodeRequiredProvidersBlock(block)
|
||||||
|
@ -119,7 +126,7 @@ func TestDecodeRequiredProvidersBlock_mixed(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "my_test",
|
Name: "my_test",
|
||||||
Source: "mycloud/test",
|
Source: Source{SourceStr: "mycloud/test", DeclRange: hcl.Range{}},
|
||||||
Requirement: testVC("2.0.0"),
|
Requirement: testVC("2.0.0"),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -162,7 +169,7 @@ func TestDecodeRequiredProvidersBlock_version_error(t *testing.T) {
|
||||||
want := []*RequiredProvider{
|
want := []*RequiredProvider{
|
||||||
{
|
{
|
||||||
Name: "my_test",
|
Name: "my_test",
|
||||||
Source: "mycloud/test",
|
Source: Source{SourceStr: "mycloud/test", DeclRange: hcl.Range{}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,3 +92,57 @@ func TestParseProviderConfigCompact(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseProviderConfigCompactStr(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
Input string
|
||||||
|
Want addrs.LocalProviderConfig
|
||||||
|
WantDiag string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
`aws`,
|
||||||
|
addrs.LocalProviderConfig{
|
||||||
|
LocalName: "aws",
|
||||||
|
},
|
||||||
|
``,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`aws.foo`,
|
||||||
|
addrs.LocalProviderConfig{
|
||||||
|
LocalName: "aws",
|
||||||
|
Alias: "foo",
|
||||||
|
},
|
||||||
|
``,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
`aws["foo"]`,
|
||||||
|
addrs.LocalProviderConfig{},
|
||||||
|
`The provider type name must either stand alone or be followed by an alias name separated with a dot.`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.Input, func(t *testing.T) {
|
||||||
|
got, diags := ParseProviderConfigCompactStr(test.Input)
|
||||||
|
|
||||||
|
if test.WantDiag != "" {
|
||||||
|
if len(diags) != 1 {
|
||||||
|
t.Fatalf("got %d diagnostics; want 1", len(diags))
|
||||||
|
}
|
||||||
|
gotDetail := diags[0].Description().Detail
|
||||||
|
if gotDetail != test.WantDiag {
|
||||||
|
t.Fatalf("wrong diagnostic detail\ngot: %s\nwant: %s", gotDetail, test.WantDiag)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
if len(diags) != 0 {
|
||||||
|
t.Fatalf("got %d diagnostics; want 0", len(diags))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, problem := range deep.Equal(got, test.Want) {
|
||||||
|
t.Error(problem)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
bar-test = {
|
||||||
|
source = "bar/test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "bar-test" {}
|
|
@ -0,0 +1,13 @@
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
foo-test = {
|
||||||
|
source = "foo/test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "foo-test" {}
|
||||||
|
|
||||||
|
module "child" {
|
||||||
|
source = "./child"
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
foo-test = {
|
||||||
|
source = "foo/test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "foo-test" {}
|
|
@ -0,0 +1,13 @@
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
your_aws = {
|
||||||
|
// This is temporarily using the legacy provider namespace so that we can
|
||||||
|
// write tests without fully supporting provider source
|
||||||
|
source = "-/aws"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "web" {
|
||||||
|
provider = "your_aws"
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
my_aws = {
|
||||||
|
// This is temporarily using the legacy provider namespace so that we can
|
||||||
|
// write tests without fully supporting provider source
|
||||||
|
source = "-/aws"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "web" {
|
||||||
|
provider = "my_aws"
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
my_aws = {
|
||||||
|
// This is temporarily using the legacy provider namespace so that we can
|
||||||
|
// write tests without fully supporting provider source
|
||||||
|
source = "-/aws"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "web" {
|
||||||
|
provider = "my_aws"
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -96,6 +97,46 @@ func TestProviderTransformer_moduleChild(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test providers with FQNs that do not match the typeName
|
||||||
|
func TestProviderTransformer_fqns(t *testing.T) {
|
||||||
|
for _, mod := range []string{"fqns", "fqns-module"} {
|
||||||
|
mod := testModule(t, fmt.Sprintf("transform-provider-%s", mod))
|
||||||
|
|
||||||
|
g := Graph{Path: addrs.RootModuleInstance}
|
||||||
|
{
|
||||||
|
tf := &ConfigTransformer{Config: mod}
|
||||||
|
if err := tf.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
transform := &AttachResourceConfigTransformer{Config: mod}
|
||||||
|
if err := transform.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
transform := &MissingProviderTransformer{Providers: []string{"aws"}, Config: mod}
|
||||||
|
if err := transform.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transform := &ProviderTransformer{Config: mod}
|
||||||
|
if err := transform.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := strings.TrimSpace(g.String())
|
||||||
|
expected := strings.TrimSpace(testTransformProviderBasicStr)
|
||||||
|
if actual != expected {
|
||||||
|
t.Fatalf("bad:\n\n%s", actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCloseProviderTransformer(t *testing.T) {
|
func TestCloseProviderTransformer(t *testing.T) {
|
||||||
mod := testModule(t, "transform-provider-basic")
|
mod := testModule(t, "transform-provider-basic")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue