open-nomad/command/meta_test.go

254 lines
5.3 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package command
import (
"flag"
"os"
"reflect"
"sort"
"testing"
"github.com/creack/pty"
"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/ci"
"github.com/hashicorp/nomad/helper/pointer"
"github.com/mitchellh/cli"
"github.com/shoenig/test/must"
"github.com/stretchr/testify/require"
)
func TestMeta_FlagSet(t *testing.T) {
ci.Parallel(t)
cases := []struct {
Flags FlagSetFlags
Expected []string
}{
{
FlagSetNone,
[]string{},
},
{
FlagSetClient,
[]string{
"address",
"no-color",
"force-color",
"region",
"namespace",
"ca-cert",
"ca-path",
"client-cert",
"client-key",
"insecure",
"tls-server-name",
"tls-skip-verify",
"token",
},
},
}
for i, tc := range cases {
var m Meta
fs := m.FlagSet("foo", tc.Flags)
actual := make([]string, 0, 0)
fs.VisitAll(func(f *flag.Flag) {
actual = append(actual, f.Name)
})
sort.Strings(actual)
sort.Strings(tc.Expected)
if !reflect.DeepEqual(actual, tc.Expected) {
t.Fatalf("%d: flags: %#v\n\nExpected: %#v\nGot: %#v",
i, tc.Flags, tc.Expected, actual)
}
}
}
func TestMeta_Colorize(t *testing.T) {
type testCaseSetupFn func(*testing.T, *Meta)
cases := []struct {
Name string
SetupFn testCaseSetupFn
ExpectColor bool
}{
{
Name: "disable colors if UI is not colored",
ExpectColor: false,
},
{
Name: "colors if UI is colored",
SetupFn: func(t *testing.T, m *Meta) {
m.Ui = &cli.ColoredUi{}
},
ExpectColor: true,
},
{
Name: "disable colors via CLI flag",
SetupFn: func(t *testing.T, m *Meta) {
m.SetupUi([]string{"-no-color"})
},
ExpectColor: false,
},
{
Name: "disable colors via env var",
SetupFn: func(t *testing.T, m *Meta) {
t.Setenv(EnvNomadCLINoColor, "1")
m.SetupUi([]string{})
},
ExpectColor: false,
},
{
Name: "force colors via CLI flag",
SetupFn: func(t *testing.T, m *Meta) {
m.SetupUi([]string{"-force-color"})
},
ExpectColor: true,
},
{
Name: "force colors via env var",
SetupFn: func(t *testing.T, m *Meta) {
t.Setenv(EnvNomadCLIForceColor, "1")
m.SetupUi([]string{})
},
ExpectColor: true,
},
{
Name: "no color take predecence over force color via CLI flag",
SetupFn: func(t *testing.T, m *Meta) {
m.SetupUi([]string{"-no-color", "-force-color"})
},
ExpectColor: false,
},
{
Name: "no color take predecence over force color via env var",
SetupFn: func(t *testing.T, m *Meta) {
t.Setenv(EnvNomadCLINoColor, "1")
m.SetupUi([]string{"-force-color"})
},
ExpectColor: false,
},
}
for _, tc := range cases {
t.Run(tc.Name, func(t *testing.T) {
// Create fake test terminal.
_, tty, err := pty.Open()
require.NoError(t, err)
defer tty.Close()
oldStdout := os.Stdout
defer func() { os.Stdout = oldStdout }()
os.Stdout = tty
// Make sure color related environment variables are clean.
t.Setenv(EnvNomadCLIForceColor, "")
t.Setenv(EnvNomadCLINoColor, "")
// Run test case.
m := &Meta{}
if tc.SetupFn != nil {
tc.SetupFn(t, m)
}
require.Equal(t, !tc.ExpectColor, m.Colorize().Disable)
})
}
}
func TestMeta_JobByPrefix(t *testing.T) {
ci.Parallel(t)
srv, client, _ := testServer(t, true, nil)
defer srv.Shutdown()
// Wait for a node to be ready
waitForNodes(t, client)
ui := cli.NewMockUi()
meta := &Meta{Ui: ui, namespace: api.AllNamespacesNamespace}
client.SetNamespace(api.AllNamespacesNamespace)
jobs := []struct {
namespace string
id string
}{
{namespace: "default", id: "example"},
{namespace: "default", id: "job"},
{namespace: "default", id: "job-1"},
{namespace: "default", id: "job-2"},
{namespace: "prod", id: "job-1"},
}
for _, j := range jobs {
job := testJob(j.id)
job.Namespace = pointer.Of(j.namespace)
_, err := client.Namespaces().Register(&api.Namespace{Name: j.namespace}, nil)
must.NoError(t, err)
w := &api.WriteOptions{Namespace: j.namespace}
resp, _, err := client.Jobs().Register(job, w)
must.NoError(t, err)
code := waitForSuccess(ui, client, fullId, t, resp.EvalID)
must.Zero(t, code)
}
testCases := []struct {
name string
prefix string
filterFunc JobByPrefixFilterFunc
expectedError string
}{
{
name: "exact match",
prefix: "job",
},
{
name: "partial match",
prefix: "exam",
},
{
name: "match with filter",
prefix: "job-",
filterFunc: func(j *api.JobListStub) bool {
// Filter out jobs with "job-" so that only "job-2" matches.
return j.ID == "job-2"
},
},
{
name: "multiple matches",
prefix: "job-",
expectedError: "matched multiple jobs",
},
{
name: "no match",
prefix: "not-found",
expectedError: "No job(s) with prefix or ID",
},
{
name: "multiple matches across namespaces",
prefix: "job-1",
expectedError: "matched multiple jobs",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
job, err := meta.JobByPrefix(client, tc.prefix, tc.filterFunc)
if tc.expectedError != "" {
must.Nil(t, job)
must.ErrorContains(t, err, tc.expectedError)
} else {
must.NoError(t, err)
must.NotNil(t, job)
must.StrContains(t, *job.ID, tc.prefix)
}
})
}
}