command: Make the tests compile again

They still aren't passing, but this is just enough updating to make the
test program compile successfully after the refactoring related to
provider installation. They are now using the mock provider source offered
by the getproviders package, which is similar but not totally identical
to the idea of mocking the entire installer as these tests used to do, and
so many of them need further adjustment to still be testing what they
intended to test under this new architecture.

Subsequent commits will gradually repair the failing tests.
This commit is contained in:
Martin Atkins 2020-03-31 14:02:40 -07:00
parent 531de52dff
commit d40085f374
6 changed files with 207 additions and 407 deletions

View File

@ -14,7 +14,6 @@ import (
"github.com/hashicorp/terraform/configs/configschema" "github.com/hashicorp/terraform/configs/configschema"
"github.com/hashicorp/terraform/helper/copy" "github.com/hashicorp/terraform/helper/copy"
"github.com/hashicorp/terraform/plugin/discovery"
"github.com/hashicorp/terraform/providers" "github.com/hashicorp/terraform/providers"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
"github.com/hashicorp/terraform/tfdiags" "github.com/hashicorp/terraform/tfdiags"
@ -160,22 +159,21 @@ func TestImport_remoteState(t *testing.T) {
statePath := "imported.tfstate" statePath := "imported.tfstate"
providerSource, close := newMockProviderSource(t, map[string][]string{
"test": []string{"1.2.3"},
})
defer close()
// init our backend // init our backend
ui := cli.NewMockUi() ui := cli.NewMockUi()
m := Meta{ m := Meta{
testingOverrides: metaOverridesForProvider(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
ProviderSource: providerSource,
} }
ic := &InitCommand{ ic := &InitCommand{
Meta: m, Meta: m,
providerInstaller: &mockProviderInstaller{
Providers: map[string][]string{
"test": []string{"1.2.3"},
},
Dir: m.pluginDir(),
},
} }
// (Using log here rather than t.Log so that these messages interleave with other trace logs) // (Using log here rather than t.Log so that these messages interleave with other trace logs)
@ -267,22 +265,21 @@ func TestImport_initializationErrorShouldUnlock(t *testing.T) {
statePath := "imported.tfstate" statePath := "imported.tfstate"
providerSource, close := newMockProviderSource(t, map[string][]string{
"test": []string{"1.2.3"},
})
defer close()
// init our backend // init our backend
ui := cli.NewMockUi() ui := cli.NewMockUi()
m := Meta{ m := Meta{
testingOverrides: metaOverridesForProvider(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
ProviderSource: providerSource,
} }
ic := &InitCommand{ ic := &InitCommand{
Meta: m, Meta: m,
providerInstaller: &mockProviderInstaller{
Providers: map[string][]string{
"test": []string{"1.2.3"},
},
Dir: m.pluginDir(),
},
} }
// (Using log here rather than t.Log so that these messages interleave with other trace logs) // (Using log here rather than t.Log so that these messages interleave with other trace logs)
@ -853,10 +850,16 @@ func TestImport_pluginDir(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
providerSource, close := newMockProviderSource(t, map[string][]string{
"test": []string{"1.2.3"},
})
defer close()
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &ImportCommand{ c := &ImportCommand{
Meta: Meta{ Meta: Meta{
Ui: ui, Ui: ui,
ProviderSource: providerSource,
}, },
} }
@ -873,9 +876,6 @@ func TestImport_pluginDir(t *testing.T) {
pluginPath: []string{"./plugins"}, pluginPath: []string{"./plugins"},
Ui: initUi, Ui: initUi,
}, },
providerInstaller: &discovery.ProviderInstaller{
PluginProtocolVersion: discovery.PluginInstallProtocolVersion,
},
} }
if code := initCmd.Run(nil); code != 0 { if code := initCmd.Run(nil); code != 0 {
t.Fatal(initUi.ErrorWriter.String()) t.Fatal(initUi.ErrorWriter.String())

View File

@ -7,12 +7,11 @@ import (
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"runtime"
"sort"
"strings" "strings"
"testing" "testing"
"github.com/davecgh/go-spew/spew"
"github.com/google/go-cmp/cmp"
"github.com/mitchellh/cli" "github.com/mitchellh/cli"
"github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty"
@ -20,12 +19,12 @@ import (
"github.com/hashicorp/terraform/backend/local" "github.com/hashicorp/terraform/backend/local"
"github.com/hashicorp/terraform/configs" "github.com/hashicorp/terraform/configs"
"github.com/hashicorp/terraform/helper/copy" "github.com/hashicorp/terraform/helper/copy"
"github.com/hashicorp/terraform/plugin/discovery" "github.com/hashicorp/terraform/internal/getproviders"
"github.com/hashicorp/terraform/internal/providercache"
"github.com/hashicorp/terraform/state" "github.com/hashicorp/terraform/state"
"github.com/hashicorp/terraform/states" "github.com/hashicorp/terraform/states"
"github.com/hashicorp/terraform/states/statemgr" "github.com/hashicorp/terraform/states/statemgr"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
"github.com/hashicorp/terraform/tfdiags"
) )
func TestInit_empty(t *testing.T) { func TestInit_empty(t *testing.T) {
@ -779,26 +778,23 @@ func TestInit_getProvider(t *testing.T) {
overrides := metaOverridesForProvider(testProvider()) overrides := metaOverridesForProvider(testProvider())
ui := new(cli.MockUi) ui := new(cli.MockUi)
providerSource, close := newMockProviderSource(t, map[string][]string{
// looking for an exact version
"exact": []string{"1.2.3"},
// config requires >= 2.3.3
"greater-than": []string{"2.3.4", "2.3.3", "2.3.0"},
// config specifies
"between": []string{"3.4.5", "2.3.4", "1.2.3"},
})
defer close()
m := Meta{ m := Meta{
testingOverrides: overrides, testingOverrides: overrides,
Ui: ui, Ui: ui,
} ProviderSource: providerSource,
installer := &mockProviderInstaller{
Providers: map[string][]string{
// looking for an exact version
"exact": []string{"1.2.3"},
// config requires >= 2.3.3
"greater-than": []string{"2.3.4", "2.3.3", "2.3.0"},
// config specifies
"between": []string{"3.4.5", "2.3.4", "1.2.3"},
},
Dir: m.pluginDir(),
} }
c := &InitCommand{ c := &InitCommand{
Meta: m, Meta: m,
providerInstaller: installer,
} }
args := []string{ args := []string{
@ -808,20 +804,16 @@ func TestInit_getProvider(t *testing.T) {
t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
} }
if !installer.PurgeUnusedCalled {
t.Errorf("init didn't purge providers, but should have")
}
// check that we got the providers for our config // check that we got the providers for our config
exactPath := filepath.Join(c.pluginDir(), installer.FileName("exact", "1.2.3")) exactPath := fmt.Sprintf(".terraform/plugins/registry.terraform.io/hashicorp/exact/1.2.3/%s", getproviders.CurrentPlatform)
if _, err := os.Stat(exactPath); os.IsNotExist(err) { if _, err := os.Stat(exactPath); os.IsNotExist(err) {
t.Fatal("provider 'exact' not downloaded") t.Fatal("provider 'exact' not downloaded")
} }
greaterThanPath := filepath.Join(c.pluginDir(), installer.FileName("greater-than", "2.3.4")) greaterThanPath := fmt.Sprintf(".terraform/plugins/registry.terraform.io/hashicorp/greater-than/2.3.4/%s", getproviders.CurrentPlatform)
if _, err := os.Stat(greaterThanPath); os.IsNotExist(err) { if _, err := os.Stat(greaterThanPath); os.IsNotExist(err) {
t.Fatal("provider 'greater-than' not downloaded") t.Fatal("provider 'greater-than' not downloaded")
} }
betweenPath := filepath.Join(c.pluginDir(), installer.FileName("between", "2.3.4")) betweenPath := fmt.Sprintf(".terraform/plugins/registry.terraform.io/hashicorp/between/2.3.4/%s", getproviders.CurrentPlatform)
if _, err := os.Stat(betweenPath); os.IsNotExist(err) { if _, err := os.Stat(betweenPath); os.IsNotExist(err) {
t.Fatal("provider 'between' not downloaded") t.Fatal("provider 'between' not downloaded")
} }
@ -842,8 +834,7 @@ func TestInit_getProvider(t *testing.T) {
ui := new(cli.MockUi) ui := new(cli.MockUi)
m.Ui = ui m.Ui = ui
c := &InitCommand{ c := &InitCommand{
Meta: m, Meta: m,
providerInstaller: installer,
} }
if code := c.Run(nil); code == 0 { if code := c.Run(nil); code == 0 {
@ -867,15 +858,19 @@ func TestInit_findVendoredProviders(t *testing.T) {
defer os.RemoveAll(td) defer os.RemoveAll(td)
defer testChdir(t, td)() defer testChdir(t, td)()
// An empty provider source
providerSource, close := newMockProviderSource(t, nil)
defer close()
ui := new(cli.MockUi) ui := new(cli.MockUi)
m := Meta{ m := Meta{
testingOverrides: metaOverridesForProvider(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
ProviderSource: providerSource,
} }
c := &InitCommand{ c := &InitCommand{
Meta: m, Meta: m,
providerInstaller: &mockProviderInstaller{},
} }
// make our plugin paths // make our plugin paths
@ -909,49 +904,6 @@ func TestInit_findVendoredProviders(t *testing.T) {
} }
} }
// make sure we can locate providers defined in the legacy rc file
func TestInit_rcProviders(t *testing.T) {
// Create a temporary working directory that is empty
td := tempDir(t)
configDirName := "init-legacy-rc"
copy.CopyDir(testFixturePath(configDirName), filepath.Join(td, configDirName))
defer os.RemoveAll(td)
defer testChdir(t, td)()
pluginDir := filepath.Join(td, "custom")
pluginPath := filepath.Join(pluginDir, "terraform-provider-legacy")
ui := new(cli.MockUi)
m := Meta{
Ui: ui,
PluginOverrides: &PluginOverrides{
Providers: map[string]string{
"legacy": pluginPath,
},
},
}
c := &InitCommand{
Meta: m,
providerInstaller: &mockProviderInstaller{},
}
// make our plugin paths
if err := os.MkdirAll(pluginDir, 0755); err != nil {
t.Fatal(err)
}
if err := ioutil.WriteFile(pluginPath, []byte("test bin"), 0755); err != nil {
t.Fatal(err)
}
args := []string{configDirName}
if code := c.Run(args); code != 0 {
t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
}
}
func TestInit_providerSource(t *testing.T) { func TestInit_providerSource(t *testing.T) {
// Create a temporary working directory that is empty // Create a temporary working directory that is empty
td := tempDir(t) td := tempDir(t)
@ -961,15 +913,19 @@ func TestInit_providerSource(t *testing.T) {
defer os.RemoveAll(td) defer os.RemoveAll(td)
defer testChdir(t, td)() defer testChdir(t, td)()
// An empty provider source
providerSource, close := newMockProviderSource(t, nil)
defer close()
ui := new(cli.MockUi) ui := new(cli.MockUi)
m := Meta{ m := Meta{
testingOverrides: metaOverridesForProvider(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
ProviderSource: providerSource,
} }
c := &InitCommand{ c := &InitCommand{
Meta: m, Meta: m,
providerInstaller: &mockProviderInstaller{},
} }
// make our plugin paths // make our plugin paths
@ -1009,48 +965,40 @@ func TestInit_getUpgradePlugins(t *testing.T) {
defer os.RemoveAll(td) defer os.RemoveAll(td)
defer testChdir(t, td)() defer testChdir(t, td)()
providerSource, close := newMockProviderSource(t, map[string][]string{
// looking for an exact version
"exact": []string{"1.2.3"},
// config requires >= 2.3.3
"greater-than": []string{"2.3.4", "2.3.3", "2.3.0"},
// config specifies
"between": []string{"3.4.5", "2.3.4", "1.2.3"},
})
defer close()
ui := new(cli.MockUi) ui := new(cli.MockUi)
m := Meta{ m := Meta{
testingOverrides: metaOverridesForProvider(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
} ProviderSource: providerSource,
installer := &mockProviderInstaller{
Providers: map[string][]string{
// looking for an exact version
"exact": []string{"1.2.3"},
// config requires >= 2.3.3
"greater-than": []string{"2.3.4", "2.3.3", "2.3.0"},
// config specifies
"between": []string{"3.4.5", "2.3.4", "1.2.3"},
},
Dir: m.pluginDir(),
} }
err := os.MkdirAll(m.pluginDir(), os.ModePerm) err := os.MkdirAll(m.pluginDir(), os.ModePerm)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
exactUnwanted := filepath.Join(m.pluginDir(), installer.FileName("exact", "0.0.1")) exactUnwanted := fmt.Sprintf(".terraform/plugins/registry.terraform.io/hashicorp/exact/0.0.1/%s", getproviders.CurrentPlatform)
err = ioutil.WriteFile(exactUnwanted, []byte{}, os.ModePerm) err = ioutil.WriteFile(exactUnwanted, []byte{}, os.ModePerm)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
greaterThanUnwanted := filepath.Join(m.pluginDir(), installer.FileName("greater-than", "2.3.3")) greaterThanUnwanted := fmt.Sprintf(".terraform/plugins/registry.terraform.io/hashicorp/greater-than/2.3.3/%s", getproviders.CurrentPlatform)
err = ioutil.WriteFile(greaterThanUnwanted, []byte{}, os.ModePerm) err = ioutil.WriteFile(greaterThanUnwanted, []byte{}, os.ModePerm)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
betweenOverride := installer.FileName("between", "2.3.4") // intentionally directly in cwd, and should override auto-install
err = ioutil.WriteFile(betweenOverride, []byte{}, os.ModePerm)
if err != nil {
t.Fatal(err)
}
c := &InitCommand{ c := &InitCommand{
Meta: m, Meta: m,
providerInstaller: installer,
} }
args := []string{ args := []string{
@ -1060,36 +1008,27 @@ func TestInit_getUpgradePlugins(t *testing.T) {
t.Fatalf("command did not complete successfully:\n%s", ui.ErrorWriter.String()) t.Fatalf("command did not complete successfully:\n%s", ui.ErrorWriter.String())
} }
files, err := ioutil.ReadDir(m.pluginDir()) cacheDir := m.providerLocalCacheDir()
if err != nil { gotPackages := cacheDir.AllAvailablePackages()
t.Fatal(err) wantPackages := []*providercache.CachedProvider{}
}
if !installer.PurgeUnusedCalled { /*
t.Errorf("init -upgrade didn't purge providers, but should have") wantFilenames := []string{
} "lock.json",
gotFilenames := make([]string, len(files)) // no "between" because the file in cwd overrides it
for i, info := range files {
gotFilenames[i] = info.Name()
}
sort.Strings(gotFilenames)
wantFilenames := []string{ // The mock PurgeUnused doesn't actually purge anything, so the dir
"lock.json", // includes both our old and new versions.
"terraform-provider-exact_v0.0.1_x4",
"terraform-provider-exact_v1.2.3_x4",
"terraform-provider-greater-than_v2.3.3_x4",
"terraform-provider-greater-than_v2.3.4_x4",
}
*/
// no "between" because the file in cwd overrides it if diff := cmp.Diff(wantPackages, gotPackages); diff != "" {
t.Errorf("wrong cache directory contents after upgrade\n%s", diff)
// The mock PurgeUnused doesn't actually purge anything, so the dir
// includes both our old and new versions.
"terraform-provider-exact_v0.0.1_x4",
"terraform-provider-exact_v1.2.3_x4",
"terraform-provider-greater-than_v2.3.3_x4",
"terraform-provider-greater-than_v2.3.4_x4",
}
if !reflect.DeepEqual(gotFilenames, wantFilenames) {
t.Errorf("wrong directory contents after upgrade\ngot: %#v\nwant: %#v", gotFilenames, wantFilenames)
} }
} }
@ -1101,28 +1040,25 @@ func TestInit_getProviderMissing(t *testing.T) {
defer os.RemoveAll(td) defer os.RemoveAll(td)
defer testChdir(t, td)() defer testChdir(t, td)()
providerSource, close := newMockProviderSource(t, map[string][]string{
// looking for exact version 1.2.3
"exact": []string{"1.2.4"},
// config requires >= 2.3.3
"greater-than": []string{"2.3.4", "2.3.3", "2.3.0"},
// config specifies
"between": []string{"3.4.5", "2.3.4", "1.2.3"},
})
defer close()
ui := new(cli.MockUi) ui := new(cli.MockUi)
m := Meta{ m := Meta{
testingOverrides: metaOverridesForProvider(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
} ProviderSource: providerSource,
installer := &mockProviderInstaller{
Providers: map[string][]string{
// looking for exact version 1.2.3
"exact": []string{"1.2.4"},
// config requires >= 2.3.3
"greater-than": []string{"2.3.4", "2.3.3", "2.3.0"},
// config specifies
"between": []string{"3.4.5", "2.3.4", "1.2.3"},
},
Dir: m.pluginDir(),
} }
c := &InitCommand{ c := &InitCommand{
Meta: m, Meta: m,
providerInstaller: installer,
} }
args := []string{} args := []string{}
@ -1135,40 +1071,6 @@ func TestInit_getProviderMissing(t *testing.T) {
} }
} }
func TestInit_getProviderHaveLegacyVersion(t *testing.T) {
// Create a temporary working directory that is empty
td := tempDir(t)
copy.CopyDir(testFixturePath("init-providers-lock"), td)
defer os.RemoveAll(td)
defer testChdir(t, td)()
if err := ioutil.WriteFile("terraform-provider-test", []byte("provider bin"), 0755); err != nil {
t.Fatal(err)
}
// provider test has a version constraint in the config, which should
// trigger the getProvider error below.
ui := new(cli.MockUi)
c := &InitCommand{
Meta: Meta{
testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui,
},
providerInstaller: callbackPluginInstaller(func(provider string, req discovery.Constraints) (discovery.PluginMeta, tfdiags.Diagnostics, error) {
return discovery.PluginMeta{}, tfdiags.Diagnostics{}, fmt.Errorf("EXPECTED PROVIDER ERROR %s", provider)
}),
}
args := []string{}
if code := c.Run(args); code == 0 {
t.Fatalf("expceted error, got output: \n%s", ui.OutputWriter.String())
}
if !strings.Contains(ui.ErrorWriter.String(), "EXPECTED PROVIDER ERROR test") {
t.Fatalf("unexpected error output: %s", ui.ErrorWriter)
}
}
func TestInit_checkRequiredVersion(t *testing.T) { func TestInit_checkRequiredVersion(t *testing.T) {
// Create a temporary working directory that is empty // Create a temporary working directory that is empty
td := tempDir(t) td := tempDir(t)
@ -1197,23 +1099,20 @@ func TestInit_providerLockFile(t *testing.T) {
defer os.RemoveAll(td) defer os.RemoveAll(td)
defer testChdir(t, td)() defer testChdir(t, td)()
providerSource, close := newMockProviderSource(t, map[string][]string{
"test": []string{"1.2.3"},
})
defer close()
ui := new(cli.MockUi) ui := new(cli.MockUi)
m := Meta{ m := Meta{
testingOverrides: metaOverridesForProvider(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
} ProviderSource: providerSource,
installer := &mockProviderInstaller{
Providers: map[string][]string{
"test": []string{"1.2.3"},
},
Dir: m.pluginDir(),
} }
c := &InitCommand{ c := &InitCommand{
Meta: m, Meta: m,
providerInstaller: installer,
} }
args := []string{} args := []string{}
@ -1221,22 +1120,23 @@ func TestInit_providerLockFile(t *testing.T) {
t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
} }
providersLockFile := fmt.Sprintf( selectionsFile := ".terraform/plugins/selections.json"
".terraform/plugins/%s_%s/lock.json", buf, err := ioutil.ReadFile(selectionsFile)
runtime.GOOS, runtime.GOARCH,
)
buf, err := ioutil.ReadFile(providersLockFile)
if err != nil { if err != nil {
t.Fatalf("failed to read providers lock file %s: %s", providersLockFile, err) t.Fatalf("failed to read provider selections file %s: %s", selectionsFile, err)
} }
// The hash in here is for the empty files that mockGetProvider produces // The hash in here is for the fake package that newMockProviderSource produces
// (so it'll change if newMockProviderSource starts producing different contents)
wantLockFile := strings.TrimSpace(` wantLockFile := strings.TrimSpace(`
{ {
"test": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" "registry.terraform.io/hashicorp/test": {
"hash": "h1:4RzJudhcE4CkEwtVNRqdMKumSXu6bj8fkFTbPaX5G14=",
"version": "1.2.3"
}
} }
`) `)
if string(buf) != wantLockFile { if string(buf) != wantLockFile {
t.Errorf("wrong provider lock file contents\ngot: %s\nwant: %s", buf, wantLockFile) t.Errorf("wrong provider selections file contents\ngot: %s\nwant: %s", buf, wantLockFile)
} }
} }
@ -1245,13 +1145,17 @@ func TestInit_pluginDirReset(t *testing.T) {
defer os.RemoveAll(td) defer os.RemoveAll(td)
defer testChdir(t, td)() defer testChdir(t, td)()
// An empty provider source
providerSource, close := newMockProviderSource(t, nil)
defer close()
ui := new(cli.MockUi) ui := new(cli.MockUi)
c := &InitCommand{ c := &InitCommand{
Meta: Meta{ Meta: Meta{
testingOverrides: metaOverridesForProvider(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
ProviderSource: providerSource,
}, },
providerInstaller: &mockProviderInstaller{},
} }
// make our vendor paths // make our vendor paths
@ -1282,8 +1186,8 @@ func TestInit_pluginDirReset(t *testing.T) {
Meta: Meta{ Meta: Meta{
testingOverrides: metaOverridesForProvider(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
ProviderSource: providerSource, // still empty
}, },
providerInstaller: &mockProviderInstaller{},
} }
// make sure we remove the plugin-dir record // make sure we remove the plugin-dir record
@ -1309,15 +1213,19 @@ func TestInit_pluginDirProviders(t *testing.T) {
defer os.RemoveAll(td) defer os.RemoveAll(td)
defer testChdir(t, td)() defer testChdir(t, td)()
// An empty provider source
providerSource, close := newMockProviderSource(t, nil)
defer close()
ui := new(cli.MockUi) ui := new(cli.MockUi)
m := Meta{ m := Meta{
testingOverrides: metaOverridesForProvider(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
ProviderSource: providerSource,
} }
c := &InitCommand{ c := &InitCommand{
Meta: m, Meta: m,
providerInstaller: &mockProviderInstaller{},
} }
// make our vendor paths // make our vendor paths
@ -1357,18 +1265,19 @@ func TestInit_pluginDirProvidersDoesNotGet(t *testing.T) {
defer os.RemoveAll(td) defer os.RemoveAll(td)
defer testChdir(t, td)() defer testChdir(t, td)()
// An empty provider source
providerSource, close := newMockProviderSource(t, nil)
defer close()
ui := new(cli.MockUi) ui := new(cli.MockUi)
m := Meta{ m := Meta{
testingOverrides: metaOverridesForProvider(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
ProviderSource: providerSource,
} }
c := &InitCommand{ c := &InitCommand{
Meta: m, Meta: m,
providerInstaller: callbackPluginInstaller(func(provider string, req discovery.Constraints) (discovery.PluginMeta, tfdiags.Diagnostics, error) {
t.Fatalf("plugin installer should not have been called for %q", provider)
return discovery.PluginMeta{}, tfdiags.Diagnostics{}, nil
}),
} }
// make our vendor paths // make our vendor paths
@ -1398,6 +1307,10 @@ func TestInit_pluginDirProvidersDoesNotGet(t *testing.T) {
// should have been an error // should have been an error
t.Fatalf("bad: \n%s", ui.OutputWriter) t.Fatalf("bad: \n%s", ui.OutputWriter)
} }
if calls := providerSource.CallLog(); len(calls) > 0 {
t.Errorf("unexpected provider source calls (want none)\n%s", spew.Sdump(calls))
}
} }
// Verify that plugin-dir doesn't prevent discovery of internal providers // Verify that plugin-dir doesn't prevent discovery of internal providers
@ -1407,10 +1320,15 @@ func TestInit_pluginWithInternal(t *testing.T) {
defer os.RemoveAll(td) defer os.RemoveAll(td)
defer testChdir(t, td)() defer testChdir(t, td)()
// An empty provider source
providerSource, close := newMockProviderSource(t, nil)
defer close()
ui := new(cli.MockUi) ui := new(cli.MockUi)
m := Meta{ m := Meta{
testingOverrides: metaOverridesForProvider(testProvider()), testingOverrides: metaOverridesForProvider(testProvider()),
Ui: ui, Ui: ui,
ProviderSource: providerSource,
} }
c := &InitCommand{ c := &InitCommand{
@ -1455,3 +1373,54 @@ func TestInit_syntaxErrorUpgradeHint(t *testing.T) {
t.Fatalf("wrong output\ngot:\n%s\n\nwant: message containing %q", got, want) t.Fatalf("wrong output\ngot:\n%s\n\nwant: message containing %q", got, want)
} }
} }
// newMockProviderSource is a helper to succinctly construct a mock provider
// source that contains a set of packages matching the given provider versions
// that are available for installation (from temporary local files).
//
// The caller must call the returned close callback once the source is no
// longer needed, at which point it will clean up all of the temporary files
// and the packages in the source will no longer be available for installation.
//
// For ease of use in the common case, this function just treats all of the
// provider given names as "default" providers under
// registry.terraform.io/hashicorp . If you need more control over the
// provider addresses, construct a getproviders.MockSource directly instead.
//
// This function also registers providers as belonging to the current platform,
// to ensure that they will be available to a provider installer operating in
// its default configuration.
//
// In case of any errors while constructing the source, this function will
// abort the current test using the given testing.T. Therefore a caller can
// assume that if this function returns then the result is valid and ready
// to use.
func newMockProviderSource(t *testing.T, availableProviderVersions map[string][]string) (source *getproviders.MockSource, close func()) {
t.Helper()
var packages []getproviders.PackageMeta
var closes []func()
close = func() {
for _, f := range closes {
f()
}
}
for name, versions := range availableProviderVersions {
addr := addrs.NewDefaultProvider(name)
for _, versionStr := range versions {
version, err := getproviders.ParseVersion(versionStr)
if err != nil {
close()
t.Fatalf("failed to parse %q as a version number for %q: %s", versionStr, name, err)
}
meta, close, err := getproviders.FakeInstallablePackageMeta(addr, version, getproviders.CurrentPlatform)
if err != nil {
close()
t.Fatalf("failed to prepare fake package for %s %s: %s", name, versionStr, err)
}
closes = append(closes, close)
packages = append(packages, meta)
}
}
return getproviders.NewMockSource(packages), close
}

View File

@ -2,8 +2,6 @@ package command
import ( import (
"testing" "testing"
"github.com/hashicorp/terraform/addrs"
) )
func TestInternalPlugin_InternalProviders(t *testing.T) { func TestInternalPlugin_InternalProviders(t *testing.T) {
@ -11,7 +9,7 @@ func TestInternalPlugin_InternalProviders(t *testing.T) {
providers := m.internalProviders() providers := m.internalProviders()
// terraform is the only provider moved back to internal // terraform is the only provider moved back to internal
for _, name := range []string{"terraform"} { for _, name := range []string{"terraform"} {
pf, ok := providers[addrs.NewLegacyProvider(name)] pf, ok := providers[name]
if !ok { if !ok {
t.Errorf("Expected to find %s in InternalProviders", name) t.Errorf("Expected to find %s in InternalProviders", name)
} }

View File

@ -1,102 +1,11 @@
package command package command
import ( import (
"fmt"
"os" "os"
"path/filepath"
"reflect" "reflect"
"testing" "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) { func TestPluginPath(t *testing.T) {
td := testTempDir(t) td := testTempDir(t)
defer os.RemoveAll(td) defer os.RemoveAll(td)
@ -122,7 +31,7 @@ func TestPluginPath(t *testing.T) {
func TestInternalProviders(t *testing.T) { func TestInternalProviders(t *testing.T) {
m := Meta{} m := Meta{}
internal := m.internalProviders() internal := m.internalProviders()
tfProvider, err := internal[addrs.NewLegacyProvider("terraform")]() tfProvider, err := internal["terraform"]()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -133,79 +42,3 @@ func TestInternalProviders(t *testing.T) {
t.Errorf("didn't find terraform_remote_state in internal \"terraform\" provider") 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
}

View File

@ -49,22 +49,22 @@ func TestProvidersSchema_output(t *testing.T) {
defer os.RemoveAll(td) defer os.RemoveAll(td)
defer testChdir(t, td)() defer testChdir(t, td)()
providerSource, close := newMockProviderSource(t, map[string][]string{
"test": []string{"1.2.3"},
})
defer close()
p := showFixtureProvider() p := showFixtureProvider()
ui := new(cli.MockUi) ui := new(cli.MockUi)
m := Meta{ m := Meta{
testingOverrides: metaOverridesForProvider(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
ProviderSource: providerSource,
} }
// `terrafrom init` // `terrafrom init`
ic := &InitCommand{ ic := &InitCommand{
Meta: m, Meta: m,
providerInstaller: &mockProviderInstaller{
Providers: map[string][]string{
"test": []string{"1.2.3"},
},
Dir: m.pluginDir(),
},
} }
if code := ic.Run([]string{}); code != 0 { if code := ic.Run([]string{}); code != 0 {
t.Fatalf("init failed\n%s", ui.ErrorWriter) t.Fatalf("init failed\n%s", ui.ErrorWriter)

View File

@ -250,22 +250,22 @@ func TestShow_json_output(t *testing.T) {
expectError := strings.Contains(entry.Name(), "error") expectError := strings.Contains(entry.Name(), "error")
providerSource, close := newMockProviderSource(t, map[string][]string{
"test": []string{"1.2.3"},
})
defer close()
p := showFixtureProvider() p := showFixtureProvider()
ui := new(cli.MockUi) ui := new(cli.MockUi)
m := Meta{ m := Meta{
testingOverrides: metaOverridesForProvider(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
ProviderSource: providerSource,
} }
// init // init
ic := &InitCommand{ ic := &InitCommand{
Meta: m, Meta: m,
providerInstaller: &mockProviderInstaller{
Providers: map[string][]string{
"test": []string{"1.2.3"},
},
Dir: m.pluginDir(),
},
} }
if code := ic.Run([]string{}); code != 0 { if code := ic.Run([]string{}); code != 0 {
if expectError { if expectError {
@ -347,22 +347,22 @@ func TestShow_json_output_state(t *testing.T) {
defer os.RemoveAll(td) defer os.RemoveAll(td)
defer testChdir(t, td)() defer testChdir(t, td)()
providerSource, close := newMockProviderSource(t, map[string][]string{
"test": []string{"1.2.3"},
})
defer close()
p := showFixtureProvider() p := showFixtureProvider()
ui := new(cli.MockUi) ui := new(cli.MockUi)
m := Meta{ m := Meta{
testingOverrides: metaOverridesForProvider(p), testingOverrides: metaOverridesForProvider(p),
Ui: ui, Ui: ui,
ProviderSource: providerSource,
} }
// init // init
ic := &InitCommand{ ic := &InitCommand{
Meta: m, Meta: m,
providerInstaller: &mockProviderInstaller{
Providers: map[string][]string{
"test": []string{"1.2.3"},
},
Dir: m.pluginDir(),
},
} }
if code := ic.Run([]string{}); code != 0 { if code := ic.Run([]string{}); code != 0 {
t.Fatalf("init failed\n%s", ui.ErrorWriter) t.Fatalf("init failed\n%s", ui.ErrorWriter)