github.com/uchennaokeke444/nomad@v0.11.8/command/node_status_test.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 "time" 8 9 "github.com/hashicorp/nomad/api" 10 "github.com/hashicorp/nomad/command/agent" 11 "github.com/hashicorp/nomad/testutil" 12 "github.com/mitchellh/cli" 13 "github.com/posener/complete" 14 "github.com/stretchr/testify/assert" 15 ) 16 17 func TestNodeStatusCommand_Implements(t *testing.T) { 18 t.Parallel() 19 var _ cli.Command = &NodeStatusCommand{} 20 } 21 22 func TestNodeStatusCommand_Self(t *testing.T) { 23 t.Parallel() 24 // Start in dev mode so we get a node registration 25 srv, client, url := testServer(t, true, func(c *agent.Config) { 26 c.NodeName = "mynode" 27 }) 28 defer srv.Shutdown() 29 30 ui := new(cli.MockUi) 31 cmd := &NodeStatusCommand{Meta: Meta{Ui: ui}} 32 33 // Wait for a node to appear 34 var nodeID string 35 testutil.WaitForResult(func() (bool, error) { 36 nodes, _, err := client.Nodes().List(nil) 37 if err != nil { 38 return false, err 39 } 40 if len(nodes) == 0 { 41 return false, fmt.Errorf("missing node") 42 } 43 nodeID = nodes[0].ID 44 return true, nil 45 }, func(err error) { 46 t.Fatalf("err: %s", err) 47 }) 48 49 // Query self node 50 if code := cmd.Run([]string{"-address=" + url, "-self"}); code != 0 { 51 t.Fatalf("expected exit 0, got: %d", code) 52 } 53 out := ui.OutputWriter.String() 54 if !strings.Contains(out, "mynode") { 55 t.Fatalf("expect to find mynode, got: %s", out) 56 } 57 if !strings.Contains(out, "No allocations placed") { 58 t.Fatalf("should not dump allocations") 59 } 60 ui.OutputWriter.Reset() 61 62 // Request full id output 63 if code := cmd.Run([]string{"-address=" + url, "-self", "-verbose"}); code != 0 { 64 t.Fatalf("expected exit 0, got: %d", code) 65 } 66 out = ui.OutputWriter.String() 67 if !strings.Contains(out, nodeID) { 68 t.Fatalf("expected full node id %q, got: %s", nodeID, out) 69 } 70 ui.OutputWriter.Reset() 71 } 72 73 func TestNodeStatusCommand_Run(t *testing.T) { 74 t.Parallel() 75 // Start in dev mode so we get a node registration 76 srv, client, url := testServer(t, true, func(c *agent.Config) { 77 c.NodeName = "mynode" 78 }) 79 defer srv.Shutdown() 80 81 ui := new(cli.MockUi) 82 cmd := &NodeStatusCommand{Meta: Meta{Ui: ui}} 83 84 // Wait for a node to appear 85 var nodeID string 86 testutil.WaitForResult(func() (bool, error) { 87 nodes, _, err := client.Nodes().List(nil) 88 if err != nil { 89 return false, err 90 } 91 if len(nodes) == 0 { 92 return false, fmt.Errorf("missing node") 93 } 94 nodeID = nodes[0].ID 95 return true, nil 96 }, func(err error) { 97 t.Fatalf("err: %s", err) 98 }) 99 100 // Query all node statuses 101 if code := cmd.Run([]string{"-address=" + url}); code != 0 { 102 t.Fatalf("expected exit 0, got: %d", code) 103 } 104 out := ui.OutputWriter.String() 105 if !strings.Contains(out, "mynode") { 106 t.Fatalf("expect to find mynode, got: %s", out) 107 } 108 ui.OutputWriter.Reset() 109 110 // Query a single node 111 if code := cmd.Run([]string{"-address=" + url, nodeID}); code != 0 { 112 t.Fatalf("expected exit 0, got: %d", code) 113 } 114 out = ui.OutputWriter.String() 115 if !strings.Contains(out, "mynode") { 116 t.Fatalf("expect to find mynode, got: %s", out) 117 } 118 ui.OutputWriter.Reset() 119 120 // Query single node in short view 121 if code := cmd.Run([]string{"-address=" + url, "-short", nodeID}); code != 0 { 122 t.Fatalf("expected exit 0, got: %d", code) 123 } 124 out = ui.OutputWriter.String() 125 if !strings.Contains(out, "mynode") { 126 t.Fatalf("expect to find mynode, got: %s", out) 127 } 128 if !strings.Contains(out, "No allocations placed") { 129 t.Fatalf("should not dump allocations") 130 } 131 132 // Query a single node based on a prefix that is even without the hyphen 133 if code := cmd.Run([]string{"-address=" + url, nodeID[:13]}); code != 0 { 134 t.Fatalf("expected exit 0, got: %d", code) 135 } 136 out = ui.OutputWriter.String() 137 if !strings.Contains(out, "mynode") { 138 t.Fatalf("expect to find mynode, got: %s", out) 139 } 140 if !strings.Contains(out, nodeID) { 141 t.Fatalf("expected node id %q, got: %s", nodeID, out) 142 } 143 ui.OutputWriter.Reset() 144 145 // Request full id output 146 if code := cmd.Run([]string{"-address=" + url, "-verbose", nodeID[:4]}); code != 0 { 147 t.Fatalf("expected exit 0, got: %d", code) 148 } 149 out = ui.OutputWriter.String() 150 if !strings.Contains(out, nodeID) { 151 t.Fatalf("expected full node id %q, got: %s", nodeID, out) 152 } 153 ui.OutputWriter.Reset() 154 155 // Identifiers with uneven length should produce a query result 156 if code := cmd.Run([]string{"-address=" + url, nodeID[:3]}); code != 0 { 157 t.Fatalf("expected exit 0, got: %d", code) 158 } 159 out = ui.OutputWriter.String() 160 if !strings.Contains(out, "mynode") { 161 t.Fatalf("expect to find mynode, got: %s", out) 162 } 163 } 164 165 func TestNodeStatusCommand_Fails(t *testing.T) { 166 t.Parallel() 167 srv, _, url := testServer(t, false, nil) 168 defer srv.Shutdown() 169 170 ui := new(cli.MockUi) 171 cmd := &NodeStatusCommand{Meta: Meta{Ui: ui}} 172 173 // Fails on misuse 174 if code := cmd.Run([]string{"some", "bad", "args"}); code != 1 { 175 t.Fatalf("expected exit code 1, got: %d", code) 176 } 177 if out := ui.ErrorWriter.String(); !strings.Contains(out, commandErrorText(cmd)) { 178 t.Fatalf("expected help output, got: %s", out) 179 } 180 ui.ErrorWriter.Reset() 181 182 // Fails on connection failure 183 if code := cmd.Run([]string{"-address=nope"}); code != 1 { 184 t.Fatalf("expected exit code 1, got: %d", code) 185 } 186 if out := ui.ErrorWriter.String(); !strings.Contains(out, "Error querying node status") { 187 t.Fatalf("expected failed query error, got: %s", out) 188 } 189 ui.ErrorWriter.Reset() 190 191 // Fails on nonexistent node 192 if code := cmd.Run([]string{"-address=" + url, "12345678-abcd-efab-cdef-123456789abc"}); code != 1 { 193 t.Fatalf("expected exit 1, got: %d", code) 194 } 195 if out := ui.ErrorWriter.String(); !strings.Contains(out, "No node(s) with prefix") { 196 t.Fatalf("expected not found error, got: %s", out) 197 } 198 ui.ErrorWriter.Reset() 199 200 // Fail on identifier with too few characters 201 if code := cmd.Run([]string{"-address=" + url, "1"}); code != 1 { 202 t.Fatalf("expected exit 1, got: %d", code) 203 } 204 if out := ui.ErrorWriter.String(); !strings.Contains(out, "must contain at least two characters.") { 205 t.Fatalf("expected too few characters error, got: %s", out) 206 } 207 ui.ErrorWriter.Reset() 208 209 // Failed on both -json and -t options are specified 210 if code := cmd.Run([]string{"-address=" + url, "-json", "-t", "{{.ID}}"}); code != 1 { 211 t.Fatalf("expected exit 1, got: %d", code) 212 } 213 if out := ui.ErrorWriter.String(); !strings.Contains(out, "Both json and template formatting are not allowed") { 214 t.Fatalf("expected getting formatter error, got: %s", out) 215 } 216 } 217 218 func TestNodeStatusCommand_AutocompleteArgs(t *testing.T) { 219 assert := assert.New(t) 220 t.Parallel() 221 222 srv, client, url := testServer(t, true, nil) 223 defer srv.Shutdown() 224 225 // Wait for a node to appear 226 var nodeID string 227 testutil.WaitForResult(func() (bool, error) { 228 nodes, _, err := client.Nodes().List(nil) 229 if err != nil { 230 return false, err 231 } 232 if len(nodes) == 0 { 233 return false, fmt.Errorf("missing node") 234 } 235 nodeID = nodes[0].ID 236 return true, nil 237 }, func(err error) { 238 t.Fatalf("err: %s", err) 239 }) 240 241 ui := new(cli.MockUi) 242 cmd := &NodeStatusCommand{Meta: Meta{Ui: ui, flagAddress: url}} 243 244 prefix := nodeID[:len(nodeID)-5] 245 args := complete.Args{Last: prefix} 246 predictor := cmd.AutocompleteArgs() 247 248 res := predictor.Predict(args) 249 assert.Equal(1, len(res)) 250 assert.Equal(nodeID, res[0]) 251 } 252 253 func TestNodeStatusCommand_FormatDrain(t *testing.T) { 254 t.Parallel() 255 assert := assert.New(t) 256 257 node := &api.Node{} 258 259 assert.Equal("false", formatDrain(node)) 260 261 node.DrainStrategy = &api.DrainStrategy{} 262 assert.Equal("true; no deadline", formatDrain(node)) 263 264 node.DrainStrategy = &api.DrainStrategy{} 265 node.DrainStrategy.Deadline = -1 * time.Second 266 assert.Equal("true; force drain", formatDrain(node)) 267 268 // formatTime special cases Unix(0, 0), so increment by 1 269 node.DrainStrategy = &api.DrainStrategy{} 270 node.DrainStrategy.ForceDeadline = time.Unix(1, 0).UTC() 271 assert.Equal("true; 1970-01-01T00:00:01Z deadline", formatDrain(node)) 272 273 node.DrainStrategy.IgnoreSystemJobs = true 274 assert.Equal("true; 1970-01-01T00:00:01Z deadline; ignoring system jobs", formatDrain(node)) 275 }