mirror of
https://github.com/opentofu/opentofu.git
synced 2025-01-17 12:12:59 -06:00
31349a9c3a
This is part of a general effort to move all of Terraform's non-library package surface under internal in order to reinforce that these are for internal use within Terraform only. If you were previously importing packages under this prefix into an external codebase, you could pin to an earlier release tag as an interim solution until you've make a plan to achieve the same functionality some other way.
290 lines
8.3 KiB
Go
290 lines
8.3 KiB
Go
package initwd
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
version "github.com/hashicorp/go-version"
|
|
"github.com/hashicorp/terraform/internal/configs"
|
|
"github.com/hashicorp/terraform/internal/configs/configload"
|
|
"github.com/hashicorp/terraform/internal/copy"
|
|
"github.com/hashicorp/terraform/internal/registry"
|
|
"github.com/hashicorp/terraform/internal/tfdiags"
|
|
)
|
|
|
|
func TestDirFromModule_registry(t *testing.T) {
|
|
if os.Getenv("TF_ACC") == "" {
|
|
t.Skip("this test accesses registry.terraform.io and github.com; set TF_ACC=1 to run it")
|
|
}
|
|
|
|
fixtureDir := filepath.Clean("testdata/empty")
|
|
tmpDir, done := tempChdir(t, fixtureDir)
|
|
defer done()
|
|
|
|
// the module installer runs filepath.EvalSymlinks() on the destination
|
|
// directory before copying files, and the resultant directory is what is
|
|
// returned by the install hooks. Without this, tests could fail on machines
|
|
// where the default temp dir was a symlink.
|
|
dir, err := filepath.EvalSymlinks(tmpDir)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
modsDir := filepath.Join(dir, ".terraform/modules")
|
|
|
|
hooks := &testInstallHooks{}
|
|
|
|
reg := registry.NewClient(nil, nil)
|
|
diags := DirFromModule(dir, modsDir, "hashicorp/module-installer-acctest/aws//examples/main", reg, hooks)
|
|
assertNoDiagnostics(t, diags)
|
|
|
|
v := version.Must(version.NewVersion("0.0.2"))
|
|
|
|
wantCalls := []testInstallHookCall{
|
|
// The module specified to populate the root directory is not mentioned
|
|
// here, because the hook mechanism is defined to talk about descendent
|
|
// modules only and so a caller to InitDirFromModule is expected to
|
|
// produce its own user-facing announcement about the root module being
|
|
// installed.
|
|
|
|
// Note that "root" in the following examples is, confusingly, the
|
|
// label on the module block in the example we've installed here:
|
|
// module "root" {
|
|
|
|
{
|
|
Name: "Download",
|
|
ModuleAddr: "root",
|
|
PackageAddr: "hashicorp/module-installer-acctest/aws",
|
|
Version: v,
|
|
},
|
|
{
|
|
Name: "Install",
|
|
ModuleAddr: "root",
|
|
Version: v,
|
|
LocalPath: filepath.Join(dir, fmt.Sprintf(".terraform/modules/root/terraform-aws-module-installer-acctest-%s", v)),
|
|
},
|
|
{
|
|
Name: "Install",
|
|
ModuleAddr: "root.child_a",
|
|
LocalPath: filepath.Join(dir, fmt.Sprintf(".terraform/modules/root/terraform-aws-module-installer-acctest-%s/modules/child_a", v)),
|
|
},
|
|
{
|
|
Name: "Install",
|
|
ModuleAddr: "root.child_a.child_b",
|
|
LocalPath: filepath.Join(dir, fmt.Sprintf(".terraform/modules/root/terraform-aws-module-installer-acctest-%s/modules/child_b", v)),
|
|
},
|
|
}
|
|
|
|
if assertResultDeepEqual(t, hooks.Calls, wantCalls) {
|
|
return
|
|
}
|
|
|
|
loader, err := configload.NewLoader(&configload.Config{
|
|
ModulesDir: modsDir,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Make sure the configuration is loadable now.
|
|
// (This ensures that correct information is recorded in the manifest.)
|
|
config, loadDiags := loader.LoadConfig(".")
|
|
if assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags)) {
|
|
return
|
|
}
|
|
|
|
wantTraces := map[string]string{
|
|
"": "in example",
|
|
"root": "in root module",
|
|
"root.child_a": "in child_a module",
|
|
"root.child_a.child_b": "in child_b module",
|
|
}
|
|
gotTraces := map[string]string{}
|
|
config.DeepEach(func(c *configs.Config) {
|
|
path := strings.Join(c.Path, ".")
|
|
if c.Module.Variables["v"] == nil {
|
|
gotTraces[path] = "<missing>"
|
|
return
|
|
}
|
|
varDesc := c.Module.Variables["v"].Description
|
|
gotTraces[path] = varDesc
|
|
})
|
|
assertResultDeepEqual(t, gotTraces, wantTraces)
|
|
}
|
|
|
|
func TestDirFromModule_submodules(t *testing.T) {
|
|
fixtureDir := filepath.Clean("testdata/empty")
|
|
fromModuleDir, err := filepath.Abs("./testdata/local-modules")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// DirFromModule will expand ("canonicalize") the pathnames, so we must do
|
|
// the same for our "wantCalls" comparison values. Otherwise this test
|
|
// will fail when building in a source tree with symlinks in $PWD.
|
|
//
|
|
// See also: https://github.com/hashicorp/terraform/issues/26014
|
|
//
|
|
fromModuleDirRealpath, err := filepath.EvalSymlinks(fromModuleDir)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
tmpDir, done := tempChdir(t, fixtureDir)
|
|
defer done()
|
|
|
|
hooks := &testInstallHooks{}
|
|
dir, err := filepath.EvalSymlinks(tmpDir)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
modInstallDir := filepath.Join(dir, ".terraform/modules")
|
|
|
|
diags := DirFromModule(dir, modInstallDir, fromModuleDir, nil, hooks)
|
|
assertNoDiagnostics(t, diags)
|
|
wantCalls := []testInstallHookCall{
|
|
{
|
|
Name: "Install",
|
|
ModuleAddr: "child_a",
|
|
LocalPath: filepath.Join(fromModuleDirRealpath, "child_a"),
|
|
},
|
|
{
|
|
Name: "Install",
|
|
ModuleAddr: "child_a.child_b",
|
|
LocalPath: filepath.Join(fromModuleDirRealpath, "child_a/child_b"),
|
|
},
|
|
}
|
|
|
|
if assertResultDeepEqual(t, hooks.Calls, wantCalls) {
|
|
return
|
|
}
|
|
|
|
loader, err := configload.NewLoader(&configload.Config{
|
|
ModulesDir: modInstallDir,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Make sure the configuration is loadable now.
|
|
// (This ensures that correct information is recorded in the manifest.)
|
|
config, loadDiags := loader.LoadConfig(".")
|
|
if assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags)) {
|
|
return
|
|
}
|
|
wantTraces := map[string]string{
|
|
"": "in root module",
|
|
"child_a": "in child_a module",
|
|
"child_a.child_b": "in child_b module",
|
|
}
|
|
gotTraces := map[string]string{}
|
|
|
|
config.DeepEach(func(c *configs.Config) {
|
|
path := strings.Join(c.Path, ".")
|
|
if c.Module.Variables["v"] == nil {
|
|
gotTraces[path] = "<missing>"
|
|
return
|
|
}
|
|
varDesc := c.Module.Variables["v"].Description
|
|
gotTraces[path] = varDesc
|
|
})
|
|
assertResultDeepEqual(t, gotTraces, wantTraces)
|
|
}
|
|
|
|
// TestDirFromModule_rel_submodules is similar to the test above, but the
|
|
// from-module is relative to the install dir ("../"):
|
|
// https://github.com/hashicorp/terraform/issues/23010
|
|
func TestDirFromModule_rel_submodules(t *testing.T) {
|
|
// This test creates a tmpdir with the following directory structure:
|
|
// - tmpdir/local-modules (with contents of testdata/local-modules)
|
|
// - tmpdir/empty: the workDir we CD into for the test
|
|
// - tmpdir/empty/target (target, the destination for init -from-module)
|
|
tmpDir, err := ioutil.TempDir("", "terraform-configload")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
fromModuleDir := filepath.Join(tmpDir, "local-modules")
|
|
workDir := filepath.Join(tmpDir, "empty")
|
|
if err := os.Mkdir(fromModuleDir, os.ModePerm); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := copy.CopyDir(fromModuleDir, "testdata/local-modules"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.Mkdir(workDir, os.ModePerm); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
targetDir := filepath.Join(tmpDir, "target")
|
|
if err := os.Mkdir(targetDir, os.ModePerm); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
oldDir, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = os.Chdir(targetDir)
|
|
if err != nil {
|
|
t.Fatalf("failed to switch to temp dir %s: %s", tmpDir, err)
|
|
}
|
|
defer os.Chdir(oldDir)
|
|
defer os.RemoveAll(tmpDir)
|
|
|
|
hooks := &testInstallHooks{}
|
|
|
|
modInstallDir := ".terraform/modules"
|
|
sourceDir := "../local-modules"
|
|
diags := DirFromModule(".", modInstallDir, sourceDir, nil, hooks)
|
|
assertNoDiagnostics(t, diags)
|
|
wantCalls := []testInstallHookCall{
|
|
{
|
|
Name: "Install",
|
|
ModuleAddr: "child_a",
|
|
LocalPath: filepath.Join(sourceDir, "child_a"),
|
|
},
|
|
{
|
|
Name: "Install",
|
|
ModuleAddr: "child_a.child_b",
|
|
LocalPath: filepath.Join(sourceDir, "child_a/child_b"),
|
|
},
|
|
}
|
|
|
|
if assertResultDeepEqual(t, hooks.Calls, wantCalls) {
|
|
return
|
|
}
|
|
|
|
loader, err := configload.NewLoader(&configload.Config{
|
|
ModulesDir: modInstallDir,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Make sure the configuration is loadable now.
|
|
// (This ensures that correct information is recorded in the manifest.)
|
|
config, loadDiags := loader.LoadConfig(".")
|
|
if assertNoDiagnostics(t, tfdiags.Diagnostics{}.Append(loadDiags)) {
|
|
return
|
|
}
|
|
wantTraces := map[string]string{
|
|
"": "in root module",
|
|
"child_a": "in child_a module",
|
|
"child_a.child_b": "in child_b module",
|
|
}
|
|
gotTraces := map[string]string{}
|
|
|
|
config.DeepEach(func(c *configs.Config) {
|
|
path := strings.Join(c.Path, ".")
|
|
if c.Module.Variables["v"] == nil {
|
|
gotTraces[path] = "<missing>"
|
|
return
|
|
}
|
|
varDesc := c.Module.Variables["v"].Description
|
|
gotTraces[path] = varDesc
|
|
})
|
|
assertResultDeepEqual(t, gotTraces, wantTraces)
|
|
}
|