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  }