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  }