diff --git a/server/etcdserver/server_test.go b/server/etcdserver/server_test.go index 858aa32a076c..eb1b73baa895 100644 --- a/server/etcdserver/server_test.go +++ b/server/etcdserver/server_test.go @@ -99,8 +99,12 @@ func TestApplyRepeat(t *testing.T) { SyncTicker: &time.Ticker{}, consistIndex: cindex.NewFakeConsistentIndex(0), uberApply: uberApplierMock{}, + kv: mvcc.New(zaptest.NewLogger(t), be, &lease.FakeLessor{}, mvcc.StoreConfig{}), } s.start() + + n.readyc <- newDummyPutReqReady() + req := &pb.InternalRaftRequest{ Header: &pb.RequestHeader{ID: 1}, Put: &pb.PutRequest{Key: []byte("foo"), Value: []byte("bar")}, @@ -885,8 +889,12 @@ func TestAddMember(t *testing.T) { SyncTicker: &time.Ticker{}, consistIndex: cindex.NewFakeConsistentIndex(0), beHooks: serverstorage.NewBackendHooks(lg, nil), + kv: mvcc.New(zaptest.NewLogger(t), be, &lease.FakeLessor{}, mvcc.StoreConfig{}), } s.start() + + n.readyc <- newDummyPutReqReady() + m := membership.Member{ID: 1234, RaftAttributes: membership.RaftAttributes{PeerURLs: []string{"foo"}}} _, err := s.AddMember(context.Background(), m) gaction := n.Action() @@ -992,8 +1000,12 @@ func TestRemoveMember(t *testing.T) { SyncTicker: &time.Ticker{}, consistIndex: cindex.NewFakeConsistentIndex(0), beHooks: serverstorage.NewBackendHooks(lg, nil), + kv: mvcc.New(zaptest.NewLogger(t), be, &lease.FakeLessor{}, mvcc.StoreConfig{}), } s.start() + + n.readyc <- newDummyPutReqReady() + _, err := s.RemoveMember(context.Background(), 1234) gaction := n.Action() s.Stop() @@ -1041,8 +1053,12 @@ func TestUpdateMember(t *testing.T) { SyncTicker: &time.Ticker{}, consistIndex: cindex.NewFakeConsistentIndex(0), beHooks: serverstorage.NewBackendHooks(lg, nil), + kv: mvcc.New(zaptest.NewLogger(t), be, &lease.FakeLessor{}, mvcc.StoreConfig{}), } s.start() + + n.readyc <- newDummyPutReqReady() + wm := membership.Member{ID: 1234, RaftAttributes: membership.RaftAttributes{PeerURLs: []string{"http://127.0.0.1:1"}}} _, err := s.UpdateMember(context.Background(), wm) gaction := n.Action() @@ -1581,3 +1597,18 @@ func TestIsActive(t *testing.T) { require.Equal(t, tc.expectActive, s.isActive()) } } + +// newDummyPutReqReady creates a dummy raft.Ready. +// +// In unit tests, EtcdServer doesn't append raft log entries upon start like the full-featured etcd does. +// This can crash the program when creating a raft log snapshot due to no available entries. +// To append raft log entries, we can send a newDummyPutReqReady() to raft.Node's readyc after the server starts. +func newDummyPutReqReady() raft.Ready { + req := &pb.InternalRaftRequest{ + Header: &pb.RequestHeader{ID: 1}, + Put: &pb.PutRequest{Key: []byte("newDummyPutReqReady"), Value: []byte("bar")}, + } + ents := []raftpb.Entry{{Index: 1, Data: pbutil.MustMarshal(req)}} + + return raft.Ready{Entries: ents} +}