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