Merge pull request #1157 from jonboulle/1019_etcdserver

etcdserver: extend storeRecorder to test parameters
release-2.0
Jonathan Boulle 2014-09-24 16:58:57 -07:00
commit 20ac7d6732
2 changed files with 327 additions and 132 deletions

View File

@ -300,7 +300,8 @@ func getExpirationTime(r *pb.Request) time.Time {
return t return t
} }
// apply interprets r as a call to store.X and returns an Response interpreted from store.Event // apply interprets r as a call to store.X and returns a Response interpreted
// from store.Event
func (s *EtcdServer) apply(r pb.Request) Response { func (s *EtcdServer) apply(r pb.Request) Response {
f := func(ev *store.Event, err error) Response { f := func(ev *store.Event, err error) Response {
return Response{Event: ev, err: err} return Response{Event: ev, err: err}
@ -315,9 +316,8 @@ func (s *EtcdServer) apply(r pb.Request) Response {
case existsSet: case existsSet:
if exists { if exists {
return f(s.Store.Update(r.Path, r.Val, expr)) return f(s.Store.Update(r.Path, r.Val, expr))
} else {
return f(s.Store.Create(r.Path, r.Dir, r.Val, false, expr))
} }
return f(s.Store.Create(r.Path, r.Dir, r.Val, false, expr))
case r.PrevIndex > 0 || r.PrevValue != "": case r.PrevIndex > 0 || r.PrevValue != "":
return f(s.Store.CompareAndSwap(r.Path, r.PrevValue, r.PrevIndex, r.Val, expr)) return f(s.Store.CompareAndSwap(r.Path, r.PrevValue, r.PrevIndex, r.Val, expr))
default: default:

View File

@ -49,21 +49,27 @@ func TestDoLocalAction(t *testing.T) {
tests := []struct { tests := []struct {
req pb.Request req pb.Request
wresp Response wresp Response
werr error werr error
waction []string wactions []action
}{ }{
{ {
pb.Request{Method: "GET", Id: 1, Wait: true}, pb.Request{Method: "GET", Id: 1, Wait: true},
Response{Watcher: &stubWatcher{}}, nil, []string{"Watch"}, Response{Watcher: &stubWatcher{}}, nil, []action{action{name: "Watch"}},
}, },
{ {
pb.Request{Method: "GET", Id: 1}, pb.Request{Method: "GET", Id: 1},
Response{Event: &store.Event{}}, nil, []string{"Get"}, Response{Event: &store.Event{}}, nil,
[]action{
action{
name: "Get",
params: []interface{}{"", false, false},
},
},
}, },
{ {
pb.Request{Method: "BADMETHOD", Id: 1}, pb.Request{Method: "BADMETHOD", Id: 1},
Response{}, ErrUnknownMethod, []string{}, Response{}, ErrUnknownMethod, []action{},
}, },
} }
for i, tt := range tests { for i, tt := range tests {
@ -77,9 +83,9 @@ func TestDoLocalAction(t *testing.T) {
if !reflect.DeepEqual(resp, tt.wresp) { if !reflect.DeepEqual(resp, tt.wresp) {
t.Errorf("#%d: resp = %+v, want %+v", i, resp, tt.wresp) t.Errorf("#%d: resp = %+v, want %+v", i, resp, tt.wresp)
} }
action := st.Action() gaction := st.Action()
if !reflect.DeepEqual(action, tt.waction) { if !reflect.DeepEqual(gaction, tt.wactions) {
t.Errorf("#%d: action = %+v, want %+v", i, action, tt.waction) t.Errorf("#%d: action = %+v, want %+v", i, gaction, tt.wactions)
} }
} }
} }
@ -91,15 +97,15 @@ func TestDoBadLocalAction(t *testing.T) {
tests := []struct { tests := []struct {
req pb.Request req pb.Request
waction []string wactions []action
}{ }{
{ {
pb.Request{Method: "GET", Id: 1, Wait: true}, pb.Request{Method: "GET", Id: 1, Wait: true},
[]string{"Watch"}, []action{action{name: "Watch"}},
}, },
{ {
pb.Request{Method: "GET", Id: 1}, pb.Request{Method: "GET", Id: 1},
[]string{"Get"}, []action{action{name: "Get"}},
}, },
} }
for i, tt := range tests { for i, tt := range tests {
@ -113,9 +119,9 @@ func TestDoBadLocalAction(t *testing.T) {
if !reflect.DeepEqual(resp, Response{}) { if !reflect.DeepEqual(resp, Response{}) {
t.Errorf("#%d: resp = %+v, want %+v", i, resp, Response{}) t.Errorf("#%d: resp = %+v, want %+v", i, resp, Response{})
} }
action := st.Action() gaction := st.Action()
if !reflect.DeepEqual(action, tt.waction) { if !reflect.DeepEqual(gaction, tt.wactions) {
t.Errorf("#%d: action = %+v, want %+v", i, action, tt.waction) t.Errorf("#%d: action = %+v, want %+v", i, gaction, tt.wactions)
} }
} }
} }
@ -124,64 +130,224 @@ func TestApply(t *testing.T) {
tests := []struct { tests := []struct {
req pb.Request req pb.Request
wresp Response wresp Response
waction []string wactions []action
}{ }{
// POST ==> Create
{ {
pb.Request{Method: "POST", Id: 1}, pb.Request{Method: "POST", Id: 1},
Response{Event: &store.Event{}}, []string{"Create"}, Response{Event: &store.Event{}},
[]action{
action{
name: "Create",
params: []interface{}{"", false, "", true, time.Time{}},
},
},
}, },
// POST ==> Create, with expiration
{ {
pb.Request{Method: "PUT", Id: 1, PrevExist: boolp(true), PrevIndex: 1}, pb.Request{Method: "POST", Id: 1, Expiration: 1337},
Response{Event: &store.Event{}}, []string{"Update"}, Response{Event: &store.Event{}},
[]action{
action{
name: "Create",
params: []interface{}{"", false, "", true, time.Unix(0, 1337)},
},
},
}, },
// POST ==> Create, with dir
{ {
pb.Request{Method: "PUT", Id: 1, PrevExist: boolp(false), PrevIndex: 1}, pb.Request{Method: "POST", Id: 1, Dir: true},
Response{Event: &store.Event{}}, []string{"Create"}, Response{Event: &store.Event{}},
}, []action{
{ action{
pb.Request{Method: "PUT", Id: 1, PrevExist: boolp(true)}, name: "Create",
Response{Event: &store.Event{}}, []string{"Update"}, params: []interface{}{"", true, "", true, time.Time{}},
}, },
{ },
pb.Request{Method: "PUT", Id: 1, PrevExist: boolp(false)},
Response{Event: &store.Event{}}, []string{"Create"},
},
{
pb.Request{Method: "PUT", Id: 1, PrevIndex: 1},
Response{Event: &store.Event{}}, []string{"CompareAndSwap"},
},
{
pb.Request{Method: "PUT", Id: 1, PrevValue: "bar"},
Response{Event: &store.Event{}}, []string{"CompareAndSwap"},
}, },
// PUT ==> Set
{ {
pb.Request{Method: "PUT", Id: 1}, pb.Request{Method: "PUT", Id: 1},
Response{Event: &store.Event{}}, []string{"Set"}, Response{Event: &store.Event{}},
[]action{
action{
name: "Set",
params: []interface{}{"", false, "", time.Time{}},
},
},
}, },
// PUT ==> Set, with dir
{ {
pb.Request{Method: "DELETE", Id: 1, PrevIndex: 1}, pb.Request{Method: "PUT", Id: 1, Dir: true},
Response{Event: &store.Event{}}, []string{"CompareAndDelete"}, Response{Event: &store.Event{}},
[]action{
action{
name: "Set",
params: []interface{}{"", true, "", time.Time{}},
},
},
}, },
// PUT with PrevExist=true ==> Update
{ {
pb.Request{Method: "DELETE", Id: 1, PrevValue: "bar"}, pb.Request{Method: "PUT", Id: 1, PrevExist: boolp(true)},
Response{Event: &store.Event{}}, []string{"CompareAndDelete"}, Response{Event: &store.Event{}},
[]action{
action{
name: "Update",
params: []interface{}{"", "", time.Time{}},
},
},
}, },
// PUT with PrevExist=false ==> Create
{
pb.Request{Method: "PUT", Id: 1, PrevExist: boolp(false)},
Response{Event: &store.Event{}},
[]action{
action{
name: "Create",
params: []interface{}{"", false, "", false, time.Time{}},
},
},
},
// PUT with PrevExist=true *and* PrevIndex set ==> Update
// TODO(jonboulle): is this expected?!
{
pb.Request{Method: "PUT", Id: 1, PrevExist: boolp(true), PrevIndex: 1},
Response{Event: &store.Event{}},
[]action{
action{
name: "Update",
params: []interface{}{"", "", time.Time{}},
},
},
},
// PUT with PrevExist=false *and* PrevIndex set ==> Create
// TODO(jonboulle): is this expected?!
{
pb.Request{Method: "PUT", Id: 1, PrevExist: boolp(false), PrevIndex: 1},
Response{Event: &store.Event{}},
[]action{
action{
name: "Create",
params: []interface{}{"", false, "", false, time.Time{}},
},
},
},
// PUT with PrevIndex set ==> CompareAndSwap
{
pb.Request{Method: "PUT", Id: 1, PrevIndex: 1},
Response{Event: &store.Event{}},
[]action{
action{
name: "CompareAndSwap",
params: []interface{}{"", "", uint64(1), "", time.Time{}},
},
},
},
// PUT with PrevValue set ==> CompareAndSwap
{
pb.Request{Method: "PUT", Id: 1, PrevValue: "bar"},
Response{Event: &store.Event{}},
[]action{
action{
name: "CompareAndSwap",
params: []interface{}{"", "bar", uint64(0), "", time.Time{}},
},
},
},
// PUT with PrevIndex and PrevValue set ==> CompareAndSwap
{
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{}},
},
},
},
// DELETE ==> Delete
{ {
pb.Request{Method: "DELETE", Id: 1}, pb.Request{Method: "DELETE", Id: 1},
Response{Event: &store.Event{}}, []string{"Delete"}, Response{Event: &store.Event{}},
[]action{
action{
name: "Delete",
params: []interface{}{"", false, false},
},
},
}, },
// DELETE with PrevIndex set ==> CompareAndDelete
{
pb.Request{Method: "DELETE", Id: 1, PrevIndex: 1},
Response{Event: &store.Event{}},
[]action{
action{
name: "CompareAndDelete",
params: []interface{}{"", "", uint64(1)},
},
},
},
// DELETE with PrevValue set ==> CompareAndDelete
{
pb.Request{Method: "DELETE", Id: 1, PrevValue: "bar"},
Response{Event: &store.Event{}},
[]action{
action{
name: "CompareAndDelete",
params: []interface{}{"", "bar", uint64(0)},
},
},
},
// DELETE with PrevIndex *and* PrevValue set ==> CompareAndDelete
{
pb.Request{Method: "DELETE", Id: 1, PrevIndex: 5, PrevValue: "bar"},
Response{Event: &store.Event{}},
[]action{
action{
name: "CompareAndDelete",
params: []interface{}{"", "bar", uint64(5)},
},
},
},
// QGET ==> Get
{ {
pb.Request{Method: "QGET", Id: 1}, pb.Request{Method: "QGET", Id: 1},
Response{Event: &store.Event{}}, []string{"Get"}, Response{Event: &store.Event{}},
[]action{
action{
name: "Get",
params: []interface{}{"", false, false},
},
},
}, },
// SYNC ==> DeleteExpiredKeys
{ {
pb.Request{Method: "SYNC", Id: 1}, pb.Request{Method: "SYNC", Id: 1},
Response{}, []string{"DeleteExpiredKeys"}, Response{},
[]action{
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)},
},
},
},
// Unknown method - error
{ {
pb.Request{Method: "BADMETHOD", Id: 1}, pb.Request{Method: "BADMETHOD", Id: 1},
Response{err: ErrUnknownMethod}, []string{}, Response{err: ErrUnknownMethod},
[]action{},
}, },
} }
@ -193,9 +359,9 @@ func TestApply(t *testing.T) {
if !reflect.DeepEqual(resp, tt.wresp) { if !reflect.DeepEqual(resp, tt.wresp) {
t.Errorf("#%d: resp = %+v, want %+v", i, resp, tt.wresp) t.Errorf("#%d: resp = %+v, want %+v", i, resp, tt.wresp)
} }
action := st.Action() gaction := st.Action()
if !reflect.DeepEqual(action, tt.waction) { if !reflect.DeepEqual(gaction, tt.wactions) {
t.Errorf("#%d: action = %+v, want %+v", i, action, tt.waction) t.Errorf("#%d: action = %#v, want %#v", i, gaction, tt.wactions)
} }
} }
} }
@ -342,14 +508,14 @@ func TestDoProposalCancelled(t *testing.T) {
cancel() cancel()
<-done <-done
action := st.Action() gaction := st.Action()
if len(action) != 0 { if len(gaction) != 0 {
t.Errorf("len(action) = %v, want 0", len(action)) t.Errorf("len(action) = %v, want 0", len(gaction))
} }
if err != context.Canceled { if err != context.Canceled {
t.Fatalf("err = %v, want %v", err, context.Canceled) t.Fatalf("err = %v, want %v", err, context.Canceled)
} }
w := []string{"Register1", "Trigger1"} w := []action{action{name: "Register1"}, action{name: "Trigger1"}}
if !reflect.DeepEqual(wait.action, w) { if !reflect.DeepEqual(wait.action, w) {
t.Errorf("wait.action = %+v, want %+v", wait.action, w) t.Errorf("wait.action = %+v, want %+v", wait.action, w)
} }
@ -438,7 +604,7 @@ func TestSyncTimeout(t *testing.T) {
// give time for goroutine in sync to cancel // give time for goroutine in sync to cancel
// TODO: use fake clock // TODO: use fake clock
testutil.ForceGosched() testutil.ForceGosched()
w := []string{"Propose blocked"} w := []action{action{name: "Propose blocked"}}
if g := n.Action(); !reflect.DeepEqual(g, w) { if g := n.Action(); !reflect.DeepEqual(g, w) {
t.Errorf("action = %v, want %v", g, w) t.Errorf("action = %v, want %v", g, w)
} }
@ -511,20 +677,20 @@ func TestSnapshot(t *testing.T) {
} }
s.snapshot() s.snapshot()
action := st.Action() gaction := st.Action()
if len(action) != 1 { if len(gaction) != 1 {
t.Fatalf("len(action) = %d, want 1", len(action)) t.Fatalf("len(action) = %d, want 1", len(gaction))
} }
if action[0] != "Save" { if !reflect.DeepEqual(gaction[0], action{name: "Save"}) {
t.Errorf("action = %s, want Save", action[0]) t.Errorf("action = %s, want Save", gaction[0])
} }
action = p.Action() gaction = p.Action()
if len(action) != 1 { if len(gaction) != 1 {
t.Fatalf("len(action) = %d, want 1", len(action)) t.Fatalf("len(action) = %d, want 1", len(gaction))
} }
if action[0] != "Cut" { if !reflect.DeepEqual(gaction[0], action{name: "Cut"}) {
t.Errorf("action = %s, want Cut", action[0]) t.Errorf("action = %s, want Cut", gaction[0])
} }
} }
@ -550,14 +716,14 @@ func TestTriggerSnap(t *testing.T) {
time.Sleep(time.Millisecond) time.Sleep(time.Millisecond)
s.Stop() s.Stop()
action := p.Action() gaction := p.Action()
// each operation is recorded as a Save // each operation is recorded as a Save
// Nop + SnapCount * Puts + Cut + SaveSnap = Save + SnapCount * Save + Cut + SaveSnap // Nop + SnapCount * Puts + Cut + SaveSnap = Save + SnapCount * Save + Cut + SaveSnap
if len(action) != 3+int(s.SnapCount) { if len(gaction) != 3+int(s.SnapCount) {
t.Fatalf("len(action) = %d, want %d", len(action), 3+int(s.SnapCount)) t.Fatalf("len(action) = %d, want %d", len(gaction), 3+int(s.SnapCount))
} }
if action[12] != "SaveSnap" { if !reflect.DeepEqual(gaction[12], action{name: "SaveSnap"}) {
t.Errorf("action = %s, want SaveSnap", action[12]) t.Errorf("action = %s, want SaveSnap", gaction[12])
} }
} }
@ -580,13 +746,13 @@ func TestRecvSnapshot(t *testing.T) {
testutil.ForceGosched() testutil.ForceGosched()
s.Stop() s.Stop()
waction := []string{"Recovery"} wactions := []action{action{name: "Recovery"}}
if g := st.Action(); !reflect.DeepEqual(g, waction) { if g := st.Action(); !reflect.DeepEqual(g, wactions) {
t.Errorf("store action = %v, want %v", g, waction) t.Errorf("store action = %v, want %v", g, wactions)
} }
waction = []string{"Save", "SaveSnap"} wactions = []action{action{name: "Save"}, action{name: "SaveSnap"}}
if g := p.Action(); !reflect.DeepEqual(g, waction) { if g := p.Action(); !reflect.DeepEqual(g, wactions) {
t.Errorf("storage action = %v, want %v", g, waction) t.Errorf("storage action = %v, want %v", g, wactions)
} }
} }
@ -629,12 +795,12 @@ func TestAddNode(t *testing.T) {
} }
s.Start() s.Start()
s.AddNode(context.TODO(), 1, []byte("foo")) s.AddNode(context.TODO(), 1, []byte("foo"))
action := n.Action() gaction := n.Action()
s.Stop() s.Stop()
waction := []string{"ProposeConfChange:ConfChangeAddNode", "ApplyConfChange:ConfChangeAddNode"} wactions := []action{action{name: "ProposeConfChange:ConfChangeAddNode"}, action{name: "ApplyConfChange:ConfChangeAddNode"}}
if !reflect.DeepEqual(action, waction) { if !reflect.DeepEqual(gaction, wactions) {
t.Errorf("action = %v, want %v", action, waction) t.Errorf("action = %v, want %v", gaction, wactions)
} }
} }
@ -649,12 +815,12 @@ func TestRemoveNode(t *testing.T) {
} }
s.Start() s.Start()
s.RemoveNode(context.TODO(), 1) s.RemoveNode(context.TODO(), 1)
action := n.Action() gaction := n.Action()
s.Stop() s.Stop()
waction := []string{"ProposeConfChange:ConfChangeRemoveNode", "ApplyConfChange:ConfChangeRemoveNode"} wactions := []action{action{name: "ProposeConfChange:ConfChangeRemoveNode"}, action{name: "ApplyConfChange:ConfChangeRemoveNode"}}
if !reflect.DeepEqual(action, waction) { if !reflect.DeepEqual(gaction, wactions) {
t.Errorf("action = %v, want %v", action, waction) t.Errorf("action = %v, want %v", gaction, wactions)
} }
} }
@ -694,20 +860,25 @@ func TestGenID(t *testing.T) {
} }
} }
type recorder struct { type action struct {
sync.Mutex name string
action []string params []interface{}
} }
func (r *recorder) record(action string) { type recorder struct {
sync.Mutex
actions []action
}
func (r *recorder) record(a action) {
r.Lock() r.Lock()
r.action = append(r.action, action) r.actions = append(r.actions, a)
r.Unlock() r.Unlock()
} }
func (r *recorder) Action() []string { func (r *recorder) Action() []action {
r.Lock() r.Lock()
cpy := make([]string, len(r.action)) cpy := make([]action, len(r.actions))
copy(cpy, r.action) copy(cpy, r.actions)
r.Unlock() r.Unlock()
return cpy return cpy
} }
@ -718,50 +889,74 @@ type storeRecorder struct {
func (s *storeRecorder) Version() int { return 0 } func (s *storeRecorder) Version() int { return 0 }
func (s *storeRecorder) Index() uint64 { return 0 } func (s *storeRecorder) Index() uint64 { return 0 }
func (s *storeRecorder) Get(_ string, _, _ bool) (*store.Event, error) { func (s *storeRecorder) Get(path string, recursive, sorted bool) (*store.Event, error) {
s.record("Get") s.record(action{
name: "Get",
params: []interface{}{path, recursive, sorted},
})
return &store.Event{}, nil return &store.Event{}, nil
} }
func (s *storeRecorder) Set(_ string, _ bool, _ string, _ time.Time) (*store.Event, error) { func (s *storeRecorder) Set(path string, dir bool, val string, expr time.Time) (*store.Event, error) {
s.record("Set") s.record(action{
name: "Set",
params: []interface{}{path, dir, val, expr},
})
return &store.Event{}, nil return &store.Event{}, nil
} }
func (s *storeRecorder) Update(_, _ string, _ time.Time) (*store.Event, error) { func (s *storeRecorder) Update(path, val string, expr time.Time) (*store.Event, error) {
s.record("Update") s.record(action{
name: "Update",
params: []interface{}{path, val, expr},
})
return &store.Event{}, nil return &store.Event{}, nil
} }
func (s *storeRecorder) Create(_ string, _ bool, _ string, _ bool, _ time.Time) (*store.Event, error) { func (s *storeRecorder) Create(path string, dir bool, val string, uniq bool, exp time.Time) (*store.Event, error) {
s.record("Create") s.record(action{
name: "Create",
params: []interface{}{path, dir, val, uniq, exp},
})
return &store.Event{}, nil return &store.Event{}, nil
} }
func (s *storeRecorder) CompareAndSwap(_, _ string, _ uint64, _ string, _ time.Time) (*store.Event, error) { func (s *storeRecorder) CompareAndSwap(path, prevVal string, prevIdx uint64, val string, expr time.Time) (*store.Event, error) {
s.record("CompareAndSwap") s.record(action{
name: "CompareAndSwap",
params: []interface{}{path, prevVal, prevIdx, val, expr},
})
return &store.Event{}, nil return &store.Event{}, nil
} }
func (s *storeRecorder) Delete(_ string, _, _ bool) (*store.Event, error) { func (s *storeRecorder) Delete(path string, dir, recursive bool) (*store.Event, error) {
s.record("Delete") s.record(action{
name: "Delete",
params: []interface{}{path, dir, recursive},
})
return &store.Event{}, nil return &store.Event{}, nil
} }
func (s *storeRecorder) CompareAndDelete(_, _ string, _ uint64) (*store.Event, error) { func (s *storeRecorder) CompareAndDelete(path, prevVal string, prevIdx uint64) (*store.Event, error) {
s.record("CompareAndDelete") s.record(action{
name: "CompareAndDelete",
params: []interface{}{path, prevVal, prevIdx},
})
return &store.Event{}, nil return &store.Event{}, nil
} }
func (s *storeRecorder) Watch(_ string, _, _ bool, _ uint64) (store.Watcher, error) { func (s *storeRecorder) Watch(_ string, _, _ bool, _ uint64) (store.Watcher, error) {
s.record("Watch") s.record(action{name: "Watch"})
return &stubWatcher{}, nil return &stubWatcher{}, nil
} }
func (s *storeRecorder) Save() ([]byte, error) { func (s *storeRecorder) Save() ([]byte, error) {
s.record("Save") s.record(action{name: "Save"})
return nil, nil return nil, nil
} }
func (s *storeRecorder) Recovery(b []byte) error { func (s *storeRecorder) Recovery(b []byte) error {
s.record("Recovery") s.record(action{name: "Recovery"})
return nil return nil
} }
func (s *storeRecorder) TotalTransactions() uint64 { return 0 } func (s *storeRecorder) TotalTransactions() uint64 { return 0 }
func (s *storeRecorder) JsonStats() []byte { return nil } func (s *storeRecorder) JsonStats() []byte { return nil }
func (s *storeRecorder) DeleteExpiredKeys(cutoff time.Time) { func (s *storeRecorder) DeleteExpiredKeys(cutoff time.Time) {
s.record("DeleteExpiredKeys") s.record(action{
name: "DeleteExpiredKeys",
params: []interface{}{cutoff},
})
} }
type stubWatcher struct{} type stubWatcher struct{}
@ -776,24 +971,24 @@ type errStoreRecorder struct {
} }
func (s *errStoreRecorder) Get(_ string, _, _ bool) (*store.Event, error) { func (s *errStoreRecorder) Get(_ string, _, _ bool) (*store.Event, error) {
s.record("Get") s.record(action{name: "Get"})
return nil, s.err return nil, s.err
} }
func (s *errStoreRecorder) Watch(_ string, _, _ bool, _ uint64) (store.Watcher, error) { func (s *errStoreRecorder) Watch(_ string, _, _ bool, _ uint64) (store.Watcher, error) {
s.record("Watch") s.record(action{name: "Watch"})
return nil, s.err return nil, s.err
} }
type waitRecorder struct { type waitRecorder struct {
action []string action []action
} }
func (w *waitRecorder) Register(id int64) <-chan interface{} { func (w *waitRecorder) Register(id int64) <-chan interface{} {
w.action = append(w.action, fmt.Sprint("Register", id)) w.action = append(w.action, action{name: fmt.Sprint("Register", id)})
return nil return nil
} }
func (w *waitRecorder) Trigger(id int64, x interface{}) { func (w *waitRecorder) Trigger(id int64, x interface{}) {
w.action = append(w.action, fmt.Sprint("Trigger", id)) w.action = append(w.action, action{name: fmt.Sprint("Trigger", id)})
} }
func boolp(b bool) *bool { return &b } func boolp(b bool) *bool { return &b }
@ -805,17 +1000,17 @@ type storageRecorder struct {
} }
func (p *storageRecorder) Save(st raftpb.HardState, ents []raftpb.Entry) { func (p *storageRecorder) Save(st raftpb.HardState, ents []raftpb.Entry) {
p.record("Save") p.record(action{name: "Save"})
} }
func (p *storageRecorder) Cut() error { func (p *storageRecorder) Cut() error {
p.record("Cut") p.record(action{name: "Cut"})
return nil return nil
} }
func (p *storageRecorder) SaveSnap(st raftpb.Snapshot) { func (p *storageRecorder) SaveSnap(st raftpb.Snapshot) {
if raft.IsEmptySnap(st) { if raft.IsEmptySnap(st) {
return return
} }
p.record("SaveSnap") p.record(action{name: "SaveSnap"})
} }
type readyNode struct { type readyNode struct {
@ -843,33 +1038,33 @@ type nodeRecorder struct {
} }
func (n *nodeRecorder) Tick() { func (n *nodeRecorder) Tick() {
n.record("Tick") n.record(action{name: "Tick"})
} }
func (n *nodeRecorder) Campaign(ctx context.Context) error { func (n *nodeRecorder) Campaign(ctx context.Context) error {
n.record("Campaign") n.record(action{name: "Campaign"})
return nil return nil
} }
func (n *nodeRecorder) Propose(ctx context.Context, data []byte) error { func (n *nodeRecorder) Propose(ctx context.Context, data []byte) error {
n.record("Propose") n.record(action{name: "Propose"})
return nil return nil
} }
func (n *nodeRecorder) ProposeConfChange(ctx context.Context, conf raftpb.ConfChange) error { func (n *nodeRecorder) ProposeConfChange(ctx context.Context, conf raftpb.ConfChange) error {
n.record("ProposeConfChange") n.record(action{name: "ProposeConfChange"})
return nil return nil
} }
func (n *nodeRecorder) Step(ctx context.Context, msg raftpb.Message) error { func (n *nodeRecorder) Step(ctx context.Context, msg raftpb.Message) error {
n.record("Step") n.record(action{name: "Step"})
return nil return nil
} }
func (n *nodeRecorder) Ready() <-chan raft.Ready { return nil } func (n *nodeRecorder) Ready() <-chan raft.Ready { return nil }
func (n *nodeRecorder) ApplyConfChange(conf raftpb.ConfChange) { func (n *nodeRecorder) ApplyConfChange(conf raftpb.ConfChange) {
n.record("ApplyConfChange") n.record(action{name: "ApplyConfChange"})
} }
func (n *nodeRecorder) Stop() { func (n *nodeRecorder) Stop() {
n.record("Stop") n.record(action{name: "Stop"})
} }
func (n *nodeRecorder) Compact(d []byte) { func (n *nodeRecorder) Compact(d []byte) {
n.record("Compact") n.record(action{name: "Compact"})
} }
type nodeProposeDataRecorder struct { type nodeProposeDataRecorder struct {
@ -898,7 +1093,7 @@ type nodeProposalBlockerRecorder struct {
func (n *nodeProposalBlockerRecorder) Propose(ctx context.Context, data []byte) error { func (n *nodeProposalBlockerRecorder) Propose(ctx context.Context, data []byte) error {
<-ctx.Done() <-ctx.Done()
n.record("Propose blocked") n.record(action{name: "Propose blocked"})
return nil return nil
} }
@ -918,12 +1113,12 @@ func (n *nodeConfChangeCommitterRecorder) ProposeConfChange(ctx context.Context,
return err return err
} }
n.readyc <- raft.Ready{CommittedEntries: []raftpb.Entry{{Type: raftpb.EntryConfChange, Data: data}}} n.readyc <- raft.Ready{CommittedEntries: []raftpb.Entry{{Type: raftpb.EntryConfChange, Data: data}}}
n.record("ProposeConfChange:" + conf.Type.String()) n.record(action{name: "ProposeConfChange:" + conf.Type.String()})
return nil return nil
} }
func (n *nodeConfChangeCommitterRecorder) Ready() <-chan raft.Ready { func (n *nodeConfChangeCommitterRecorder) Ready() <-chan raft.Ready {
return n.readyc return n.readyc
} }
func (n *nodeConfChangeCommitterRecorder) ApplyConfChange(conf raftpb.ConfChange) { func (n *nodeConfChangeCommitterRecorder) ApplyConfChange(conf raftpb.ConfChange) {
n.record("ApplyConfChange:" + conf.Type.String()) n.record(action{name: "ApplyConfChange:" + conf.Type.String()})
} }