Beispiel #1
0
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
}
Beispiel #2
0
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)

}
Beispiel #3
0
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)

}
Beispiel #4
0
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")

}
Beispiel #5
0
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)
}
Beispiel #6
0
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)
}
Beispiel #7
0
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)
	}
}
Beispiel #8
0
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")
	}
}
Beispiel #9
0
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)
}
Beispiel #10
0
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)
	}
}
Beispiel #11
0
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)
}
Beispiel #12
0
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)
}
Beispiel #13
0
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)
	}

}
Beispiel #14
0
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)
}
Beispiel #15
0
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)
	}
}
Beispiel #16
0
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)
}
Beispiel #17
0
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},
	})
}
Beispiel #18
0
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"},
	})
}