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