Skip to content

Commit

Permalink
add another test and port internal test factory
Browse files Browse the repository at this point in the history
  • Loading branch information
cmwaters committed Aug 6, 2022
1 parent 35bb8e3 commit 4be2e22
Show file tree
Hide file tree
Showing 9 changed files with 330 additions and 1 deletion.
39 changes: 38 additions & 1 deletion consensus/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"time"

"github.com/go-kit/log/term"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"path"
Expand Down Expand Up @@ -462,12 +463,16 @@ func loadPrivValidator(config *cfg.Config) *privval.FilePV {
}

func randState(nValidators int) (*State, []*validatorStub) {
return randStateWithApp(nValidators, counter.NewApplication(true))
}

func randStateWithApp(nValidators int, app abci.Application) (*State, []*validatorStub) {
// Get State
state, privVals := randGenesisState(nValidators, false, 10)

vss := make([]*validatorStub, nValidators)

cs := newState(state, privVals[0], counter.NewApplication(true))
cs := newState(state, privVals[0], app)

for i := 0; i < nValidators; i++ {
vss[i] = newValidatorStub(privVals[i], int32(i))
Expand Down Expand Up @@ -682,6 +687,38 @@ func ensureVote(voteCh <-chan tmpubsub.Message, height int64, round int32,
}
}

func ensurePrevoteMatch(t *testing.T, voteCh <-chan tmpubsub.Message, height int64, round int32, hash []byte) {
t.Helper()
ensureVoteMatch(t, voteCh, height, round, hash, tmproto.PrevoteType)
}

func ensurePrecommitMatch(t *testing.T, voteCh <-chan tmpubsub.Message, height int64, round int32, hash []byte) {
t.Helper()
ensureVoteMatch(t, voteCh, height, round, hash, tmproto.PrecommitType)
}

func ensureVoteMatch(t *testing.T, voteCh <-chan tmpubsub.Message, height int64, round int32, hash []byte, voteType tmproto.SignedMsgType) {
t.Helper()
select {
case <-time.After(ensureTimeout):
t.Fatal("Timeout expired while waiting for NewVote event")
case msg := <-voteCh:
voteEvent, ok := msg.Data().(types.EventDataVote)
require.True(t, ok, "expected a EventDataVote, got %T. Wrong subscription channel?",
msg.Data())

vote := voteEvent.Vote
assert.Equal(t, height, vote.Height, "expected height %d, but got %d", height, vote.Height)
assert.Equal(t, round, vote.Round, "expected round %d, but got %d", round, vote.Round)
assert.Equal(t, voteType, vote.Type, "expected type %s, but got %s", voteType, vote.Type)
if hash == nil {
require.Nil(t, vote.BlockID.Hash, "Expected prevote to be for nil, got %X", vote.BlockID.Hash)
} else {
require.True(t, bytes.Equal(vote.BlockID.Hash, hash), "Expected prevote to be for %X, got %X", hash, vote.BlockID.Hash)
}
}
}

func ensurePrecommitTimeout(ch <-chan tmpubsub.Message) {
select {
case <-time.After(ensureTimeout):
Expand Down
53 changes: 53 additions & 0 deletions consensus/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ import (
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"

"github.com/tendermint/tendermint/abci/example/counter"
abci "github.com/tendermint/tendermint/abci/types"
abcimocks "github.com/tendermint/tendermint/abci/types/mocks"
cstypes "github.com/tendermint/tendermint/consensus/types"
"github.com/tendermint/tendermint/crypto/tmhash"
tmbytes "github.com/tendermint/tendermint/libs/bytes"
"github.com/tendermint/tendermint/libs/log"
tmpubsub "github.com/tendermint/tendermint/libs/pubsub"
tmrand "github.com/tendermint/tendermint/libs/rand"
Expand Down Expand Up @@ -1368,6 +1372,55 @@ func TestSetValidBlockOnDelayedProposal(t *testing.T) {
assert.True(t, rs.ValidRound == round)
}

func TestProcessProposalAccept(t *testing.T) {
for _, testCase := range []struct {
name string
accept bool
expectedNilPrevote bool
}{
{
name: "accepted block is prevoted",
accept: true,
expectedNilPrevote: false,
},
{
name: "rejected block is not prevoted",
accept: false,
expectedNilPrevote: true,
},
} {
t.Run(testCase.name, func(t *testing.T) {
m := abcimocks.NewApplication(t)
status := abci.ResponseProcessProposal_REJECT
if testCase.accept {
status = abci.ResponseProcessProposal_ACCEPT
}
m.On("ProcessProposal", mock.Anything).Return(abci.ResponseProcessProposal{Status: status})
m.On("PrepareProposal", mock.Anything).Return(abci.ResponsePrepareProposal{}).Maybe()
cs1, _ := randStateWithApp(4, m)
height, round := cs1.Height, cs1.Round

proposalCh := subscribe(cs1.eventBus, types.EventQueryCompleteProposal)
newRoundCh := subscribe(cs1.eventBus, types.EventQueryNewRound)
pv1, err := cs1.privValidator.GetPubKey()
require.NoError(t, err)
addr := pv1.Address()
voteCh := subscribeToVoter(cs1, addr)

startTestRound(cs1, cs1.Height, round)
ensureNewRound(newRoundCh, height, round)

ensureNewProposal(proposalCh, height, round)
rs := cs1.GetRoundState()
var prevoteHash tmbytes.HexBytes
if !testCase.expectedNilPrevote {
prevoteHash = rs.ProposalBlock.Hash()
}
ensurePrevoteMatch(t, voteCh, height, round, prevoteHash)
})
}
}

// 4 vals, 3 Nil Precommits at P0
// What we want:
// P0 waits for timeoutPrecommit before starting next round
Expand Down
92 changes: 92 additions & 0 deletions internal/test/block.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package factory

import (
"testing"
"time"

"github.com/stretchr/testify/require"

"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/tmhash"
"github.com/tendermint/tendermint/types"
"github.com/tendermint/tendermint/version"
)

const (
DefaultTestChainID = "test-chain"
)

var (
DefaultTestTime = time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
)

func RandomAddress() []byte {
return crypto.CRandBytes(crypto.AddressSize)
}

func RandomHash() []byte {
return crypto.CRandBytes(tmhash.Size)
}

func MakeBlockID() types.BlockID {
return MakeBlockIDWithHash(RandomHash())
}

func MakeBlockIDWithHash(hash []byte) types.BlockID {
return types.BlockID{
Hash: hash,
PartSetHeader: types.PartSetHeader{
Total: 100,
Hash: RandomHash(),
},
}
}

// MakeHeader fills the rest of the contents of the header such that it passes
// validate basic
func MakeHeader(t *testing.T, h *types.Header) *types.Header {
t.Helper()
if h.Version.Block == 0 {
h.Version.Block = version.BlockProtocol
}
if h.Height == 0 {
h.Height = 1
}
if h.LastBlockID.IsZero() {
h.LastBlockID = MakeBlockID()
}
if h.ChainID == "" {
h.ChainID = DefaultTestChainID
}
if len(h.LastCommitHash) == 0 {
h.LastCommitHash = RandomHash()
}
if len(h.DataHash) == 0 {
h.DataHash = RandomHash()
}
if len(h.ValidatorsHash) == 0 {
h.ValidatorsHash = RandomHash()
}
if len(h.NextValidatorsHash) == 0 {
h.NextValidatorsHash = RandomHash()
}
if len(h.ConsensusHash) == 0 {
h.ConsensusHash = RandomHash()
}
if len(h.AppHash) == 0 {
h.AppHash = RandomHash()
}
if len(h.LastResultsHash) == 0 {
h.LastResultsHash = RandomHash()
}
if len(h.EvidenceHash) == 0 {
h.EvidenceHash = RandomHash()
}
if len(h.ProposerAddress) == 0 {
h.ProposerAddress = RandomAddress()
}

require.NoError(t, h.ValidateBasic())

return h
}
6 changes: 6 additions & 0 deletions internal/test/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*
Package factory provides generation code for common structs in Tendermint.
It is used primarily for the testing of internal components such as statesync,
consensus, blocksync etc..
*/
package factory
11 changes: 11 additions & 0 deletions internal/test/factory_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package factory

import (
"testing"

"github.com/tendermint/tendermint/types"
)

func TestMakeHeader(t *testing.T) {
MakeHeader(t, &types.Header{})
}
34 changes: 34 additions & 0 deletions internal/test/genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package factory

import (
"time"

cfg "github.com/tendermint/tendermint/config"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/tendermint/tendermint/types"
)

func GenesisDoc(
config *cfg.Config,
time time.Time,
validators []*types.Validator,
consensusParams *tmproto.ConsensusParams,
) *types.GenesisDoc {

genesisValidators := make([]types.GenesisValidator, len(validators))

for i := range validators {
genesisValidators[i] = types.GenesisValidator{
Power: validators[i].VotingPower,
PubKey: validators[i].PubKey,
}
}

return &types.GenesisDoc{
GenesisTime: time,
InitialHeight: 1,
ChainID: config.ChainID(),
Validators: genesisValidators,
ConsensusParams: consensusParams,
}
}
11 changes: 11 additions & 0 deletions internal/test/tx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package factory

import "github.com/tendermint/tendermint/types"

func MakeNTxs(height, n int64) []types.Tx {
txs := make([]types.Tx, n)
for i := range txs {
txs[i] = types.Tx([]byte{byte(height), byte(i / 256), byte(i % 256)})
}
return txs
}
41 changes: 41 additions & 0 deletions internal/test/validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package factory

import (
"context"
"sort"
"testing"

"github.com/stretchr/testify/require"

"github.com/tendermint/tendermint/types"
)

func Validator(ctx context.Context, votingPower int64) (*types.Validator, types.PrivValidator, error) {
privVal := types.NewMockPV()
pubKey, err := privVal.GetPubKey()
if err != nil {
return nil, nil, err
}

val := types.NewValidator(pubKey, votingPower)
return val, privVal, nil
}

func ValidatorSet(ctx context.Context, t *testing.T, numValidators int, votingPower int64) (*types.ValidatorSet, []types.PrivValidator) {
var (
valz = make([]*types.Validator, numValidators)
privValidators = make([]types.PrivValidator, numValidators)
)
t.Helper()

for i := 0; i < numValidators; i++ {
val, privValidator, err := Validator(ctx, votingPower)
require.NoError(t, err)
valz[i] = val
privValidators[i] = privValidator
}

sort.Sort(types.PrivValidatorsByAddress(privValidators))

return types.NewValidatorSet(valz), privValidators
}
44 changes: 44 additions & 0 deletions internal/test/vote.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package factory

import (
"context"
"time"

tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/tendermint/tendermint/types"
)

func MakeVote(
ctx context.Context,
val types.PrivValidator,
chainID string,
valIndex int32,
height int64,
round int32,
step int,
blockID types.BlockID,
time time.Time,
) (*types.Vote, error) {
pubKey, err := val.GetPubKey()
if err != nil {
return nil, err
}

v := &types.Vote{
ValidatorAddress: pubKey.Address(),
ValidatorIndex: valIndex,
Height: height,
Round: round,
Type: tmproto.SignedMsgType(step),
BlockID: blockID,
Timestamp: time,
}

vpb := v.ToProto()
if err := val.SignVote(chainID, vpb); err != nil {
return nil, err
}

v.Signature = vpb.Signature
return v, nil
}

0 comments on commit 4be2e22

Please sign in to comment.