etcdserver: move recorder to testutil

This commit is contained in:
Xiang Li 2015-01-02 11:21:23 -08:00
parent ac6cd03365
commit 27d47977d9
3 changed files with 226 additions and 207 deletions

View File

@ -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)

View File

@ -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{}
}

42
pkg/testutil/recorder.go Normal file
View File

@ -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
}