github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/command/status_test.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "regexp" 6 "testing" 7 8 "github.com/hashicorp/nomad/ci" 9 "github.com/hashicorp/nomad/command/agent" 10 "github.com/hashicorp/nomad/nomad/mock" 11 "github.com/hashicorp/nomad/nomad/structs" 12 "github.com/hashicorp/nomad/testutil" 13 "github.com/mitchellh/cli" 14 "github.com/posener/complete" 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 ) 18 19 func TestStatusCommand_Run_JobStatus(t *testing.T) { 20 ci.Parallel(t) 21 assert := assert.New(t) 22 23 srv, _, url := testServer(t, true, nil) 24 defer srv.Shutdown() 25 26 ui := cli.NewMockUi() 27 cmd := &StatusCommand{Meta: Meta{Ui: ui, flagAddress: url}} 28 29 // Create a fake job 30 state := srv.Agent.Server().State() 31 j := mock.Job() 32 assert.Nil(state.UpsertJob(structs.MsgTypeTestSetup, 1000, j)) 33 34 // Query to check the job status 35 if code := cmd.Run([]string{"-address=" + url, j.ID}); code != 0 { 36 t.Fatalf("expected exit 0, got: %d", code) 37 } 38 39 out := ui.OutputWriter.String() 40 assert.Contains(out, j.ID) 41 42 ui.OutputWriter.Reset() 43 } 44 45 func TestStatusCommand_Run_JobStatus_MultiMatch(t *testing.T) { 46 ci.Parallel(t) 47 assert := assert.New(t) 48 49 srv, _, url := testServer(t, true, nil) 50 defer srv.Shutdown() 51 52 ui := cli.NewMockUi() 53 cmd := &StatusCommand{Meta: Meta{Ui: ui, flagAddress: url}} 54 55 // Create two fake jobs sharing a prefix 56 state := srv.Agent.Server().State() 57 j := mock.Job() 58 j2 := mock.Job() 59 j2.ID = fmt.Sprintf("%s-more", j.ID) 60 assert.Nil(state.UpsertJob(structs.MsgTypeTestSetup, 1000, j)) 61 assert.Nil(state.UpsertJob(structs.MsgTypeTestSetup, 1001, j2)) 62 63 // Query to check the job status 64 if code := cmd.Run([]string{"-address=" + url, j.ID}); code != 0 { 65 t.Fatalf("expected exit 0, got: %d", code) 66 } 67 68 out := ui.OutputWriter.String() 69 assert.Contains(out, j.ID) 70 71 ui.OutputWriter.Reset() 72 } 73 74 func TestStatusCommand_Run_EvalStatus(t *testing.T) { 75 assert := assert.New(t) 76 ci.Parallel(t) 77 78 srv, _, url := testServer(t, true, nil) 79 defer srv.Shutdown() 80 81 ui := cli.NewMockUi() 82 cmd := &StatusCommand{Meta: Meta{Ui: ui, flagAddress: url}} 83 84 // Create a fake eval 85 state := srv.Agent.Server().State() 86 eval := mock.Eval() 87 assert.Nil(state.UpsertEvals(structs.MsgTypeTestSetup, 1000, []*structs.Evaluation{eval})) 88 89 // Query to check the eval status 90 if code := cmd.Run([]string{"-address=" + url, eval.ID}); code != 0 { 91 t.Fatalf("expected exit 0, got: %d", code) 92 } 93 94 out := ui.OutputWriter.String() 95 assert.Contains(out, eval.ID[:shortId]) 96 97 ui.OutputWriter.Reset() 98 } 99 100 func TestStatusCommand_Run_NodeStatus(t *testing.T) { 101 assert := assert.New(t) 102 ci.Parallel(t) 103 104 // Start in dev mode so we get a node registration 105 srv, client, url := testServer(t, true, func(c *agent.Config) { 106 c.NodeName = "mynode" 107 }) 108 defer srv.Shutdown() 109 110 ui := cli.NewMockUi() 111 cmd := &StatusCommand{Meta: Meta{Ui: ui, flagAddress: url}} 112 113 // Wait for a node to appear 114 var nodeID string 115 testutil.WaitForResult(func() (bool, error) { 116 nodes, _, err := client.Nodes().List(nil) 117 if err != nil { 118 return false, err 119 } 120 if len(nodes) == 0 { 121 return false, fmt.Errorf("missing node") 122 } 123 nodeID = nodes[0].ID 124 return true, nil 125 }, func(err error) { 126 t.Fatalf("err: %s", err) 127 }) 128 129 // Query to check the node status 130 if code := cmd.Run([]string{"-address=" + url, nodeID}); code != 0 { 131 t.Fatalf("expected exit 0, got: %d", code) 132 } 133 134 out := ui.OutputWriter.String() 135 assert.Contains(out, "mynode") 136 137 ui.OutputWriter.Reset() 138 } 139 140 func TestStatusCommand_Run_AllocStatus(t *testing.T) { 141 assert := assert.New(t) 142 ci.Parallel(t) 143 144 srv, _, url := testServer(t, true, nil) 145 defer srv.Shutdown() 146 147 ui := cli.NewMockUi() 148 cmd := &StatusCommand{Meta: Meta{Ui: ui, flagAddress: url}} 149 150 // Create a fake alloc 151 state := srv.Agent.Server().State() 152 alloc := mock.Alloc() 153 assert.Nil(state.UpsertAllocs(structs.MsgTypeTestSetup, 1000, []*structs.Allocation{alloc})) 154 155 if code := cmd.Run([]string{"-address=" + url, alloc.ID}); code != 0 { 156 t.Fatalf("expected exit 0, got: %d", code) 157 } 158 159 out := ui.OutputWriter.String() 160 assert.Contains(out, alloc.ID[:shortId]) 161 162 ui.OutputWriter.Reset() 163 } 164 165 func TestStatusCommand_Run_DeploymentStatus(t *testing.T) { 166 assert := assert.New(t) 167 ci.Parallel(t) 168 169 srv, _, url := testServer(t, true, nil) 170 defer srv.Shutdown() 171 172 ui := cli.NewMockUi() 173 cmd := &StatusCommand{Meta: Meta{Ui: ui, flagAddress: url}} 174 175 // Create a fake deployment 176 state := srv.Agent.Server().State() 177 deployment := mock.Deployment() 178 assert.Nil(state.UpsertDeployment(1000, deployment)) 179 180 // Query to check the deployment status 181 if code := cmd.Run([]string{"-address=" + url, deployment.ID}); code != 0 { 182 t.Fatalf("expected exit 0, got: %d", code) 183 } 184 185 out := ui.OutputWriter.String() 186 assert.Contains(out, deployment.ID[:shortId]) 187 188 ui.OutputWriter.Reset() 189 } 190 191 func TestStatusCommand_Run_NoPrefix(t *testing.T) { 192 assert := assert.New(t) 193 ci.Parallel(t) 194 195 srv, _, url := testServer(t, true, nil) 196 defer srv.Shutdown() 197 198 ui := cli.NewMockUi() 199 cmd := &StatusCommand{Meta: Meta{Ui: ui, flagAddress: url}} 200 201 // Create a fake job 202 state := srv.Agent.Server().State() 203 job := mock.Job() 204 assert.Nil(state.UpsertJob(structs.MsgTypeTestSetup, 1000, job)) 205 206 // Query to check status 207 if code := cmd.Run([]string{"-address=" + url}); code != 0 { 208 t.Fatalf("expected exit 0, got: %d", code) 209 } 210 211 out := ui.OutputWriter.String() 212 assert.Contains(out, job.ID) 213 214 ui.OutputWriter.Reset() 215 } 216 217 func TestStatusCommand_AutocompleteArgs(t *testing.T) { 218 assert := assert.New(t) 219 ci.Parallel(t) 220 221 srv, _, url := testServer(t, true, nil) 222 defer srv.Shutdown() 223 224 ui := cli.NewMockUi() 225 cmd := &StatusCommand{Meta: Meta{Ui: ui, flagAddress: url}} 226 227 // Create a fake job 228 state := srv.Agent.Server().State() 229 job := mock.Job() 230 assert.Nil(state.UpsertJob(structs.MsgTypeTestSetup, 1000, job)) 231 232 prefix := job.ID[:len(job.ID)-5] 233 args := complete.Args{Last: prefix} 234 predictor := cmd.AutocompleteArgs() 235 236 res := predictor.Predict(args) 237 assert.Contains(res, job.ID) 238 } 239 240 func TestStatusCommand_Run_HostNetwork(t *testing.T) { 241 ci.Parallel(t) 242 243 ui := cli.NewMockUi() 244 245 testCases := []struct { 246 name string 247 clientHostNetworks []*structs.ClientHostNetworkConfig 248 verbose bool 249 assertions func(string) 250 }{ 251 { 252 name: "short", 253 clientHostNetworks: []*structs.ClientHostNetworkConfig{{ 254 Name: "internal", 255 CIDR: "127.0.0.1/8", 256 Interface: "lo", 257 }}, 258 verbose: false, 259 assertions: func(out string) { 260 hostNetworksRegexpStr := `Host Networks\s+=\s+internal\n` 261 require.Regexp(t, regexp.MustCompile(hostNetworksRegexpStr), out) 262 }, 263 }, 264 { 265 name: "verbose", 266 clientHostNetworks: []*structs.ClientHostNetworkConfig{{ 267 Name: "internal", 268 CIDR: "127.0.0.1/8", 269 Interface: "lo", 270 }}, 271 verbose: true, 272 assertions: func(out string) { 273 verboseHostNetworksHeadRegexpStr := `Name\s+CIDR\s+Interface\s+ReservedPorts\n` 274 require.Regexp(t, regexp.MustCompile(verboseHostNetworksHeadRegexpStr), out) 275 276 verboseHostNetworksBodyRegexpStr := `internal\s+127\.0\.0\.1/8\s+lo\s+<none>\n` 277 require.Regexp(t, regexp.MustCompile(verboseHostNetworksBodyRegexpStr), out) 278 }, 279 }, 280 { 281 name: "verbose_nointerface", 282 clientHostNetworks: []*structs.ClientHostNetworkConfig{{ 283 Name: "public", 284 CIDR: "10.199.0.200/24", 285 }}, 286 verbose: true, 287 assertions: func(out string) { 288 verboseHostNetworksHeadRegexpStr := `Name\s+CIDR\s+Interface\s+ReservedPorts\n` 289 require.Regexp(t, regexp.MustCompile(verboseHostNetworksHeadRegexpStr), out) 290 291 verboseHostNetworksBodyRegexpStr := `public\s+10\.199\.0\.200/24\s+<none>\s+<none>\n` 292 require.Regexp(t, regexp.MustCompile(verboseHostNetworksBodyRegexpStr), out) 293 }, 294 }, 295 { 296 name: "verbose_nointerface_with_reservedports", 297 clientHostNetworks: []*structs.ClientHostNetworkConfig{{ 298 Name: "public", 299 CIDR: "10.199.0.200/24", 300 ReservedPorts: "8080,8081", 301 }}, 302 verbose: true, 303 assertions: func(out string) { 304 verboseHostNetworksHeadRegexpStr := `Name\s+CIDR\s+Interface\s+ReservedPorts\n` 305 require.Regexp(t, regexp.MustCompile(verboseHostNetworksHeadRegexpStr), out) 306 307 verboseHostNetworksBodyRegexpStr := `public\s+10\.199\.0\.200/24\s+<none>\s+8080,8081\n` 308 require.Regexp(t, regexp.MustCompile(verboseHostNetworksBodyRegexpStr), out) 309 }, 310 }, 311 } 312 313 for _, tt := range testCases { 314 t.Run(tt.name, func(t *testing.T) { 315 316 // Start in dev mode so we get a node registration 317 srv, client, url := testServer(t, true, func(c *agent.Config) { 318 c.Client.HostNetworks = tt.clientHostNetworks 319 }) 320 defer srv.Shutdown() 321 322 cmd := &StatusCommand{Meta: Meta{Ui: ui, flagAddress: url}} 323 324 // Wait for a node to appear 325 var nodeID string 326 testutil.WaitForResult(func() (bool, error) { 327 nodes, _, err := client.Nodes().List(nil) 328 if err != nil { 329 return false, err 330 } 331 if len(nodes) == 0 { 332 return false, fmt.Errorf("missing node") 333 } 334 nodeID = nodes[0].ID 335 return true, nil 336 }, func(err error) { 337 t.Fatalf("err: %s", err) 338 }) 339 340 // Query to check the node status 341 args := []string{"-address=" + url} 342 if tt.verbose { 343 args = append(args, "-verbose") 344 } 345 args = append(args, nodeID) 346 347 if code := cmd.Run(args); code != 0 { 348 t.Fatalf("expected exit 0, got: %d", code) 349 } 350 351 out := ui.OutputWriter.String() 352 353 tt.assertions(out) 354 355 ui.OutputWriter.Reset() 356 }) 357 } 358 359 }