Example #1
0
func TestWatch(t *testing.T) {
	storeMock, err := libkvmock.New([]string{"127.0.0.1:1234"}, nil)
	assert.NotNil(t, storeMock)
	assert.NoError(t, err)

	d := &Discovery{backend: store.CONSUL}
	d.Initialize("127.0.0.1:1234/path", 0, 0)
	d.store = storeMock

	s := d.store.(*libkvmock.Mock)
	mockCh := make(chan []*store.KVPair)

	// The first watch will fail.
	s.On("WatchTree", "path/"+discoveryPath, mock.Anything).Return(mockCh, errors.New("test error")).Once()
	// The second one will succeed.
	s.On("WatchTree", "path/"+discoveryPath, mock.Anything).Return(mockCh, nil).Once()
	expected := discovery.Entries{
		&discovery.Entry{Host: "1.1.1.1", Port: "1111"},
		&discovery.Entry{Host: "2.2.2.2", Port: "2222"},
	}
	kvs := []*store.KVPair{
		{Key: path.Join("path", discoveryPath, "1.1.1.1"), Value: []byte("1.1.1.1:1111")},
		{Key: path.Join("path", discoveryPath, "2.2.2.2"), Value: []byte("2.2.2.2:2222")},
	}

	stopCh := make(chan struct{})
	ch, errCh := d.Watch(stopCh)

	// It should fire an error since the first WatchTree call failed.
	assert.EqualError(t, <-errCh, "test error")
	// We have to drain the error channel otherwise Watch will get stuck.
	go func() {
		for range errCh {
		}
	}()

	// Push the entries into the store channel and make sure discovery emits.
	mockCh <- kvs
	assert.Equal(t, <-ch, expected)

	// Add a new entry.
	expected = append(expected, &discovery.Entry{Host: "3.3.3.3", Port: "3333"})
	kvs = append(kvs, &store.KVPair{Key: path.Join("path", discoveryPath, "3.3.3.3"), Value: []byte("3.3.3.3:3333")})
	mockCh <- kvs
	assert.Equal(t, <-ch, expected)

	// Make sure that if an error occurs it retries.
	// This third call to WatchTree will be checked later by AssertExpectations.
	s.On("WatchTree", "path/"+discoveryPath, mock.Anything).Return(mockCh, nil)
	close(mockCh)
	// Give it enough time to call WatchTree.
	time.Sleep(3)

	// Stop and make sure it closes all channels.
	close(stopCh)
	assert.Nil(t, <-ch)
	assert.Nil(t, <-errCh)

	s.AssertExpectations(t)
}
Example #2
0
func TestInitialize(t *testing.T) {
	storeMock, err := libkvmock.New([]string{"127.0.0.1"}, nil)
	assert.NotNil(t, storeMock)
	assert.NoError(t, err)

	d := &Discovery{backend: store.CONSUL}
	d.Initialize("127.0.0.1", 0, 0, nil)
	d.store = storeMock

	s := d.store.(*libkvmock.Mock)
	assert.Len(t, s.Endpoints, 1)
	assert.Equal(t, s.Endpoints[0], "127.0.0.1")
	assert.Equal(t, d.path, discoveryPath)

	storeMock, err = libkvmock.New([]string{"127.0.0.1:1234"}, nil)
	assert.NotNil(t, storeMock)
	assert.NoError(t, err)

	d = &Discovery{backend: store.CONSUL}
	d.Initialize("127.0.0.1:1234/path", 0, 0, nil)
	d.store = storeMock

	s = d.store.(*libkvmock.Mock)
	assert.Len(t, s.Endpoints, 1)
	assert.Equal(t, s.Endpoints[0], "127.0.0.1:1234")
	assert.Equal(t, d.path, "path/"+discoveryPath)

	storeMock, err = libkvmock.New([]string{"127.0.0.1:1234", "127.0.0.2:1234", "127.0.0.3:1234"}, nil)
	assert.NotNil(t, storeMock)
	assert.NoError(t, err)

	d = &Discovery{backend: store.CONSUL}
	d.Initialize("127.0.0.1:1234,127.0.0.2:1234,127.0.0.3:1234/path", 0, 0, nil)
	d.store = storeMock

	s = d.store.(*libkvmock.Mock)
	if assert.Len(t, s.Endpoints, 3) {
		assert.Equal(t, s.Endpoints[0], "127.0.0.1:1234")
		assert.Equal(t, s.Endpoints[1], "127.0.0.2:1234")
		assert.Equal(t, s.Endpoints[2], "127.0.0.3:1234")
	}
	assert.Equal(t, d.path, "path/"+discoveryPath)
}
Example #3
0
func (ds *DiscoverySuite) TestInitialize(c *check.C) {
	storeMock, err := libkvmock.New([]string{"127.0.0.1"}, nil)
	c.Assert(storeMock, check.NotNil)
	c.Assert(err, check.IsNil)

	d := &Discovery{backend: store.CONSUL}
	d.Initialize("127.0.0.1", 0, 0)
	d.store = storeMock

	s := d.store.(*libkvmock.Mock)
	c.Assert(s.Endpoints, check.HasLen, 1)
	c.Assert(s.Endpoints[0], check.Equals, "127.0.0.1")
	c.Assert(d.path, check.Equals, discoveryPath)

	storeMock, err = libkvmock.New([]string{"127.0.0.1:1234"}, nil)
	c.Assert(storeMock, check.NotNil)
	c.Assert(err, check.IsNil)

	d = &Discovery{backend: store.CONSUL}
	d.Initialize("127.0.0.1:1234/path", 0, 0)
	d.store = storeMock

	s = d.store.(*libkvmock.Mock)
	c.Assert(s.Endpoints, check.HasLen, 1)
	c.Assert(s.Endpoints[0], check.Equals, "127.0.0.1:1234")
	c.Assert(d.path, check.Equals, "path/"+discoveryPath)

	storeMock, err = libkvmock.New([]string{"127.0.0.1:1234", "127.0.0.2:1234", "127.0.0.3:1234"}, nil)
	c.Assert(storeMock, check.NotNil)
	c.Assert(err, check.IsNil)

	d = &Discovery{backend: store.CONSUL}
	d.Initialize("127.0.0.1:1234,127.0.0.2:1234,127.0.0.3:1234/path", 0, 0)
	d.store = storeMock

	s = d.store.(*libkvmock.Mock)
	c.Assert(s.Endpoints, check.HasLen, 3)
	c.Assert(s.Endpoints[0], check.Equals, "127.0.0.1:1234")
	c.Assert(s.Endpoints[1], check.Equals, "127.0.0.2:1234")
	c.Assert(s.Endpoints[2], check.Equals, "127.0.0.3:1234")

	c.Assert(d.path, check.Equals, "path/"+discoveryPath)
}
Example #4
0
func TestCandidate(t *testing.T) {
	kv, err := libkvmock.New([]string{}, nil)
	assert.NoError(t, err)
	assert.NotNil(t, kv)

	mockStore := kv.(*libkvmock.Mock)
	mockLock := &libkvmock.Lock{}
	mockStore.On("NewLock", "test_key", mock.Anything).Return(mockLock, nil)

	// Lock and unlock always succeeds.
	lostCh := make(chan struct{})
	var mockLostCh <-chan struct{} = lostCh
	mockLock.On("Lock", mock.Anything).Return(mockLostCh, nil)
	mockLock.On("Unlock").Return(nil)

	candidate := NewCandidate(kv, "test_key", "test_node", 0)
	electedCh, _, err := candidate.RunForElection()
	assert.Nil(t, err)

	// Should issue a false upon start, no matter what.
	assert.False(t, <-electedCh)

	// Since the lock always succeeeds, we should get elected.
	assert.True(t, <-electedCh)
	assert.True(t, candidate.IsLeader())

	// Signaling a lost lock should get us de-elected...
	close(lostCh)
	assert.False(t, <-electedCh)

	// And we should attempt to get re-elected again.
	assert.True(t, <-electedCh)

	// When we resign, unlock will get called, we'll be notified of the
	// de-election and we'll try to get the lock again.
	go candidate.Resign()
	assert.False(t, <-electedCh)
	assert.True(t, <-electedCh)

	candidate.Stop()

	// Ensure that the chan closes after some time
	for {
		select {
		case _, open := <-electedCh:
			if !open {
				mockStore.AssertExpectations(t)
				return
			}
		case <-time.After(1 * time.Second):
			t.Fatalf("electedCh not closed correctly")
		}
	}
}
Example #5
0
func TestFollower(t *testing.T) {
	kv, err := libkvmock.New([]string{}, nil)
	assert.NoError(t, err)
	assert.NotNil(t, kv)

	mockStore := kv.(*libkvmock.Mock)

	kvCh := make(chan *store.KVPair)
	var mockKVCh <-chan *store.KVPair = kvCh
	mockStore.On("Watch", "test_key", mock.Anything).Return(mockKVCh, nil)

	follower := NewFollower(kv, "test_key")
	leaderCh, errCh, err := follower.FollowElection()
	assert.Nil(t, err)

	// Simulate leader updates
	go func() {
		kvCh <- &store.KVPair{Key: "test_key", Value: []byte("leader1")}
		kvCh <- &store.KVPair{Key: "test_key", Value: []byte("leader1")}
		kvCh <- &store.KVPair{Key: "test_key", Value: []byte("leader2")}
		kvCh <- &store.KVPair{Key: "test_key", Value: []byte("leader1")}
	}()

	// We shouldn't see duplicate events.
	assert.Equal(t, <-leaderCh, "leader1")
	assert.Equal(t, <-leaderCh, "leader2")
	assert.Equal(t, <-leaderCh, "leader1")
	assert.Equal(t, follower.Leader(), "leader1")

	// Once stopped, iteration over the leader channel should stop.
	follower.Stop()
	close(kvCh)

	// Assert that we receive an error from the error chan to deal with the failover
	err, open := <-errCh
	assert.True(t, open)
	assert.NotNil(t, err)

	// Ensure that the chan is closed
	_, open = <-leaderCh
	assert.False(t, open)

	mockStore.AssertExpectations(t)
}
Example #6
0
func TestFollower(t *testing.T) {
	kv, err := libkvmock.New([]string{}, nil)
	assert.NoError(t, err)
	assert.NotNil(t, kv)

	mockStore := kv.(*libkvmock.Mock)

	kvCh := make(chan *store.KVPair)
	var mockKVCh <-chan *store.KVPair = kvCh
	mockStore.On("Watch", "test_key", mock.Anything).Return(mockKVCh, nil)

	follower := NewFollower(kv, "test_key")
	follower.FollowElection()
	leaderCh := follower.LeaderCh()

	// Simulate leader updates
	go func() {
		kvCh <- &store.KVPair{Key: "test_key", Value: []byte("leader1")}
		kvCh <- &store.KVPair{Key: "test_key", Value: []byte("leader1")}
		kvCh <- &store.KVPair{Key: "test_key", Value: []byte("leader2")}
		kvCh <- &store.KVPair{Key: "test_key", Value: []byte("leader1")}
	}()

	// We shouldn't see duplicate events.
	assert.Equal(t, <-leaderCh, "leader1")
	assert.Equal(t, <-leaderCh, "leader2")
	assert.Equal(t, <-leaderCh, "leader1")
	assert.Equal(t, follower.Leader(), "leader1")

	// Once stopped, iteration over the leader channel should stop.
	follower.Stop()
	close(kvCh)
	assert.Equal(t, "", <-leaderCh)

	mockStore.AssertExpectations(t)
}