mirror of
https://github.com/hashicorp/terraform.git
synced 2026-05-13 01:28:49 -04:00
339 lines
7.9 KiB
Go
339 lines
7.9 KiB
Go
// Copyright IBM Corp. 2014, 2026
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package command
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"reflect"
|
|
"runtime"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
|
|
"github.com/hashicorp/cli"
|
|
"github.com/hashicorp/terraform/internal/backend"
|
|
backendInit "github.com/hashicorp/terraform/internal/backend/init"
|
|
backendCloud "github.com/hashicorp/terraform/internal/cloud"
|
|
"github.com/hashicorp/terraform/internal/moduleref"
|
|
)
|
|
|
|
func TestModules_noJsonFlag(t *testing.T) {
|
|
dir := t.TempDir()
|
|
os.MkdirAll(dir, 0755)
|
|
testCopyDir(t, testFixturePath("modules-nested-dependencies"), dir)
|
|
t.Chdir(dir)
|
|
|
|
ui := new(cli.MockUi)
|
|
view, done := testView(t)
|
|
|
|
cmd := &ModulesCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
View: view,
|
|
},
|
|
}
|
|
|
|
args := []string{}
|
|
code := cmd.Run(args)
|
|
if code != 0 {
|
|
t.Fatalf("Got a non-zero exit code: %d\n", code)
|
|
}
|
|
|
|
actual := done(t).All()
|
|
|
|
expectedOutputHuman := `
|
|
Modules declared by configuration:
|
|
.
|
|
├── "other"[./mods/other]
|
|
└── "test"[./mods/test]
|
|
└── "test2"[./test2]
|
|
└── "test3"[./test3]
|
|
|
|
`
|
|
if runtime.GOOS == "windows" {
|
|
expectedOutputHuman = `
|
|
Modules declared by configuration:
|
|
.
|
|
├── "other"[.\mods\other]
|
|
└── "test"[.\mods\test]
|
|
└── "test2"[.\test2]
|
|
└── "test3"[.\test3]
|
|
|
|
`
|
|
}
|
|
|
|
if diff := cmp.Diff(expectedOutputHuman, actual); diff != "" {
|
|
t.Fatalf("unexpected output:\n%s\n", diff)
|
|
}
|
|
}
|
|
|
|
func TestModules_noJsonFlag_noModules(t *testing.T) {
|
|
dir := t.TempDir()
|
|
os.MkdirAll(dir, 0755)
|
|
t.Chdir(dir)
|
|
|
|
ui := new(cli.MockUi)
|
|
view, done := testView(t)
|
|
|
|
cmd := &ModulesCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
View: view,
|
|
},
|
|
}
|
|
|
|
args := []string{}
|
|
code := cmd.Run(args)
|
|
if code != 0 {
|
|
t.Fatalf("Got a non-zero exit code: %d\n", code)
|
|
}
|
|
|
|
actual := done(t).All()
|
|
|
|
if diff := cmp.Diff("No modules found in configuration.\n", actual); diff != "" {
|
|
t.Fatalf("unexpected output (-want +got):\n%s", diff)
|
|
}
|
|
}
|
|
|
|
func TestModules_fullCmd(t *testing.T) {
|
|
dir := t.TempDir()
|
|
os.MkdirAll(dir, 0755)
|
|
testCopyDir(t, testFixturePath("modules-nested-dependencies"), dir)
|
|
t.Chdir(dir)
|
|
|
|
ui := new(cli.MockUi)
|
|
view, done := testView(t)
|
|
|
|
cmd := &ModulesCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
View: view,
|
|
},
|
|
}
|
|
|
|
args := []string{"-json"}
|
|
code := cmd.Run(args)
|
|
if code != 0 {
|
|
t.Fatalf("Got a non-zero exit code: %d\n", code)
|
|
}
|
|
|
|
output := done(t).All()
|
|
compareJSONOutput(t, output, expectedOutputJSON)
|
|
}
|
|
|
|
func TestModules_fullCmd_unreferencedEntries(t *testing.T) {
|
|
dir := t.TempDir()
|
|
os.MkdirAll(dir, 0755)
|
|
testCopyDir(t, testFixturePath("modules-unreferenced-entries"), dir)
|
|
t.Chdir(dir)
|
|
|
|
ui := new(cli.MockUi)
|
|
view, done := testView(t)
|
|
|
|
cmd := &ModulesCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
View: view,
|
|
},
|
|
}
|
|
|
|
args := []string{"-json"}
|
|
code := cmd.Run(args)
|
|
if code != 0 {
|
|
t.Fatalf("Got a non-zero exit code: %d\n", code)
|
|
}
|
|
output := done(t).All()
|
|
compareJSONOutput(t, output, expectedOutputJSON)
|
|
}
|
|
|
|
func TestModules_uninstalledModules(t *testing.T) {
|
|
dir := t.TempDir()
|
|
os.MkdirAll(dir, 0755)
|
|
testCopyDir(t, testFixturePath("modules-uninstalled-entries"), dir)
|
|
t.Chdir(dir)
|
|
|
|
ui := new(cli.MockUi)
|
|
view, done := testView(t)
|
|
|
|
cmd := &ModulesCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
View: view,
|
|
},
|
|
}
|
|
|
|
args := []string{"-json"}
|
|
code := cmd.Run(args)
|
|
if code == 0 {
|
|
t.Fatal("Expected a non-zero exit code\n")
|
|
}
|
|
output := done(t).All()
|
|
if !strings.Contains(output, "Module not installed") {
|
|
t.Fatalf("expected to see a `not installed` error message: %s\n", output)
|
|
}
|
|
|
|
if !strings.Contains(output, `Run "terraform init"`) {
|
|
t.Fatalf("expected error message to ask user to run terraform init: %s\n", output)
|
|
}
|
|
}
|
|
|
|
func TestModules_constVariable(t *testing.T) {
|
|
t.Run("missing value", func(t *testing.T) {
|
|
wd := tempWorkingDirFixture(t, "dynamic-module-sources/command-with-const-var")
|
|
t.Chdir(wd.RootModuleDir())
|
|
|
|
ui := cli.NewMockUi()
|
|
view, done := testView(t)
|
|
|
|
cmd := &ModulesCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
View: view,
|
|
WorkingDir: wd,
|
|
},
|
|
}
|
|
|
|
args := []string{}
|
|
code := cmd.Run(args)
|
|
if code == 0 {
|
|
t.Fatalf("expected error, got 0")
|
|
}
|
|
|
|
output := done(t).All()
|
|
if !strings.Contains(output, "No value for required variable") {
|
|
t.Fatalf("expected missing variable error, got: %s", output)
|
|
}
|
|
})
|
|
|
|
t.Run("value via cli", func(t *testing.T) {
|
|
wd := tempWorkingDirFixture(t, "dynamic-module-sources/command-with-const-var")
|
|
t.Chdir(wd.RootModuleDir())
|
|
|
|
ui := cli.NewMockUi()
|
|
view, done := testView(t)
|
|
|
|
cmd := &ModulesCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
View: view,
|
|
WorkingDir: wd,
|
|
},
|
|
}
|
|
|
|
args := []string{}
|
|
code := cmd.Run(append(args, "-var", "module_name=child"))
|
|
if code != 0 {
|
|
t.Fatalf("Got a non-zero exit code: %d\n%s", code, done(t).All())
|
|
}
|
|
|
|
actual := done(t).All()
|
|
|
|
expectedOutputHuman := `
|
|
Modules declared by configuration:
|
|
.
|
|
└── "child"[./modules/child]
|
|
|
|
`
|
|
if runtime.GOOS == "windows" {
|
|
expectedOutputHuman = `
|
|
Modules declared by configuration:
|
|
.
|
|
└── "child"[.\modules\child]
|
|
|
|
`
|
|
}
|
|
|
|
if diff := cmp.Diff(expectedOutputHuman, actual); diff != "" {
|
|
t.Fatalf("unexpected output:\n%s\n", diff)
|
|
}
|
|
})
|
|
|
|
t.Run("value via backend", func(t *testing.T) {
|
|
server := cloudTestServerWithVars(t)
|
|
defer server.Close()
|
|
d := testDisco(server)
|
|
|
|
previousBackend := backendInit.Backend("cloud")
|
|
backendInit.Set("cloud", func() backend.Backend { return backendCloud.New(d) })
|
|
defer backendInit.Set("cloud", previousBackend)
|
|
|
|
wd := tempWorkingDirFixture(t, "dynamic-module-sources/command-with-const-var-cloud-backend")
|
|
t.Chdir(wd.RootModuleDir())
|
|
|
|
ui := cli.NewMockUi()
|
|
view, done := testView(t)
|
|
|
|
cmd := &ModulesCommand{
|
|
Meta: Meta{
|
|
testingOverrides: metaOverridesForProvider(testProvider()),
|
|
Ui: ui,
|
|
View: view,
|
|
WorkingDir: wd,
|
|
Services: d,
|
|
},
|
|
}
|
|
|
|
args := []string{}
|
|
code := cmd.Run(args)
|
|
if code != 0 {
|
|
t.Fatalf("Got a non-zero exit code: %d\n%s", code, done(t).All())
|
|
}
|
|
|
|
actual := done(t).All()
|
|
|
|
expectedOutputHuman := `
|
|
Modules declared by configuration:
|
|
.
|
|
└── "child"[./modules/example]
|
|
|
|
`
|
|
if runtime.GOOS == "windows" {
|
|
expectedOutputHuman = `
|
|
Modules declared by configuration:
|
|
.
|
|
└── "child"[.\modules\example]
|
|
|
|
`
|
|
}
|
|
|
|
if diff := cmp.Diff(expectedOutputHuman, actual); diff != "" {
|
|
t.Fatalf("unexpected output:\n%s\n", diff)
|
|
}
|
|
})
|
|
}
|
|
|
|
func compareJSONOutput(t *testing.T, got string, want string) {
|
|
var expected, actual moduleref.Manifest
|
|
|
|
if err := json.Unmarshal([]byte(got), &actual); err != nil {
|
|
t.Fatalf("Failed to unmarshal actual JSON: %v", err)
|
|
}
|
|
|
|
if err := json.Unmarshal([]byte(want), &expected); err != nil {
|
|
t.Fatalf("Failed to unmarshal expected JSON: %v", err)
|
|
}
|
|
|
|
sort.Slice(actual.Records, func(i, j int) bool {
|
|
return actual.Records[i].Key < actual.Records[j].Key
|
|
})
|
|
sort.Slice(expected.Records, func(i, j int) bool {
|
|
return expected.Records[i].Key < expected.Records[j].Key
|
|
})
|
|
|
|
if !reflect.DeepEqual(expected, actual) {
|
|
t.Fatalf("unexpected output, got: %s\n, want:%s\n", got, want)
|
|
}
|
|
}
|
|
|
|
var expectedOutputJSON = `{"format_version":"1.0","modules":[{"key":"test","source":"./mods/test","version":""},{"key":"test2","source":"./test2","version":""},{"key":"test3","source":"./test3","version":""},{"key":"other","source":"./mods/other","version":""}]}`
|