mirror of
https://github.com/QuilibriumNetwork/ceremonyclient.git
synced 2026-02-21 10:27:26 +08:00
* wip: conversion of hotstuff from flow into Q-oriented model * bulk of tests * remaining non-integration tests * add integration test, adjust log interface, small tweaks * further adjustments, restore full pacemaker shape * add component lifecycle management+supervisor * further refinements * resolve timeout hanging * mostly finalized state for consensus * bulk of engine swap out * lifecycle-ify most types * wiring nearly complete, missing needed hooks for proposals * plugged in, vetting message validation paths * global consensus, plugged in and verified * app shard now wired in too * do not decode empty keys.yml (#456) * remove obsolete engine.maxFrames config parameter (#454) * default to Info log level unless debug is enabled (#453) * respect config's "logging" section params, remove obsolete single-file logging (#452) * Trivial code cleanup aiming to reduce Go compiler warnings (#451) * simplify range traversal * simplify channel read for single select case * delete rand.Seed() deprecated in Go 1.20 and no-op as of Go 1.24 * simplify range traversal * simplify channel read for single select case * remove redundant type from array * simplify range traversal * simplify channel read for single select case * RC slate * finalize 2.1.0.5 * Update comments in StrictMonotonicCounter Fix comment formatting and clarify description. --------- Co-authored-by: Black Swan <3999712+blacks1ne@users.noreply.github.com>
109 lines
4.0 KiB
Go
109 lines
4.0 KiB
Go
package voteaggregator
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/mock"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
"source.quilibrium.com/quilibrium/monorepo/consensus/helper"
|
|
"source.quilibrium.com/quilibrium/monorepo/consensus/mocks"
|
|
"source.quilibrium.com/quilibrium/monorepo/consensus/models"
|
|
"source.quilibrium.com/quilibrium/monorepo/lifecycle"
|
|
"source.quilibrium.com/quilibrium/monorepo/lifecycle/unittest"
|
|
)
|
|
|
|
func TestVoteAggregator(t *testing.T) {
|
|
ts := new(VoteAggregatorTestSuite)
|
|
ts.errs = make(chan error, 1)
|
|
suite.Run(t, ts)
|
|
}
|
|
|
|
// VoteAggregatorTestSuite is a test suite for isolated testing of VoteAggregator.
|
|
// Contains mocked state which is used to verify correct behavior of VoteAggregator.
|
|
// Automatically starts and stops module.Startable in SetupTest and TearDownTest respectively.
|
|
type VoteAggregatorTestSuite struct {
|
|
suite.Suite
|
|
|
|
aggregator *VoteAggregator[*helper.TestState, *helper.TestVote]
|
|
collectors *mocks.VoteCollectors[*helper.TestState, *helper.TestVote]
|
|
consumer *mocks.VoteAggregationConsumer[*helper.TestState, *helper.TestVote]
|
|
stopAggregator context.CancelFunc
|
|
errs <-chan error
|
|
}
|
|
|
|
func (s *VoteAggregatorTestSuite) SetupTest() {
|
|
var err error
|
|
s.collectors = mocks.NewVoteCollectors[*helper.TestState, *helper.TestVote](s.T())
|
|
s.consumer = mocks.NewVoteAggregationConsumer[*helper.TestState, *helper.TestVote](s.T())
|
|
|
|
s.collectors.On("Start", mock.Anything).Return(nil).Once()
|
|
unittest.Componentify(&s.collectors.Mock)
|
|
s.aggregator, err = NewVoteAggregator(
|
|
helper.Logger(),
|
|
s.consumer,
|
|
0,
|
|
s.collectors,
|
|
)
|
|
require.NoError(s.T(), err)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
signalerCtx, errs := lifecycle.WithSignaler(ctx)
|
|
s.stopAggregator = cancel
|
|
s.errs = errs
|
|
s.aggregator.Start(signalerCtx)
|
|
unittest.RequireCloseBefore(s.T(), s.aggregator.Ready(), 100*time.Millisecond, "should close before timeout")
|
|
}
|
|
|
|
func (s *VoteAggregatorTestSuite) TearDownTest() {
|
|
s.stopAggregator()
|
|
unittest.RequireCloseBefore(s.T(), s.aggregator.Done(), 10*time.Second, "should close before timeout")
|
|
}
|
|
|
|
// TestOnFinalizedState tests if finalized state gets processed when send through `VoteAggregator`.
|
|
// Tests the whole processing pipeline.
|
|
func (s *VoteAggregatorTestSuite) TestOnFinalizedState() {
|
|
finalizedState := helper.MakeState(helper.WithStateRank[*helper.TestState](100))
|
|
done := make(chan struct{})
|
|
s.collectors.On("PruneUpToRank", uint64(100)).Run(func(args mock.Arguments) {
|
|
close(done)
|
|
}).Once()
|
|
s.aggregator.OnFinalizedState(finalizedState)
|
|
unittest.AssertClosesBefore(s.T(), done, time.Second)
|
|
}
|
|
|
|
// TestProcessInvalidState tests that processing invalid state results in exception, when given as
|
|
// an input to AddState (only expects _valid_ states per API contract).
|
|
// The exception should be propagated to the VoteAggregator's internal `ComponentManager`.
|
|
func (s *VoteAggregatorTestSuite) TestProcessInvalidState() {
|
|
state := helper.MakeSignedProposal(helper.WithProposal[*helper.TestState, *helper.TestVote](helper.MakeProposal(
|
|
helper.WithState(
|
|
helper.MakeState(
|
|
helper.WithStateRank[*helper.TestState](100),
|
|
),
|
|
),
|
|
)))
|
|
processed := make(chan struct{})
|
|
collector := mocks.NewVoteCollector[*helper.TestState, *helper.TestVote](s.T())
|
|
collector.On("ProcessState", state).Run(func(_ mock.Arguments) {
|
|
close(processed)
|
|
}).Return(models.InvalidProposalError[*helper.TestState, *helper.TestVote]{})
|
|
s.collectors.On("GetOrCreateCollector", state.State.Rank).Return(collector, true, nil).Once()
|
|
|
|
// submit state for processing
|
|
s.aggregator.AddState(state)
|
|
unittest.RequireCloseBefore(s.T(), processed, 100*time.Millisecond, "should close before timeout")
|
|
|
|
// expect a thrown error
|
|
select {
|
|
case err := <-s.errs:
|
|
require.Error(s.T(), err)
|
|
require.True(s.T(), models.IsInvalidProposalError[*helper.TestState, *helper.TestVote](err))
|
|
case <-time.After(100 * time.Millisecond):
|
|
s.T().Fatalf("expected error but haven't received anything")
|
|
}
|
|
}
|