helper/resource: Allow multiple providers in a single TestCase
Due to incorrect use of a loop iterator variable inside a closure, all of the given providers were ending up with the same factory function. Now we copy the factory function to a local within the loop first so that each iteration has its own variable. This is the second round of similar bugs in this function, so we'll also add a test case for it to reduce the risk of future regressions given that most real callers don't exercise this with multiple providers in practice.
This commit is contained in:
parent
d0e6a4c69a
commit
cdad78d69b
|
@ -635,9 +635,9 @@ func testProviderConfig(c TestCase) string {
|
||||||
// Any errors are stored so that they can be returned by the factory in
|
// Any errors are stored so that they can be returned by the factory in
|
||||||
// terraform to match non-test behavior.
|
// terraform to match non-test behavior.
|
||||||
func testProviderResolver(c TestCase) (providers.Resolver, error) {
|
func testProviderResolver(c TestCase) (providers.Resolver, error) {
|
||||||
ctxProviders := c.ProviderFactories
|
ctxProviders := make(map[string]terraform.ResourceProviderFactory)
|
||||||
if ctxProviders == nil {
|
for k, pf := range c.ProviderFactories {
|
||||||
ctxProviders = make(map[string]terraform.ResourceProviderFactory)
|
ctxProviders[k] = pf
|
||||||
}
|
}
|
||||||
|
|
||||||
// add any fixed providers
|
// add any fixed providers
|
||||||
|
@ -650,8 +650,9 @@ func testProviderResolver(c TestCase) (providers.Resolver, error) {
|
||||||
newProviders := make(map[string]providers.Factory)
|
newProviders := make(map[string]providers.Factory)
|
||||||
|
|
||||||
for k, pf := range ctxProviders {
|
for k, pf := range ctxProviders {
|
||||||
|
factory := pf // must copy to ensure each closure sees its own value
|
||||||
newProviders[k] = func() (providers.Interface, error) {
|
newProviders[k] = func() (providers.Interface, error) {
|
||||||
p, err := pf()
|
p, err := factory()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform/plugin/discovery"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1033,6 +1035,77 @@ func TestTest_Taint(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTestProviderResolver(t *testing.T) {
|
||||||
|
stubProvider := func(name string) terraform.ResourceProvider {
|
||||||
|
return &schema.Provider{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
name: &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c := TestCase{
|
||||||
|
ProviderFactories: map[string]terraform.ResourceProviderFactory{
|
||||||
|
"foo": terraform.ResourceProviderFactoryFixed(stubProvider("foo")),
|
||||||
|
"bar": terraform.ResourceProviderFactoryFixed(stubProvider("bar")),
|
||||||
|
},
|
||||||
|
Providers: map[string]terraform.ResourceProvider{
|
||||||
|
"baz": stubProvider("baz"),
|
||||||
|
"bop": stubProvider("bop"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
resolver, err := testProviderResolver(c)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reqd := discovery.PluginRequirements{
|
||||||
|
"foo": &discovery.PluginConstraints{},
|
||||||
|
"bar": &discovery.PluginConstraints{},
|
||||||
|
"baz": &discovery.PluginConstraints{},
|
||||||
|
"bop": &discovery.PluginConstraints{},
|
||||||
|
}
|
||||||
|
|
||||||
|
factories, errs := resolver.ResolveProviders(reqd)
|
||||||
|
if len(errs) != 0 {
|
||||||
|
for _, err := range errs {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
t.Fatal("unexpected errors")
|
||||||
|
}
|
||||||
|
|
||||||
|
for name := range reqd {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
pf, ok := factories[name]
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("no factory for %q", name)
|
||||||
|
}
|
||||||
|
p, err := pf()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
resp := p.GetSchema()
|
||||||
|
_, ok = resp.Provider.Block.Attributes[name]
|
||||||
|
if !ok {
|
||||||
|
var has string
|
||||||
|
for k := range resp.Provider.Block.Attributes {
|
||||||
|
has = k
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if has != "" {
|
||||||
|
t.Errorf("provider %q does not have the expected schema attribute %q (but has %q)", name, name, has)
|
||||||
|
} else {
|
||||||
|
t.Errorf("provider %q does not have the expected schema attribute %q", name, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const testConfigStr = `
|
const testConfigStr = `
|
||||||
resource "test_instance" "foo" {}
|
resource "test_instance" "foo" {}
|
||||||
`
|
`
|
||||||
|
|
Loading…
Reference in New Issue