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
|
||||
// terraform to match non-test behavior.
|
||||
func testProviderResolver(c TestCase) (providers.Resolver, error) {
|
||||
ctxProviders := c.ProviderFactories
|
||||
if ctxProviders == nil {
|
||||
ctxProviders = make(map[string]terraform.ResourceProviderFactory)
|
||||
ctxProviders := make(map[string]terraform.ResourceProviderFactory)
|
||||
for k, pf := range c.ProviderFactories {
|
||||
ctxProviders[k] = pf
|
||||
}
|
||||
|
||||
// add any fixed providers
|
||||
|
@ -650,8 +650,9 @@ func testProviderResolver(c TestCase) (providers.Resolver, error) {
|
|||
newProviders := make(map[string]providers.Factory)
|
||||
|
||||
for k, pf := range ctxProviders {
|
||||
factory := pf // must copy to ensure each closure sees its own value
|
||||
newProviders[k] = func() (providers.Interface, error) {
|
||||
p, err := pf()
|
||||
p, err := factory()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/plugin/discovery"
|
||||
"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 = `
|
||||
resource "test_instance" "foo" {}
|
||||
`
|
||||
|
|
Loading…
Reference in New Issue