open-nomad/command/var_get_test.go

205 lines
5.5 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package command
import (
"fmt"
"strings"
"testing"
"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/ci"
"github.com/mitchellh/cli"
"github.com/posener/complete"
"github.com/stretchr/testify/require"
)
func TestVarGetCommand_Implements(t *testing.T) {
ci.Parallel(t)
var _ cli.Command = &VarGetCommand{}
}
func TestVarGetCommand_Fails(t *testing.T) {
ci.Parallel(t)
t.Run("bad_args", func(t *testing.T) {
ci.Parallel(t)
ui := cli.NewMockUi()
cmd := &VarGetCommand{Meta: Meta{Ui: ui}}
code := cmd.Run([]string{"some", "bad", "args"})
out := ui.ErrorWriter.String()
require.Equal(t, 1, code, "expected exit code 1, got: %d")
require.Contains(t, out, commandErrorText(cmd), "expected help output, got: %s", out)
})
t.Run("bad_address", func(t *testing.T) {
ci.Parallel(t)
ui := cli.NewMockUi()
cmd := &VarGetCommand{Meta: Meta{Ui: ui}}
code := cmd.Run([]string{"-address=nope", "foo"})
out := ui.ErrorWriter.String()
require.Equal(t, 1, code, "expected exit code 1, got: %d")
require.Contains(t, ui.ErrorWriter.String(), "retrieving variable", "connection error, got: %s", out)
require.Zero(t, ui.OutputWriter.String())
})
t.Run("missing_template", func(t *testing.T) {
ci.Parallel(t)
ui := cli.NewMockUi()
cmd := &VarGetCommand{Meta: Meta{Ui: ui}}
code := cmd.Run([]string{`-out=go-template`, "foo"})
out := strings.TrimSpace(ui.ErrorWriter.String())
require.Equal(t, 1, code, "expected exit code 1, got: %d", code)
require.Equal(t, errMissingTemplate+"\n"+commandErrorText(cmd), out)
require.Zero(t, ui.OutputWriter.String())
})
t.Run("unexpected_template", func(t *testing.T) {
ci.Parallel(t)
ui := cli.NewMockUi()
cmd := &VarGetCommand{Meta: Meta{Ui: ui}}
code := cmd.Run([]string{`-out=json`, `-template="bad"`, "foo"})
out := strings.TrimSpace(ui.ErrorWriter.String())
require.Equal(t, 1, code, "expected exit code 1, got: %d", code)
require.Equal(t, errUnexpectedTemplate+"\n"+commandErrorText(cmd), out)
require.Zero(t, ui.OutputWriter.String())
})
}
func TestVarGetCommand(t *testing.T) {
ci.Parallel(t)
// Create a server
srv, client, url := testServer(t, true, nil)
defer srv.Shutdown()
testCases := []struct {
name string
format string
template string
expected string
testPath string // defaulted to "test/var" in code; used for not-found
exitCode int
isError bool
}{
{
name: "json",
format: "json",
},
{
name: "table",
format: "table",
},
{
name: "go-template",
format: "go-template",
template: `{{.Namespace}}.{{.Path}}`,
expected: "TestVarGetCommand-2-go-template.test/var",
},
{
name: "not-found",
format: "json",
expected: errVariableNotFound,
testPath: "not-found",
isError: true,
exitCode: 1,
},
}
for i, tc := range testCases {
t.Run(fmt.Sprintf("%v_%s", i, tc.name), func(t *testing.T) {
tc := tc
ci.Parallel(t)
var err error
// Create a namespace for the test case
testNS := strings.Map(validNS, t.Name())
_, err = client.Namespaces().Register(&api.Namespace{Name: testNS}, nil)
require.NoError(t, err)
t.Cleanup(func() {
_, _ = client.Namespaces().Delete(testNS, nil)
})
// Create a var to get
sv := testVariable()
sv.Namespace = testNS
sv, _, err = client.Variables().Create(sv, nil)
require.NoError(t, err)
t.Cleanup(func() {
_, _ = client.Variables().Delete(sv.Path, nil)
})
// Build and run the command
ui := cli.NewMockUi()
cmd := &VarGetCommand{Meta: Meta{Ui: ui}}
args := []string{
"-address=" + url,
"-namespace=" + testNS,
"-out=" + tc.format,
}
if tc.template != "" {
args = append(args, "-template="+tc.template)
}
args = append(args, sv.Path)
if tc.testPath != "" {
// replace path with test case override
args[len(args)-1] = tc.testPath
}
code := cmd.Run(args)
// Check the output
require.Equal(t, tc.exitCode, code, "expected exit %v, got: %d; %v", tc.exitCode, code, ui.ErrorWriter.String())
if tc.isError {
require.Equal(t, tc.expected, strings.TrimSpace(ui.ErrorWriter.String()))
return
}
switch tc.format {
case "json":
require.Equal(t, sv.AsPrettyJSON(), strings.TrimSpace(ui.OutputWriter.String()))
case "table":
out := ui.OutputWriter.String()
outs := strings.Split(out, "\n")
require.Len(t, outs, 9)
require.Equal(t, "Namespace = "+testNS, outs[0])
require.Equal(t, "Path = test/var", outs[1])
case "go-template":
require.Equal(t, tc.expected, strings.TrimSpace(ui.OutputWriter.String()))
default:
t.Fatalf("invalid format: %q", tc.format)
}
})
}
t.Run("Autocomplete", func(t *testing.T) {
ci.Parallel(t)
ui := cli.NewMockUi()
cmd := &VarGetCommand{Meta: Meta{Ui: ui, flagAddress: url}}
// Create a var
testNS := strings.Map(validNS, t.Name())
_, err := client.Namespaces().Register(&api.Namespace{Name: testNS}, nil)
require.NoError(t, err)
t.Cleanup(func() {
_, _ = client.Namespaces().Delete(testNS, nil)
})
sv := testVariable()
sv.Path = "special/variable"
sv.Namespace = testNS
sv, _, err = client.Variables().Create(sv, nil)
require.NoError(t, err)
t.Cleanup(func() {
_, _ = client.Variables().Delete(sv.Path, nil)
})
args := complete.Args{Last: "s"}
predictor := cmd.AutocompleteArgs()
res := predictor.Predict(args)
require.Equal(t, 1, len(res))
require.Equal(t, sv.Path, res[0])
})
}
func validNS(r rune) rune {
if r == '/' || r == '_' {
return '-'
}
return r
}