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 }