2020-03-11 19:52:25 +00:00
package keeper_test
import (
"reflect"
2020-03-12 17:05:40 +00:00
"time"
2020-03-11 19:52:25 +00:00
2020-03-26 20:17:49 +00:00
"github.com/cosmos/cosmos-sdk/codec"
2020-03-11 19:52:25 +00:00
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/gov"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/kava-labs/kava/app"
2020-03-26 20:17:49 +00:00
"github.com/kava-labs/kava/x/committee"
2020-03-11 19:52:25 +00:00
"github.com/kava-labs/kava/x/committee/types"
)
func ( suite * KeeperTestSuite ) TestSubmitProposal ( ) {
normalCom := types . Committee {
ID : 12 ,
Members : suite . addresses [ : 2 ] ,
Permissions : [ ] types . Permission { types . GodPermission { } } ,
}
noPermissionsCom := types . Committee {
ID : 12 ,
Members : suite . addresses [ : 2 ] ,
Permissions : [ ] types . Permission { } ,
}
testcases := [ ] struct {
name string
committee types . Committee
pubProposal types . PubProposal
proposer sdk . AccAddress
committeeID uint64
expectPass bool
} {
{
name : "normal" ,
committee : normalCom ,
pubProposal : gov . NewTextProposal ( "A Title" , "A description of this proposal." ) ,
proposer : normalCom . Members [ 0 ] ,
committeeID : normalCom . ID ,
expectPass : true ,
} ,
{
name : "invalid proposal" ,
committee : normalCom ,
pubProposal : nil ,
proposer : normalCom . Members [ 0 ] ,
committeeID : normalCom . ID ,
expectPass : false ,
} ,
{
name : "missing committee" ,
// no committee
pubProposal : gov . NewTextProposal ( "A Title" , "A description of this proposal." ) ,
proposer : suite . addresses [ 0 ] ,
committeeID : 0 ,
expectPass : false ,
} ,
{
name : "not a member" ,
committee : normalCom ,
pubProposal : gov . NewTextProposal ( "A Title" , "A description of this proposal." ) ,
proposer : suite . addresses [ 4 ] ,
committeeID : normalCom . ID ,
expectPass : false ,
} ,
{
name : "not enough permissions" ,
committee : noPermissionsCom ,
pubProposal : gov . NewTextProposal ( "A Title" , "A description of this proposal." ) ,
proposer : noPermissionsCom . Members [ 0 ] ,
committeeID : noPermissionsCom . ID ,
expectPass : false ,
} ,
}
for _ , tc := range testcases {
suite . Run ( tc . name , func ( ) {
2020-03-26 20:17:49 +00:00
// Create local testApp because suite doesn't run the SetupTest function for subtests,
// which would mean the app state is not be reset between subtests.
2020-03-11 19:52:25 +00:00
tApp := app . NewTestApp ( )
keeper := tApp . GetCommitteeKeeper ( )
ctx := tApp . NewContext ( true , abci . Header { } )
tApp . InitializeFromGenesisStates ( )
// setup committee (if required)
if ! ( reflect . DeepEqual ( tc . committee , types . Committee { } ) ) {
keeper . SetCommittee ( ctx , tc . committee )
}
id , err := keeper . SubmitProposal ( ctx , tc . proposer , tc . committeeID , tc . pubProposal )
if tc . expectPass {
suite . NoError ( err )
2020-03-12 17:05:40 +00:00
pr , found := keeper . GetProposal ( ctx , id )
2020-03-11 19:52:25 +00:00
suite . True ( found )
2020-03-12 17:05:40 +00:00
suite . Equal ( tc . committeeID , pr . CommitteeID )
suite . Equal ( ctx . BlockTime ( ) . Add ( types . MaxProposalDuration ) , pr . Deadline )
2020-03-11 19:52:25 +00:00
} else {
suite . NotNil ( err )
}
} )
}
}
func ( suite * KeeperTestSuite ) TestAddVote ( ) {
normalCom := types . Committee {
ID : 12 ,
Members : suite . addresses [ : 2 ] ,
Permissions : [ ] types . Permission { types . GodPermission { } } ,
}
2020-03-12 17:05:40 +00:00
firstBlockTime := time . Date ( 1998 , time . January , 1 , 1 , 0 , 0 , 0 , time . UTC )
2020-03-11 19:52:25 +00:00
testcases := [ ] struct {
name string
proposalID uint64
voter sdk . AccAddress
2020-03-12 17:05:40 +00:00
voteTime time . Time
2020-03-11 19:52:25 +00:00
expectPass bool
} {
{
name : "normal" ,
proposalID : types . DefaultNextProposalID ,
voter : normalCom . Members [ 0 ] ,
expectPass : true ,
} ,
{
name : "nonexistent proposal" ,
proposalID : 9999999 ,
voter : normalCom . Members [ 0 ] ,
expectPass : false ,
} ,
{
name : "voter not committee member" ,
proposalID : types . DefaultNextProposalID ,
voter : suite . addresses [ 4 ] ,
expectPass : false ,
} ,
2020-03-12 17:05:40 +00:00
{
name : "proposal expired" ,
proposalID : types . DefaultNextProposalID ,
voter : normalCom . Members [ 0 ] ,
voteTime : firstBlockTime . Add ( types . MaxProposalDuration ) ,
expectPass : false ,
} ,
2020-03-11 19:52:25 +00:00
}
for _ , tc := range testcases {
suite . Run ( tc . name , func ( ) {
// Create local testApp because suite doesn't run the SetupTest function for subtests, which would mean the app state is not be reset between subtests.
tApp := app . NewTestApp ( )
keeper := tApp . GetCommitteeKeeper ( )
2020-03-12 17:05:40 +00:00
ctx := tApp . NewContext ( true , abci . Header { Height : 1 , Time : firstBlockTime } )
2020-03-11 19:52:25 +00:00
tApp . InitializeFromGenesisStates ( )
// setup the committee and proposal
keeper . SetCommittee ( ctx , normalCom )
_ , err := keeper . SubmitProposal ( ctx , normalCom . Members [ 0 ] , normalCom . ID , gov . NewTextProposal ( "A Title" , "A description of this proposal." ) )
suite . NoError ( err )
2020-03-12 17:05:40 +00:00
ctx = ctx . WithBlockTime ( tc . voteTime )
2020-03-11 19:52:25 +00:00
err = keeper . AddVote ( ctx , tc . proposalID , tc . voter )
if tc . expectPass {
suite . NoError ( err )
_ , found := keeper . GetVote ( ctx , tc . proposalID , tc . voter )
suite . True ( found )
} else {
suite . NotNil ( err )
}
} )
}
}
2020-03-26 20:17:49 +00:00
func ( suite * KeeperTestSuite ) TestGetProposalResult ( ) {
var defaultID uint64 = 1
firstBlockTime := time . Date ( 1998 , time . January , 1 , 1 , 0 , 0 , 0 , time . UTC )
testcases := [ ] struct {
name string
committee types . Committee
votes [ ] types . Vote
proposalPasses bool
expectPass bool
} {
{
name : "enough votes" ,
committee : types . Committee {
ID : 12 ,
Members : suite . addresses [ : 5 ] ,
Permissions : [ ] types . Permission { types . GodPermission { } } ,
} ,
votes : [ ] types . Vote {
{ ProposalID : defaultID , Voter : suite . addresses [ 0 ] } ,
{ ProposalID : defaultID , Voter : suite . addresses [ 1 ] } ,
{ ProposalID : defaultID , Voter : suite . addresses [ 2 ] } ,
{ ProposalID : defaultID , Voter : suite . addresses [ 3 ] } ,
} ,
proposalPasses : true ,
expectPass : true ,
} ,
{
name : "not enough votes" ,
committee : types . Committee {
ID : 12 ,
Members : suite . addresses [ : 5 ] ,
Permissions : [ ] types . Permission { types . GodPermission { } } ,
} ,
votes : [ ] types . Vote {
{ ProposalID : defaultID , Voter : suite . addresses [ 0 ] } ,
} ,
proposalPasses : false ,
expectPass : true ,
} ,
2020-03-11 19:52:25 +00:00
}
2020-03-26 20:17:49 +00:00
for _ , tc := range testcases {
suite . Run ( tc . name , func ( ) {
// Create local testApp because suite doesn't run the SetupTest function for subtests, which would mean the app state is not be reset between subtests.
tApp := app . NewTestApp ( )
keeper := tApp . GetCommitteeKeeper ( )
ctx := tApp . NewContext ( true , abci . Header { Height : 1 , Time : firstBlockTime } )
tApp . InitializeFromGenesisStates (
committeeGenState (
tApp . Codec ( ) ,
[ ] types . Committee { tc . committee } ,
[ ] types . Proposal { {
PubProposal : gov . NewTextProposal ( "A Title" , "A description of this proposal." ) ,
ID : defaultID ,
CommitteeID : tc . committee . ID ,
Deadline : firstBlockTime . Add ( time . Hour * 24 * 7 ) ,
} } ,
tc . votes ,
) ,
)
proposalPasses , err := keeper . GetProposalResult ( ctx , defaultID )
if tc . expectPass {
suite . NoError ( err )
suite . Equal ( tc . proposalPasses , proposalPasses )
} else {
suite . NotNil ( err )
}
} )
}
}
func committeeGenState ( cdc * codec . Codec , committees [ ] types . Committee , proposals [ ] types . Proposal , votes [ ] types . Vote ) app . GenesisState {
gs := types . NewGenesisState (
uint64 ( len ( proposals ) + 1 ) ,
committees ,
proposals ,
votes ,
)
return app . GenesisState { committee . ModuleName : cdc . MustMarshalJSON ( gs ) }
2020-03-11 19:52:25 +00:00
}
type UnregisteredProposal struct {
gov . TextProposal
}
func ( UnregisteredProposal ) ProposalRoute ( ) string { return "unregistered" }
func ( UnregisteredProposal ) ProposalType ( ) string { return "unregistered" }
var _ types . PubProposal = UnregisteredProposal { }
func ( suite * KeeperTestSuite ) TestValidatePubProposal ( ) {
testcases := [ ] struct {
name string
pubProposal types . PubProposal
expectPass bool
} {
{
name : "valid" ,
pubProposal : gov . NewTextProposal ( "A Title" , "A description of this proposal." ) ,
expectPass : true ,
} ,
{
name : "invalid (missing title)" ,
pubProposal : gov . TextProposal { Description : "A description of this proposal." } ,
expectPass : false ,
} ,
{
name : "invalid (unregistered)" ,
pubProposal : UnregisteredProposal { gov . TextProposal { Title : "A Title" , Description : "A description of this proposal." } } ,
expectPass : false ,
} ,
{
name : "invalid (nil)" ,
pubProposal : nil ,
expectPass : false ,
} ,
// TODO test case when the handler fails
}
for _ , tc := range testcases {
suite . Run ( tc . name , func ( ) {
err := suite . keeper . ValidatePubProposal ( suite . ctx , tc . pubProposal )
if tc . expectPass {
suite . NoError ( err )
} else {
suite . NotNil ( err )
}
} )
}
}