github.com/onflow/flow-go@v0.33.17/engine/testutil/mock/nodes.go (about)

     1  package mock
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"sync"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/dgraph-io/badger/v2"
    11  	"github.com/rs/zerolog"
    12  	"github.com/stretchr/testify/require"
    13  
    14  	"github.com/onflow/flow-go/engine/collection/epochmgr"
    15  	collectioningest "github.com/onflow/flow-go/engine/collection/ingest"
    16  	"github.com/onflow/flow-go/engine/collection/pusher"
    17  	followereng "github.com/onflow/flow-go/engine/common/follower"
    18  	"github.com/onflow/flow-go/engine/common/provider"
    19  	"github.com/onflow/flow-go/engine/common/requester"
    20  	"github.com/onflow/flow-go/engine/common/synchronization"
    21  	consensusingest "github.com/onflow/flow-go/engine/consensus/ingestion"
    22  	"github.com/onflow/flow-go/engine/consensus/matching"
    23  	"github.com/onflow/flow-go/engine/consensus/sealing"
    24  	"github.com/onflow/flow-go/engine/execution/computation"
    25  	"github.com/onflow/flow-go/engine/execution/ingestion"
    26  	executionprovider "github.com/onflow/flow-go/engine/execution/provider"
    27  	"github.com/onflow/flow-go/engine/execution/state"
    28  	"github.com/onflow/flow-go/engine/verification/assigner"
    29  	"github.com/onflow/flow-go/engine/verification/assigner/blockconsumer"
    30  	"github.com/onflow/flow-go/engine/verification/fetcher"
    31  	"github.com/onflow/flow-go/engine/verification/fetcher/chunkconsumer"
    32  	verificationrequester "github.com/onflow/flow-go/engine/verification/requester"
    33  	"github.com/onflow/flow-go/engine/verification/verifier"
    34  	"github.com/onflow/flow-go/fvm"
    35  	"github.com/onflow/flow-go/ledger"
    36  	"github.com/onflow/flow-go/ledger/complete"
    37  	"github.com/onflow/flow-go/model/flow"
    38  	"github.com/onflow/flow-go/module"
    39  	"github.com/onflow/flow-go/module/finalizer/consensus"
    40  	"github.com/onflow/flow-go/module/irrecoverable"
    41  	"github.com/onflow/flow-go/module/mempool"
    42  	epochpool "github.com/onflow/flow-go/module/mempool/epochs"
    43  	"github.com/onflow/flow-go/module/metrics"
    44  	"github.com/onflow/flow-go/module/util"
    45  	"github.com/onflow/flow-go/network/stub"
    46  	"github.com/onflow/flow-go/state/protocol"
    47  	"github.com/onflow/flow-go/state/protocol/events"
    48  	"github.com/onflow/flow-go/storage"
    49  	bstorage "github.com/onflow/flow-go/storage/badger"
    50  	"github.com/onflow/flow-go/utils/unittest"
    51  )
    52  
    53  // StateFixture is a test helper struct that encapsulates a flow protocol state
    54  // as well as all of its backend dependencies.
    55  type StateFixture struct {
    56  	DBDir          string
    57  	PublicDB       *badger.DB
    58  	SecretsDB      *badger.DB
    59  	Storage        *storage.All
    60  	ProtocolEvents *events.Distributor
    61  	State          protocol.ParticipantState
    62  }
    63  
    64  // GenericNode implements a generic in-process node for tests.
    65  type GenericNode struct {
    66  	// context and cancel function used to start/stop components
    67  	Ctx    irrecoverable.SignalerContext
    68  	Cancel context.CancelFunc
    69  	Errs   <-chan error
    70  
    71  	Log                zerolog.Logger
    72  	Metrics            *metrics.NoopCollector
    73  	Tracer             module.Tracer
    74  	PublicDB           *badger.DB
    75  	SecretsDB          *badger.DB
    76  	Headers            storage.Headers
    77  	Guarantees         storage.Guarantees
    78  	Seals              storage.Seals
    79  	Payloads           storage.Payloads
    80  	Blocks             storage.Blocks
    81  	QuorumCertificates storage.QuorumCertificates
    82  	State              protocol.ParticipantState
    83  	Index              storage.Index
    84  	Me                 module.Local
    85  	Net                *stub.Network
    86  	DBDir              string
    87  	ChainID            flow.ChainID
    88  	ProtocolEvents     *events.Distributor
    89  }
    90  
    91  func (g *GenericNode) Done() {
    92  	_ = g.PublicDB.Close()
    93  	_ = os.RemoveAll(g.DBDir)
    94  
    95  	<-g.Tracer.Done()
    96  }
    97  
    98  // RequireGenericNodesDoneBefore invokes the done method of all input generic nodes concurrently, and
    99  // fails the test if any generic node's shutdown takes longer than the specified duration.
   100  func RequireGenericNodesDoneBefore(t testing.TB, duration time.Duration, nodes ...*GenericNode) {
   101  	wg := &sync.WaitGroup{}
   102  	wg.Add(len(nodes))
   103  
   104  	for _, node := range nodes {
   105  		go func(n *GenericNode) {
   106  			n.Done()
   107  			wg.Done()
   108  		}(node)
   109  	}
   110  
   111  	unittest.RequireReturnsBefore(t, wg.Wait, duration, "failed to shutdown all components on time")
   112  }
   113  
   114  // CloseDB closes the badger database of the node
   115  func (g *GenericNode) CloseDB() error {
   116  	return g.PublicDB.Close()
   117  }
   118  
   119  // CollectionNode implements an in-process collection node for tests.
   120  type CollectionNode struct {
   121  	GenericNode
   122  	Collections        storage.Collections
   123  	Transactions       storage.Transactions
   124  	ClusterPayloads    storage.ClusterPayloads
   125  	TxPools            *epochpool.TransactionPools
   126  	Voter              module.ClusterRootQCVoter
   127  	IngestionEngine    *collectioningest.Engine
   128  	PusherEngine       *pusher.Engine
   129  	ProviderEngine     *provider.Engine
   130  	EpochManagerEngine *epochmgr.Engine
   131  }
   132  
   133  func (n CollectionNode) Start(t *testing.T) {
   134  	go unittest.FailOnIrrecoverableError(t, n.Ctx.Done(), n.Errs)
   135  	n.IngestionEngine.Start(n.Ctx)
   136  	n.EpochManagerEngine.Start(n.Ctx)
   137  	n.ProviderEngine.Start(n.Ctx)
   138  }
   139  
   140  func (n CollectionNode) Ready() <-chan struct{} {
   141  	return util.AllReady(
   142  		n.PusherEngine,
   143  		n.ProviderEngine,
   144  		n.IngestionEngine,
   145  		n.EpochManagerEngine,
   146  	)
   147  }
   148  
   149  func (n CollectionNode) Done() <-chan struct{} {
   150  	done := make(chan struct{})
   151  	go func() {
   152  		n.GenericNode.Cancel()
   153  		<-util.AllDone(
   154  			n.PusherEngine,
   155  			n.ProviderEngine,
   156  			n.IngestionEngine,
   157  			n.EpochManagerEngine,
   158  		)
   159  		n.GenericNode.Done()
   160  		close(done)
   161  	}()
   162  	return done
   163  }
   164  
   165  // ConsensusNode implements an in-process consensus node for tests.
   166  type ConsensusNode struct {
   167  	GenericNode
   168  	Guarantees      mempool.Guarantees
   169  	Receipts        mempool.ExecutionTree
   170  	Seals           mempool.IncorporatedResultSeals
   171  	IngestionEngine *consensusingest.Engine
   172  	SealingEngine   *sealing.Engine
   173  	MatchingEngine  *matching.Engine
   174  }
   175  
   176  func (cn ConsensusNode) Ready() {
   177  	<-cn.IngestionEngine.Ready()
   178  	<-cn.SealingEngine.Ready()
   179  }
   180  
   181  func (cn ConsensusNode) Done() {
   182  	<-cn.IngestionEngine.Done()
   183  	<-cn.SealingEngine.Done()
   184  }
   185  
   186  // ExecutionNode implements a mocked execution node for tests.
   187  type ExecutionNode struct {
   188  	GenericNode
   189  	FollowerState       protocol.FollowerState
   190  	IngestionEngine     *ingestion.Engine
   191  	ExecutionEngine     *computation.Manager
   192  	RequestEngine       *requester.Engine
   193  	ReceiptsEngine      *executionprovider.Engine
   194  	FollowerCore        module.HotStuffFollower
   195  	FollowerEngine      *followereng.ComplianceEngine
   196  	SyncEngine          *synchronization.Engine
   197  	Compactor           *complete.Compactor
   198  	BadgerDB            *badger.DB
   199  	VM                  fvm.VM
   200  	ExecutionState      state.ExecutionState
   201  	Ledger              ledger.Ledger
   202  	LevelDbDir          string
   203  	Collections         storage.Collections
   204  	Finalizer           *consensus.Finalizer
   205  	MyExecutionReceipts storage.MyExecutionReceipts
   206  	StorehouseEnabled   bool
   207  }
   208  
   209  func (en ExecutionNode) Ready(ctx context.Context) {
   210  	// TODO: receipt engine has been migrated to the new component interface, hence
   211  	// is using Start. Other engines' startup should be refactored once migrated to
   212  	// new interface.
   213  	irctx, _ := irrecoverable.WithSignaler(ctx)
   214  	en.ReceiptsEngine.Start(irctx)
   215  	en.FollowerCore.Start(irctx)
   216  	en.FollowerEngine.Start(irctx)
   217  	en.SyncEngine.Start(irctx)
   218  
   219  	<-util.AllReady(
   220  		en.Ledger,
   221  		en.ReceiptsEngine,
   222  		en.IngestionEngine,
   223  		en.FollowerCore,
   224  		en.FollowerEngine,
   225  		en.RequestEngine,
   226  		en.SyncEngine,
   227  	)
   228  }
   229  
   230  func (en ExecutionNode) Done(cancelFunc context.CancelFunc) {
   231  	// to stop all components running with a component manager.
   232  	cancelFunc()
   233  
   234  	// to stop all (deprecated) ready-done-aware
   235  	<-util.AllDone(
   236  		en.IngestionEngine,
   237  		en.IngestionEngine,
   238  		en.ReceiptsEngine,
   239  		en.Ledger,
   240  		en.FollowerCore,
   241  		en.FollowerEngine,
   242  		en.RequestEngine,
   243  		en.SyncEngine,
   244  		en.Compactor,
   245  	)
   246  	os.RemoveAll(en.LevelDbDir)
   247  	en.GenericNode.Done()
   248  }
   249  
   250  func (en ExecutionNode) AssertHighestExecutedBlock(t *testing.T, header *flow.Header) {
   251  	height, blockID, err := en.ExecutionState.GetHighestExecutedBlockID(context.Background())
   252  	require.NoError(t, err)
   253  
   254  	require.Equal(t, header.ID(), blockID)
   255  	require.Equal(t, header.Height, height)
   256  }
   257  
   258  func (en ExecutionNode) AssertBlockIsExecuted(t *testing.T, header *flow.Header) {
   259  	executed, err := en.ExecutionState.IsBlockExecuted(header.Height, header.ID())
   260  	require.NoError(t, err)
   261  	require.True(t, executed)
   262  }
   263  
   264  func (en ExecutionNode) AssertBlockNotExecuted(t *testing.T, header *flow.Header) {
   265  	executed, err := en.ExecutionState.IsBlockExecuted(header.Height, header.ID())
   266  	require.NoError(t, err)
   267  	require.False(t, executed)
   268  }
   269  
   270  // VerificationNode implements an in-process verification node for tests.
   271  type VerificationNode struct {
   272  	*GenericNode
   273  	ChunkStatuses mempool.ChunkStatuses
   274  	ChunkRequests mempool.ChunkRequests
   275  	Results       storage.ExecutionResults
   276  	Receipts      storage.ExecutionReceipts
   277  
   278  	// chunk consumer and processor for fetcher engine
   279  	ProcessedChunkIndex storage.ConsumerProgress
   280  	ChunksQueue         *bstorage.ChunksQueue
   281  	ChunkConsumer       *chunkconsumer.ChunkConsumer
   282  
   283  	// block consumer for chunk consumer
   284  	ProcessedBlockHeight storage.ConsumerProgress
   285  	BlockConsumer        *blockconsumer.BlockConsumer
   286  
   287  	VerifierEngine  *verifier.Engine
   288  	AssignerEngine  *assigner.Engine
   289  	FetcherEngine   *fetcher.Engine
   290  	RequesterEngine *verificationrequester.Engine
   291  }