github.com/hernad/nomad@v1.6.112/command/meta_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package command
     5  
     6  import (
     7  	"flag"
     8  	"os"
     9  	"reflect"
    10  	"sort"
    11  	"testing"
    12  
    13  	"github.com/creack/pty"
    14  	"github.com/hernad/nomad/api"
    15  	"github.com/hernad/nomad/ci"
    16  	"github.com/hernad/nomad/helper/pointer"
    17  	"github.com/mitchellh/cli"
    18  	"github.com/shoenig/test/must"
    19  	"github.com/stretchr/testify/require"
    20  )
    21  
    22  func TestMeta_FlagSet(t *testing.T) {
    23  	ci.Parallel(t)
    24  	cases := []struct {
    25  		Flags    FlagSetFlags
    26  		Expected []string
    27  	}{
    28  		{
    29  			FlagSetNone,
    30  			[]string{},
    31  		},
    32  		{
    33  			FlagSetClient,
    34  			[]string{
    35  				"address",
    36  				"no-color",
    37  				"force-color",
    38  				"region",
    39  				"namespace",
    40  				"ca-cert",
    41  				"ca-path",
    42  				"client-cert",
    43  				"client-key",
    44  				"insecure",
    45  				"tls-server-name",
    46  				"tls-skip-verify",
    47  				"token",
    48  			},
    49  		},
    50  	}
    51  
    52  	for i, tc := range cases {
    53  		var m Meta
    54  		fs := m.FlagSet("foo", tc.Flags)
    55  
    56  		actual := make([]string, 0, 0)
    57  		fs.VisitAll(func(f *flag.Flag) {
    58  			actual = append(actual, f.Name)
    59  		})
    60  		sort.Strings(actual)
    61  		sort.Strings(tc.Expected)
    62  
    63  		if !reflect.DeepEqual(actual, tc.Expected) {
    64  			t.Fatalf("%d: flags: %#v\n\nExpected: %#v\nGot: %#v",
    65  				i, tc.Flags, tc.Expected, actual)
    66  		}
    67  	}
    68  }
    69  
    70  func TestMeta_Colorize(t *testing.T) {
    71  
    72  	type testCaseSetupFn func(*testing.T, *Meta)
    73  
    74  	cases := []struct {
    75  		Name        string
    76  		SetupFn     testCaseSetupFn
    77  		ExpectColor bool
    78  	}{
    79  		{
    80  			Name:        "disable colors if UI is not colored",
    81  			ExpectColor: false,
    82  		},
    83  		{
    84  			Name: "colors if UI is colored",
    85  			SetupFn: func(t *testing.T, m *Meta) {
    86  				m.Ui = &cli.ColoredUi{}
    87  			},
    88  			ExpectColor: true,
    89  		},
    90  		{
    91  			Name: "disable colors via CLI flag",
    92  			SetupFn: func(t *testing.T, m *Meta) {
    93  				m.SetupUi([]string{"-no-color"})
    94  			},
    95  			ExpectColor: false,
    96  		},
    97  		{
    98  			Name: "disable colors via env var",
    99  			SetupFn: func(t *testing.T, m *Meta) {
   100  				t.Setenv(EnvNomadCLINoColor, "1")
   101  				m.SetupUi([]string{})
   102  			},
   103  			ExpectColor: false,
   104  		},
   105  		{
   106  			Name: "force colors via CLI flag",
   107  			SetupFn: func(t *testing.T, m *Meta) {
   108  				m.SetupUi([]string{"-force-color"})
   109  			},
   110  			ExpectColor: true,
   111  		},
   112  		{
   113  			Name: "force colors via env var",
   114  			SetupFn: func(t *testing.T, m *Meta) {
   115  				t.Setenv(EnvNomadCLIForceColor, "1")
   116  				m.SetupUi([]string{})
   117  			},
   118  			ExpectColor: true,
   119  		},
   120  		{
   121  			Name: "no color take predecence over force color via CLI flag",
   122  			SetupFn: func(t *testing.T, m *Meta) {
   123  				m.SetupUi([]string{"-no-color", "-force-color"})
   124  			},
   125  			ExpectColor: false,
   126  		},
   127  		{
   128  			Name: "no color take predecence over force color via env var",
   129  			SetupFn: func(t *testing.T, m *Meta) {
   130  				t.Setenv(EnvNomadCLINoColor, "1")
   131  				m.SetupUi([]string{"-force-color"})
   132  			},
   133  			ExpectColor: false,
   134  		},
   135  	}
   136  
   137  	for _, tc := range cases {
   138  		t.Run(tc.Name, func(t *testing.T) {
   139  			// Create fake test terminal.
   140  			_, tty, err := pty.Open()
   141  			require.NoError(t, err)
   142  			defer tty.Close()
   143  
   144  			oldStdout := os.Stdout
   145  			defer func() { os.Stdout = oldStdout }()
   146  			os.Stdout = tty
   147  
   148  			// Make sure color related environment variables are clean.
   149  			t.Setenv(EnvNomadCLIForceColor, "")
   150  			t.Setenv(EnvNomadCLINoColor, "")
   151  
   152  			// Run test case.
   153  			m := &Meta{}
   154  			if tc.SetupFn != nil {
   155  				tc.SetupFn(t, m)
   156  			}
   157  
   158  			require.Equal(t, !tc.ExpectColor, m.Colorize().Disable)
   159  		})
   160  	}
   161  }
   162  
   163  func TestMeta_JobByPrefix(t *testing.T) {
   164  	ci.Parallel(t)
   165  
   166  	srv, client, _ := testServer(t, true, nil)
   167  	defer srv.Shutdown()
   168  
   169  	// Wait for a node to be ready
   170  	waitForNodes(t, client)
   171  
   172  	ui := cli.NewMockUi()
   173  	meta := &Meta{Ui: ui, namespace: api.AllNamespacesNamespace}
   174  	client.SetNamespace(api.AllNamespacesNamespace)
   175  
   176  	jobs := []struct {
   177  		namespace string
   178  		id        string
   179  	}{
   180  		{namespace: "default", id: "example"},
   181  		{namespace: "default", id: "job"},
   182  		{namespace: "default", id: "job-1"},
   183  		{namespace: "default", id: "job-2"},
   184  		{namespace: "prod", id: "job-1"},
   185  	}
   186  	for _, j := range jobs {
   187  		job := testJob(j.id)
   188  		job.Namespace = pointer.Of(j.namespace)
   189  
   190  		_, err := client.Namespaces().Register(&api.Namespace{Name: j.namespace}, nil)
   191  		must.NoError(t, err)
   192  
   193  		w := &api.WriteOptions{Namespace: j.namespace}
   194  		resp, _, err := client.Jobs().Register(job, w)
   195  		must.NoError(t, err)
   196  
   197  		code := waitForSuccess(ui, client, fullId, t, resp.EvalID)
   198  		must.Zero(t, code)
   199  	}
   200  
   201  	testCases := []struct {
   202  		name          string
   203  		prefix        string
   204  		filterFunc    JobByPrefixFilterFunc
   205  		expectedError string
   206  	}{
   207  		{
   208  			name:   "exact match",
   209  			prefix: "job",
   210  		},
   211  		{
   212  			name:   "partial match",
   213  			prefix: "exam",
   214  		},
   215  		{
   216  			name:   "match with filter",
   217  			prefix: "job-",
   218  			filterFunc: func(j *api.JobListStub) bool {
   219  				// Filter out jobs with "job-" so that only "job-2" matches.
   220  				return j.ID == "job-2"
   221  			},
   222  		},
   223  		{
   224  			name:          "multiple matches",
   225  			prefix:        "job-",
   226  			expectedError: "matched multiple jobs",
   227  		},
   228  		{
   229  			name:          "no match",
   230  			prefix:        "not-found",
   231  			expectedError: "No job(s) with prefix or ID",
   232  		},
   233  		{
   234  			name:          "multiple matches across namespaces",
   235  			prefix:        "job-1",
   236  			expectedError: "matched multiple jobs",
   237  		},
   238  	}
   239  
   240  	for _, tc := range testCases {
   241  		t.Run(tc.name, func(t *testing.T) {
   242  			job, err := meta.JobByPrefix(client, tc.prefix, tc.filterFunc)
   243  			if tc.expectedError != "" {
   244  				must.Nil(t, job)
   245  				must.ErrorContains(t, err, tc.expectedError)
   246  			} else {
   247  				must.NoError(t, err)
   248  				must.NotNil(t, job)
   249  				must.StrContains(t, *job.ID, tc.prefix)
   250  			}
   251  		})
   252  	}
   253  }