Commit 75d588eb authored by jiangpeng's avatar jiangpeng

dapp/vote:add test

parent ae0dcb83
......@@ -173,15 +173,18 @@ func (a *action) commitVote(commit *vty.CommitVote) (*types.Receipt, error) {
elog.Error("vote exec commitVote", "txHash", a.txHash, "get group err", err)
return nil, errStateDBGet
}
var voteWeight uint32
for _, member := range group.Members {
if member.Addr == a.fromAddr {
vote.VoteOptions[commit.OptionIndex].Score += member.VoteWeight
voteWeight = member.VoteWeight
}
}
vote.VoteOptions[commit.OptionIndex].Score += voteWeight
info := &vty.CommitInfo{Addr: a.fromAddr}
vote.CommitInfos = append(vote.CommitInfos, info)
voteValue := types.Encode(vote)
//提交的哈希和权重等信息不记录到statedb中
info.VoteWeight = voteWeight
info.TxHash = hex.EncodeToString(a.txHash)
receipt.KV = append(receipt.KV, &types.KeyValue{Key: formatStateIDKey(vote.ID), Value: voteValue})
receipt.Logs = append(receipt.Logs, &types.ReceiptLog{Ty: vty.TyCommitVoteLog, Log: types.Encode(info)})
......
......@@ -152,6 +152,9 @@ func (v *vote) checkCommitVote(commit *vty.CommitVote, tx *types.Transaction, in
return err
}
if voteInfo.BeginTimestamp > action.blockTime {
return errVoteNotStarted
}
if voteInfo.EndTimestamp <= action.blockTime {
return errVoteAlreadyFinished
}
......
package executor
import (
"testing"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
vty "github.com/33cn/plugin/plugin/dapp/vote/types"
)
func TestVote_CheckTx_CreateGroup(t *testing.T) {
tcArr := []*testcase{{
index: 1,
payload: &vty.CreateGroup{},
expectCheckErr: errEmptyName,
}, {
index: 2,
payload: &vty.CreateGroup{Name: "test", Members: []*vty.GroupMember{{}}},
expectCheckErr: errNilMember,
}, {
index: 3,
payload: &vty.CreateGroup{
Name: "test",
Members: []*vty.GroupMember{{
Addr: testAddrs[0],
}, {
Addr: testAddrs[0],
}},
},
expectCheckErr: errDuplicateMember,
}, {
index: 4,
payload: &vty.CreateGroup{Name: "test", Admins: []string{testAddrs[0], testAddrs[0]}},
expectCheckErr: errDuplicateAdmin,
}, {
index: 5,
payload: &vty.CreateGroup{Name: "test"},
},
}
testExec(t, nil, testTypeCheckTx, tcArr, privKeys[0])
}
func TestVote_CheckTx_UpdateGroup(t *testing.T) {
groupID := formatGroupID(dapp.HeightIndexStr(testHeight, 0))
tcArr := []*testcase{{
index: 0,
payload: &vty.CreateGroup{Name: "test"},
execType: testTypeExecLocal,
}, {
index: 1,
payload: &vty.UpdateGroup{},
expectCheckErr: errGroupNotExist,
}, {
index: 2,
payload: &vty.UpdateGroup{GroupID: groupID},
priv: privKeys[1],
expectCheckErr: errAddrPermissionDenied,
}, {
index: 3,
payload: &vty.UpdateGroup{GroupID: groupID, RemoveAdmins: testAddrs[:]},
expectCheckErr: errAddrPermissionDenied,
}, {
index: 4,
payload: &vty.UpdateGroup{GroupID: groupID, AddMembers: []*vty.GroupMember{{Addr: "errAddr"}}},
expectCheckErr: types.ErrInvalidAddress,
}, {
index: 5,
payload: &vty.UpdateGroup{GroupID: groupID, AddAdmins: []string{"errAddr"}},
expectCheckErr: types.ErrInvalidAddress,
}, {
index: 6,
payload: &vty.UpdateGroup{GroupID: groupID, AddAdmins: []string{address.MultiSignAddress(privKeys[0].PubKey().Bytes())}},
expectCheckErr: types.ErrInvalidAddress,
}, {
index: 7,
payload: &vty.UpdateGroup{GroupID: groupID, AddAdmins: []string{testAddrs[1]}},
},
}
testExec(t, nil, testTypeCheckTx, tcArr, privKeys[0])
}
func TestVote_CheckTx_CreateVote(t *testing.T) {
groupID := formatGroupID(dapp.HeightIndexStr(testHeight, 0))
tcArr := []*testcase{{
index: 0,
payload: &vty.CreateGroup{Name: "test"},
execType: testTypeExecLocal,
}, {
index: 1,
payload: &vty.CreateVote{},
expectCheckErr: errEmptyName,
}, {
index: 2,
payload: &vty.CreateVote{Name: "vote"},
expectCheckErr: errGroupNotExist,
}, {
index: 3,
payload: &vty.CreateVote{Name: "vote", GroupID: groupID},
priv: privKeys[1],
expectCheckErr: errAddrPermissionDenied,
}, {
index: 4,
payload: &vty.CreateVote{Name: "vote", GroupID: groupID},
expectCheckErr: errInvalidVoteTime,
}, {
index: 5,
payload: &vty.CreateVote{
Name: "vote",
GroupID: groupID,
BeginTimestamp: testBlockTime + 1,
EndTimestamp: testBlockTime + 1,
},
expectCheckErr: errInvalidVoteTime,
}, {
index: 6,
payload: &vty.CreateVote{
Name: "vote",
GroupID: groupID,
EndTimestamp: testBlockTime + 1,
},
expectCheckErr: errInvalidVoteOption,
}, {
index: 7,
payload: &vty.CreateVote{
Name: "vote",
GroupID: groupID,
EndTimestamp: testBlockTime + 1,
VoteOptions: []string{"A", "B"},
},
},
}
testExec(t, nil, testTypeCheckTx, tcArr, privKeys[0])
}
func TestVote_CheckTx_CommitVote(t *testing.T) {
groupID := formatGroupID(dapp.HeightIndexStr(testHeight, 0))
voteID := formatVoteID(dapp.HeightIndexStr(testHeight, 1))
vote2 := formatVoteID(dapp.HeightIndexStr(testHeight, 7))
tcArr := []*testcase{{
index: 0,
payload: &vty.CreateGroup{Name: "test", Members: []*vty.GroupMember{{Addr: testAddrs[0]}}},
execType: testTypeExecLocal,
}, {
index: 1,
payload: &vty.CreateVote{
Name: "vote",
GroupID: groupID,
EndTimestamp: testBlockTime + 1,
VoteOptions: []string{"A", "B"},
},
execType: testTypeExecLocal,
}, {
index: 2,
payload: &vty.CommitVote{},
expectCheckErr: errVoteNotExist,
}, {
index: 3,
payload: &vty.CommitVote{VoteID: voteID, OptionIndex: 10},
expectCheckErr: errInvalidOptionIndex,
}, {
index: 4,
payload: &vty.CommitVote{VoteID: voteID},
priv: privKeys[1],
expectCheckErr: errAddrPermissionDenied,
}, {
index: 5,
payload: &vty.CommitVote{VoteID: voteID},
execType: testTypeExecLocal,
}, {
index: 6,
payload: &vty.CommitVote{VoteID: voteID},
expectCheckErr: errAddrAlreadyVoted,
}, {
index: 7,
payload: &vty.CreateVote{
Name: "vote",
GroupID: groupID,
BeginTimestamp: testBlockTime + 1,
EndTimestamp: testBlockTime + 2,
VoteOptions: []string{"A", "B"},
},
execType: testTypeExecLocal,
}, {
index: 8,
payload: &vty.CommitVote{VoteID: vote2},
expectCheckErr: errVoteNotStarted,
}}
testExec(t, nil, testTypeCheckTx, tcArr, privKeys[0])
}
func TestVote_CheckTx_CloseVote(t *testing.T) {
groupID := formatGroupID(dapp.HeightIndexStr(testHeight, 0))
voteID := formatVoteID(dapp.HeightIndexStr(testHeight, 1))
tcArr := []*testcase{{
index: 0,
payload: &vty.CreateGroup{Name: "test", Members: []*vty.GroupMember{{Addr: testAddrs[0]}}},
execType: testTypeExecLocal,
}, {
index: 1,
payload: &vty.CreateVote{
Name: "vote",
GroupID: groupID,
EndTimestamp: testBlockTime + 1,
VoteOptions: []string{"A", "B"},
},
execType: testTypeExecLocal,
}, {
index: 2,
payload: &vty.CloseVote{},
expectCheckErr: errVoteNotExist,
}, {
index: 3,
payload: &vty.CloseVote{VoteID: voteID},
priv: privKeys[1],
expectCheckErr: errAddrPermissionDenied,
}, {
index: 4,
payload: &vty.CloseVote{VoteID: voteID},
execType: testTypeExecLocal,
}, {
index: 5,
payload: &vty.CloseVote{VoteID: voteID},
expectCheckErr: errVoteAlreadyClosed,
},
}
testExec(t, nil, testTypeCheckTx, tcArr, privKeys[0])
}
func TestVote_CheckTx_UpdateMember(t *testing.T) {
tcArr := []*testcase{{
index: 0,
payload: &vty.UpdateMember{},
expectCheckErr: errEmptyName,
}, {
index: 1,
payload: &vty.UpdateMember{Name: "test"},
},
}
testExec(t, nil, testTypeCheckTx, tcArr, privKeys[0])
}
......@@ -21,6 +21,7 @@ var (
errAddrAlreadyVoted = errors.New("errAddrAlreadyVoted")
errInvalidGroupMember = errors.New("errInvalidGroupMember")
errVoteAlreadyFinished = errors.New("errVoteAlreadyFinished")
errVoteNotStarted = errors.New("errVoteNotStarted")
errVoteAlreadyClosed = errors.New("errVoteAlreadyClosed")
errAddrPermissionDenied = errors.New("errAddrPermissionDenied")
)
......@@ -25,7 +25,9 @@ func (v *vote) ExecLocal_CreateGroup(payload *vty.CreateGroup, tx *types.Transac
addAddrs := make([]string, 0)
addAddrs = append(addAddrs, groupInfo.Admins...)
for _, member := range groupInfo.Members {
addAddrs = append(addAddrs, member.Addr)
if !checkSliceItemExist(member.Addr, groupInfo.Admins) {
addAddrs = append(addAddrs, member.Addr)
}
}
kvs, err = v.addGroupMember(groupInfo.GetID(), addAddrs)
if err != nil {
......@@ -47,12 +49,14 @@ func (v *vote) ExecLocal_UpdateGroup(update *vty.UpdateGroup, tx *types.Transact
return nil, err
}
dbSet.KV = kvs
removeAddrs := append(update.RemoveAdmins, update.RemoveMembers...)
removeAddrs := make([]string, 0)
//仍然为管理员或群成员之一,不删除groupID索引
for i, addr := range removeAddrs {
tempAddrs := append(update.RemoveAdmins, update.RemoveMembers...)
for _, addr := range tempAddrs {
if checkMemberExist(addr, groupInfo.Members) || checkSliceItemExist(addr, groupInfo.Admins) {
removeAddrs = append(removeAddrs[:i], removeAddrs[i+1:]...)
continue
}
removeAddrs = append(removeAddrs, addr)
}
kvs, err = v.removeGroupMember(groupInfo.GetID(), removeAddrs)
if err != nil {
......@@ -63,7 +67,9 @@ func (v *vote) ExecLocal_UpdateGroup(update *vty.UpdateGroup, tx *types.Transact
addAddrs := make([]string, 0)
addAddrs = append(addAddrs, update.AddAdmins...)
for _, member := range update.AddMembers {
addAddrs = append(addAddrs, member.Addr)
if !checkSliceItemExist(member.Addr, update.AddAdmins) {
addAddrs = append(addAddrs, member.Addr)
}
}
kvs, err = v.addGroupMember(groupInfo.GetID(), addAddrs)
if err != nil {
......@@ -112,6 +118,7 @@ func (v *vote) ExecLocal_CommitVote(payload *vty.CommitVote, tx *types.Transacti
return nil, err
}
voteInfo, _ := row.Data.(*vty.VoteInfo)
voteInfo.VoteOptions[payload.OptionIndex].Score += commitInfo.VoteWeight
voteInfo.CommitInfos = append(voteInfo.CommitInfos, commitInfo)
dbSet.KV, err = v.updateAndSaveTable(table.Replace, table.Save, voteInfo, tx, vty.NameCommitVoteAction, "vote")
if err != nil {
......
package executor
import (
"testing"
"github.com/33cn/chain33/system/dapp"
vty "github.com/33cn/plugin/plugin/dapp/vote/types"
"github.com/33cn/chain33/common/crypto"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util"
"github.com/stretchr/testify/require"
)
const (
testTypeCheckTx = iota + 1
testTypeExec
testTypeExecLocal
testTypeExecDelLocal
)
func testExec(t *testing.T, mock *testExecMock, testExecType int, tcArr []*testcase, priv crypto.PrivKey) {
if mock == nil {
mock = &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
}
exec := mock.exec
for i, tc := range tcArr {
signPriv := priv
if tc.priv != nil {
signPriv = tc.priv
}
tx, err := createTx(mock, tc.payload, signPriv)
require.NoErrorf(t, err, "createTxErr, testIndex=%d", tc.index)
if err != nil {
continue
}
err = exec.CheckTx(tx, i)
require.Equalf(t, tc.expectCheckErr, err, "checkTx err index %d", tc.index)
execType := testExecType
if tc.execType > 0 {
execType = tc.execType
}
if execType == testTypeCheckTx {
continue
}
recp, err := exec.Exec(tx, i)
recpData := &types.ReceiptData{
Ty: recp.GetTy(),
Logs: recp.GetLogs(),
}
if err == nil && len(recp.GetKV()) > 0 {
util.SaveKVList(mock.stateDB, recp.KV)
}
require.Equalf(t, tc.expectExecErr, err, "execTx err index %d", tc.index)
if execType == testTypeExec {
continue
}
kvSet, err := exec.ExecLocal(tx, recpData, i)
for _, kv := range kvSet.GetKV() {
err := mock.localDB.Set(kv.Key, kv.Value)
require.Nil(t, err)
}
require.Equalf(t, tc.expectExecLocalErr, err, "execLocalTx err index %d", tc.index)
if execType == testTypeExecLocal {
continue
}
kvSet, err = exec.ExecDelLocal(tx, recpData, i)
for _, kv := range kvSet.GetKV() {
err := mock.localDB.Set(kv.Key, kv.Value)
require.Nil(t, err)
}
require.Equalf(t, tc.expectExecDelErr, err, "execDelLocalTx err index %d", tc.index)
}
}
func TestVote_Exec(t *testing.T) {
groupID := formatGroupID(dapp.HeightIndexStr(testHeight, 0))
voteID := formatVoteID(dapp.HeightIndexStr(testHeight, 1))
tcArr := []*testcase{{
index: 0,
payload: &vty.CreateGroup{Name: "test", Members: []*vty.GroupMember{{Addr: testAddrs[0]}}},
}, {
index: 1,
payload: &vty.CreateVote{
Name: "vote",
GroupID: groupID,
EndTimestamp: testBlockTime + 1,
VoteOptions: []string{"A", "B"},
},
}, {
index: 2,
payload: &vty.UpdateGroup{GroupID: groupID, RemoveAdmins: testAddrs, AddAdmins: []string{testAddrs[1]}},
}, {
index: 3,
payload: &vty.CommitVote{VoteID: voteID},
}, {
index: 4,
payload: &vty.UpdateGroup{GroupID: groupID, AddAdmins: []string{testAddrs[0]}},
expectCheckErr: errAddrPermissionDenied,
execType: testTypeCheckTx,
}, {
index: 5,
payload: &vty.UpdateGroup{GroupID: groupID, RemoveAdmins: testAddrs, AddAdmins: []string{testAddrs[0]}},
priv: privKeys[1],
}, {
index: 6,
payload: &vty.UpdateGroup{GroupID: groupID, AddMembers: []*vty.GroupMember{{Addr: testAddrs[1]}}, RemoveMembers: testAddrs},
}, {
index: 7,
payload: &vty.CommitVote{VoteID: voteID},
expectCheckErr: errAddrPermissionDenied,
execType: testTypeCheckTx,
}, {
index: 8,
payload: &vty.CommitVote{VoteID: voteID},
priv: privKeys[1],
}, {
index: 9,
payload: &vty.CloseVote{VoteID: voteID},
}, {
index: 10,
payload: &vty.CloseVote{VoteID: voteID},
execType: testTypeCheckTx,
expectCheckErr: errVoteAlreadyClosed,
}, {
index: 11,
payload: &vty.UpdateMember{Name: "testName"},
},
}
testExec(t, nil, testTypeExec, tcArr, privKeys[0])
}
package executor
import (
"testing"
tab "github.com/33cn/chain33/common/db/table"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util"
vty "github.com/33cn/plugin/plugin/dapp/vote/types"
"github.com/stretchr/testify/require"
)
type tableCase struct {
index int
key []byte
expectGetErr error
expectData types.Message
}
func testTableData(t *testing.T, table *tab.Table, tcArr []*tableCase, msg string) {
for _, tc := range tcArr {
row, err := table.GetData(tc.key)
require.Equalf(t, tc.expectGetErr, err, msg+",index=%d", tc.index)
if err != nil {
continue
}
require.Equalf(t, tc.expectData.String(), row.Data.String(),
msg+",index=%d", tc.index)
}
}
func TestVote_ExecLocal_CreateGroup(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
groupID := formatGroupID(dapp.HeightIndexStr(testHeight, 0))
groupID2 := formatGroupID(dapp.HeightIndexStr(testHeight, 1))
members1 := []*vty.GroupMember{{Addr: testAddrs[1], VoteWeight: 1}}
members2 := []*vty.GroupMember{{Addr: testAddrs[2], VoteWeight: 1}}
tcArr := []*testcase{{
index: 0,
payload: &vty.CreateGroup{
Name: "test",
Members: members1},
}, {
index: 1,
payload: &vty.CreateGroup{
Name: "test",
Members: members2},
},
}
testExec(t, mock, testTypeExecLocal, tcArr, privKeys[0])
table := newMemberTable(mock.exec.GetLocalDB())
tcArr1 := []*tableCase{{
index: 0,
key: []byte(testAddrs[0]),
expectData: &vty.MemberInfo{Addr: testAddrs[0], GroupIDs: []string{groupID, groupID2}},
}, {
index: 1,
key: []byte(testAddrs[1]),
expectData: &vty.MemberInfo{Addr: testAddrs[1], GroupIDs: []string{groupID}},
}, {
index: 2,
key: []byte(testAddrs[2]),
expectData: &vty.MemberInfo{Addr: testAddrs[2], GroupIDs: []string{groupID2}},
}, {
index: 3,
key: []byte("addr"),
expectGetErr: types.ErrNotFound,
}}
testTableData(t, table, tcArr1, "check member groupIDs")
table = newGroupTable(mock.exec.GetLocalDB())
tcArr1 = []*tableCase{{
index: 0,
key: []byte(groupID),
expectData: &vty.GroupInfo{ID: groupID, Name: "test", MemberNum: 1,
Admins: []string{testAddrs[0]}, Creator: testAddrs[0], Members: members1},
}, {
index: 1,
key: []byte(groupID2),
expectData: &vty.GroupInfo{ID: groupID2, Name: "test", MemberNum: 1,
Admins: []string{testAddrs[0]}, Creator: testAddrs[0], Members: members2},
}}
testTableData(t, table, tcArr1, "check groupInfo")
}
func TestVote_ExecLocal_UpdateGroup(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
groupID := formatGroupID(dapp.HeightIndexStr(testHeight, 0))
members := []*vty.GroupMember{{Addr: testAddrs[2], VoteWeight: 1}}
tcArr := []*testcase{{
index: 0,
payload: &vty.CreateGroup{Name: "test"},
}, {
index: 1,
payload: &vty.UpdateGroup{GroupID: groupID, RemoveAdmins: []string{testAddrs[0]}, AddAdmins: []string{testAddrs[1]}},
}, {
index: 2,
priv: privKeys[1],
payload: &vty.UpdateGroup{GroupID: groupID, RemoveMembers: testAddrs, AddMembers: members},
}}
testExec(t, mock, testTypeExecLocal, tcArr, privKeys[0])
table := newMemberTable(mock.exec.GetLocalDB())
tcArr1 := []*tableCase{{
index: 0,
key: []byte(testAddrs[0]),
expectData: &vty.MemberInfo{Addr: testAddrs[0]},
}, {
index: 1,
key: []byte(testAddrs[1]),
expectData: &vty.MemberInfo{Addr: testAddrs[1], GroupIDs: []string{groupID}},
}, {
index: 2,
key: []byte(testAddrs[2]),
expectData: &vty.MemberInfo{Addr: testAddrs[2], GroupIDs: []string{groupID}},
}}
testTableData(t, table, tcArr1, "check member groupIDs")
table = newGroupTable(mock.exec.GetLocalDB())
expectInfo := &vty.GroupInfo{ID: groupID, Name: "test", Admins: []string{testAddrs[1]},
Members: members, MemberNum: 1, Creator: testAddrs[0]}
testTableData(t, table, []*tableCase{{
index: 0,
key: []byte(groupID),
expectData: expectInfo,
}, {
index: 1,
key: []byte("testid"),
expectGetErr: types.ErrNotFound,
}}, "check group Info")
tx := util.CreateNoneTx(mock.cfg, privKeys[0])
group, err := newAction(mock.exec, tx, 0).getGroupInfo(groupID)
require.Nil(t, err)
require.Equal(t, group.String(), expectInfo.String())
}
func TestVote_ExecLocal_CreateVote(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
groupID := formatGroupID(dapp.HeightIndexStr(testHeight, 0))
voteID := formatVoteID(dapp.HeightIndexStr(testHeight, 1))
options := []*vty.VoteOption{{Option: "A"}, {Option: "B"}}
tcArr := []*testcase{{
index: 0,
payload: &vty.CreateGroup{Name: "test"},
}, {
index: 1,
payload: &vty.CreateVote{Name: "test", GroupID: groupID, VoteOptions: []string{"A", "B"},
BeginTimestamp: testBlockTime, EndTimestamp: testBlockTime + 1},
}}
testExec(t, mock, testTypeExecLocal, tcArr, privKeys[0])
table := newVoteTable(mock.exec.GetLocalDB())
expectVoteInfo := &vty.VoteInfo{
Name: "test", VoteOptions: options, BeginTimestamp: testBlockTime, EndTimestamp: testBlockTime + 1,
GroupID: groupID, ID: voteID, Creator: testAddrs[0],
}
testTableData(t, table, []*tableCase{{
index: 0,
key: []byte(voteID),
expectData: expectVoteInfo,
}}, "check vote Info")
table = newGroupTable(mock.exec.GetLocalDB())
row, err := table.GetData([]byte(groupID))
require.Nil(t, err)
info, _ := row.Data.(*vty.GroupInfo)
require.Equal(t, uint32(1), info.VoteNum)
tx := util.CreateNoneTx(mock.cfg, privKeys[0])
group, err := newAction(mock.exec, tx, 0).getGroupInfo(groupID)
require.Nil(t, err)
group.VoteNum = info.VoteNum
require.Equal(t, group.String(), info.String())
}
func TestVote_ExecLocal_CloseVote(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
groupID := formatGroupID(dapp.HeightIndexStr(testHeight, 0))
voteID := formatVoteID(dapp.HeightIndexStr(testHeight, 1))
tcArr := []*testcase{{
index: 0,
payload: &vty.CreateGroup{Name: "test"},
}, {
index: 1,
payload: &vty.CreateVote{Name: "test", GroupID: groupID, VoteOptions: []string{"A", "B"},
BeginTimestamp: testBlockTime, EndTimestamp: testBlockTime + 1},
}, {
index: 2,
payload: &vty.CloseVote{VoteID: voteID},
}}
testExec(t, mock, testTypeExecLocal, tcArr, privKeys[0])
table := newVoteTable(mock.exec.GetLocalDB())
row, err := table.GetData([]byte(voteID))
require.Nil(t, err)
info, _ := row.Data.(*vty.VoteInfo)
require.Equal(t, uint32(voteStatusClosed), info.Status)
tx := util.CreateNoneTx(mock.cfg, privKeys[0])
vote, err := newAction(mock.exec, tx, 0).getVoteInfo(voteID)
require.Nil(t, err)
require.Equal(t, vote.String(), info.String())
}
func TestVote_ExecLocal_CommitVote(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
groupID := formatGroupID(dapp.HeightIndexStr(testHeight, 0))
voteID := formatVoteID(dapp.HeightIndexStr(testHeight, 1))
members := []*vty.GroupMember{{Addr: testAddrs[0], VoteWeight: 1}}
tcArr := []*testcase{{
index: 0,
payload: &vty.CreateGroup{Name: "test", Members: members},
}, {
index: 1,
payload: &vty.CreateVote{Name: "test", GroupID: groupID, VoteOptions: []string{"A", "B"},
BeginTimestamp: testBlockTime, EndTimestamp: testBlockTime + 1},
}, {
index: 2,
payload: &vty.CommitVote{VoteID: voteID},
}}
testExec(t, mock, testTypeExecLocal, tcArr, privKeys[0])
table := newVoteTable(mock.exec.GetLocalDB())
row, err := table.GetData([]byte(voteID))
require.Nil(t, err)
info, _ := row.Data.(*vty.VoteInfo)
require.Equal(t, testAddrs[0], info.CommitInfos[0].Addr)
require.Equal(t, uint32(1), info.VoteOptions[0].Score)
tx := util.CreateNoneTx(mock.cfg, privKeys[0])
vote, err := newAction(mock.exec, tx, 0).getVoteInfo(voteID)
require.Nil(t, err)
vote.CommitInfos[0].TxHash = info.CommitInfos[0].TxHash
vote.CommitInfos[0].VoteWeight = info.CommitInfos[0].VoteWeight
require.Equal(t, vote.String(), info.String())
}
func TestVote_ExecDelLocal(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
groupID := formatGroupID(dapp.HeightIndexStr(testHeight, 0))
voteID := formatVoteID(dapp.HeightIndexStr(testHeight, 1))
tcArr := []*testcase{{
index: 0,
payload: &vty.CreateGroup{Name: "test"},
execType: testTypeExecLocal,
}, {
index: 1,
payload: &vty.CreateVote{Name: "test", GroupID: groupID, VoteOptions: []string{"A", "B"},
BeginTimestamp: testBlockTime, EndTimestamp: testBlockTime + 1},
}}
testExec(t, mock, testTypeExecDelLocal, tcArr, privKeys[0])
table := newVoteTable(mock.exec.GetLocalDB())
_, err := table.GetData([]byte(voteID))
require.Equal(t, types.ErrDecode, err)
}
......@@ -29,7 +29,7 @@ func (v *vote) getGroup(groupID string) (*vty.GroupInfo, error) {
// Query_GroupInfo query group info
func (v *vote) Query_GetGroups(in *vty.ReqStrings) (types.Message, error) {
if in == nil {
if len(in.GetItems()) == 0 {
return nil, types.ErrInvalidParam
}
infos := &vty.GroupInfos{GroupList: make([]*vty.GroupInfo, 0, len(in.GetItems()))}
......@@ -65,7 +65,7 @@ func (v *vote) getVote(voteID string) (*vty.VoteInfo, error) {
func (v *vote) Query_GetVotes(in *vty.ReqStrings) (types.Message, error) {
if in == nil {
if len(in.GetItems()) == 0 {
return nil, types.ErrInvalidParam
}
voteList := make([]*vty.VoteInfo, 0, len(in.GetItems()))
......@@ -104,7 +104,7 @@ func (v *vote) getMember(addr string) (*vty.MemberInfo, error) {
func (v *vote) Query_GetMembers(in *vty.ReqStrings) (types.Message, error) {
if in == nil {
if len(in.GetItems()) == 0 {
return nil, types.ErrInvalidParam
}
infos := &vty.MemberInfos{MemberList: make([]*vty.MemberInfo, 0, len(in.GetItems()))}
......
package executor
import (
"testing"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
vty "github.com/33cn/plugin/plugin/dapp/vote/types"
"github.com/stretchr/testify/require"
)
func TestVote_Query_GetGroups(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
groupID := formatGroupID(dapp.HeightIndexStr(testHeight, 0))
groupID2 := formatGroupID(dapp.HeightIndexStr(testHeight, 1))
groupID3 := formatGroupID(dapp.HeightIndexStr(testHeight, 2))
groupIDs := []string{groupID, groupID2, groupID3, "testid"}
tcArr := []*testcase{{
index: 0,
payload: &vty.CreateGroup{Name: "test"},
}, {
index: 1,
payload: &vty.CreateGroup{Name: "test"},
},
}
testExec(t, mock, testTypeExecLocal, tcArr, privKeys[0])
exec := mock.exec
funcName := "GetGroups"
data, err := exec.Query(funcName, nil)
require.Equal(t, types.ErrInvalidParam, err)
data, err = exec.Query(funcName, types.Encode(&vty.ReqStrings{Items: groupIDs[3:]}))
require.Equal(t, errInvalidGroupID, err)
data, err = exec.Query(funcName, types.Encode(&vty.ReqStrings{Items: groupIDs[:3]}))
require.Equal(t, types.ErrNotFound, err)
data, err = exec.Query(funcName, types.Encode(&vty.ReqStrings{Items: groupIDs[:2]}))
require.Equal(t, nil, err)
groups := data.(*vty.GroupInfos)
require.Equal(t, 2, len(groups.GroupList))
require.Equal(t, groupID, groups.GroupList[0].ID)
require.Equal(t, groupID2, groups.GroupList[1].ID)
}
func TestVote_Query_GetVotes(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
groupID := formatGroupID(dapp.HeightIndexStr(testHeight, 0))
voteID := formatVoteID(dapp.HeightIndexStr(testHeight, 1))
voteID2 := formatVoteID(dapp.HeightIndexStr(testHeight, 2))
tcArr := []*testcase{{
index: 0,
payload: &vty.CreateGroup{Name: "test"},
}, {
index: 1,
payload: &vty.CreateVote{Name: "test", GroupID: groupID, VoteOptions: []string{"A", "B"},
BeginTimestamp: testBlockTime, EndTimestamp: testBlockTime + 1},
}}
testExec(t, mock, testTypeExecLocal, tcArr, privKeys[0])
exec := mock.exec
funcName := "GetVotes"
data, err := exec.Query(funcName, nil)
require.Equal(t, types.ErrInvalidParam, err)
data, err = exec.Query(funcName, types.Encode(&vty.ReqStrings{Items: []string{voteID2}}))
require.Equal(t, types.ErrNotFound, err)
data, err = exec.Query(funcName, types.Encode(&vty.ReqStrings{Items: []string{"voteid"}}))
require.Equal(t, errInvalidVoteID, err)
data, err = exec.Query(funcName, types.Encode(&vty.ReqStrings{Items: []string{voteID}}))
require.Equal(t, nil, err)
vote := data.(*vty.ReplyVoteList)
require.Equal(t, voteID, vote.VoteList[0].ID)
}
func TestVote_Query_GetMembers(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
groupID := formatGroupID(dapp.HeightIndexStr(testHeight, 0))
tcArr := []*testcase{{
index: 0,
payload: &vty.CreateGroup{Name: "test", Members: []*vty.GroupMember{{Addr: testAddrs[0]}}},
}}
testExec(t, mock, testTypeExecLocal, tcArr, privKeys[0])
exec := mock.exec
funcName := "GetMembers"
data, err := exec.Query(funcName, nil)
require.Equal(t, types.ErrInvalidParam, err)
data, err = exec.Query(funcName, types.Encode(&vty.ReqStrings{Items: []string{testAddrs[1]}}))
require.Equal(t, types.ErrNotFound, err)
data, err = exec.Query(funcName, types.Encode(&vty.ReqStrings{Items: []string{"addr"}}))
require.Equal(t, types.ErrInvalidAddress, err)
data, err = exec.Query(funcName, types.Encode(&vty.ReqStrings{Items: []string{testAddrs[0]}}))
require.Equal(t, nil, err)
members := data.(*vty.MemberInfos)
require.Equal(t, testAddrs[0], members.MemberList[0].Addr)
require.Equal(t, []string{groupID}, members.MemberList[0].GroupIDs)
}
func TestVote_Query_ListGroup(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
groupID := formatGroupID(dapp.HeightIndexStr(testHeight, 0))
groupID2 := formatGroupID(dapp.HeightIndexStr(testHeight, 1))
tcArr := []*testcase{{
index: 0,
payload: &vty.CreateGroup{Name: "test"},
}, {
index: 1,
payload: &vty.CreateGroup{Name: "test"},
},
}
testExec(t, mock, testTypeExecLocal, tcArr, privKeys[0])
exec := mock.exec
funcName := "ListGroup"
data, err := exec.Query(funcName, nil)
require.Equal(t, nil, err)
list := data.(*vty.GroupInfos)
require.Equal(t, 2, len(list.GroupList))
data, err = exec.Query(funcName, types.Encode(&vty.ReqListItem{Count: 1, Direction: 1}))
require.Equal(t, nil, err)
list = data.(*vty.GroupInfos)
require.Equal(t, 1, len(list.GroupList))
require.Equal(t, groupID, list.GroupList[0].ID)
data, err = exec.Query(funcName, types.Encode(&vty.ReqListItem{StartItemID: groupID2}))
require.Equal(t, nil, err)
list = data.(*vty.GroupInfos)
require.Equal(t, 1, len(list.GroupList))
require.Equal(t, groupID, list.GroupList[0].ID)
}
func TestVote_Query_ListVote(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
groupID := formatGroupID(dapp.HeightIndexStr(testHeight, 0))
now := types.Now().Unix() + 1000
tcArr := []*testcase{{
index: 0,
payload: &vty.CreateGroup{Name: "test"},
}, {
index: 1,
payload: &vty.CreateVote{Name: "test", GroupID: groupID, VoteOptions: []string{"A", "B"},
EndTimestamp: testBlockTime + 1},
}, {
index: 2,
payload: &vty.CreateVote{Name: "test", GroupID: groupID, VoteOptions: []string{"A", "B"},
BeginTimestamp: now, EndTimestamp: now + 1},
}}
testExec(t, mock, testTypeExecLocal, tcArr, privKeys[0])
exec := mock.exec
funcName := "ListVote"
data, err := exec.Query(funcName, nil)
require.Equal(t, types.ErrInvalidParam, err)
data, err = exec.Query(funcName, types.Encode(&vty.ReqListVote{GroupID: groupID, ListReq: &vty.ReqListItem{}}))
require.Nil(t, err)
list := data.(*vty.ReplyVoteList)
require.Equal(t, 2, len(list.VoteList))
data, err = exec.Query(funcName, types.Encode(&vty.ReqListVote{GroupID: groupID, Status: voteStatusPending, ListReq: &vty.ReqListItem{}}))
require.Nil(t, err)
list = data.(*vty.ReplyVoteList)
require.Equal(t, 1, len(list.VoteList))
require.Equal(t, uint32(voteStatusPending), list.VoteList[0].Status)
}
func TestVote_Query_ListMember(t *testing.T) {
mock := &testExecMock{}
mock.InitEnv()
defer mock.FreeEnv()
groupID := formatGroupID(dapp.HeightIndexStr(testHeight, 0))
tcArr := []*testcase{{
index: 0,
payload: &vty.CreateGroup{Name: "test", Members: []*vty.GroupMember{{Addr: testAddrs[0]}}},
}}
testExec(t, mock, testTypeExecLocal, tcArr, privKeys[0])
exec := mock.exec
funcName := "ListMember"
data, err := exec.Query(funcName, nil)
require.Equal(t, nil, err)
list := data.(*vty.MemberInfos)
require.Equal(t, 1, len(list.MemberList))
require.Equal(t, testAddrs[0], list.MemberList[0].Addr)
require.Equal(t, []string{groupID}, list.MemberList[0].GroupIDs)
data, err = exec.Query(funcName, types.Encode(&vty.ReqListItem{StartItemID: "addr"}))
require.Equal(t, nil, err)
list = data.(*vty.MemberInfos)
require.Equal(t, &vty.MemberInfos{}, list)
}
package executor
import (
"errors"
"testing"
"github.com/33cn/chain33/client"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/crypto"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/log"
"github.com/33cn/chain33/queue"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util"
wcom "github.com/33cn/chain33/wallet/common"
vty "github.com/33cn/plugin/plugin/dapp/vote/types"
"github.com/stretchr/testify/require"
)
var (
testHeight = int64(100)
testBlockTime = int64(1539918074)
// 测试的私钥
testPrivateKeys = []string{
"0x8dea7332c7bb3e3b0ce542db41161fd021e3cfda9d7dabacf24f98f2dfd69558",
"0x920976ffe83b5a98f603b999681a0bc790d97e22ffc4e578a707c2234d55cc8a",
"0xb59f2b02781678356c231ad565f73699753a28fd3226f1082b513ebf6756c15c",
}
// 测试的地址
testAddrs = []string{
"1EDDghAtgBsamrNEtNmYdQzC1QEhLkr87t",
"13cS5G1BDN2YfGudsxRxr7X25yu6ZdgxMU",
"1JSRSwp16NvXiTjYBYK9iUQ9wqp3sCxz2p",
}
// 测试的隐私公钥对
testPubkeyPairs = []string{
"92fe6cfec2e19cd15f203f83b5d440ddb63d0cb71559f96dc81208d819fea85886b08f6e874fca15108d244b40f9086d8c03260d4b954a40dfb3cbe41ebc7389",
"6326126c968a93a546d8f67d623ad9729da0e3e4b47c328a273dfea6930ffdc87bcc365822b80b90c72d30e955e7870a7a9725e9a946b9e89aec6db9455557eb",
"44bf54abcbae297baf3dec4dd998b313eafb01166760f0c3a4b36509b33d3b50239de0a5f2f47c2fc98a98a382dcd95a2c5bf1f4910467418a3c2595b853338e",
}
privKeys = make([]crypto.PrivKey, len(testPrivateKeys))
testCfg = types.NewChain33Config(types.GetDefaultCfgstring())
)
func init() {
log.SetLogLevel("error")
Init(vty.VoteX, testCfg, nil)
for i, priv := range testPrivateKeys {
privKeys[i], _ = decodePrivKey(priv)
}
}
type testExecMock struct {
dbDir string
localDB dbm.KVDB
stateDB dbm.DB
exec *vote
policy wcom.WalletBizPolicy
cfg *types.Chain33Config
q queue.Queue
qapi client.QueueProtocolAPI
execType types.ExecutorType
}
type testcase struct {
payload types.Message
expectExecErr error
expectCheckErr error
expectExecLocalErr error
expectExecDelErr error
priv crypto.PrivKey
execType int
index int
}
// InitEnv init env
func (mock *testExecMock) InitEnv() {
mock.cfg = testCfg
util.ResetDatadir(mock.cfg.GetModuleConfig(), "$TEMP/")
mock.q = queue.New("channel")
mock.q.SetConfig(mock.cfg)
mock.qapi, _ = client.New(mock.q.Client(), nil)
mock.initExec()
}
func (mock *testExecMock) FreeEnv() {
util.CloseTestDB(mock.dbDir, mock.stateDB)
}
func (mock *testExecMock) initExec() {
mock.dbDir, mock.stateDB, mock.localDB = util.CreateTestDB()
exec := newVote()
exec.SetAPI(mock.qapi)
exec.SetStateDB(mock.stateDB)
exec.SetLocalDB(mock.localDB)
exec.SetEnv(testHeight, testBlockTime, 1539918074)
mock.exec = exec.(*vote)
mock.execType = types.LoadExecutorType(vty.VoteX)
}
func decodePrivKey(priv string) (crypto.PrivKey, error) {
c, err := crypto.New(crypto.GetName(types.SECP256K1))
if err != nil {
return nil, err
}
bytes, err := common.FromHex(priv[:])
if err != nil {
return nil, err
}
privKey, err := c.PrivKeyFromBytes(bytes)
if err != nil {
return nil, err
}
return privKey, nil
}
func createTx(mock *testExecMock, payload types.Message, privKey crypto.PrivKey) (*types.Transaction, error) {
action, _ := getActionName(payload)
tx, err := mock.execType.CreateTransaction(action, payload)
if err != nil {
return nil, errors.New("createTxErr:" + err.Error())
}
tx, err = types.FormatTx(mock.cfg, vty.VoteX, tx)
if err != nil {
return nil, errors.New("formatTxErr:" + err.Error())
}
tx.Sign(int32(types.SECP256K1), privKey)
return tx, nil
}
func getActionName(param types.Message) (string, error) {
if _, ok := param.(*vty.CreateGroup); ok {
return vty.NameCreateGroupAction, nil
} else if _, ok := param.(*vty.UpdateGroup); ok {
return vty.NameUpdateGroupAction, nil
} else if _, ok := param.(*vty.CreateVote); ok {
return vty.NameCreateVoteAction, nil
} else if _, ok := param.(*vty.CommitVote); ok {
return vty.NameCommitVoteAction, nil
} else if _, ok := param.(*vty.CloseVote); ok {
return vty.NameCloseVoteAction, nil
} else if _, ok := param.(*vty.UpdateMember); ok {
return vty.NameUpdateMemberAction, nil
} else {
return "", types.ErrActionNotSupport
}
}
func TestUtil(t *testing.T) {
heightIndex := dapp.HeightIndexStr(100, 0)
require.Equal(t, IDLen, len(formatGroupID(heightIndex)))
require.Equal(t, IDLen, len(formatVoteID(heightIndex)))
strs := []string{"a", "b", "c"}
require.True(t, checkSliceItemExist("a", strs))
require.False(t, checkSliceItemExist("d", strs))
require.False(t, checkSliceItemDuplicate(strs))
strs = append(strs, "c")
require.True(t, checkSliceItemDuplicate(strs))
members := make([]*vty.GroupMember, 0)
for _, addr := range testAddrs {
members = append(members, &vty.GroupMember{
Addr: addr,
})
}
require.True(t, checkMemberExist(testAddrs[0], members))
require.False(t, checkMemberExist("testaddr", members))
require.Equal(t, addrLen, len(testAddrs[0]))
}
func TestFilterVoteWithStatus(t *testing.T) {
currentTime := types.Now().Unix()
voteList := []*vty.VoteInfo{
{
BeginTimestamp: currentTime + 1,
},
{
EndTimestamp: currentTime + 1,
},
{
BeginTimestamp: currentTime,
EndTimestamp: currentTime,
},
{
Status: voteStatusClosed,
},
}
statusList := []uint32{voteStatusPending, voteStatusOngoing, voteStatusFinished, voteStatusClosed}
voteList = filterVoteWithStatus(voteList, 0, currentTime)
for i, info := range voteList {
require.Equal(t, statusList[i], info.Status)
}
for _, status := range statusList {
list := filterVoteWithStatus(voteList, status, currentTime)
require.Equal(t, 1, len(list))
require.Equal(t, status, list[0].Status)
}
}
......@@ -80,6 +80,7 @@ message CommitVote {
message CommitInfo {
string addr = 1; //提交地址
string txHash = 2; //提交交易哈希
uint32 voteWeight = 3;//投票权重
}
message CloseVote {
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment