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" "reflect"
"testing" "testing"
"github.com/coreos/etcd/pkg/testutil"
"github.com/coreos/etcd/pkg/types" "github.com/coreos/etcd/pkg/types"
"github.com/coreos/etcd/raft/raftpb" "github.com/coreos/etcd/raft/raftpb"
"github.com/coreos/etcd/store" "github.com/coreos/etcd/store"
@ -535,10 +536,10 @@ func TestClusterAddMember(t *testing.T) {
c.SetStore(st) c.SetStore(st)
c.AddMember(newTestMember(1, nil, "node1", nil)) c.AddMember(newTestMember(1, nil, "node1", nil))
wactions := []action{ wactions := []testutil.Action{
{ {
name: "Create", Name: "Create",
params: []interface{}{ Params: []interface{}{
path.Join(storeMembersPrefix, "1", "raftAttributes"), path.Join(storeMembersPrefix, "1", "raftAttributes"),
false, false,
`{"peerURLs":null}`, `{"peerURLs":null}`,
@ -623,9 +624,9 @@ func TestClusterRemoveMember(t *testing.T) {
c.SetStore(st) c.SetStore(st)
c.RemoveMember(1) c.RemoveMember(1)
wactions := []action{ wactions := []testutil.Action{
{name: "Delete", params: []interface{}{memberStoreKey(1), true, true}}, {Name: "Delete", Params: []interface{}{memberStoreKey(1), true, true}},
{name: "Create", params: []interface{}{removedMemberStoreKey(1), false, "", false, store.Permanent}}, {Name: "Create", Params: []interface{}{removedMemberStoreKey(1), false, "", false, store.Permanent}},
} }
if !reflect.DeepEqual(st.Action(), wactions) { if !reflect.DeepEqual(st.Action(), wactions) {
t.Errorf("actions = %v, want %v", st.Action(), wactions) t.Errorf("actions = %v, want %v", st.Action(), wactions)

View File

@ -26,7 +26,6 @@ import (
"path" "path"
"reflect" "reflect"
"strconv" "strconv"
"sync"
"testing" "testing"
"time" "time"
@ -49,35 +48,35 @@ func TestDoLocalAction(t *testing.T) {
wresp Response wresp Response
werr error werr error
wactions []action wactions []testutil.Action
}{ }{
{ {
pb.Request{Method: "GET", ID: 1, Wait: true}, 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}, pb.Request{Method: "GET", ID: 1},
Response{Event: &store.Event{}}, nil, Response{Event: &store.Event{}}, nil,
[]action{ []testutil.Action{
action{ {
name: "Get", Name: "Get",
params: []interface{}{"", false, false}, Params: []interface{}{"", false, false},
}, },
}, },
}, },
{ {
pb.Request{Method: "HEAD", ID: 1}, pb.Request{Method: "HEAD", ID: 1},
Response{Event: &store.Event{}}, nil, Response{Event: &store.Event{}}, nil,
[]action{ []testutil.Action{
action{ {
name: "Get", Name: "Get",
params: []interface{}{"", false, false}, Params: []interface{}{"", false, false},
}, },
}, },
}, },
{ {
pb.Request{Method: "BADMETHOD", ID: 1}, pb.Request{Method: "BADMETHOD", ID: 1},
Response{}, ErrUnknownMethod, []action{}, Response{}, ErrUnknownMethod, []testutil.Action{},
}, },
} }
for i, tt := range tests { for i, tt := range tests {
@ -108,25 +107,29 @@ func TestDoBadLocalAction(t *testing.T) {
tests := []struct { tests := []struct {
req pb.Request req pb.Request
wactions []action wactions []testutil.Action
}{ }{
{ {
pb.Request{Method: "GET", ID: 1, Wait: true}, pb.Request{Method: "GET", ID: 1, Wait: true},
[]action{action{name: "Watch"}}, []testutil.Action{{Name: "Watch"}},
}, },
{ {
pb.Request{Method: "GET", ID: 1}, pb.Request{Method: "GET", ID: 1},
[]action{action{ []testutil.Action{
name: "Get", {
params: []interface{}{"", false, false}, Name: "Get",
}}, Params: []interface{}{"", false, false},
},
},
}, },
{ {
pb.Request{Method: "HEAD", ID: 1}, pb.Request{Method: "HEAD", ID: 1},
[]action{action{ []testutil.Action{
name: "Get", {
params: []interface{}{"", false, false}, Name: "Get",
}}, Params: []interface{}{"", false, false},
},
},
}, },
} }
for i, tt := range tests { for i, tt := range tests {
@ -155,16 +158,16 @@ func TestApplyRequest(t *testing.T) {
req pb.Request req pb.Request
wresp Response wresp Response
wactions []action wactions []testutil.Action
}{ }{
// POST ==> Create // POST ==> Create
{ {
pb.Request{Method: "POST", ID: 1}, pb.Request{Method: "POST", ID: 1},
Response{Event: &store.Event{}}, Response{Event: &store.Event{}},
[]action{ []testutil.Action{
action{ {
name: "Create", Name: "Create",
params: []interface{}{"", false, "", true, time.Time{}}, Params: []interface{}{"", false, "", true, time.Time{}},
}, },
}, },
}, },
@ -172,10 +175,10 @@ func TestApplyRequest(t *testing.T) {
{ {
pb.Request{Method: "POST", ID: 1, Expiration: 1337}, pb.Request{Method: "POST", ID: 1, Expiration: 1337},
Response{Event: &store.Event{}}, Response{Event: &store.Event{}},
[]action{ []testutil.Action{
action{ {
name: "Create", Name: "Create",
params: []interface{}{"", false, "", true, time.Unix(0, 1337)}, 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}, pb.Request{Method: "POST", ID: 1, Dir: true},
Response{Event: &store.Event{}}, Response{Event: &store.Event{}},
[]action{ []testutil.Action{
action{ {
name: "Create", Name: "Create",
params: []interface{}{"", true, "", true, time.Time{}}, Params: []interface{}{"", true, "", true, time.Time{}},
}, },
}, },
}, },
@ -194,10 +197,10 @@ func TestApplyRequest(t *testing.T) {
{ {
pb.Request{Method: "PUT", ID: 1}, pb.Request{Method: "PUT", ID: 1},
Response{Event: &store.Event{}}, Response{Event: &store.Event{}},
[]action{ []testutil.Action{
action{ {
name: "Set", Name: "Set",
params: []interface{}{"", false, "", time.Time{}}, Params: []interface{}{"", false, "", time.Time{}},
}, },
}, },
}, },
@ -205,10 +208,10 @@ func TestApplyRequest(t *testing.T) {
{ {
pb.Request{Method: "PUT", ID: 1, Dir: true}, pb.Request{Method: "PUT", ID: 1, Dir: true},
Response{Event: &store.Event{}}, Response{Event: &store.Event{}},
[]action{ []testutil.Action{
action{ {
name: "Set", Name: "Set",
params: []interface{}{"", true, "", time.Time{}}, Params: []interface{}{"", true, "", time.Time{}},
}, },
}, },
}, },
@ -216,10 +219,10 @@ func TestApplyRequest(t *testing.T) {
{ {
pb.Request{Method: "PUT", ID: 1, PrevExist: pbutil.Boolp(true)}, pb.Request{Method: "PUT", ID: 1, PrevExist: pbutil.Boolp(true)},
Response{Event: &store.Event{}}, Response{Event: &store.Event{}},
[]action{ []testutil.Action{
action{ {
name: "Update", Name: "Update",
params: []interface{}{"", "", time.Time{}}, Params: []interface{}{"", "", time.Time{}},
}, },
}, },
}, },
@ -227,10 +230,10 @@ func TestApplyRequest(t *testing.T) {
{ {
pb.Request{Method: "PUT", ID: 1, PrevExist: pbutil.Boolp(false)}, pb.Request{Method: "PUT", ID: 1, PrevExist: pbutil.Boolp(false)},
Response{Event: &store.Event{}}, Response{Event: &store.Event{}},
[]action{ []testutil.Action{
action{ {
name: "Create", Name: "Create",
params: []interface{}{"", false, "", false, time.Time{}}, 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}, pb.Request{Method: "PUT", ID: 1, PrevExist: pbutil.Boolp(true), PrevIndex: 1},
Response{Event: &store.Event{}}, Response{Event: &store.Event{}},
[]action{ []testutil.Action{
action{ {
name: "Update", Name: "Update",
params: []interface{}{"", "", time.Time{}}, 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}, pb.Request{Method: "PUT", ID: 1, PrevExist: pbutil.Boolp(false), PrevIndex: 1},
Response{Event: &store.Event{}}, Response{Event: &store.Event{}},
[]action{ []testutil.Action{
action{ {
name: "Create", Name: "Create",
params: []interface{}{"", false, "", false, time.Time{}}, Params: []interface{}{"", false, "", false, time.Time{}},
}, },
}, },
}, },
@ -262,10 +265,10 @@ func TestApplyRequest(t *testing.T) {
{ {
pb.Request{Method: "PUT", ID: 1, PrevIndex: 1}, pb.Request{Method: "PUT", ID: 1, PrevIndex: 1},
Response{Event: &store.Event{}}, Response{Event: &store.Event{}},
[]action{ []testutil.Action{
action{ {
name: "CompareAndSwap", Name: "CompareAndSwap",
params: []interface{}{"", "", uint64(1), "", time.Time{}}, Params: []interface{}{"", "", uint64(1), "", time.Time{}},
}, },
}, },
}, },
@ -273,10 +276,10 @@ func TestApplyRequest(t *testing.T) {
{ {
pb.Request{Method: "PUT", ID: 1, PrevValue: "bar"}, pb.Request{Method: "PUT", ID: 1, PrevValue: "bar"},
Response{Event: &store.Event{}}, Response{Event: &store.Event{}},
[]action{ []testutil.Action{
action{ {
name: "CompareAndSwap", Name: "CompareAndSwap",
params: []interface{}{"", "bar", uint64(0), "", time.Time{}}, 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"}, pb.Request{Method: "PUT", ID: 1, PrevIndex: 1, PrevValue: "bar"},
Response{Event: &store.Event{}}, Response{Event: &store.Event{}},
[]action{ []testutil.Action{
action{ {
name: "CompareAndSwap", Name: "CompareAndSwap",
params: []interface{}{"", "bar", uint64(1), "", time.Time{}}, Params: []interface{}{"", "bar", uint64(1), "", time.Time{}},
}, },
}, },
}, },
@ -295,10 +298,10 @@ func TestApplyRequest(t *testing.T) {
{ {
pb.Request{Method: "DELETE", ID: 1}, pb.Request{Method: "DELETE", ID: 1},
Response{Event: &store.Event{}}, Response{Event: &store.Event{}},
[]action{ []testutil.Action{
action{ {
name: "Delete", Name: "Delete",
params: []interface{}{"", false, false}, Params: []interface{}{"", false, false},
}, },
}, },
}, },
@ -306,10 +309,10 @@ func TestApplyRequest(t *testing.T) {
{ {
pb.Request{Method: "DELETE", ID: 1, PrevIndex: 1}, pb.Request{Method: "DELETE", ID: 1, PrevIndex: 1},
Response{Event: &store.Event{}}, Response{Event: &store.Event{}},
[]action{ []testutil.Action{
action{ {
name: "CompareAndDelete", Name: "CompareAndDelete",
params: []interface{}{"", "", uint64(1)}, Params: []interface{}{"", "", uint64(1)},
}, },
}, },
}, },
@ -317,10 +320,10 @@ func TestApplyRequest(t *testing.T) {
{ {
pb.Request{Method: "DELETE", ID: 1, PrevValue: "bar"}, pb.Request{Method: "DELETE", ID: 1, PrevValue: "bar"},
Response{Event: &store.Event{}}, Response{Event: &store.Event{}},
[]action{ []testutil.Action{
action{ {
name: "CompareAndDelete", Name: "CompareAndDelete",
params: []interface{}{"", "bar", uint64(0)}, Params: []interface{}{"", "bar", uint64(0)},
}, },
}, },
}, },
@ -328,10 +331,10 @@ func TestApplyRequest(t *testing.T) {
{ {
pb.Request{Method: "DELETE", ID: 1, PrevIndex: 5, PrevValue: "bar"}, pb.Request{Method: "DELETE", ID: 1, PrevIndex: 5, PrevValue: "bar"},
Response{Event: &store.Event{}}, Response{Event: &store.Event{}},
[]action{ []testutil.Action{
action{ {
name: "CompareAndDelete", Name: "CompareAndDelete",
params: []interface{}{"", "bar", uint64(5)}, Params: []interface{}{"", "bar", uint64(5)},
}, },
}, },
}, },
@ -339,10 +342,10 @@ func TestApplyRequest(t *testing.T) {
{ {
pb.Request{Method: "QGET", ID: 1}, pb.Request{Method: "QGET", ID: 1},
Response{Event: &store.Event{}}, Response{Event: &store.Event{}},
[]action{ []testutil.Action{
action{ {
name: "Get", Name: "Get",
params: []interface{}{"", false, false}, Params: []interface{}{"", false, false},
}, },
}, },
}, },
@ -350,20 +353,20 @@ func TestApplyRequest(t *testing.T) {
{ {
pb.Request{Method: "SYNC", ID: 1}, pb.Request{Method: "SYNC", ID: 1},
Response{}, Response{},
[]action{ []testutil.Action{
action{ {
name: "DeleteExpiredKeys", Name: "DeleteExpiredKeys",
params: []interface{}{time.Unix(0, 0)}, Params: []interface{}{time.Unix(0, 0)},
}, },
}, },
}, },
{ {
pb.Request{Method: "SYNC", ID: 1, Time: 12345}, pb.Request{Method: "SYNC", ID: 1, Time: 12345},
Response{}, Response{},
[]action{ []testutil.Action{
action{ {
name: "DeleteExpiredKeys", Name: "DeleteExpiredKeys",
params: []interface{}{time.Unix(0, 12345)}, Params: []interface{}{time.Unix(0, 12345)},
}, },
}, },
}, },
@ -371,7 +374,7 @@ func TestApplyRequest(t *testing.T) {
{ {
pb.Request{Method: "BADMETHOD", ID: 1}, pb.Request{Method: "BADMETHOD", ID: 1},
Response{err: ErrUnknownMethod}, 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) t.Errorf("#%d: applyConfChange error = %v, want %v", i, err, tt.werr)
} }
cc := raftpb.ConfChange{Type: tt.cc.Type, NodeID: raft.None} cc := raftpb.ConfChange{Type: tt.cc.Type, NodeID: raft.None}
w := []action{ w := []testutil.Action{
{ {
name: "ApplyConfChange", Name: "ApplyConfChange",
params: []interface{}{cc}, Params: []interface{}{cc},
}, },
} }
if g := n.Action(); !reflect.DeepEqual(g, w) { if g := n.Action(); !reflect.DeepEqual(g, w) {
@ -558,7 +561,7 @@ func TestDoProposalCancelled(t *testing.T) {
if err != ErrCanceled { if err != ErrCanceled {
t.Fatalf("err = %v, want %v", 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) { 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)
} }
@ -610,10 +613,10 @@ func TestSync(t *testing.T) {
if len(action) != 1 { if len(action) != 1 {
t.Fatalf("len(action) = %d, want 1", len(action)) t.Fatalf("len(action) = %d, want 1", len(action))
} }
if action[0].name != "Propose" { if action[0].Name != "Propose" {
t.Fatalf("action = %s, want Propose", action[0].name) 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 var r pb.Request
if err := r.Unmarshal(data); err != nil { if err := r.Unmarshal(data); err != nil {
t.Fatalf("unmarshal request error: %v", err) t.Fatalf("unmarshal request error: %v", err)
@ -640,7 +643,7 @@ func TestSyncTimeout(t *testing.T) {
// give time for goroutine in sync to cancel // give time for goroutine in sync to cancel
testutil.ForceGosched() testutil.ForceGosched()
w := []action{action{name: "Propose blocked"}} w := []testutil.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)
} }
@ -677,10 +680,10 @@ func TestSyncTrigger(t *testing.T) {
if len(action) != 1 { if len(action) != 1 {
t.Fatalf("len(action) = %d, want 1", len(action)) t.Fatalf("len(action) = %d, want 1", len(action))
} }
if action[0].name != "Propose" { if action[0].Name != "Propose" {
t.Fatalf("action = %s, want Propose", action[0].name) 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 var req pb.Request
if err := req.Unmarshal(data); err != nil { if err := req.Unmarshal(data); err != nil {
t.Fatalf("error unmarshalling data: %v", err) t.Fatalf("error unmarshalling data: %v", err)
@ -707,17 +710,17 @@ func TestSnapshot(t *testing.T) {
if len(gaction) != 1 { if len(gaction) != 1 {
t.Fatalf("len(action) = %d, want 1", len(gaction)) 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]) t.Errorf("action = %s, want Save", gaction[0])
} }
gaction = p.Action() gaction = p.Action()
if len(gaction) != 2 { if len(gaction) != 2 {
t.Fatalf("len(action) = %d, want 2", len(gaction)) 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]) 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]) t.Errorf("action = %s, want SaveSnap", gaction[1])
} }
} }
@ -749,7 +752,7 @@ func TestTriggerSnap(t *testing.T) {
if len(gaction) != wcnt { if len(gaction) != wcnt {
t.Fatalf("len(action) = %d, want %d", 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]) t.Errorf("action = %s, want SaveSnap", gaction[wcnt-1])
} }
} }
@ -777,11 +780,11 @@ func TestRecvSnapshot(t *testing.T) {
testutil.ForceGosched() testutil.ForceGosched()
s.Stop() s.Stop()
wactions := []action{action{name: "Recovery"}} wactions := []testutil.Action{{Name: "Recovery"}}
if g := st.Action(); !reflect.DeepEqual(g, wactions) { if g := st.Action(); !reflect.DeepEqual(g, wactions) {
t.Errorf("store action = %v, want %v", 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) { if g := p.Action(); !reflect.DeepEqual(g, wactions) {
t.Errorf("storage action = %v, want %v", g, wactions) t.Errorf("storage action = %v, want %v", g, wactions)
} }
@ -853,11 +856,11 @@ func TestApplySnapshotAndCommittedEntries(t *testing.T) {
if len(actions) != 2 { if len(actions) != 2 {
t.Fatalf("len(action) = %d, want 2", len(actions)) t.Fatalf("len(action) = %d, want 2", len(actions))
} }
if actions[0].name != "Recovery" { if actions[0].Name != "Recovery" {
t.Errorf("actions[0] = %s, want %s", actions[0].name, "Recovery") t.Errorf("actions[0] = %s, want %s", actions[0].Name, "Recovery")
} }
if actions[1].name != "Get" { if actions[1].Name != "Get" {
t.Errorf("actions[1] = %s, want %s", 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 { if err != nil {
t.Fatalf("AddMember error: %v", err) 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) { if !reflect.DeepEqual(gaction, wactions) {
t.Errorf("action = %v, want %v", gaction, wactions) t.Errorf("action = %v, want %v", gaction, wactions)
} }
@ -922,7 +925,7 @@ func TestRemoveMember(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("RemoveMember error: %v", err) 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) { if !reflect.DeepEqual(gaction, wactions) {
t.Errorf("action = %v, want %v", gaction, wactions) t.Errorf("action = %v, want %v", gaction, wactions)
} }
@ -958,7 +961,7 @@ func TestUpdateMember(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("UpdateMember error: %v", err) 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) { if !reflect.DeepEqual(gaction, wactions) {
t.Errorf("action = %v, want %v", gaction, wactions) t.Errorf("action = %v, want %v", gaction, wactions)
} }
@ -989,10 +992,10 @@ func TestPublish(t *testing.T) {
if len(action) != 1 { if len(action) != 1 {
t.Fatalf("len(action) = %d, want 1", len(action)) t.Fatalf("len(action) = %d, want 1", len(action))
} }
if action[0].name != "Propose" { if action[0].Name != "Propose" {
t.Fatalf("action = %s, want Propose", action[0].name) 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 var r pb.Request
if err := r.Unmarshal(data); err != nil { if err := r.Unmarshal(data); err != nil {
t.Fatalf("unmarshal request error: %v", err) 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 records all the methods it receives.
// storeRecorder DOES NOT work as a actual store. // storeRecorder DOES NOT work as a actual store.
// It always returns invaild empty response and no error. // 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) Version() int { return 0 }
func (s *storeRecorder) Index() uint64 { return 0 } func (s *storeRecorder) Index() uint64 { return 0 }
func (s *storeRecorder) Get(path string, recursive, sorted bool) (*store.Event, error) { func (s *storeRecorder) Get(path string, recursive, sorted bool) (*store.Event, error) {
s.record(action{ s.Record(testutil.Action{
name: "Get", Name: "Get",
params: []interface{}{path, recursive, sorted}, Params: []interface{}{path, recursive, sorted},
}) })
return &store.Event{}, nil return &store.Event{}, nil
} }
func (s *storeRecorder) Set(path string, dir bool, val string, expr time.Time) (*store.Event, error) { func (s *storeRecorder) Set(path string, dir bool, val string, expr time.Time) (*store.Event, error) {
s.record(action{ s.Record(testutil.Action{
name: "Set", Name: "Set",
params: []interface{}{path, dir, val, expr}, Params: []interface{}{path, dir, val, expr},
}) })
return &store.Event{}, nil return &store.Event{}, nil
} }
func (s *storeRecorder) Update(path, val string, expr time.Time) (*store.Event, error) { func (s *storeRecorder) Update(path, val string, expr time.Time) (*store.Event, error) {
s.record(action{ s.Record(testutil.Action{
name: "Update", Name: "Update",
params: []interface{}{path, val, expr}, Params: []interface{}{path, val, expr},
}) })
return &store.Event{}, nil return &store.Event{}, nil
} }
func (s *storeRecorder) Create(path string, dir bool, val string, uniq bool, exp 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(action{ s.Record(testutil.Action{
name: "Create", Name: "Create",
params: []interface{}{path, dir, val, uniq, exp}, Params: []interface{}{path, dir, val, uniq, exp},
}) })
return &store.Event{}, nil return &store.Event{}, nil
} }
func (s *storeRecorder) CompareAndSwap(path, prevVal string, prevIdx uint64, val string, expr time.Time) (*store.Event, error) { func (s *storeRecorder) CompareAndSwap(path, prevVal string, prevIdx uint64, val string, expr time.Time) (*store.Event, error) {
s.record(action{ s.Record(testutil.Action{
name: "CompareAndSwap", Name: "CompareAndSwap",
params: []interface{}{path, prevVal, prevIdx, val, expr}, Params: []interface{}{path, prevVal, prevIdx, val, expr},
}) })
return &store.Event{}, nil return &store.Event{}, nil
} }
func (s *storeRecorder) Delete(path string, dir, recursive bool) (*store.Event, error) { func (s *storeRecorder) Delete(path string, dir, recursive bool) (*store.Event, error) {
s.record(action{ s.Record(testutil.Action{
name: "Delete", Name: "Delete",
params: []interface{}{path, dir, recursive}, Params: []interface{}{path, dir, recursive},
}) })
return &store.Event{}, nil return &store.Event{}, nil
} }
func (s *storeRecorder) CompareAndDelete(path, prevVal string, prevIdx uint64) (*store.Event, error) { func (s *storeRecorder) CompareAndDelete(path, prevVal string, prevIdx uint64) (*store.Event, error) {
s.record(action{ s.Record(testutil.Action{
name: "CompareAndDelete", Name: "CompareAndDelete",
params: []interface{}{path, prevVal, prevIdx}, 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(action{name: "Watch"}) s.Record(testutil.Action{Name: "Watch"})
return &nopWatcher{}, nil return &nopWatcher{}, nil
} }
func (s *storeRecorder) Save() ([]byte, error) { func (s *storeRecorder) Save() ([]byte, error) {
s.record(action{name: "Save"}) s.Record(testutil.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(action{name: "Recovery"}) s.Record(testutil.Action{Name: "Recovery"})
return nil return nil
} }
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(action{ s.Record(testutil.Action{
name: "DeleteExpiredKeys", Name: "DeleteExpiredKeys",
params: []interface{}{cutoff}, Params: []interface{}{cutoff},
}) })
} }
@ -1236,15 +1216,15 @@ func (s *errStoreRecorder) Watch(path string, recursive, sorted bool, index uint
} }
type waitRecorder struct { type waitRecorder struct {
action []action action []testutil.Action
} }
func (w *waitRecorder) Register(id uint64) <-chan interface{} { 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 return nil
} }
func (w *waitRecorder) Trigger(id uint64, x interface{}) { 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 { type waitWithResponse struct {
@ -1256,58 +1236,54 @@ func (w *waitWithResponse) Register(id uint64) <-chan interface{} {
} }
func (w *waitWithResponse) Trigger(id uint64, x interface{}) {} func (w *waitWithResponse) Trigger(id uint64, x interface{}) {}
type storageRecorder struct { type storageRecorder struct{ testutil.Recorder }
recorder
}
func (p *storageRecorder) Save(st raftpb.HardState, ents []raftpb.Entry) error { func (p *storageRecorder) Save(st raftpb.HardState, ents []raftpb.Entry) error {
p.record(action{name: "Save"}) p.Record(testutil.Action{Name: "Save"})
return nil return nil
} }
func (p *storageRecorder) Cut() error { func (p *storageRecorder) Cut() error {
p.record(action{name: "Cut"}) p.Record(testutil.Action{Name: "Cut"})
return nil return nil
} }
func (p *storageRecorder) SaveSnap(st raftpb.Snapshot) error { func (p *storageRecorder) SaveSnap(st raftpb.Snapshot) error {
if !raft.IsEmptySnap(st) { if !raft.IsEmptySnap(st) {
p.record(action{name: "SaveSnap"}) p.Record(testutil.Action{Name: "SaveSnap"})
} }
return nil return nil
} }
func (p *storageRecorder) Close() error { return nil } func (p *storageRecorder) Close() error { return nil }
type nodeRecorder struct { type nodeRecorder struct{ testutil.Recorder }
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 { func (n *nodeRecorder) Campaign(ctx context.Context) error {
n.record(action{name: "Campaign"}) n.Record(testutil.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(action{name: "Propose", params: []interface{}{data}}) n.Record(testutil.Action{Name: "Propose", Params: []interface{}{data}})
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(action{name: "ProposeConfChange"}) n.Record(testutil.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(action{name: "Step"}) n.Record(testutil.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) Advance() {} func (n *nodeRecorder) Advance() {}
func (n *nodeRecorder) ApplyConfChange(conf raftpb.ConfChange) *raftpb.ConfState { 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{} return &raftpb.ConfState{}
} }
func (n *nodeRecorder) Stop() { 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) { func (n *nodeRecorder) Compact(index uint64, nodes []uint64, d []byte) {
n.record(action{name: "Compact"}) n.Record(testutil.Action{Name: "Compact"})
} }
type nodeProposalBlockerRecorder struct { type nodeProposalBlockerRecorder struct {
@ -1316,7 +1292,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(action{name: "Propose blocked"}) n.Record(testutil.Action{Name: "Propose blocked"})
return nil return nil
} }
@ -1337,14 +1313,14 @@ func (n *nodeConfChangeCommitterRecorder) ProposeConfChange(ctx context.Context,
} }
n.index++ n.index++
n.readyc <- raft.Ready{CommittedEntries: []raftpb.Entry{{Index: n.index, Type: raftpb.EntryConfChange, Data: data}}} 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 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) *raftpb.ConfState { 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{} 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
}