opentofu/command/console_test.go
Alisdair McDiarmid ca23a096d8 cli: Remove legacy positional path arguments
Several commands continued to support the legacy positional path
argument to specify a working directory. This functionality has been
replaced with the global -chdir flag, which is specified before any
other arguments, including the sub-command name.

This commit removes support for the trailing path parameter from
most commands. The only command which still supports a path argument is
fmt, which also supports "-" to indicate receiving configuration from
standard input.

Any invocation of a command with an invalid trailing path parameter will
result in a short error message, pointing at the -chdir alternative.

There are many test updates in this commit, almost all of which are
migrations from using positional arguments to specify a working
directory. Because of the layer at which these tests run, we are unable
to use the -chdir argument, so the churn in test files is larger than
ideal. Sorry!
2021-02-02 13:21:26 -05:00

235 lines
5.6 KiB
Go

package command
import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/hashicorp/terraform/configs/configschema"
"github.com/hashicorp/terraform/providers"
"github.com/mitchellh/cli"
"github.com/zclconf/go-cty/cty"
)
// ConsoleCommand is tested primarily with tests in the "repl" package.
// It is not tested here because the Console uses a readline-like library
// that takes over stdin/stdout. It is difficult to test directly. The
// core logic is tested in "repl"
//
// This file still contains some tests using the stdin-based input.
func TestConsole_basic(t *testing.T) {
tmp, cwd := testCwd(t)
defer testFixCwd(t, tmp, cwd)
p := testProvider()
ui := cli.NewMockUi()
c := &ConsoleCommand{
Meta: Meta{
testingOverrides: metaOverridesForProvider(p),
Ui: ui,
},
}
var output bytes.Buffer
defer testStdinPipe(t, strings.NewReader("1+5\n"))()
outCloser := testStdoutCapture(t, &output)
args := []string{}
code := c.Run(args)
outCloser()
if code != 0 {
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
}
actual := output.String()
if actual != "6\n" {
t.Fatalf("bad: %q", actual)
}
}
func TestConsole_tfvars(t *testing.T) {
td := tempDir(t)
testCopyDir(t, testFixturePath("apply-vars"), td)
defer os.RemoveAll(td)
defer testChdir(t, td)()
// Write a terraform.tvars
varFilePath := filepath.Join(td, "terraform.tfvars")
if err := ioutil.WriteFile(varFilePath, []byte(applyVarFile), 0644); err != nil {
t.Fatalf("err: %s", err)
}
p := testProvider()
p.GetSchemaResponse = &providers.GetSchemaResponse{
ResourceTypes: map[string]providers.Schema{
"test_instance": {
Block: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"value": {Type: cty.String, Optional: true},
},
},
},
},
}
ui := cli.NewMockUi()
c := &ConsoleCommand{
Meta: Meta{
testingOverrides: metaOverridesForProvider(p),
Ui: ui,
},
}
var output bytes.Buffer
defer testStdinPipe(t, strings.NewReader("var.foo\n"))()
outCloser := testStdoutCapture(t, &output)
args := []string{}
code := c.Run(args)
outCloser()
if code != 0 {
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
}
actual := output.String()
if actual != "\"bar\"\n" {
t.Fatalf("bad: %q", actual)
}
}
func TestConsole_unsetRequiredVars(t *testing.T) {
// This test is verifying that it's possible to run "terraform console"
// without providing values for all required variables, without
// "terraform console" producing an interactive prompt for those variables
// or producing errors. Instead, it should allow evaluation in that
// partial context but see the unset variables values as being unknown.
//
// This test fixture includes variable "foo" {}, which we are
// intentionally not setting here.
td := tempDir(t)
testCopyDir(t, testFixturePath("apply-vars"), td)
defer os.RemoveAll(td)
defer testChdir(t, td)()
p := testProvider()
p.GetSchemaResponse = &providers.GetSchemaResponse{
ResourceTypes: map[string]providers.Schema{
"test_instance": {
Block: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"value": {Type: cty.String, Optional: true},
},
},
},
},
}
ui := cli.NewMockUi()
c := &ConsoleCommand{
Meta: Meta{
testingOverrides: metaOverridesForProvider(p),
Ui: ui,
},
}
var output bytes.Buffer
defer testStdinPipe(t, strings.NewReader("var.foo\n"))()
outCloser := testStdoutCapture(t, &output)
args := []string{}
code := c.Run(args)
outCloser()
if code != 0 {
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
}
if got, want := output.String(), "(known after apply)\n"; got != want {
t.Fatalf("unexpected output\n got: %q\nwant: %q", got, want)
}
}
func TestConsole_variables(t *testing.T) {
td := tempDir(t)
testCopyDir(t, testFixturePath("variables"), td)
defer os.RemoveAll(td)
defer testChdir(t, td)()
p := testProvider()
ui := cli.NewMockUi()
c := &ConsoleCommand{
Meta: Meta{
testingOverrides: metaOverridesForProvider(p),
Ui: ui,
},
}
commands := map[string]string{
"var.foo\n": "\"bar\"\n",
"var.snack\n": "\"popcorn\"\n",
"var.secret_snack\n": "(sensitive)\n",
"local.snack_bar\n": "[\n \"popcorn\",\n (sensitive),\n]\n",
}
args := []string{}
for cmd, val := range commands {
var output bytes.Buffer
defer testStdinPipe(t, strings.NewReader(cmd))()
outCloser := testStdoutCapture(t, &output)
code := c.Run(args)
outCloser()
if code != 0 {
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
}
actual := output.String()
if output.String() != val {
t.Fatalf("bad: %q, expected %q", actual, val)
}
}
}
func TestConsole_modules(t *testing.T) {
td := tempDir(t)
testCopyDir(t, testFixturePath("modules"), td)
defer os.RemoveAll(td)
defer testChdir(t, td)()
p := applyFixtureProvider()
ui := cli.NewMockUi()
c := &ConsoleCommand{
Meta: Meta{
testingOverrides: metaOverridesForProvider(p),
Ui: ui,
},
}
commands := map[string]string{
"module.child.myoutput\n": "\"bar\"\n",
"module.count_child[0].myoutput\n": "\"bar\"\n",
"local.foo\n": "3\n",
}
args := []string{}
for cmd, val := range commands {
var output bytes.Buffer
defer testStdinPipe(t, strings.NewReader(cmd))()
outCloser := testStdoutCapture(t, &output)
code := c.Run(args)
outCloser()
if code != 0 {
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
}
actual := output.String()
if output.String() != val {
t.Fatalf("bad: %q, expected %q", actual, val)
}
}
}