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 }