1package command
2
3import (
4	"fmt"
5	"strings"
6	"testing"
7
8	"github.com/hashicorp/nomad/command/agent"
9	"github.com/mitchellh/cli"
10)
11
12func TestServerMembersCommand_Implements(t *testing.T) {
13	t.Parallel()
14	var _ cli.Command = &ServerMembersCommand{}
15}
16
17func TestServerMembersCommand_Run(t *testing.T) {
18	t.Parallel()
19	srv, client, url := testServer(t, false, nil)
20	defer srv.Shutdown()
21
22	ui := new(cli.MockUi)
23	cmd := &ServerMembersCommand{Meta: Meta{Ui: ui}}
24
25	// Get our own node name
26	name, err := client.Agent().NodeName()
27	if err != nil {
28		t.Fatalf("err: %s", err)
29	}
30
31	// Query the members
32	if code := cmd.Run([]string{"-address=" + url}); code != 0 {
33		t.Fatalf("expected exit 0, got: %d", code)
34	}
35	if out := ui.OutputWriter.String(); !strings.Contains(out, name) {
36		t.Fatalf("expected %q in output, got: %s", name, out)
37	}
38	ui.OutputWriter.Reset()
39
40	// Query members with detailed output
41	if code := cmd.Run([]string{"-address=" + url, "-detailed"}); code != 0 {
42		t.Fatalf("expected exit 0, got: %d", code)
43	}
44	if out := ui.OutputWriter.String(); !strings.Contains(out, "Tags") {
45		t.Fatalf("expected tags in output, got: %s", out)
46	}
47}
48
49func TestMembersCommand_Fails(t *testing.T) {
50	t.Parallel()
51	ui := new(cli.MockUi)
52	cmd := &ServerMembersCommand{Meta: Meta{Ui: ui}}
53
54	// Fails on misuse
55	if code := cmd.Run([]string{"some", "bad", "args"}); code != 1 {
56		t.Fatalf("expected exit code 1, got: %d", code)
57	}
58	if out := ui.ErrorWriter.String(); !strings.Contains(out, commandErrorText(cmd)) {
59		t.Fatalf("expected help output, got: %s", out)
60	}
61	ui.ErrorWriter.Reset()
62
63	// Fails on connection failure
64	if code := cmd.Run([]string{"-address=nope"}); code != 1 {
65		t.Fatalf("expected exit code 1, got: %d", code)
66	}
67	if out := ui.ErrorWriter.String(); !strings.Contains(out, "Error querying servers") {
68		t.Fatalf("expected failed query error, got: %s", out)
69	}
70}
71
72// Tests that a single server region that left should still
73// not return an error and list other members in other regions
74func TestServerMembersCommand_MultiRegion_Leave(t *testing.T) {
75	t.Parallel()
76
77	config1 := func(c *agent.Config) {
78		c.Region = "r1"
79		c.Datacenter = "d1"
80	}
81
82	srv1, client1, url := testServer(t, false, config1)
83	defer srv1.Shutdown()
84
85	config2 := func(c *agent.Config) {
86		c.Region = "r2"
87		c.Datacenter = "d2"
88	}
89
90	srv2, _, _ := testServer(t, false, config2)
91	defer srv1.Shutdown()
92
93	// Join with srv1
94	addr := fmt.Sprintf("127.0.0.1:%d",
95		srv1.Agent.Server().GetConfig().SerfConfig.MemberlistConfig.BindPort)
96
97	if _, err := srv2.Agent.Server().Join([]string{addr}); err != nil {
98		t.Fatalf("Join err: %v", err)
99	}
100	ui := new(cli.MockUi)
101	cmd := &ServerMembersCommand{Meta: Meta{Ui: ui}}
102
103	// Get our own node name
104	name, err := client1.Agent().NodeName()
105	if err != nil {
106		t.Fatalf("err: %s", err)
107	}
108
109	// Query the members
110	if code := cmd.Run([]string{"-address=" + url}); code != 0 {
111		t.Fatalf("expected exit 0, got: %d", code)
112	}
113	if out := ui.OutputWriter.String(); !strings.Contains(out, name) {
114		t.Fatalf("expected %q in output, got: %s", name, out)
115	}
116	ui.OutputWriter.Reset()
117
118	// Make one of the servers leave
119	srv2.Agent.Leave()
120
121	// Query again, should still contain expected output
122	if code := cmd.Run([]string{"-address=" + url}); code != 0 {
123		t.Fatalf("expected exit 0, got: %d", code)
124	}
125	if out := ui.OutputWriter.String(); !strings.Contains(out, name) {
126		t.Fatalf("expected %q in output, got: %s", name, out)
127	}
128}
129