github.com/koko1123/flow-go-1@v0.29.6/module/state_synchronization/requester/unittest/unittest.go (about) 1 package unittest 2 3 import ( 4 "context" 5 "fmt" 6 "sync" 7 8 "github.com/ipfs/go-cid" 9 blockstore "github.com/ipfs/go-ipfs-blockstore" 10 "github.com/stretchr/testify/mock" 11 12 "github.com/koko1123/flow-go-1/model/flow" 13 "github.com/koko1123/flow-go-1/module" 14 "github.com/koko1123/flow-go-1/module/blobs" 15 "github.com/koko1123/flow-go-1/module/executiondatasync/execution_data" 16 "github.com/koko1123/flow-go-1/network/mocknetwork" 17 statemock "github.com/koko1123/flow-go-1/state/protocol/mock" 18 "github.com/koko1123/flow-go-1/storage" 19 storagemock "github.com/koko1123/flow-go-1/storage/mock" 20 ) 21 22 func ExecutionDataFixture(blockID flow.Identifier) *execution_data.BlockExecutionData { 23 return &execution_data.BlockExecutionData{ 24 BlockID: blockID, 25 ChunkExecutionDatas: []*execution_data.ChunkExecutionData{}, 26 } 27 } 28 29 func MockBlobService(bs blockstore.Blockstore) *mocknetwork.BlobService { 30 bex := new(mocknetwork.BlobService) 31 32 bex.On("GetBlobs", mock.Anything, mock.AnythingOfType("[]cid.Cid")). 33 Return(func(ctx context.Context, cids []cid.Cid) <-chan blobs.Blob { 34 ch := make(chan blobs.Blob) 35 36 var wg sync.WaitGroup 37 wg.Add(len(cids)) 38 39 for _, c := range cids { 40 c := c 41 go func() { 42 defer wg.Done() 43 44 blob, err := bs.Get(ctx, c) 45 46 if err != nil { 47 // In the real implementation, Bitswap would keep trying to get the blob from 48 // the network indefinitely, sending requests to more and more peers until it 49 // eventually finds the blob, or the context is canceled. Here, we know that 50 // if the blob is not already in the blobstore, then we will never appear, so 51 // we just wait for the context to be canceled. 52 <-ctx.Done() 53 54 return 55 } 56 57 ch <- blob 58 }() 59 } 60 61 go func() { 62 wg.Wait() 63 close(ch) 64 }() 65 66 return ch 67 }).Maybe() 68 69 bex.On("AddBlobs", mock.Anything, mock.AnythingOfType("[]blocks.Block")).Return(bs.PutMany).Maybe() 70 bex.On("DeleteBlob", mock.Anything, mock.AnythingOfType("cid.Cid")).Return(bs.DeleteBlock).Maybe() 71 72 noop := module.NoopReadyDoneAware{} 73 bex.On("Ready").Return(func() <-chan struct{} { return noop.Ready() }).Maybe() 74 75 return bex 76 } 77 78 type SnapshotMockOptions func(*statemock.Snapshot) 79 80 func WithHead(head *flow.Header) SnapshotMockOptions { 81 return func(snapshot *statemock.Snapshot) { 82 snapshot.On("Head").Return(head, nil) 83 } 84 } 85 86 func WithSeal(seal *flow.Seal) SnapshotMockOptions { 87 return func(snapshot *statemock.Snapshot) { 88 snapshot.On("Seal").Return(seal, nil) 89 } 90 } 91 92 func MockProtocolStateSnapshot(opts ...SnapshotMockOptions) *statemock.Snapshot { 93 snapshot := new(statemock.Snapshot) 94 95 for _, opt := range opts { 96 opt(snapshot) 97 } 98 99 return snapshot 100 } 101 102 type StateMockOptions func(*statemock.State) 103 104 func WithSealedSnapshot(snapshot *statemock.Snapshot) StateMockOptions { 105 return func(state *statemock.State) { 106 state.On("Sealed").Return(snapshot) 107 } 108 } 109 110 func MockProtocolState(opts ...StateMockOptions) *statemock.State { 111 state := new(statemock.State) 112 113 for _, opt := range opts { 114 opt(state) 115 } 116 117 return state 118 } 119 120 type BlockHeaderMockOptions func(*storagemock.Headers) 121 122 func WithByHeight(blocksByHeight map[uint64]*flow.Block) BlockHeaderMockOptions { 123 return func(blocks *storagemock.Headers) { 124 blocks.On("ByHeight", mock.AnythingOfType("uint64")).Return( 125 func(height uint64) *flow.Header { 126 if _, has := blocksByHeight[height]; !has { 127 return nil 128 } 129 return blocksByHeight[height].Header 130 }, 131 func(height uint64) error { 132 if _, has := blocksByHeight[height]; !has { 133 return fmt.Errorf("block %d not found: %w", height, storage.ErrNotFound) 134 } 135 return nil 136 }, 137 ) 138 } 139 } 140 141 func WithByID(blocksByID map[flow.Identifier]*flow.Block) BlockHeaderMockOptions { 142 return func(blocks *storagemock.Headers) { 143 blocks.On("ByBlockID", mock.AnythingOfType("flow.Identifier")).Return( 144 func(blockID flow.Identifier) *flow.Header { 145 if _, has := blocksByID[blockID]; !has { 146 return nil 147 } 148 return blocksByID[blockID].Header 149 }, 150 func(blockID flow.Identifier) error { 151 if _, has := blocksByID[blockID]; !has { 152 return fmt.Errorf("block %s not found: %w", blockID, storage.ErrNotFound) 153 } 154 return nil 155 }, 156 ) 157 } 158 } 159 160 func MockBlockHeaderStorage(opts ...BlockHeaderMockOptions) *storagemock.Headers { 161 headers := new(storagemock.Headers) 162 163 for _, opt := range opts { 164 opt(headers) 165 } 166 167 return headers 168 } 169 170 type ResultsMockOptions func(*storagemock.ExecutionResults) 171 172 func WithByBlockID(resultsByID map[flow.Identifier]*flow.ExecutionResult) ResultsMockOptions { 173 return func(results *storagemock.ExecutionResults) { 174 results.On("ByBlockID", mock.AnythingOfType("flow.Identifier")).Return( 175 func(blockID flow.Identifier) *flow.ExecutionResult { 176 if _, has := resultsByID[blockID]; !has { 177 return nil 178 } 179 return resultsByID[blockID] 180 }, 181 func(blockID flow.Identifier) error { 182 if _, has := resultsByID[blockID]; !has { 183 return fmt.Errorf("result %s not found: %w", blockID, storage.ErrNotFound) 184 } 185 return nil 186 }, 187 ) 188 } 189 } 190 191 func WithResultByID(resultsByID map[flow.Identifier]*flow.ExecutionResult) ResultsMockOptions { 192 return func(results *storagemock.ExecutionResults) { 193 results.On("ByID", mock.AnythingOfType("flow.Identifier")).Return( 194 func(resultID flow.Identifier) *flow.ExecutionResult { 195 if _, has := resultsByID[resultID]; !has { 196 return nil 197 } 198 return resultsByID[resultID] 199 }, 200 func(resultID flow.Identifier) error { 201 if _, has := resultsByID[resultID]; !has { 202 return fmt.Errorf("result %s not found: %w", resultID, storage.ErrNotFound) 203 } 204 return nil 205 }, 206 ) 207 } 208 } 209 210 func MockResultsStorage(opts ...ResultsMockOptions) *storagemock.ExecutionResults { 211 results := new(storagemock.ExecutionResults) 212 213 for _, opt := range opts { 214 opt(results) 215 } 216 217 return results 218 } 219 220 type SealsMockOptions func(*storagemock.Seals) 221 222 func WithSealsByBlockID(sealsByBlockID map[flow.Identifier]*flow.Seal) SealsMockOptions { 223 return func(seals *storagemock.Seals) { 224 seals.On("FinalizedSealForBlock", mock.AnythingOfType("flow.Identifier")).Return( 225 func(blockID flow.Identifier) *flow.Seal { 226 if _, has := sealsByBlockID[blockID]; !has { 227 return nil 228 } 229 return sealsByBlockID[blockID] 230 }, 231 func(blockID flow.Identifier) error { 232 if _, has := sealsByBlockID[blockID]; !has { 233 return fmt.Errorf("seal for block %s not found: %w", blockID, storage.ErrNotFound) 234 } 235 return nil 236 }, 237 ) 238 } 239 } 240 241 func MockSealsStorage(opts ...SealsMockOptions) *storagemock.Seals { 242 seals := new(storagemock.Seals) 243 244 for _, opt := range opts { 245 opt(seals) 246 } 247 248 return seals 249 } 250 251 func RemoveExpectedCall(method string, expectedCalls []*mock.Call) []*mock.Call { 252 for i, call := range expectedCalls { 253 if call.Method == method { 254 expectedCalls = append(expectedCalls[:i], expectedCalls[i+1:]...) 255 } 256 } 257 return expectedCalls 258 }