opentofu/command/console_test.go
Pam Selle 87bce5f9dd
Support reading module outputs in terraform console (#24808)
* Include eval in output walk

This allows outputs to be evaluated in the evalwalk,
impacting terraform console. Outputs are still not evaluated
for terraform console in the root module, so this has
no impact on writing to state (as child module outputs are not
written to state). Also adds test coverage to the console command,
including for evaluating locals (another use of the evalwalk)
2020-04-30 09:21:42 -04:00

181 lines
4.5 KiB
Go

package command
import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/hashicorp/terraform/helper/copy"
"github.com/mitchellh/cli"
)
// 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 := new(cli.MockUi)
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) {
tmp, cwd := testCwd(t)
defer testFixCwd(t, tmp, cwd)
// Write a terraform.tvars
varFilePath := filepath.Join(tmp, "terraform.tfvars")
if err := ioutil.WriteFile(varFilePath, []byte(applyVarFile), 0644); err != nil {
t.Fatalf("err: %s", err)
}
p := testProvider()
ui := new(cli.MockUi)
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{
testFixturePath("apply-vars"),
}
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.
tmp, cwd := testCwd(t)
defer testFixCwd(t, tmp, cwd)
p := testProvider()
ui := new(cli.MockUi)
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{
// This test fixture includes variable "foo" {}, which we are
// intentionally not setting here.
testFixturePath("apply-vars"),
}
code := c.Run(args)
outCloser()
// Because we're running "terraform console" in piped input mode, we're
// expecting it to return a nonzero exit status here but the message
// must be the one indicating that it did attempt to evaluate var.foo and
// got an unknown value in return, rather than an error about var.foo
// not being set or a failure to prompt for it.
if code == 0 {
t.Fatalf("unexpected success\n%s", ui.OutputWriter.String())
}
// The error message should be the one console produces when it encounters
// an unknown value.
got := ui.ErrorWriter.String()
want := `Error: Result depends on values that cannot be determined`
if !strings.Contains(got, want) {
t.Fatalf("wrong output\ngot:\n%s\n\nwant string containing %q", got, want)
}
}
func TestConsole_modules(t *testing.T) {
td := tempDir(t)
copy.CopyDir(testFixturePath("modules"), td)
defer os.RemoveAll(td)
defer testChdir(t, td)()
p := testProvider()
ui := new(cli.MockUi)
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{
testFixturePath("modules"),
}
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)
}
}
}