opentofu/command/plugins_test.go
Kristin Laemmert 92f427779d
command/show: fix issue with show and aliased provider (#23848)
The formatter in `command/format/state.go`, when formatting a resource
with an aliased provider, was looking for a schema with the alias (ie,
test.foo), but the schemas are only listed by provider type (test).
Update the state formatter to lookup schemas by provider type only.

Some of the show tests (and a couple others) were not properly cleaning
up the created tmpdirs, so I fixed those. Also, the show tests are using
a statefile named `state.tfstate`, but were not passing that path to the
show command, so we were getting some false positives (a `show` command
that returns `no state` exits 0).

Fixes #21462
2020-01-13 15:10:00 -05:00

212 lines
5.8 KiB
Go

package command
import (
"fmt"
"os"
"path/filepath"
"reflect"
"testing"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/configs/configschema"
"github.com/hashicorp/terraform/plugin/discovery"
"github.com/hashicorp/terraform/providers"
"github.com/hashicorp/terraform/terraform"
"github.com/hashicorp/terraform/tfdiags"
)
func TestMultiVersionProviderResolver(t *testing.T) {
available := make(discovery.PluginMetaSet)
available.Add(discovery.PluginMeta{
Name: "plugin",
Version: "1.0.0",
Path: "testdata/empty-file",
})
resolver := &multiVersionProviderResolver{
Internal: map[addrs.Provider]providers.Factory{
addrs.NewLegacyProvider("internal"): providers.FactoryFixed(
&terraform.MockProvider{
GetSchemaReturn: &terraform.ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"internal_foo": {},
},
},
},
),
},
Available: available,
}
t.Run("plugin matches", func(t *testing.T) {
reqd := discovery.PluginRequirements{
"plugin": &discovery.PluginConstraints{
Versions: discovery.ConstraintStr("1.0.0").MustParse(),
},
}
got, err := resolver.ResolveProviders(reqd)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if ct := len(got); ct != 1 {
t.Errorf("wrong number of results %d; want 1", ct)
}
if _, exists := got[addrs.NewLegacyProvider("plugin")]; !exists {
t.Errorf("provider \"plugin\" not in result")
}
})
t.Run("plugin doesn't match", func(t *testing.T) {
reqd := discovery.PluginRequirements{
"plugin": &discovery.PluginConstraints{
Versions: discovery.ConstraintStr("2.0.0").MustParse(),
},
}
_, err := resolver.ResolveProviders(reqd)
if err == nil {
t.Errorf("resolved successfully, but want error")
}
})
t.Run("internal matches", func(t *testing.T) {
reqd := discovery.PluginRequirements{
"internal": &discovery.PluginConstraints{
Versions: discovery.AllVersions,
},
}
got, err := resolver.ResolveProviders(reqd)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if ct := len(got); ct != 1 {
t.Errorf("wrong number of results %d; want 1", ct)
}
if _, exists := got[addrs.NewLegacyProvider("internal")]; !exists {
t.Errorf("provider \"internal\" not in result")
}
})
t.Run("internal with version constraint", func(t *testing.T) {
// Version constraints are not permitted for internal providers
reqd := discovery.PluginRequirements{
"internal": &discovery.PluginConstraints{
Versions: discovery.ConstraintStr("2.0.0").MustParse(),
},
}
_, err := resolver.ResolveProviders(reqd)
if err == nil {
t.Errorf("resolved successfully, but want error")
}
})
}
func TestPluginPath(t *testing.T) {
td := testTempDir(t)
defer os.RemoveAll(td)
defer testChdir(t, td)()
pluginPath := []string{"a", "b", "c"}
m := Meta{}
if err := m.storePluginPath(pluginPath); err != nil {
t.Fatal(err)
}
restoredPath, err := m.loadPluginPath()
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(pluginPath, restoredPath) {
t.Fatalf("expected plugin path %#v, got %#v", pluginPath, restoredPath)
}
}
func TestInternalProviders(t *testing.T) {
m := Meta{}
internal := m.internalProviders()
tfProvider, err := internal[addrs.NewLegacyProvider("terraform")]()
if err != nil {
t.Fatal(err)
}
schema := tfProvider.GetSchema()
_, found := schema.DataSources["terraform_remote_state"]
if !found {
t.Errorf("didn't find terraform_remote_state in internal \"terraform\" provider")
}
}
// mockProviderInstaller is a discovery.PluginInstaller implementation that
// is a mock for discovery.ProviderInstaller.
type mockProviderInstaller struct {
// A map of provider names to available versions.
// The tests expect the versions to be in order from newest to oldest.
Providers map[string][]string
Dir string
PurgeUnusedCalled bool
}
func (i *mockProviderInstaller) FileName(provider, version string) string {
return fmt.Sprintf("terraform-provider-%s_v%s_x4", provider, version)
}
func (i *mockProviderInstaller) Get(provider addrs.Provider, req discovery.Constraints) (discovery.PluginMeta, tfdiags.Diagnostics, error) {
var diags tfdiags.Diagnostics
noMeta := discovery.PluginMeta{}
versions := i.Providers[provider.Type]
if len(versions) == 0 {
return noMeta, diags, fmt.Errorf("provider %q not found", provider)
}
err := os.MkdirAll(i.Dir, 0755)
if err != nil {
return noMeta, diags, fmt.Errorf("error creating plugins directory: %s", err)
}
for _, v := range versions {
version, err := discovery.VersionStr(v).Parse()
if err != nil {
panic(err)
}
if req.Allows(version) {
// provider filename
name := i.FileName(provider.Type, v)
path := filepath.Join(i.Dir, name)
f, err := os.Create(path)
if err != nil {
return noMeta, diags, fmt.Errorf("error fetching provider: %s", err)
}
f.Close()
return discovery.PluginMeta{
Name: provider.Type,
Version: discovery.VersionStr(v),
Path: path,
}, diags, nil
}
}
return noMeta, diags, fmt.Errorf("no suitable version for provider %q found with constraints %s", provider, req)
}
func (i *mockProviderInstaller) PurgeUnused(map[string]discovery.PluginMeta) (discovery.PluginMetaSet, error) {
i.PurgeUnusedCalled = true
ret := make(discovery.PluginMetaSet)
ret.Add(discovery.PluginMeta{
Name: "test",
Version: "0.0.0",
Path: "mock-test",
})
return ret, nil
}
type callbackPluginInstaller func(provider string, req discovery.Constraints) (discovery.PluginMeta, tfdiags.Diagnostics, error)
func (cb callbackPluginInstaller) Get(provider addrs.Provider, req discovery.Constraints) (discovery.PluginMeta, tfdiags.Diagnostics, error) {
return cb(provider.Type, req)
}
func (cb callbackPluginInstaller) PurgeUnused(map[string]discovery.PluginMeta) (discovery.PluginMetaSet, error) {
// does nothing
return make(discovery.PluginMetaSet), nil
}