github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/engine/execution/ingestion/uploader/retryable_uploader_wrapper_test.go (about)

     1  package uploader
     2  
     3  import (
     4  	"sync"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/rs/zerolog"
     9  
    10  	"github.com/onflow/flow-go/ledger"
    11  	"github.com/onflow/flow-go/model/flow"
    12  	"github.com/onflow/flow-go/module/executiondatasync/execution_data"
    13  	executionDataMock "github.com/onflow/flow-go/module/executiondatasync/execution_data/mock"
    14  	"github.com/onflow/flow-go/module/mempool/entity"
    15  	"github.com/onflow/flow-go/module/metrics"
    16  
    17  	"github.com/onflow/flow-go/utils/unittest"
    18  
    19  	"github.com/stretchr/testify/mock"
    20  
    21  	storageMock "github.com/onflow/flow-go/storage/mock"
    22  
    23  	"gotest.tools/assert"
    24  
    25  	"github.com/onflow/flow-go/engine/execution"
    26  )
    27  
    28  func Test_Upload_invoke(t *testing.T) {
    29  	wg := sync.WaitGroup{}
    30  	uploaderCalled := false
    31  
    32  	dummyUploader := &DummyUploader{
    33  		f: func() error {
    34  			uploaderCalled = true
    35  			wg.Done()
    36  			return nil
    37  		},
    38  	}
    39  	asyncUploader := NewAsyncUploader(dummyUploader,
    40  		1*time.Nanosecond, 1, zerolog.Nop(), &metrics.NoopCollector{})
    41  
    42  	testRetryableUploaderWrapper := createTestBadgerRetryableUploaderWrapper(asyncUploader)
    43  	defer testRetryableUploaderWrapper.Done()
    44  
    45  	// nil input - no call to Upload()
    46  	err := testRetryableUploaderWrapper.Upload(nil)
    47  	assert.Assert(t, err != nil)
    48  	assert.Assert(t, !uploaderCalled)
    49  
    50  	// non-nil input - Upload() should be called
    51  	wg.Add(1)
    52  	testComputationResult := createTestComputationResult()
    53  	err = testRetryableUploaderWrapper.Upload(testComputationResult)
    54  	wg.Wait()
    55  
    56  	assert.NilError(t, err)
    57  	assert.Assert(t, uploaderCalled)
    58  }
    59  
    60  func Test_RetryUpload(t *testing.T) {
    61  	wg := sync.WaitGroup{}
    62  	wg.Add(1)
    63  	uploaderCalled := false
    64  	dummyUploader := &DummyUploader{
    65  		f: func() error {
    66  			uploaderCalled = true
    67  			wg.Done()
    68  			return nil
    69  		},
    70  	}
    71  	asyncUploader := NewAsyncUploader(dummyUploader,
    72  		1*time.Nanosecond, 1, zerolog.Nop(), &metrics.NoopCollector{})
    73  
    74  	testRetryableUploaderWrapper := createTestBadgerRetryableUploaderWrapper(asyncUploader)
    75  	defer testRetryableUploaderWrapper.Done()
    76  
    77  	err := testRetryableUploaderWrapper.RetryUpload()
    78  	wg.Wait()
    79  
    80  	assert.NilError(t, err)
    81  	assert.Assert(t, uploaderCalled)
    82  }
    83  
    84  func Test_AsyncUploaderCallback(t *testing.T) {
    85  	wgUploadCalleded := sync.WaitGroup{}
    86  	wgUploadCalleded.Add(1)
    87  
    88  	uploader := &DummyUploader{
    89  		f: func() error {
    90  			wgUploadCalleded.Done()
    91  			return nil
    92  		},
    93  	}
    94  	asyncUploader := NewAsyncUploader(uploader,
    95  		1*time.Nanosecond, 1, zerolog.Nop(), &metrics.NoopCollector{})
    96  
    97  	testRetryableUploaderWrapper := createTestBadgerRetryableUploaderWrapper(asyncUploader)
    98  	defer testRetryableUploaderWrapper.Done()
    99  
   100  	testComputationResult := createTestComputationResult()
   101  	err := testRetryableUploaderWrapper.Upload(testComputationResult)
   102  	assert.NilError(t, err)
   103  
   104  	wgUploadCalleded.Wait()
   105  }
   106  
   107  func Test_ReconstructComputationResultFromStorage(t *testing.T) {
   108  	// test data
   109  	testBlockID := flow.HashToID([]byte{1, 2, 3})
   110  	testEDID := flow.HashToID([]byte{4, 5, 6})
   111  	testTrieUpdateRootHash, _ := ledger.ToRootHash([]byte{7, 8, 9})
   112  	testTrieUpdate := &ledger.TrieUpdate{
   113  		RootHash: testTrieUpdateRootHash,
   114  	}
   115  	testChunkExecutionDatas := []*execution_data.ChunkExecutionData{
   116  		{
   117  			TrieUpdate: testTrieUpdate,
   118  		},
   119  	}
   120  	testEvents := []flow.Event{
   121  		unittest.EventFixture(flow.EventAccountCreated, 0, 0, flow.HashToID([]byte{11, 22, 33}), 200),
   122  	}
   123  	testCollectionID := flow.HashToID([]byte{0xA, 0xB, 0xC})
   124  	testBlock := &flow.Block{
   125  		Header: &flow.Header{},
   126  		Payload: &flow.Payload{
   127  			Guarantees: []*flow.CollectionGuarantee{
   128  				{
   129  					CollectionID: testCollectionID,
   130  				},
   131  			},
   132  		},
   133  	}
   134  	testTransactionBody := &flow.TransactionBody{
   135  		Script: []byte("random script"),
   136  	}
   137  	testCollectionData := &flow.Collection{
   138  		Transactions: []*flow.TransactionBody{testTransactionBody},
   139  	}
   140  	testTransactionResult := flow.TransactionResult{ /*TODO*/ }
   141  	testStateCommit := flow.StateCommitment{}
   142  
   143  	// mock storage interfaces
   144  
   145  	mockBlocksStorage := new(storageMock.Blocks)
   146  	mockBlocksStorage.On("ByID", testBlockID).Return(testBlock, nil)
   147  
   148  	mockCommitsStorage := new(storageMock.Commits)
   149  	mockCommitsStorage.On("ByBlockID", testBlockID).Return(testStateCommit, nil)
   150  
   151  	mockCollectionsStorage := new(storageMock.Collections)
   152  	mockCollectionsStorage.On("ByID", testCollectionID).Return(testCollectionData, nil)
   153  
   154  	mockEventsStorage := new(storageMock.Events)
   155  	mockEventsStorage.On("ByBlockID", testBlockID).Return(testEvents, nil)
   156  
   157  	mockResultsStorage := new(storageMock.ExecutionResults)
   158  	mockResultsStorage.On("ByBlockID", testBlockID).Return(&flow.ExecutionResult{
   159  		ExecutionDataID: testEDID,
   160  	}, nil)
   161  
   162  	mockTransactionResultsStorage := new(storageMock.TransactionResults)
   163  	mockTransactionResultsStorage.On("ByBlockID", testBlockID).Return([]flow.TransactionResult{testTransactionResult}, nil)
   164  
   165  	mockComputationResultStorage := new(storageMock.ComputationResultUploadStatus)
   166  	mockComputationResultStorage.On("GetIDsByUploadStatus", mock.Anything).Return([]flow.Identifier{testBlockID}, nil)
   167  	testComputationResultUploadStatus := false
   168  	mockComputationResultStorage.On("ByID", testBlockID).Return(testComputationResultUploadStatus, nil)
   169  	mockComputationResultStorage.On("Upsert", testBlockID, mock.Anything).Return(nil)
   170  
   171  	mockExecutionDataDowloader := new(executionDataMock.Downloader)
   172  	mockExecutionDataDowloader.On("Get", mock.Anything, testEDID).Return(
   173  		&execution_data.BlockExecutionData{
   174  			BlockID:             testBlockID,
   175  			ChunkExecutionDatas: testChunkExecutionDatas,
   176  		}, nil)
   177  
   178  	dummyUploader := &DummyUploader{
   179  		f: func() error {
   180  			return nil
   181  		},
   182  	}
   183  	testRetryableUploaderWrapper := NewBadgerRetryableUploaderWrapper(
   184  		NewAsyncUploader(dummyUploader,
   185  			1*time.Nanosecond, 1, zerolog.Nop(), &metrics.NoopCollector{}),
   186  		mockBlocksStorage,
   187  		mockCommitsStorage,
   188  		mockCollectionsStorage,
   189  		mockEventsStorage,
   190  		mockResultsStorage,
   191  		mockTransactionResultsStorage,
   192  		mockComputationResultStorage,
   193  		mockExecutionDataDowloader,
   194  		&metrics.NoopCollector{},
   195  	)
   196  
   197  	reconstructedComputationResult, err := testRetryableUploaderWrapper.reconstructComputationResult(testBlockID)
   198  	assert.NilError(t, err)
   199  
   200  	expectedCompleteCollections := make([]*entity.CompleteCollection, 1)
   201  	expectedCompleteCollections[0] = &entity.CompleteCollection{
   202  		Guarantee: &flow.CollectionGuarantee{
   203  			CollectionID: testCollectionID,
   204  		},
   205  		Transactions: []*flow.TransactionBody{testTransactionBody},
   206  	}
   207  
   208  	expectedTestEvents := make([]*flow.Event, len(testEvents))
   209  	for i, event := range testEvents {
   210  		expectedTestEvents[i] = &event
   211  	}
   212  
   213  	expectedBlockData := &BlockData{
   214  		Block:                testBlock,
   215  		Collections:          expectedCompleteCollections,
   216  		TxResults:            []*flow.TransactionResult{&testTransactionResult},
   217  		Events:               expectedTestEvents,
   218  		TrieUpdates:          []*ledger.TrieUpdate{testTrieUpdate},
   219  		FinalStateCommitment: testStateCommit,
   220  	}
   221  
   222  	assert.DeepEqual(
   223  		t,
   224  		expectedBlockData,
   225  		ComputationResultToBlockData(reconstructedComputationResult),
   226  	)
   227  }
   228  
   229  // createTestBadgerRetryableUploaderWrapper() create BadgerRetryableUploaderWrapper instance with given
   230  // AsyncUploader instance and proper mock storage and EDS interfaces.
   231  func createTestBadgerRetryableUploaderWrapper(asyncUploader *AsyncUploader) *BadgerRetryableUploaderWrapper {
   232  	mockBlocksStorage := new(storageMock.Blocks)
   233  	mockBlocksStorage.On("ByID", mock.Anything).Return(&flow.Block{
   234  		Header:  &flow.Header{},
   235  		Payload: nil,
   236  	}, nil)
   237  
   238  	mockCommitsStorage := new(storageMock.Commits)
   239  	mockCommitsStorage.On("ByBlockID", mock.Anything).Return(nil, nil)
   240  
   241  	mockCollectionsStorage := new(storageMock.Collections)
   242  
   243  	mockEventsStorage := new(storageMock.Events)
   244  	mockEventsStorage.On("ByBlockID", mock.Anything).Return([]flow.Event{}, nil)
   245  
   246  	mockResultsStorage := new(storageMock.ExecutionResults)
   247  	mockResultsStorage.On("ByBlockID", mock.Anything).Return(&flow.ExecutionResult{
   248  		ExecutionDataID: flow.ZeroID,
   249  	}, nil)
   250  
   251  	mockTransactionResultsStorage := new(storageMock.TransactionResults)
   252  	mockTransactionResultsStorage.On("ByBlockID", mock.Anything).Return(nil, nil)
   253  
   254  	mockComputationResultStorage := new(storageMock.ComputationResultUploadStatus)
   255  	testID := flow.HashToID([]byte{1, 2, 3})
   256  	mockComputationResultStorage.On("GetIDsByUploadStatus", mock.Anything).Return([]flow.Identifier{testID}, nil)
   257  	testComputationResultUploadStatus := false
   258  	mockComputationResultStorage.On("ByID", testID).Return(testComputationResultUploadStatus, nil)
   259  	mockComputationResultStorage.On("Upsert", mock.Anything, mock.Anything).Return(nil)
   260  
   261  	mockExecutionDataDowloader := new(executionDataMock.Downloader)
   262  	mockExecutionDataDowloader.On("Get", mock.Anything, mock.Anything).Return(
   263  		&execution_data.BlockExecutionData{
   264  			BlockID:             flow.ZeroID,
   265  			ChunkExecutionDatas: make([]*execution_data.ChunkExecutionData, 0),
   266  		}, nil)
   267  
   268  	return NewBadgerRetryableUploaderWrapper(
   269  		asyncUploader,
   270  		mockBlocksStorage,
   271  		mockCommitsStorage,
   272  		mockCollectionsStorage,
   273  		mockEventsStorage,
   274  		mockResultsStorage,
   275  		mockTransactionResultsStorage,
   276  		mockComputationResultStorage,
   277  		mockExecutionDataDowloader,
   278  		&metrics.NoopCollector{},
   279  	)
   280  }
   281  
   282  // createTestComputationResult() creates ComputationResult with valid ExecutableBlock ID
   283  func createTestComputationResult() *execution.ComputationResult {
   284  	blockA := unittest.BlockHeaderFixture()
   285  	start := unittest.StateCommitmentFixture()
   286  	blockB := unittest.ExecutableBlockFixtureWithParent(nil, blockA, &start)
   287  	testComputationResult := execution.NewEmptyComputationResult(blockB)
   288  	return testComputationResult
   289  }