1package agent
2
3import (
4	"encoding/json"
5	"io/ioutil"
6	"os"
7	"path/filepath"
8	"reflect"
9	"strings"
10	"testing"
11
12	"github.com/hashicorp/serf/serf"
13	"github.com/hashicorp/serf/testutil"
14)
15
16func TestAgent_eventHandler(t *testing.T) {
17	a1 := testAgent(nil)
18	defer a1.Shutdown()
19	defer a1.Leave()
20
21	handler := new(MockEventHandler)
22	a1.RegisterEventHandler(handler)
23
24	if err := a1.Start(); err != nil {
25		t.Fatalf("err: %s", err)
26	}
27
28	testutil.Yield()
29
30	if len(handler.Events) != 1 {
31		t.Fatalf("bad: %#v", handler.Events)
32	}
33
34	if handler.Events[0].EventType() != serf.EventMemberJoin {
35		t.Fatalf("bad: %#v", handler.Events[0])
36	}
37}
38
39func TestAgentShutdown_multiple(t *testing.T) {
40	a := testAgent(nil)
41	if err := a.Start(); err != nil {
42		t.Fatalf("err: %s", err)
43	}
44
45	for i := 0; i < 5; i++ {
46		if err := a.Shutdown(); err != nil {
47			t.Fatalf("err: %s", err)
48		}
49	}
50}
51
52func TestAgentUserEvent(t *testing.T) {
53	a1 := testAgent(nil)
54	defer a1.Shutdown()
55	defer a1.Leave()
56
57	handler := new(MockEventHandler)
58	a1.RegisterEventHandler(handler)
59
60	if err := a1.Start(); err != nil {
61		t.Fatalf("err: %s", err)
62	}
63
64	testutil.Yield()
65
66	if err := a1.UserEvent("deploy", []byte("foo"), false); err != nil {
67		t.Fatalf("err: %s", err)
68	}
69
70	testutil.Yield()
71
72	handler.Lock()
73	defer handler.Unlock()
74
75	if len(handler.Events) == 0 {
76		t.Fatal("no events")
77	}
78
79	e, ok := handler.Events[len(handler.Events)-1].(serf.UserEvent)
80	if !ok {
81		t.Fatalf("bad: %#v", e)
82	}
83
84	if e.Name != "deploy" {
85		t.Fatalf("bad: %#v", e)
86	}
87
88	if string(e.Payload) != "foo" {
89		t.Fatalf("bad: %#v", e)
90	}
91}
92
93func TestAgentQuery_BadPrefix(t *testing.T) {
94	a1 := testAgent(nil)
95	defer a1.Shutdown()
96	defer a1.Leave()
97
98	if err := a1.Start(); err != nil {
99		t.Fatalf("err: %s", err)
100	}
101
102	testutil.Yield()
103
104	_, err := a1.Query("_serf_test", nil, nil)
105	if err == nil || !strings.Contains(err.Error(), "cannot contain") {
106		t.Fatalf("err: %s", err)
107	}
108}
109
110func TestAgentTagsFile(t *testing.T) {
111	tags := map[string]string{
112		"role":       "webserver",
113		"datacenter": "us-east",
114	}
115
116	td, err := ioutil.TempDir("", "serf")
117	if err != nil {
118		t.Fatalf("err: %s", err)
119	}
120	defer os.RemoveAll(td)
121
122	agentConfig := DefaultConfig()
123	agentConfig.TagsFile = filepath.Join(td, "tags.json")
124
125	a1 := testAgentWithConfig(agentConfig, serf.DefaultConfig(), nil)
126
127	if err := a1.Start(); err != nil {
128		t.Fatalf("err: %s", err)
129	}
130	defer a1.Shutdown()
131	defer a1.Leave()
132
133	testutil.Yield()
134
135	err = a1.SetTags(tags)
136
137	if err != nil {
138		t.Fatalf("err: %s", err)
139	}
140
141	testutil.Yield()
142
143	a2 := testAgentWithConfig(agentConfig, serf.DefaultConfig(), nil)
144
145	if err := a2.Start(); err != nil {
146		t.Fatalf("err: %s", err)
147	}
148	defer a2.Shutdown()
149	defer a2.Leave()
150
151	testutil.Yield()
152
153	m := a2.Serf().LocalMember()
154
155	if !reflect.DeepEqual(m.Tags, tags) {
156		t.Fatalf("tags not restored: %#v", m.Tags)
157	}
158}
159
160func TestAgentTagsFile_BadOptions(t *testing.T) {
161	agentConfig := DefaultConfig()
162	agentConfig.TagsFile = "/some/path"
163	agentConfig.Tags = map[string]string{
164		"tag1": "val1",
165	}
166
167	_, err := Create(agentConfig, serf.DefaultConfig(), nil)
168	if err == nil || !strings.Contains(err.Error(), "not allowed") {
169		t.Fatalf("err: %s", err)
170	}
171}
172
173func TestAgent_MarshalTags(t *testing.T) {
174	tags := map[string]string{
175		"tag1": "val1",
176		"tag2": "val2",
177	}
178
179	tagPairs := MarshalTags(tags)
180
181	if !containsKey(tagPairs, "tag1=val1") {
182		t.Fatalf("bad: %v", tagPairs)
183	}
184	if !containsKey(tagPairs, "tag2=val2") {
185		t.Fatalf("bad: %v", tagPairs)
186	}
187}
188
189func TestAgent_UnmarshalTags(t *testing.T) {
190	tagPairs := []string{
191		"tag1=val1",
192		"tag2=val2",
193	}
194
195	tags, err := UnmarshalTags(tagPairs)
196
197	if err != nil {
198		t.Fatalf("err: %s", err)
199	}
200
201	if v, ok := tags["tag1"]; !ok || v != "val1" {
202		t.Fatalf("bad: %v", tags)
203	}
204	if v, ok := tags["tag2"]; !ok || v != "val2" {
205		t.Fatalf("bad: %v", tags)
206	}
207}
208
209func TestAgent_UnmarshalTagsError(t *testing.T) {
210	tagSets := [][]string{
211		[]string{"="},
212		[]string{"=x"},
213		[]string{""},
214		[]string{"x"},
215	}
216	for _, tagPairs := range tagSets {
217		if _, err := UnmarshalTags(tagPairs); err == nil {
218			t.Fatalf("Expected tag error: %s", tagPairs[0])
219		}
220	}
221}
222
223func TestAgentKeyringFile(t *testing.T) {
224	keys := []string{
225		"HvY8ubRZMgafUOWvrOadwOckVa1wN3QWAo46FVKbVN8=",
226		"T9jncgl9mbLus+baTTa7q7nPSUrXwbDi2dhbtqir37s=",
227		"5K9OtfP7efFrNKe5WCQvXvnaXJ5cWP0SvXiwe0kkjM4=",
228	}
229
230	td, err := ioutil.TempDir("", "serf")
231	if err != nil {
232		t.Fatalf("err: %s", err)
233	}
234	defer os.RemoveAll(td)
235
236	keyringFile := filepath.Join(td, "keyring.json")
237
238	serfConfig := serf.DefaultConfig()
239	agentConfig := DefaultConfig()
240	agentConfig.KeyringFile = keyringFile
241
242	encodedKeys, err := json.Marshal(keys)
243	if err != nil {
244		t.Fatalf("err: %s", err)
245	}
246
247	if err := ioutil.WriteFile(keyringFile, encodedKeys, 0600); err != nil {
248		t.Fatalf("err: %s", err)
249	}
250
251	a1 := testAgentWithConfig(agentConfig, serfConfig, nil)
252
253	if err := a1.Start(); err != nil {
254		t.Fatalf("err: %s", err)
255	}
256	defer a1.Shutdown()
257
258	testutil.Yield()
259
260	totalLoadedKeys := len(serfConfig.MemberlistConfig.Keyring.GetKeys())
261	if totalLoadedKeys != 3 {
262		t.Fatalf("Expected to load 3 keys but got %d", totalLoadedKeys)
263	}
264}
265
266func TestAgentKeyringFile_BadOptions(t *testing.T) {
267	agentConfig := DefaultConfig()
268	agentConfig.KeyringFile = "/some/path"
269	agentConfig.EncryptKey = "5K9OtfP7efFrNKe5WCQvXvnaXJ5cWP0SvXiwe0kkjM4="
270
271	_, err := Create(agentConfig, serf.DefaultConfig(), nil)
272	if err == nil || !strings.Contains(err.Error(), "not allowed") {
273		t.Fatalf("err: %s", err)
274	}
275}
276
277func TestAgentKeyringFile_NoKeys(t *testing.T) {
278	dir, err := ioutil.TempDir("", "serf")
279	if err != nil {
280		t.Fatalf("err: %s", err)
281	}
282	defer os.RemoveAll(dir)
283
284	keysFile := filepath.Join(dir, "keyring")
285	if err := ioutil.WriteFile(keysFile, []byte("[]"), 0600); err != nil {
286		t.Fatalf("err: %s", err)
287	}
288
289	agentConfig := DefaultConfig()
290	agentConfig.KeyringFile = keysFile
291
292	_, err = Create(agentConfig, serf.DefaultConfig(), nil)
293	if err == nil {
294		t.Fatalf("should have errored")
295	}
296	if !strings.Contains(err.Error(), "contains no keys") {
297		t.Fatalf("bad: %s", err)
298	}
299}
300