github.com/hernad/nomad@v1.6.112/command/node_pool_nodes_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package command 5 6 import ( 7 "encoding/json" 8 "sort" 9 "strings" 10 "testing" 11 12 "github.com/hernad/nomad/api" 13 "github.com/hernad/nomad/ci" 14 "github.com/hernad/nomad/command/agent" 15 "github.com/hernad/nomad/helper" 16 "github.com/hernad/nomad/testutil" 17 "github.com/mitchellh/cli" 18 "github.com/shoenig/test/must" 19 ) 20 21 func TestNodePoolNodesCommand_Implements(t *testing.T) { 22 ci.Parallel(t) 23 var _ cli.Command = &NodePoolNodesCommand{} 24 } 25 26 func TestNodePoolNodesCommand_Run(t *testing.T) { 27 ci.Parallel(t) 28 29 // Start test server. 30 srv, client, url := testServer(t, true, func(c *agent.Config) { 31 c.Client.Enabled = false 32 }) 33 testutil.WaitForLeader(t, srv.Agent.RPC) 34 35 // Start some test clients. 36 rpcAddr := srv.GetConfig().AdvertiseAddrs.RPC 37 clientNodePoolConfig := func(pool string) func(*agent.Config) { 38 return func(c *agent.Config) { 39 c.Client.NodePool = pool 40 c.Client.Servers = []string{rpcAddr} 41 c.Client.Enabled = true 42 c.Server.Enabled = false 43 } 44 } 45 46 testClient(t, "client-default", clientNodePoolConfig("")) 47 testClient(t, "client-dev", clientNodePoolConfig("dev")) 48 testClient(t, "client-prod-1", clientNodePoolConfig("prod")) 49 testClient(t, "client-prod-2", clientNodePoolConfig("prod")) 50 waitForNodes(t, client) 51 52 nodes, _, err := client.Nodes().List(nil) 53 must.NoError(t, err) 54 55 // Nodes().List() sort results by CreateIndex, but for pagination we need 56 // nodes sorted by ID. 57 sort.Slice(nodes, func(i, j int) bool { 58 return nodes[i].ID < nodes[j].ID 59 }) 60 61 testCases := []struct { 62 name string 63 args []string 64 expectedCode int 65 expectedNodes []string 66 expectedErr string 67 }{ 68 { 69 name: "nodes in prod", 70 args: []string{"prod"}, 71 expectedCode: 0, 72 expectedNodes: []string{ 73 "client-prod-1", 74 "client-prod-2", 75 }, 76 }, 77 { 78 name: "nodes in all", 79 args: []string{"all"}, 80 expectedCode: 0, 81 expectedNodes: []string{ 82 "client-default", 83 "client-dev", 84 "client-prod-1", 85 "client-prod-2", 86 }, 87 }, 88 { 89 name: "filter nodes", 90 args: []string{"-filter", `Name matches "dev"`, "all"}, 91 expectedCode: 0, 92 expectedNodes: []string{ 93 "client-dev", 94 }, 95 }, 96 { 97 name: "pool by prefix", 98 args: []string{"def"}, 99 expectedNodes: []string{ 100 "client-default", 101 }, 102 }, 103 { 104 name: "paginate page 1", 105 args: []string{"-per-page=2", "all"}, 106 expectedCode: 0, 107 expectedNodes: []string{ 108 nodes[0].Name, 109 nodes[1].Name, 110 }, 111 }, 112 { 113 name: "paginate page 2", 114 args: []string{"-per-page", "2", "-page-token", nodes[2].ID, "all"}, 115 expectedCode: 0, 116 expectedNodes: []string{ 117 nodes[2].Name, 118 nodes[3].Name, 119 }, 120 }, 121 { 122 name: "missing pool name", 123 args: []string{}, 124 expectedCode: 1, 125 expectedErr: "This command takes one argument", 126 }, 127 { 128 name: "prefix match multiple", 129 args: []string{"de"}, 130 expectedCode: 1, 131 expectedErr: "Prefix matched multiple node pools", 132 }, 133 { 134 name: "json and template not allowed", 135 args: []string{"-t", "{{.}}", "all"}, 136 expectedCode: 1, 137 expectedErr: "Both json and template formatting are not allowed", 138 }, 139 } 140 for _, tc := range testCases { 141 t.Run(tc.name, func(t *testing.T) { 142 // Initialize UI and command. 143 ui := cli.NewMockUi() 144 cmd := &NodePoolNodesCommand{Meta: Meta{Ui: ui}} 145 146 // Run command. 147 // Add -json to help parse and validate results. 148 args := []string{"-address", url, "-json"} 149 args = append(args, tc.args...) 150 code := cmd.Run(args) 151 152 if tc.expectedErr != "" { 153 must.StrContains(t, ui.ErrorWriter.String(), strings.TrimSpace(tc.expectedErr)) 154 } else { 155 must.Eq(t, "", ui.ErrorWriter.String()) 156 157 var nodes []*api.NodeListStub 158 err := json.Unmarshal(ui.OutputWriter.Bytes(), &nodes) 159 must.NoError(t, err) 160 161 gotNodes := helper.ConvertSlice(nodes, 162 func(n *api.NodeListStub) string { return n.Name }) 163 must.SliceContainsAll(t, tc.expectedNodes, gotNodes) 164 } 165 must.Eq(t, tc.expectedCode, code) 166 }) 167 } 168 169 t.Run("template formatting", func(t *testing.T) { 170 // Initialize UI and command. 171 ui := cli.NewMockUi() 172 cmd := &NodePoolNodesCommand{Meta: Meta{Ui: ui}} 173 174 // Run command. 175 args := []string{"-address", url, "-t", `{{range .}}{{.ID}} {{end}}`, "all"} 176 code := cmd.Run(args) 177 must.Zero(t, code) 178 179 var expected string 180 for _, n := range nodes { 181 expected += n.ID + " " 182 } 183 got := ui.OutputWriter.String() 184 185 must.Eq(t, strings.TrimSpace(expected), strings.TrimSpace(got)) 186 }) 187 }