Merge pull request #1118 from unihorn/133

etcdserver: add TestRecvSnapshot
This commit is contained in:
Yicheng Qin
2014-09-20 17:10:01 -07:00
3 changed files with 101 additions and 19 deletions

View File

@ -13,6 +13,7 @@ import (
"github.com/coreos/etcd/raft"
"github.com/coreos/etcd/raft/raftpb"
"github.com/coreos/etcd/store"
"github.com/coreos/etcd/testutil"
"github.com/coreos/etcd/third_party/code.google.com/p/go.net/context"
)
@ -508,9 +509,6 @@ func TestSnapshot(t *testing.T) {
}
// Applied > SnapCount should trigger a SaveSnap event
// TODO: receive a snapshot from raft leader should also be able
// to trigger snapSave and also trigger a store.Recover.
// We need fake node!
func TestTriggerSnap(t *testing.T) {
ctx := context.Background()
n := raft.StartNode(0xBAD0, []int64{0xBAD0}, 10, 1)
@ -543,6 +541,63 @@ func TestTriggerSnap(t *testing.T) {
}
}
// TestRecvSnapshot tests when it receives a snapshot from raft leader,
// it should trigger storage.SaveSnap and also store.Recover.
func TestRecvSnapshot(t *testing.T) {
n := newReadyNode()
st := &storeRecorder{}
p := &storageRecorder{}
s := &EtcdServer{
Store: st,
Send: func(_ []raftpb.Message) {},
Storage: p,
Node: n,
}
s.Start()
n.readyc <- raft.Ready{Snapshot: raftpb.Snapshot{Index: 1}}
// make goroutines move forward to receive snapshot
testutil.ForceGosched()
s.Stop()
waction := []string{"Recovery"}
if g := st.Action(); !reflect.DeepEqual(g, waction) {
t.Errorf("store action = %v, want %v", g, waction)
}
waction = []string{"Save", "SaveSnap"}
if g := p.Action(); !reflect.DeepEqual(g, waction) {
t.Errorf("storage action = %v, want %v", g, waction)
}
}
// TestRecvSlowSnapshot tests that slow snapshot will not be applied
// to store.
func TestRecvSlowSnapshot(t *testing.T) {
n := newReadyNode()
st := &storeRecorder{}
s := &EtcdServer{
Store: st,
Send: func(_ []raftpb.Message) {},
Storage: &storageRecorder{},
Node: n,
}
s.Start()
n.readyc <- raft.Ready{Snapshot: raftpb.Snapshot{Index: 1}}
// make goroutines move forward to receive snapshot
testutil.ForceGosched()
action := st.Action()
n.readyc <- raft.Ready{Snapshot: raftpb.Snapshot{Index: 1}}
// make goroutines move forward to receive snapshot
testutil.ForceGosched()
s.Stop()
if g := st.Action(); !reflect.DeepEqual(g, action) {
t.Errorf("store action = %v, want %v", g, action)
}
}
// TODO: test wait trigger correctness in multi-server case
func TestGetBool(t *testing.T) {
@ -626,7 +681,10 @@ func (s *storeRecorder) Save() ([]byte, error) {
s.record("Save")
return nil, nil
}
func (s *storeRecorder) Recovery(b []byte) error { return nil }
func (s *storeRecorder) Recovery(b []byte) error {
s.record("Recovery")
return nil
}
func (s *storeRecorder) TotalTransactions() uint64 { return 0 }
func (s *storeRecorder) JsonStats() []byte { return nil }
func (s *storeRecorder) DeleteExpiredKeys(cutoff time.Time) {
@ -687,6 +745,25 @@ func (p *storageRecorder) SaveSnap(st raftpb.Snapshot) {
p.record("SaveSnap")
}
type readyNode struct {
readyc chan raft.Ready
}
func newReadyNode() *readyNode {
readyc := make(chan raft.Ready, 1)
return &readyNode{readyc: readyc}
}
func (n *readyNode) Tick() {}
func (n *readyNode) Campaign(ctx context.Context) error { return nil }
func (n *readyNode) Propose(ctx context.Context, data []byte) error { return nil }
func (n *readyNode) Configure(ctx context.Context, data []byte) error { return nil }
func (n *readyNode) Step(ctx context.Context, msg raftpb.Message) error { return nil }
func (n *readyNode) Ready() <-chan raft.Ready { return n.readyc }
func (n *readyNode) Stop() {}
func (n *readyNode) Compact(d []byte) {}
func (n *readyNode) AddNode(id int64) {}
func (n *readyNode) RemoveNode(id int64) {}
func TestGenID(t *testing.T) {
// Sanity check that the GenID function has been seeded appropriately
// (math/rand is seeded with 1 by default)