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 }