Merge pull request #2030 from xiang90/server_test

Server test
This commit is contained in:
Xiang Li 2015-01-02 12:27:39 -08:00
commit 5bb43b5276
3 changed files with 248 additions and 218 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: &stubWatcher{}}, 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,19 +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"}},
[]testutil.Action{
{
Name: "Get",
Params: []interface{}{"", false, false},
},
},
},
{
pb.Request{Method: "HEAD", ID: 1},
[]action{action{name: "Get"}},
[]testutil.Action{
{
Name: "Get",
Params: []interface{}{"", false, false},
},
},
},
}
for i, tt := range tests {
@ -149,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{}},
},
},
},
@ -166,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)},
},
},
},
@ -177,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{}},
},
},
},
@ -188,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{}},
},
},
},
@ -199,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{}},
},
},
},
@ -210,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{}},
},
},
},
@ -221,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{}},
},
},
},
@ -233,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{}},
},
},
},
@ -245,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{}},
},
},
},
@ -256,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{}},
},
},
},
@ -267,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{}},
},
},
},
@ -278,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{}},
},
},
},
@ -289,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},
},
},
},
@ -300,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)},
},
},
},
@ -311,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)},
},
},
},
@ -322,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)},
},
},
},
@ -333,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},
},
},
},
@ -344,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)},
},
},
},
@ -365,7 +374,7 @@ func TestApplyRequest(t *testing.T) {
{
pb.Request{Method: "BADMETHOD", ID: 1},
Response{err: ErrUnknownMethod},
[]action{},
[]testutil.Action{},
},
}
@ -455,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) {
@ -552,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)
}
@ -604,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)
@ -634,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)
}
@ -671,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)
@ -701,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])
}
}
@ -743,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])
}
}
@ -771,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)
}
@ -847,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")
}
}
@ -862,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,
@ -881,7 +891,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)
}
@ -897,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,
@ -916,7 +927,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)
}
@ -932,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,
@ -952,7 +964,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)
}
@ -983,10 +995,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)
@ -1108,135 +1120,114 @@ 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
}
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{ 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"})
return &stubWatcher{}, nil
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},
})
}
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
}
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 {
@ -1248,58 +1239,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 {
@ -1308,7 +1295,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
}
@ -1329,14 +1316,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
}