func TestDefaultClient(t *testing.T) { _, cleanup := testutil.SetupDiscoverd(t) defer cleanup() serviceName := "defaultClientTest" assert(discoverd.Register(serviceName, ":1111"), t) assert(discoverd.Register(serviceName, ":2222"), t) assert(discoverd.Register(serviceName, ":3333"), t) services, err := discoverd.Services(serviceName, 1) assert(err, t) if len(services) != 3 { t.Fatal("Wrong number of services") } assert(discoverd.UnregisterAll(), t) set, err := discoverd.NewServiceSet(serviceName) assert(err, t) if len(set.Services()) != 0 { t.Fatal("There should be no services") } assert(set.Close(), t) discoverd.DefaultClient.Close() discoverd.DefaultClient = nil }
func TestUnregisterAll(t *testing.T) { client, cleanup := testutil.SetupDiscoverd(t) defer cleanup() serviceName := "unregisterAllTest" assert(client.Register(serviceName, ":1111"), t) assert(client.Register(serviceName, ":2222"), t) assert(client.Register(serviceName, ":3333"), t) services, err := client.Services(serviceName, 1) assert(err, t) if len(services) != 3 { t.Fatal("Wrong number of services") } assert(client.UnregisterAll(), t) set, err := client.NewServiceSet(serviceName) assert(err, t) if len(set.Services()) != 0 { t.Fatal("There should be no services") } assert(set.Close(), t) }
func TestRegisterWithSetLeaderSelf(t *testing.T) { client, cleanup := testutil.SetupDiscoverd(t) defer cleanup() serviceName := "registerWithSetLeaderSelfTest" assert(client.Register(serviceName, ":1111"), t) set, err := client.RegisterWithSet(serviceName, ":2222", nil) assert(err, t) leader := make(chan *discoverd.Service, 2) go func() { leaders := set.Leaders() for { leader <- <-leaders } }() assert(client.Register(serviceName, ":3333"), t) if (<-leader).Addr != "127.0.0.1:1111" { t.Fatal("Incorrect leader") } assert(client.Unregister(serviceName, ":1111"), t) if (<-leader).Addr != set.SelfAddr() { t.Fatal("Incorrect leader", leader) } assert(set.Close(), t) }
func TestServiceAge(t *testing.T) { client, cleanup := testutil.SetupDiscoverd(t) defer cleanup() serviceName := "ageTest" checkOldest := func(addr string) { services, err := client.Services(serviceName, 1) assert(err, t) if services[0].Addr != "127.0.0.1"+addr { t.Fatal("Oldest service is not first in Services() slice") } } assert(client.Register(serviceName, ":1111"), t) checkOldest(":1111") assert(client.Register(serviceName, ":2222"), t) checkOldest(":1111") assert(client.Register(serviceName, ":3333"), t) checkOldest(":1111") assert(client.Register(serviceName, ":4444"), t) checkOldest(":1111") assert(client.Unregister(serviceName, ":1111"), t) checkOldest(":2222") }
func TestWatch(t *testing.T) { client, cleanup := testutil.SetupDiscoverd(t) defer cleanup() serviceName := "watchTest" assert(client.Register(serviceName, ":1111"), t) assert(client.Register(serviceName, ":2222"), t) set, err := client.NewServiceSet(serviceName) assert(err, t) updates := set.Watch(true) assert(client.Register(serviceName, ":3333"), t) for i := 0; i < 3; i++ { var update *agent.ServiceUpdate select { case update = <-updates: case <-time.After(3 * time.Second): t.Fatal("Timeout exceeded", i) } if update.Online != true { t.Fatal("Service update of unexected status: ", update, i) } if update.Name != serviceName { t.Fatal("Service update of unexected name: ", update, i) } } assert(set.Close(), t) }
func TestBasicRegisterAndServiceSet(t *testing.T) { client, cleanup := testutil.SetupDiscoverd(t) defer cleanup() serviceName := "basicTest" assert(client.RegisterWithAttributes(serviceName, ":1111", map[string]string{"foo": "bar"}), t) assert(client.Register(serviceName, ":2222"), t) set, err := client.NewServiceSet(serviceName) assert(err, t) waitUpdates(t, set, true, 2)() if len(set.Services()) < 2 || len(set.Addrs()) < 2 { t.Fatal("Registered services not online") } wait := waitUpdates(t, set, false, 1) assert(client.Unregister(serviceName, ":2222"), t) wait() if len(set.Services()) != 1 || len(set.Addrs()) != 1 { t.Fatal("Only 1 registered service should be left") } if set.Services()[0].Attrs["foo"] != "bar" { t.Fatal("Attribute not set on service as 'bar'") } assert(set.Close(), t) }
func TestRegisterWithSet(t *testing.T) { client, cleanup := testutil.SetupDiscoverd(t) defer cleanup() serviceName := "registerWithSetTest" assert(client.Register(serviceName, ":1111"), t) set, err := client.RegisterWithSet(serviceName, ":2222", nil) assert(err, t) if len(set.Services()) != 1 { t.Fatal("There should only be one other service") } if set.Services()[0].Addr != "127.0.0.1:1111" { t.Fatal("Set contains the wrong service") } assert(set.Close(), t) services, err := client.Services(serviceName, 1) assert(err, t) if len(services) != 2 { t.Fatal("Not all registered services were returned:", services) } }
func TestHeartbeat(t *testing.T) { client, cleanup := testutil.SetupDiscoverd(t) defer cleanup() serviceName := "heartbeatTest" assert(client.Register(serviceName, ":1111"), t) time.Sleep(12 * time.Second) // wait for one heartbeat services, err := client.Services(serviceName, 1) assert(err, t) if len(services) != 1 { t.Fatal("Missing services") } }
func TestNoServices(t *testing.T) { client, cleanup := testutil.SetupDiscoverd(t) defer cleanup() set, err := client.NewServiceSet("nonexistent") assert(err, t) if len(set.Services()) != 0 { t.Fatal("There should be no services") } assert(set.Close(), t) }
func TestServices(t *testing.T) { client, cleanup := testutil.SetupDiscoverd(t) defer cleanup() serviceName := "servicesTest" assert(client.Register(serviceName, ":1111"), t) assert(client.Register(serviceName, ":2222"), t) services, err := client.Services(serviceName, 1) assert(err, t) if len(services) != 2 { t.Fatal("Not all registered services were returned:", services) } }
func TestLeaderChannel(t *testing.T) { client, cleanup := testutil.SetupDiscoverd(t) defer cleanup() serviceName := "leadersTest" assert(client.Register(serviceName, ":1111"), t) set, err := client.NewServiceSet(serviceName) assert(err, t) leader := make(chan *discoverd.Service, 3) go func() { leaders := set.Leaders() for { leader <- <-leaders } }() if (<-leader).Addr != "127.0.0.1:1111" { t.Fatal("Incorrect leader") } assert(client.Unregister(serviceName, ":1111"), t) if (<-leader) != nil { t.Fatal("Incorrect leader") } assert(client.Register(serviceName, ":2222"), t) assert(client.Register(serviceName, ":3333"), t) if (<-leader).Addr != "127.0.0.1:2222" { t.Fatal("Incorrect leader", leader) } assert(client.Unregister(serviceName, ":2222"), t) if (<-leader).Addr != "127.0.0.1:3333" { t.Fatal("Incorrect leader") } assert(set.Close(), t) }
func TestSelecting(t *testing.T) { client, cleanup := testutil.SetupDiscoverd(t) defer cleanup() serviceName := "selectTest" set, err := client.NewServiceSet(serviceName) assert(err, t) assert(client.Register(serviceName, ":1111"), t) assert(client.RegisterWithAttributes(serviceName, ":2222", map[string]string{"foo": "qux", "id": "2"}), t) assert(client.RegisterWithAttributes(serviceName, ":3333", map[string]string{"foo": "qux", "id": "3"}), t) waitUpdates(t, set, true, 3)() if s := set.Select(map[string]string{"id": "3"}); len(s) != 1 { t.Fatalf("Expected one service, got: %#v", s) } assert(set.Close(), t) }
func TestRegisterAndStandby(t *testing.T) { client, cleanup := testutil.SetupDiscoverd(t) defer cleanup() serviceName := "registerAndStandbyTest" assert(client.Register(serviceName, ":1111"), t) standbyCh, err := client.RegisterAndStandby(serviceName, ":2222", nil) assert(err, t) assert(client.Register(serviceName, ":3333"), t) assert(client.Unregister(serviceName, ":3333"), t) assert(client.Unregister(serviceName, ":1111"), t) leader := <-standbyCh if leader.Addr != "127.0.0.1:2222" { t.Fatal("Incorrect leader", leader) } }
func TestNewAttributes(t *testing.T) { client, cleanup := testutil.SetupDiscoverd(t) defer cleanup() serviceName := "attributeTest" set, err := client.NewServiceSet(serviceName) assert(err, t) assert(client.RegisterWithAttributes(serviceName, ":1111", map[string]string{"foo": "bar"}), t) waitUpdates(t, set, true, 1)() wait := waitUpdates(t, set, false, 1) assert(client.RegisterWithAttributes(serviceName, ":1111", map[string]string{"foo": "baz"}), t) wait() if s := set.Services()[0]; s.Attrs["foo"] != "baz" { t.Fatalf(`Expected attribute set on re-registered service to be "baz", not %q`, s.Attrs["foo"]) } assert(set.Close(), t) }
func TestHTTPClient(t *testing.T) { client, cleanup := testutil.SetupDiscoverd(t) defer cleanup() hc := dialer.NewHTTPClient(client) _, err := hc.Get("http://httpclient/") if ue, ok := err.(*url.Error); !ok || ue.Err != balancer.ErrNoServices { t.Error("Expected err to be ErrNoServices, got", ue.Err) } s := httptest.NewServer(nil) defer s.Close() client.Register("httpclient", s.URL[7:]) set, _ := discoverd.NewServiceSet("httpclient") waitUpdates(t, set, true, 1)() set.Close() _, err = hc.Get("http://httpclient/") if err != nil { t.Error("Unexpected error during request:", err) } }
func TestFiltering(t *testing.T) { client, cleanup := testutil.SetupDiscoverd(t) defer cleanup() serviceName := "filterTest" set, err := client.NewServiceSet(serviceName) assert(err, t) watchSet, err := client.NewServiceSet(serviceName) assert(err, t) assert(client.Register(serviceName, ":1111"), t) assert(client.RegisterWithAttributes(serviceName, ":2222", map[string]string{"foo": "qux", "id": "2"}), t) set.Filter(map[string]string{"foo": "qux"}) waitUpdates(t, watchSet, true, 2)() if len(set.Services()) > 1 { t.Fatal("Filter not limiting online services in set") } assert(client.RegisterWithAttributes(serviceName, ":3333", map[string]string{"foo": "qux", "id": "3"}), t) waitUpdates(t, set, true, 2)() if s := set.Services(); len(s) < 2 { t.Fatalf("Filter not letting new matching services in set: %#v", s[0]) } assert(client.RegisterWithAttributes(serviceName, ":4444", map[string]string{"foo": "baz"}), t) waitUpdates(t, watchSet, true, 4)() if len(set.Services()) > 2 { t.Fatal("Filter not limiting new unmatching services from set") } assert(set.Close(), t) assert(watchSet.Close(), t) }
func (s *ClientSuite) TestWatchReconnect(c *C) { c.Skip("fix discoverd watch reconnect") // FIXME(benbjohnson) raftPort, err := testutil.RandomPort() c.Assert(err, IsNil) httpPort, err := testutil.RandomPort() c.Assert(err, IsNil) // clientA is used to register services and instances, and remains connected clientA, cleanup := testutil.SetupDiscoverd(c) defer cleanup() // clientB is connected to the server which will be restarted, and is used to // test that the watch generates the correct events after reconnecting clientB, killDiscoverd := testutil.BootDiscoverd(c, raftPort, httpPort) defer func() { killDiscoverd() }() // create a service with manual leader and some metadata service := "foo" config := &discoverd.ServiceConfig{LeaderType: discoverd.LeaderTypeManual} c.Assert(clientA.AddService(service, config), IsNil) serviceMeta := &discoverd.ServiceMeta{Data: []byte(`{"foo": "bar"}`)} c.Assert(clientA.Service(service).SetMeta(serviceMeta), IsNil) register := func(client *discoverd.Client, addr string, meta map[string]string) (discoverd.Heartbeater, *discoverd.Instance) { inst := &discoverd.Instance{Addr: addr, Proto: "tcp", Meta: meta} hb, err := client.RegisterInstance(service, inst) c.Assert(err, IsNil) return hb, inst } waitForEvent := func(events chan *discoverd.Event, addr string, kind discoverd.EventKind) { for { select { case e := <-events: if e.Kind == kind && (addr == "" || addr == e.Instance.Addr) { return } case <-time.After(10 * time.Second): c.Fatalf("timed out wating for %s event", kind) } } } waitForWatchState := func(ch chan discoverd.WatchState, state discoverd.WatchState) { for { select { case s := <-ch: if s == state { return } case <-time.After(10 * time.Second): c.Fatalf("timed out waiting for watch %s state", state) } } } // register three services register(clientA, ":1111", nil) hb2, _ := register(clientA, ":2222", map[string]string{"foo": "bar"}) hb3, _ := register(clientA, ":3333", nil) // create watches using both clients so we can synchronize assertions eventsA := make(chan *discoverd.Event) watchA, err := clientA.Service(service).Watch(eventsA) c.Assert(err, IsNil) defer watchA.Close() waitForEvent(eventsA, "", discoverd.EventKindCurrent) eventsB := make(chan *discoverd.Event) watchB, err := clientB.Service(service).Watch(eventsB) c.Assert(err, IsNil) defer watchB.Close() waitForEvent(eventsB, "", discoverd.EventKindCurrent) // kill clientB's server and wait for the watch to disconnect stateCh := make(chan discoverd.WatchState) watchB.(*discoverd.Watch).SetStateChannel(stateCh) killDiscoverd() waitForWatchState(stateCh, discoverd.WatchStateDisconnected) // make some changes using clientA // change some metadata c.Assert(hb2.SetMeta(map[string]string{"foo": "baz"}), IsNil) waitForEvent(eventsA, ":2222", discoverd.EventKindUpdate) // register a new instance _, inst := register(clientA, ":4444", nil) waitForEvent(eventsA, ":4444", discoverd.EventKindUp) // set a new leader clientA.Service(service).SetLeader(inst.ID) waitForEvent(eventsA, ":4444", discoverd.EventKindLeader) // unregister an instance hb3.Close() waitForEvent(eventsA, ":3333", discoverd.EventKindDown) // update the service metadata serviceMeta.Data = []byte(`{"foo": "baz"}`) c.Assert(clientA.Service(service).SetMeta(serviceMeta), IsNil) waitForEvent(eventsA, "", discoverd.EventKindServiceMeta) // restart clientB's server and wait for the watch to reconnect _, killDiscoverd = testutil.RunDiscoverdServer(c, raftPort, httpPort) waitForWatchState(stateCh, discoverd.WatchStateConnected) type expectedEvent struct { Addr string Kind discoverd.EventKind ServiceMeta *discoverd.ServiceMeta } assertCurrent := func(events chan *discoverd.Event, expected []*expectedEvent) { count := 0 isExpected := func(event *discoverd.Event) bool { for _, e := range expected { if e.Kind != event.Kind { continue } switch event.Kind { case discoverd.EventKindServiceMeta: if reflect.DeepEqual(event.ServiceMeta, e.ServiceMeta) { return true } default: if event.Instance != nil && event.Instance.Addr == e.Addr { return true } } } return false } for { select { case event := <-events: if event.Kind == discoverd.EventKindCurrent { if count != len(expected) { c.Fatalf("expected %d events, got %d", len(expected), count) } return } if !isExpected(event) { c.Fatalf("unexpected event: %+v", event) } count++ case <-time.After(10 * time.Second): c.Fatal("timed out waiting for events") } } } // check watchB emits missed events assertCurrent(eventsB, []*expectedEvent{ {Addr: ":2222", Kind: discoverd.EventKindUpdate}, {Addr: ":4444", Kind: discoverd.EventKindUp}, {Addr: ":4444", Kind: discoverd.EventKindLeader}, {Kind: discoverd.EventKindServiceMeta, ServiceMeta: serviceMeta}, {Addr: ":3333", Kind: discoverd.EventKindDown}, }) }
func TestReconnect(t *testing.T) { clientA, cleanup := testutil.SetupDiscoverd(t) defer cleanup() clientB, killDiscoverd := testutil.BootDiscoverd(t, "127.0.0.1:1112") defer func() { clientB.UnregisterAll() clientB.Close() killDiscoverd() }() service1 := "serviceReconnect-1" service2 := "serviceReconnect-2" assert(clientA.Register(service1, ":1111"), t) assert(clientA.Register(service1, ":2222"), t) assert(clientA.Register(service2, ":1111"), t) assert(clientA.Register(service2, ":2222"), t) set1, err := clientB.NewServiceSet(service1) assert(err, t) waitUpdates(t, set1, true, 2)() set2, err := clientB.NewServiceSet(service2) assert(err, t) waitUpdates(t, set2, true, 2)() updates1 := set1.Watch(false) updates2 := set2.Watch(false) reconnCh := clientB.WatchReconnects() defer clientB.UnwatchReconnects(reconnCh) killDiscoverd() waitForConnStatus(t, reconnCh, discoverd.ConnStatusDisconnected) if err := clientB.Register(service1, ":3333"); err != discoverd.ErrDisconnected { t.Fatal("expected ErrDisconnected from clientB, got:", err) } if _, err := clientB.Services(service2, 1); err != discoverd.ErrDisconnected { t.Fatal("expected ErrDisconnected from clientB, got:", err) } assert(clientA.RegisterWithAttributes(service1, ":1111", map[string]string{"foo": "bar"}), t) assert(clientA.Unregister(service1, ":2222"), t) assert(clientA.Unregister(service2, ":1111"), t) assert(clientA.Register(service2, ":3333"), t) killDiscoverd = testutil.RunDiscoverdServer(t, "127.0.0.1:1112") waitForConnStatus(t, reconnCh, discoverd.ConnStatusConnected) // use goroutines to check for updates so slow watchers don't block the rpc stream updateErrors := make(chan error) go func() { updateErrors <- checkUpdates(updates1, []*agent.ServiceUpdate{ { Name: service1, Addr: "127.0.0.1:1111", Online: true, Attrs: map[string]string{"foo": "bar"}, }, { Name: service1, Addr: "127.0.0.1:2222", Online: false, }, }) }() go func() { updateErrors <- checkUpdates(updates2, []*agent.ServiceUpdate{ { Name: service2, Addr: "127.0.0.1:3333", Online: true, }, { Name: service2, Addr: "127.0.0.1:2222", Online: true, }, { Name: service2, Addr: "127.0.0.1:1111", Online: false, }, }) }() var updateError error for i := 0; i < 2; i++ { if err := <-updateErrors; err != nil && updateError == nil { updateError = err } } if updateError != nil { t.Fatal(updateError) } assert(clientA.Register(service1, ":3333"), t) if err := checkUpdate(updates1, &agent.ServiceUpdate{ Name: service1, Addr: "127.0.0.1:3333", Online: true, }); err != nil { t.Fatal(err) } // wait for one heartbeat time.Sleep(agent.HeartbeatIntervalSecs*time.Second + time.Second) checkServices(t, set1.Services(), []*discoverd.Service{ {Name: service1, Host: "127.0.0.1", Port: "1111", Addr: "127.0.0.1:1111", Attrs: map[string]string{"foo": "bar"}}, {Name: service1, Host: "127.0.0.1", Port: "3333", Addr: "127.0.0.1:3333"}, }) checkServices(t, set2.Services(), []*discoverd.Service{ {Name: service2, Host: "127.0.0.1", Port: "2222", Addr: "127.0.0.1:2222"}, {Name: service2, Host: "127.0.0.1", Port: "3333", Addr: "127.0.0.1:3333"}, }) }