From ac6cd03365991af2164af8ec0b922e2bf5c9ca57 Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Fri, 2 Jan 2015 10:56:09 -0800 Subject: [PATCH 1/3] etcdserver: refactor server_test.go --- etcdserver/server_test.go | 40 +++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/etcdserver/server_test.go b/etcdserver/server_test.go index 1f7147253..521927eba 100644 --- a/etcdserver/server_test.go +++ b/etcdserver/server_test.go @@ -53,7 +53,7 @@ func TestDoLocalAction(t *testing.T) { }{ { pb.Request{Method: "GET", ID: 1, Wait: true}, - Response{Watcher: &stubWatcher{}}, nil, []action{action{name: "Watch"}}, + Response{Watcher: &nopWatcher{}}, nil, []action{action{name: "Watch"}}, }, { pb.Request{Method: "GET", ID: 1}, @@ -116,11 +116,17 @@ func TestDoBadLocalAction(t *testing.T) { }, { pb.Request{Method: "GET", ID: 1}, - []action{action{name: "Get"}}, + []action{action{ + name: "Get", + params: []interface{}{"", false, false}, + }}, }, { pb.Request{Method: "HEAD", ID: 1}, - []action{action{name: "Get"}}, + []action{action{ + name: "Get", + params: []interface{}{"", false, false}, + }}, }, } for i, tt := range tests { @@ -1131,9 +1137,10 @@ func (r *recorder) Action() []action { return cpy } -type storeRecorder struct { - recorder -} +// storeRecorder records all the methods it receives. +// storeRecorder DOES NOT work as a actual store. +// It always returns invaild empty response and no error. +type storeRecorder struct{ recorder } func (s *storeRecorder) Version() int { return 0 } func (s *storeRecorder) Index() uint64 { return 0 } @@ -1188,7 +1195,7 @@ func (s *storeRecorder) CompareAndDelete(path, prevVal string, prevIdx uint64) ( } func (s *storeRecorder) Watch(_ string, _, _ bool, _ uint64) (store.Watcher, error) { s.record(action{name: "Watch"}) - return &stubWatcher{}, nil + return &nopWatcher{}, nil } func (s *storeRecorder) Save() ([]byte, error) { s.record(action{name: "Save"}) @@ -1206,24 +1213,25 @@ func (s *storeRecorder) DeleteExpiredKeys(cutoff time.Time) { }) } -type stubWatcher struct{} +type nopWatcher struct{} -func (w *stubWatcher) EventChan() chan *store.Event { return nil } -func (w *stubWatcher) StartIndex() uint64 { return 0 } -func (w *stubWatcher) Remove() {} +func (w *nopWatcher) EventChan() chan *store.Event { return nil } +func (w *nopWatcher) StartIndex() uint64 { return 0 } +func (w *nopWatcher) Remove() {} -// errStoreRecorder returns an store error on Get, Watch request +// errStoreRecorder is a storeRecorder, but returns the given error on +// Get, Watch methods. type errStoreRecorder struct { storeRecorder err error } -func (s *errStoreRecorder) Get(_ string, _, _ bool) (*store.Event, error) { - s.record(action{name: "Get"}) +func (s *errStoreRecorder) Get(path string, recursive, sorted bool) (*store.Event, error) { + s.storeRecorder.Get(path, recursive, sorted) return nil, s.err } -func (s *errStoreRecorder) Watch(_ string, _, _ bool, _ uint64) (store.Watcher, error) { - s.record(action{name: "Watch"}) +func (s *errStoreRecorder) Watch(path string, recursive, sorted bool, index uint64) (store.Watcher, error) { + s.storeRecorder.Watch(path, recursive, sorted, index) return nil, s.err } From 27d47977d92ff162679e070426f76f934c11f858 Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Fri, 2 Jan 2015 11:21:23 -0800 Subject: [PATCH 2/3] etcdserver: move recorder to testutil --- etcdserver/cluster_test.go | 13 +- etcdserver/server_test.go | 378 +++++++++++++++++-------------------- pkg/testutil/recorder.go | 42 +++++ 3 files changed, 226 insertions(+), 207 deletions(-) create mode 100644 pkg/testutil/recorder.go diff --git a/etcdserver/cluster_test.go b/etcdserver/cluster_test.go index 52a7e609d..1836f5753 100644 --- a/etcdserver/cluster_test.go +++ b/etcdserver/cluster_test.go @@ -23,6 +23,7 @@ import ( "reflect" "testing" + "github.com/coreos/etcd/pkg/testutil" "github.com/coreos/etcd/pkg/types" "github.com/coreos/etcd/raft/raftpb" "github.com/coreos/etcd/store" @@ -535,10 +536,10 @@ func TestClusterAddMember(t *testing.T) { c.SetStore(st) c.AddMember(newTestMember(1, nil, "node1", nil)) - wactions := []action{ + wactions := []testutil.Action{ { - name: "Create", - params: []interface{}{ + Name: "Create", + Params: []interface{}{ path.Join(storeMembersPrefix, "1", "raftAttributes"), false, `{"peerURLs":null}`, @@ -623,9 +624,9 @@ func TestClusterRemoveMember(t *testing.T) { c.SetStore(st) c.RemoveMember(1) - wactions := []action{ - {name: "Delete", params: []interface{}{memberStoreKey(1), true, true}}, - {name: "Create", params: []interface{}{removedMemberStoreKey(1), false, "", false, store.Permanent}}, + wactions := []testutil.Action{ + {Name: "Delete", Params: []interface{}{memberStoreKey(1), true, true}}, + {Name: "Create", Params: []interface{}{removedMemberStoreKey(1), false, "", false, store.Permanent}}, } if !reflect.DeepEqual(st.Action(), wactions) { t.Errorf("actions = %v, want %v", st.Action(), wactions) diff --git a/etcdserver/server_test.go b/etcdserver/server_test.go index 521927eba..7098154ea 100644 --- a/etcdserver/server_test.go +++ b/etcdserver/server_test.go @@ -26,7 +26,6 @@ import ( "path" "reflect" "strconv" - "sync" "testing" "time" @@ -49,35 +48,35 @@ func TestDoLocalAction(t *testing.T) { wresp Response werr error - wactions []action + wactions []testutil.Action }{ { pb.Request{Method: "GET", ID: 1, Wait: true}, - Response{Watcher: &nopWatcher{}}, nil, []action{action{name: "Watch"}}, + Response{Watcher: &nopWatcher{}}, nil, []testutil.Action{{Name: "Watch"}}, }, { pb.Request{Method: "GET", ID: 1}, Response{Event: &store.Event{}}, nil, - []action{ - action{ - name: "Get", - params: []interface{}{"", false, false}, + []testutil.Action{ + { + Name: "Get", + Params: []interface{}{"", false, false}, }, }, }, { pb.Request{Method: "HEAD", ID: 1}, Response{Event: &store.Event{}}, nil, - []action{ - action{ - name: "Get", - params: []interface{}{"", false, false}, + []testutil.Action{ + { + Name: "Get", + Params: []interface{}{"", false, false}, }, }, }, { pb.Request{Method: "BADMETHOD", ID: 1}, - Response{}, ErrUnknownMethod, []action{}, + Response{}, ErrUnknownMethod, []testutil.Action{}, }, } for i, tt := range tests { @@ -108,25 +107,29 @@ func TestDoBadLocalAction(t *testing.T) { tests := []struct { req pb.Request - wactions []action + wactions []testutil.Action }{ { pb.Request{Method: "GET", ID: 1, Wait: true}, - []action{action{name: "Watch"}}, + []testutil.Action{{Name: "Watch"}}, }, { pb.Request{Method: "GET", ID: 1}, - []action{action{ - name: "Get", - params: []interface{}{"", false, false}, - }}, + []testutil.Action{ + { + Name: "Get", + Params: []interface{}{"", false, false}, + }, + }, }, { pb.Request{Method: "HEAD", ID: 1}, - []action{action{ - name: "Get", - params: []interface{}{"", false, false}, - }}, + []testutil.Action{ + { + Name: "Get", + Params: []interface{}{"", false, false}, + }, + }, }, } for i, tt := range tests { @@ -155,16 +158,16 @@ func TestApplyRequest(t *testing.T) { req pb.Request wresp Response - wactions []action + wactions []testutil.Action }{ // POST ==> Create { pb.Request{Method: "POST", ID: 1}, Response{Event: &store.Event{}}, - []action{ - action{ - name: "Create", - params: []interface{}{"", false, "", true, time.Time{}}, + []testutil.Action{ + { + Name: "Create", + Params: []interface{}{"", false, "", true, time.Time{}}, }, }, }, @@ -172,10 +175,10 @@ func TestApplyRequest(t *testing.T) { { pb.Request{Method: "POST", ID: 1, Expiration: 1337}, Response{Event: &store.Event{}}, - []action{ - action{ - name: "Create", - params: []interface{}{"", false, "", true, time.Unix(0, 1337)}, + []testutil.Action{ + { + Name: "Create", + Params: []interface{}{"", false, "", true, time.Unix(0, 1337)}, }, }, }, @@ -183,10 +186,10 @@ func TestApplyRequest(t *testing.T) { { pb.Request{Method: "POST", ID: 1, Dir: true}, Response{Event: &store.Event{}}, - []action{ - action{ - name: "Create", - params: []interface{}{"", true, "", true, time.Time{}}, + []testutil.Action{ + { + Name: "Create", + Params: []interface{}{"", true, "", true, time.Time{}}, }, }, }, @@ -194,10 +197,10 @@ func TestApplyRequest(t *testing.T) { { pb.Request{Method: "PUT", ID: 1}, Response{Event: &store.Event{}}, - []action{ - action{ - name: "Set", - params: []interface{}{"", false, "", time.Time{}}, + []testutil.Action{ + { + Name: "Set", + Params: []interface{}{"", false, "", time.Time{}}, }, }, }, @@ -205,10 +208,10 @@ func TestApplyRequest(t *testing.T) { { pb.Request{Method: "PUT", ID: 1, Dir: true}, Response{Event: &store.Event{}}, - []action{ - action{ - name: "Set", - params: []interface{}{"", true, "", time.Time{}}, + []testutil.Action{ + { + Name: "Set", + Params: []interface{}{"", true, "", time.Time{}}, }, }, }, @@ -216,10 +219,10 @@ func TestApplyRequest(t *testing.T) { { pb.Request{Method: "PUT", ID: 1, PrevExist: pbutil.Boolp(true)}, Response{Event: &store.Event{}}, - []action{ - action{ - name: "Update", - params: []interface{}{"", "", time.Time{}}, + []testutil.Action{ + { + Name: "Update", + Params: []interface{}{"", "", time.Time{}}, }, }, }, @@ -227,10 +230,10 @@ func TestApplyRequest(t *testing.T) { { pb.Request{Method: "PUT", ID: 1, PrevExist: pbutil.Boolp(false)}, Response{Event: &store.Event{}}, - []action{ - action{ - name: "Create", - params: []interface{}{"", false, "", false, time.Time{}}, + []testutil.Action{ + { + Name: "Create", + Params: []interface{}{"", false, "", false, time.Time{}}, }, }, }, @@ -239,10 +242,10 @@ func TestApplyRequest(t *testing.T) { { pb.Request{Method: "PUT", ID: 1, PrevExist: pbutil.Boolp(true), PrevIndex: 1}, Response{Event: &store.Event{}}, - []action{ - action{ - name: "Update", - params: []interface{}{"", "", time.Time{}}, + []testutil.Action{ + { + Name: "Update", + Params: []interface{}{"", "", time.Time{}}, }, }, }, @@ -251,10 +254,10 @@ func TestApplyRequest(t *testing.T) { { pb.Request{Method: "PUT", ID: 1, PrevExist: pbutil.Boolp(false), PrevIndex: 1}, Response{Event: &store.Event{}}, - []action{ - action{ - name: "Create", - params: []interface{}{"", false, "", false, time.Time{}}, + []testutil.Action{ + { + Name: "Create", + Params: []interface{}{"", false, "", false, time.Time{}}, }, }, }, @@ -262,10 +265,10 @@ func TestApplyRequest(t *testing.T) { { pb.Request{Method: "PUT", ID: 1, PrevIndex: 1}, Response{Event: &store.Event{}}, - []action{ - action{ - name: "CompareAndSwap", - params: []interface{}{"", "", uint64(1), "", time.Time{}}, + []testutil.Action{ + { + Name: "CompareAndSwap", + Params: []interface{}{"", "", uint64(1), "", time.Time{}}, }, }, }, @@ -273,10 +276,10 @@ func TestApplyRequest(t *testing.T) { { pb.Request{Method: "PUT", ID: 1, PrevValue: "bar"}, Response{Event: &store.Event{}}, - []action{ - action{ - name: "CompareAndSwap", - params: []interface{}{"", "bar", uint64(0), "", time.Time{}}, + []testutil.Action{ + { + Name: "CompareAndSwap", + Params: []interface{}{"", "bar", uint64(0), "", time.Time{}}, }, }, }, @@ -284,10 +287,10 @@ func TestApplyRequest(t *testing.T) { { pb.Request{Method: "PUT", ID: 1, PrevIndex: 1, PrevValue: "bar"}, Response{Event: &store.Event{}}, - []action{ - action{ - name: "CompareAndSwap", - params: []interface{}{"", "bar", uint64(1), "", time.Time{}}, + []testutil.Action{ + { + Name: "CompareAndSwap", + Params: []interface{}{"", "bar", uint64(1), "", time.Time{}}, }, }, }, @@ -295,10 +298,10 @@ func TestApplyRequest(t *testing.T) { { pb.Request{Method: "DELETE", ID: 1}, Response{Event: &store.Event{}}, - []action{ - action{ - name: "Delete", - params: []interface{}{"", false, false}, + []testutil.Action{ + { + Name: "Delete", + Params: []interface{}{"", false, false}, }, }, }, @@ -306,10 +309,10 @@ func TestApplyRequest(t *testing.T) { { pb.Request{Method: "DELETE", ID: 1, PrevIndex: 1}, Response{Event: &store.Event{}}, - []action{ - action{ - name: "CompareAndDelete", - params: []interface{}{"", "", uint64(1)}, + []testutil.Action{ + { + Name: "CompareAndDelete", + Params: []interface{}{"", "", uint64(1)}, }, }, }, @@ -317,10 +320,10 @@ func TestApplyRequest(t *testing.T) { { pb.Request{Method: "DELETE", ID: 1, PrevValue: "bar"}, Response{Event: &store.Event{}}, - []action{ - action{ - name: "CompareAndDelete", - params: []interface{}{"", "bar", uint64(0)}, + []testutil.Action{ + { + Name: "CompareAndDelete", + Params: []interface{}{"", "bar", uint64(0)}, }, }, }, @@ -328,10 +331,10 @@ func TestApplyRequest(t *testing.T) { { pb.Request{Method: "DELETE", ID: 1, PrevIndex: 5, PrevValue: "bar"}, Response{Event: &store.Event{}}, - []action{ - action{ - name: "CompareAndDelete", - params: []interface{}{"", "bar", uint64(5)}, + []testutil.Action{ + { + Name: "CompareAndDelete", + Params: []interface{}{"", "bar", uint64(5)}, }, }, }, @@ -339,10 +342,10 @@ func TestApplyRequest(t *testing.T) { { pb.Request{Method: "QGET", ID: 1}, Response{Event: &store.Event{}}, - []action{ - action{ - name: "Get", - params: []interface{}{"", false, false}, + []testutil.Action{ + { + Name: "Get", + Params: []interface{}{"", false, false}, }, }, }, @@ -350,20 +353,20 @@ func TestApplyRequest(t *testing.T) { { pb.Request{Method: "SYNC", ID: 1}, Response{}, - []action{ - action{ - name: "DeleteExpiredKeys", - params: []interface{}{time.Unix(0, 0)}, + []testutil.Action{ + { + Name: "DeleteExpiredKeys", + Params: []interface{}{time.Unix(0, 0)}, }, }, }, { pb.Request{Method: "SYNC", ID: 1, Time: 12345}, Response{}, - []action{ - action{ - name: "DeleteExpiredKeys", - params: []interface{}{time.Unix(0, 12345)}, + []testutil.Action{ + { + Name: "DeleteExpiredKeys", + Params: []interface{}{time.Unix(0, 12345)}, }, }, }, @@ -371,7 +374,7 @@ func TestApplyRequest(t *testing.T) { { pb.Request{Method: "BADMETHOD", ID: 1}, Response{err: ErrUnknownMethod}, - []action{}, + []testutil.Action{}, }, } @@ -461,10 +464,10 @@ func TestApplyConfChangeError(t *testing.T) { t.Errorf("#%d: applyConfChange error = %v, want %v", i, err, tt.werr) } cc := raftpb.ConfChange{Type: tt.cc.Type, NodeID: raft.None} - w := []action{ + w := []testutil.Action{ { - name: "ApplyConfChange", - params: []interface{}{cc}, + Name: "ApplyConfChange", + Params: []interface{}{cc}, }, } if g := n.Action(); !reflect.DeepEqual(g, w) { @@ -558,7 +561,7 @@ func TestDoProposalCancelled(t *testing.T) { if err != ErrCanceled { t.Fatalf("err = %v, want %v", err, ErrCanceled) } - w := []action{action{name: "Register"}, action{name: "Trigger"}} + w := []testutil.Action{{Name: "Register"}, {Name: "Trigger"}} if !reflect.DeepEqual(wait.action, w) { t.Errorf("wait.action = %+v, want %+v", wait.action, w) } @@ -610,10 +613,10 @@ func TestSync(t *testing.T) { if len(action) != 1 { t.Fatalf("len(action) = %d, want 1", len(action)) } - if action[0].name != "Propose" { - t.Fatalf("action = %s, want Propose", action[0].name) + if action[0].Name != "Propose" { + t.Fatalf("action = %s, want Propose", action[0].Name) } - data := action[0].params[0].([]byte) + data := action[0].Params[0].([]byte) var r pb.Request if err := r.Unmarshal(data); err != nil { t.Fatalf("unmarshal request error: %v", err) @@ -640,7 +643,7 @@ func TestSyncTimeout(t *testing.T) { // give time for goroutine in sync to cancel testutil.ForceGosched() - w := []action{action{name: "Propose blocked"}} + w := []testutil.Action{{Name: "Propose blocked"}} if g := n.Action(); !reflect.DeepEqual(g, w) { t.Errorf("action = %v, want %v", g, w) } @@ -677,10 +680,10 @@ func TestSyncTrigger(t *testing.T) { if len(action) != 1 { t.Fatalf("len(action) = %d, want 1", len(action)) } - if action[0].name != "Propose" { - t.Fatalf("action = %s, want Propose", action[0].name) + if action[0].Name != "Propose" { + t.Fatalf("action = %s, want Propose", action[0].Name) } - data := action[0].params[0].([]byte) + data := action[0].Params[0].([]byte) var req pb.Request if err := req.Unmarshal(data); err != nil { t.Fatalf("error unmarshalling data: %v", err) @@ -707,17 +710,17 @@ func TestSnapshot(t *testing.T) { if len(gaction) != 1 { t.Fatalf("len(action) = %d, want 1", len(gaction)) } - if !reflect.DeepEqual(gaction[0], action{name: "Save"}) { + if !reflect.DeepEqual(gaction[0], testutil.Action{Name: "Save"}) { t.Errorf("action = %s, want Save", gaction[0]) } gaction = p.Action() if len(gaction) != 2 { t.Fatalf("len(action) = %d, want 2", len(gaction)) } - if !reflect.DeepEqual(gaction[0], action{name: "Cut"}) { + if !reflect.DeepEqual(gaction[0], testutil.Action{Name: "Cut"}) { t.Errorf("action = %s, want Cut", gaction[0]) } - if !reflect.DeepEqual(gaction[1], action{name: "SaveSnap"}) { + if !reflect.DeepEqual(gaction[1], testutil.Action{Name: "SaveSnap"}) { t.Errorf("action = %s, want SaveSnap", gaction[1]) } } @@ -749,7 +752,7 @@ func TestTriggerSnap(t *testing.T) { if len(gaction) != wcnt { t.Fatalf("len(action) = %d, want %d", len(gaction), wcnt) } - if !reflect.DeepEqual(gaction[wcnt-1], action{name: "SaveSnap"}) { + if !reflect.DeepEqual(gaction[wcnt-1], testutil.Action{Name: "SaveSnap"}) { t.Errorf("action = %s, want SaveSnap", gaction[wcnt-1]) } } @@ -777,11 +780,11 @@ func TestRecvSnapshot(t *testing.T) { testutil.ForceGosched() s.Stop() - wactions := []action{action{name: "Recovery"}} + wactions := []testutil.Action{{Name: "Recovery"}} if g := st.Action(); !reflect.DeepEqual(g, wactions) { t.Errorf("store action = %v, want %v", g, wactions) } - wactions = []action{action{name: "SaveSnap"}, action{name: "Save"}} + wactions = []testutil.Action{{Name: "SaveSnap"}, {Name: "Save"}} if g := p.Action(); !reflect.DeepEqual(g, wactions) { t.Errorf("storage action = %v, want %v", g, wactions) } @@ -853,11 +856,11 @@ func TestApplySnapshotAndCommittedEntries(t *testing.T) { if len(actions) != 2 { t.Fatalf("len(action) = %d, want 2", len(actions)) } - if actions[0].name != "Recovery" { - t.Errorf("actions[0] = %s, want %s", actions[0].name, "Recovery") + if actions[0].Name != "Recovery" { + t.Errorf("actions[0] = %s, want %s", actions[0].Name, "Recovery") } - if actions[1].name != "Get" { - t.Errorf("actions[1] = %s, want %s", actions[1].name, "Get") + if actions[1].Name != "Get" { + t.Errorf("actions[1] = %s, want %s", actions[1].Name, "Get") } } @@ -887,7 +890,7 @@ func TestAddMember(t *testing.T) { if err != nil { t.Fatalf("AddMember error: %v", err) } - wactions := []action{action{name: "ProposeConfChange:ConfChangeAddNode"}, action{name: "ApplyConfChange:ConfChangeAddNode"}} + wactions := []testutil.Action{{Name: "ProposeConfChange:ConfChangeAddNode"}, {Name: "ApplyConfChange:ConfChangeAddNode"}} if !reflect.DeepEqual(gaction, wactions) { t.Errorf("action = %v, want %v", gaction, wactions) } @@ -922,7 +925,7 @@ func TestRemoveMember(t *testing.T) { if err != nil { t.Fatalf("RemoveMember error: %v", err) } - wactions := []action{action{name: "ProposeConfChange:ConfChangeRemoveNode"}, action{name: "ApplyConfChange:ConfChangeRemoveNode"}} + wactions := []testutil.Action{{Name: "ProposeConfChange:ConfChangeRemoveNode"}, {Name: "ApplyConfChange:ConfChangeRemoveNode"}} if !reflect.DeepEqual(gaction, wactions) { t.Errorf("action = %v, want %v", gaction, wactions) } @@ -958,7 +961,7 @@ func TestUpdateMember(t *testing.T) { if err != nil { t.Fatalf("UpdateMember error: %v", err) } - wactions := []action{action{name: "ProposeConfChange:ConfChangeUpdateNode"}, action{name: "ApplyConfChange:ConfChangeUpdateNode"}} + wactions := []testutil.Action{{Name: "ProposeConfChange:ConfChangeUpdateNode"}, {Name: "ApplyConfChange:ConfChangeUpdateNode"}} if !reflect.DeepEqual(gaction, wactions) { t.Errorf("action = %v, want %v", gaction, wactions) } @@ -989,10 +992,10 @@ func TestPublish(t *testing.T) { if len(action) != 1 { t.Fatalf("len(action) = %d, want 1", len(action)) } - if action[0].name != "Propose" { - t.Fatalf("action = %s, want Propose", action[0].name) + if action[0].Name != "Propose" { + t.Fatalf("action = %s, want Propose", action[0].Name) } - data := action[0].params[0].([]byte) + data := action[0].Params[0].([]byte) var r pb.Request if err := r.Unmarshal(data); err != nil { t.Fatalf("unmarshal request error: %v", err) @@ -1114,102 +1117,79 @@ func TestGetOtherPeerURLs(t *testing.T) { } } -type action struct { - name string - params []interface{} -} - -type recorder struct { - sync.Mutex - actions []action -} - -func (r *recorder) record(a action) { - r.Lock() - r.actions = append(r.actions, a) - r.Unlock() -} -func (r *recorder) Action() []action { - r.Lock() - cpy := make([]action, len(r.actions)) - copy(cpy, r.actions) - r.Unlock() - return cpy -} - // storeRecorder records all the methods it receives. // storeRecorder DOES NOT work as a actual store. // It always returns invaild empty response and no error. -type storeRecorder struct{ recorder } +type storeRecorder struct{ testutil.Recorder } func (s *storeRecorder) Version() int { return 0 } func (s *storeRecorder) Index() uint64 { return 0 } func (s *storeRecorder) Get(path string, recursive, sorted bool) (*store.Event, error) { - s.record(action{ - name: "Get", - params: []interface{}{path, recursive, sorted}, + s.Record(testutil.Action{ + Name: "Get", + Params: []interface{}{path, recursive, sorted}, }) return &store.Event{}, nil } func (s *storeRecorder) Set(path string, dir bool, val string, expr time.Time) (*store.Event, error) { - s.record(action{ - name: "Set", - params: []interface{}{path, dir, val, expr}, + s.Record(testutil.Action{ + Name: "Set", + Params: []interface{}{path, dir, val, expr}, }) return &store.Event{}, nil } func (s *storeRecorder) Update(path, val string, expr time.Time) (*store.Event, error) { - s.record(action{ - name: "Update", - params: []interface{}{path, val, expr}, + s.Record(testutil.Action{ + Name: "Update", + Params: []interface{}{path, val, expr}, }) return &store.Event{}, nil } func (s *storeRecorder) Create(path string, dir bool, val string, uniq bool, exp time.Time) (*store.Event, error) { - s.record(action{ - name: "Create", - params: []interface{}{path, dir, val, uniq, exp}, + s.Record(testutil.Action{ + Name: "Create", + Params: []interface{}{path, dir, val, uniq, exp}, }) return &store.Event{}, nil } func (s *storeRecorder) CompareAndSwap(path, prevVal string, prevIdx uint64, val string, expr time.Time) (*store.Event, error) { - s.record(action{ - name: "CompareAndSwap", - params: []interface{}{path, prevVal, prevIdx, val, expr}, + s.Record(testutil.Action{ + Name: "CompareAndSwap", + Params: []interface{}{path, prevVal, prevIdx, val, expr}, }) return &store.Event{}, nil } func (s *storeRecorder) Delete(path string, dir, recursive bool) (*store.Event, error) { - s.record(action{ - name: "Delete", - params: []interface{}{path, dir, recursive}, + s.Record(testutil.Action{ + Name: "Delete", + Params: []interface{}{path, dir, recursive}, }) return &store.Event{}, nil } func (s *storeRecorder) CompareAndDelete(path, prevVal string, prevIdx uint64) (*store.Event, error) { - s.record(action{ - name: "CompareAndDelete", - params: []interface{}{path, prevVal, prevIdx}, + s.Record(testutil.Action{ + Name: "CompareAndDelete", + Params: []interface{}{path, prevVal, prevIdx}, }) return &store.Event{}, nil } func (s *storeRecorder) Watch(_ string, _, _ bool, _ uint64) (store.Watcher, error) { - s.record(action{name: "Watch"}) + s.Record(testutil.Action{Name: "Watch"}) return &nopWatcher{}, nil } func (s *storeRecorder) Save() ([]byte, error) { - s.record(action{name: "Save"}) + s.Record(testutil.Action{Name: "Save"}) return nil, nil } func (s *storeRecorder) Recovery(b []byte) error { - s.record(action{name: "Recovery"}) + s.Record(testutil.Action{Name: "Recovery"}) return nil } func (s *storeRecorder) JsonStats() []byte { return nil } func (s *storeRecorder) DeleteExpiredKeys(cutoff time.Time) { - s.record(action{ - name: "DeleteExpiredKeys", - params: []interface{}{cutoff}, + s.Record(testutil.Action{ + Name: "DeleteExpiredKeys", + Params: []interface{}{cutoff}, }) } @@ -1236,15 +1216,15 @@ func (s *errStoreRecorder) Watch(path string, recursive, sorted bool, index uint } type waitRecorder struct { - action []action + action []testutil.Action } func (w *waitRecorder) Register(id uint64) <-chan interface{} { - w.action = append(w.action, action{name: "Register"}) + w.action = append(w.action, testutil.Action{Name: "Register"}) return nil } func (w *waitRecorder) Trigger(id uint64, x interface{}) { - w.action = append(w.action, action{name: "Trigger"}) + w.action = append(w.action, testutil.Action{Name: "Trigger"}) } type waitWithResponse struct { @@ -1256,58 +1236,54 @@ func (w *waitWithResponse) Register(id uint64) <-chan interface{} { } func (w *waitWithResponse) Trigger(id uint64, x interface{}) {} -type storageRecorder struct { - recorder -} +type storageRecorder struct{ testutil.Recorder } func (p *storageRecorder) Save(st raftpb.HardState, ents []raftpb.Entry) error { - p.record(action{name: "Save"}) + p.Record(testutil.Action{Name: "Save"}) return nil } func (p *storageRecorder) Cut() error { - p.record(action{name: "Cut"}) + p.Record(testutil.Action{Name: "Cut"}) return nil } func (p *storageRecorder) SaveSnap(st raftpb.Snapshot) error { if !raft.IsEmptySnap(st) { - p.record(action{name: "SaveSnap"}) + p.Record(testutil.Action{Name: "SaveSnap"}) } return nil } func (p *storageRecorder) Close() error { return nil } -type nodeRecorder struct { - recorder -} +type nodeRecorder struct{ testutil.Recorder } -func (n *nodeRecorder) Tick() { n.record(action{name: "Tick"}) } +func (n *nodeRecorder) Tick() { n.Record(testutil.Action{Name: "Tick"}) } func (n *nodeRecorder) Campaign(ctx context.Context) error { - n.record(action{name: "Campaign"}) + n.Record(testutil.Action{Name: "Campaign"}) return nil } func (n *nodeRecorder) Propose(ctx context.Context, data []byte) error { - n.record(action{name: "Propose", params: []interface{}{data}}) + n.Record(testutil.Action{Name: "Propose", Params: []interface{}{data}}) return nil } func (n *nodeRecorder) ProposeConfChange(ctx context.Context, conf raftpb.ConfChange) error { - n.record(action{name: "ProposeConfChange"}) + n.Record(testutil.Action{Name: "ProposeConfChange"}) return nil } func (n *nodeRecorder) Step(ctx context.Context, msg raftpb.Message) error { - n.record(action{name: "Step"}) + n.Record(testutil.Action{Name: "Step"}) return nil } func (n *nodeRecorder) Ready() <-chan raft.Ready { return nil } func (n *nodeRecorder) Advance() {} func (n *nodeRecorder) ApplyConfChange(conf raftpb.ConfChange) *raftpb.ConfState { - n.record(action{name: "ApplyConfChange", params: []interface{}{conf}}) + n.Record(testutil.Action{Name: "ApplyConfChange", Params: []interface{}{conf}}) return &raftpb.ConfState{} } func (n *nodeRecorder) Stop() { - n.record(action{name: "Stop"}) + n.Record(testutil.Action{Name: "Stop"}) } func (n *nodeRecorder) Compact(index uint64, nodes []uint64, d []byte) { - n.record(action{name: "Compact"}) + n.Record(testutil.Action{Name: "Compact"}) } type nodeProposalBlockerRecorder struct { @@ -1316,7 +1292,7 @@ type nodeProposalBlockerRecorder struct { func (n *nodeProposalBlockerRecorder) Propose(ctx context.Context, data []byte) error { <-ctx.Done() - n.record(action{name: "Propose blocked"}) + n.Record(testutil.Action{Name: "Propose blocked"}) return nil } @@ -1337,14 +1313,14 @@ func (n *nodeConfChangeCommitterRecorder) ProposeConfChange(ctx context.Context, } n.index++ n.readyc <- raft.Ready{CommittedEntries: []raftpb.Entry{{Index: n.index, Type: raftpb.EntryConfChange, Data: data}}} - n.record(action{name: "ProposeConfChange:" + conf.Type.String()}) + n.Record(testutil.Action{Name: "ProposeConfChange:" + conf.Type.String()}) return nil } func (n *nodeConfChangeCommitterRecorder) Ready() <-chan raft.Ready { return n.readyc } func (n *nodeConfChangeCommitterRecorder) ApplyConfChange(conf raftpb.ConfChange) *raftpb.ConfState { - n.record(action{name: "ApplyConfChange:" + conf.Type.String()}) + n.Record(testutil.Action{Name: "ApplyConfChange:" + conf.Type.String()}) return &raftpb.ConfState{} } diff --git a/pkg/testutil/recorder.go b/pkg/testutil/recorder.go new file mode 100644 index 000000000..2bb888ef0 --- /dev/null +++ b/pkg/testutil/recorder.go @@ -0,0 +1,42 @@ +/* + Copyright 2015 CoreOS, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package testutil + +import "sync" + +type Action struct { + Name string + Params []interface{} +} + +type Recorder struct { + sync.Mutex + actions []Action +} + +func (r *Recorder) Record(a Action) { + r.Lock() + r.actions = append(r.actions, a) + r.Unlock() +} +func (r *Recorder) Action() []Action { + r.Lock() + cpy := make([]Action, len(r.actions)) + copy(cpy, r.actions) + r.Unlock() + return cpy +} From 41f6137261c55317c9f46e2598f5d730671efcfb Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Fri, 2 Jan 2015 12:22:01 -0800 Subject: [PATCH 3/3] etcdserver: use the actual store implementation when we need the actual implementation --- etcdserver/server_test.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/etcdserver/server_test.go b/etcdserver/server_test.go index 7098154ea..fe86ecdad 100644 --- a/etcdserver/server_test.go +++ b/etcdserver/server_test.go @@ -871,11 +871,12 @@ func TestAddMember(t *testing.T) { SoftState: &raft.SoftState{RaftState: raft.StateLeader}, } cl := newTestCluster(nil) - cl.SetStore(store.New()) + st := store.New() + cl.SetStore(st) s := &EtcdServer{ node: n, raftStorage: raft.NewMemoryStorage(), - store: &storeRecorder{}, + store: st, transport: &nopTransporter{}, storage: &storageRecorder{}, Cluster: cl, @@ -906,12 +907,13 @@ func TestRemoveMember(t *testing.T) { SoftState: &raft.SoftState{RaftState: raft.StateLeader}, } cl := newTestCluster(nil) + st := store.New() cl.SetStore(store.New()) cl.AddMember(&Member{ID: 1234}) s := &EtcdServer{ node: n, raftStorage: raft.NewMemoryStorage(), - store: &storeRecorder{}, + store: st, transport: &nopTransporter{}, storage: &storageRecorder{}, Cluster: cl, @@ -941,12 +943,13 @@ func TestUpdateMember(t *testing.T) { SoftState: &raft.SoftState{RaftState: raft.StateLeader}, } cl := newTestCluster(nil) - cl.SetStore(store.New()) + st := store.New() + cl.SetStore(st) cl.AddMember(&Member{ID: 1234}) s := &EtcdServer{ node: n, raftStorage: raft.NewMemoryStorage(), - store: &storeRecorder{}, + store: st, transport: &nopTransporter{}, storage: &storageRecorder{}, Cluster: cl,