github.com/koko1123/flow-go-1@v0.29.6/admin/commands/storage/read_results_test.go (about) 1 package storage 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "testing" 8 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/mock" 11 "github.com/stretchr/testify/require" 12 "github.com/stretchr/testify/suite" 13 14 "github.com/koko1123/flow-go-1/admin" 15 "github.com/koko1123/flow-go-1/admin/commands" 16 "github.com/koko1123/flow-go-1/model/flow" 17 "github.com/koko1123/flow-go-1/state/protocol" 18 "github.com/koko1123/flow-go-1/state/protocol/invalid" 19 protocolmock "github.com/koko1123/flow-go-1/state/protocol/mock" 20 storagemock "github.com/koko1123/flow-go-1/storage/mock" 21 "github.com/koko1123/flow-go-1/utils/unittest" 22 ) 23 24 type ReadResultsSuite struct { 25 suite.Suite 26 27 command commands.AdminCommand 28 state *protocolmock.State 29 results *storagemock.ExecutionResults 30 31 final *flow.Block 32 sealed *flow.Block 33 allBlocks []*flow.Block 34 35 finalResult *flow.ExecutionResult 36 sealedResult *flow.ExecutionResult 37 allResults []*flow.ExecutionResult 38 } 39 40 func TestReadResults(t *testing.T) { 41 t.Parallel() 42 suite.Run(t, new(ReadResultsSuite)) 43 } 44 45 func (suite *ReadResultsSuite) SetupTest() { 46 suite.state = new(protocolmock.State) 47 suite.results = new(storagemock.ExecutionResults) 48 49 var blocks []*flow.Block 50 var results []*flow.ExecutionResult 51 52 genesis := unittest.GenesisFixture() 53 genesisResult := unittest.ExecutionResultFixture(unittest.WithBlock(genesis)) 54 blocks = append(blocks, genesis) 55 results = append(results, genesisResult) 56 57 sealed := unittest.BlockWithParentFixture(genesis.Header) 58 sealedResult := unittest.ExecutionResultFixture( 59 unittest.WithBlock(sealed), 60 unittest.WithPreviousResult(*genesisResult), 61 ) 62 blocks = append(blocks, sealed) 63 results = append(results, sealedResult) 64 65 final := unittest.BlockWithParentFixture(sealed.Header) 66 finalResult := unittest.ExecutionResultFixture( 67 unittest.WithBlock(final), 68 unittest.WithPreviousResult(*sealedResult), 69 ) 70 blocks = append(blocks, final) 71 results = append(results, finalResult) 72 73 final = unittest.BlockWithParentFixture(final.Header) 74 finalResult = unittest.ExecutionResultFixture( 75 unittest.WithBlock(final), 76 unittest.WithPreviousResult(*finalResult), 77 ) 78 blocks = append(blocks, final) 79 results = append(results, finalResult) 80 81 final = unittest.BlockWithParentFixture(final.Header) 82 finalResult = unittest.ExecutionResultFixture( 83 unittest.WithBlock(final), 84 unittest.WithPreviousResult(*finalResult), 85 ) 86 blocks = append(blocks, final) 87 results = append(results, finalResult) 88 89 suite.allBlocks = blocks 90 suite.sealed = sealed 91 suite.final = final 92 suite.allResults = results 93 suite.finalResult = finalResult 94 suite.sealedResult = sealedResult 95 96 suite.state.On("Final").Return(createSnapshot(final.Header)) 97 suite.state.On("Sealed").Return(createSnapshot(sealed.Header)) 98 suite.state.On("AtBlockID", mock.Anything).Return( 99 func(blockID flow.Identifier) protocol.Snapshot { 100 for _, block := range blocks { 101 if block.ID() == blockID { 102 return createSnapshot(block.Header) 103 } 104 } 105 return invalid.NewSnapshot(fmt.Errorf("invalid block ID: %v", blockID)) 106 }, 107 ) 108 suite.state.On("AtHeight", mock.Anything).Return( 109 func(height uint64) protocol.Snapshot { 110 if int(height) < len(blocks) { 111 block := blocks[height] 112 return createSnapshot(block.Header) 113 } 114 return invalid.NewSnapshot(fmt.Errorf("invalid height: %v", height)) 115 }, 116 ) 117 118 suite.results.On("ByID", mock.Anything).Return( 119 func(resultID flow.Identifier) *flow.ExecutionResult { 120 for _, result := range results { 121 if result.ID() == resultID { 122 return result 123 } 124 } 125 return nil 126 }, 127 func(resultID flow.Identifier) error { 128 for _, result := range results { 129 if result.ID() == resultID { 130 return nil 131 } 132 } 133 return fmt.Errorf("result %#v not found", resultID) 134 }, 135 ) 136 137 suite.results.On("ByBlockID", mock.Anything).Return( 138 func(blockID flow.Identifier) *flow.ExecutionResult { 139 for _, result := range results { 140 if result.BlockID == blockID { 141 return result 142 } 143 } 144 return nil 145 }, 146 func(blockID flow.Identifier) error { 147 for _, result := range results { 148 if result.BlockID == blockID { 149 return nil 150 } 151 } 152 return fmt.Errorf("result for block %#v not found", blockID) 153 }, 154 ) 155 156 suite.command = NewReadResultsCommand(suite.state, suite.results) 157 } 158 159 func (suite *ReadResultsSuite) TestValidateInvalidResultID() { 160 assert.Error(suite.T(), suite.command.Validator(&admin.CommandRequest{ 161 Data: map[string]interface{}{ 162 "result": true, 163 }, 164 })) 165 assert.Error(suite.T(), suite.command.Validator(&admin.CommandRequest{ 166 Data: map[string]interface{}{ 167 "result": "", 168 }, 169 })) 170 assert.Error(suite.T(), suite.command.Validator(&admin.CommandRequest{ 171 Data: map[string]interface{}{ 172 "result": "uhznms", 173 }, 174 })) 175 assert.Error(suite.T(), suite.command.Validator(&admin.CommandRequest{ 176 Data: map[string]interface{}{ 177 "result": "deadbeef", 178 }, 179 })) 180 assert.Error(suite.T(), suite.command.Validator(&admin.CommandRequest{ 181 Data: map[string]interface{}{ 182 "result": 1, 183 }, 184 })) 185 } 186 187 func (suite *ReadResultsSuite) getResults(reqData map[string]interface{}) []*flow.ExecutionResult { 188 ctx, cancel := context.WithCancel(context.Background()) 189 defer cancel() 190 191 req := &admin.CommandRequest{ 192 Data: reqData, 193 } 194 require.NoError(suite.T(), suite.command.Validator(req)) 195 result, err := suite.command.Handler(ctx, req) 196 require.NoError(suite.T(), err) 197 198 var results []*flow.ExecutionResult 199 data, err := json.Marshal(result) 200 require.NoError(suite.T(), err) 201 require.NoError(suite.T(), json.Unmarshal(data, &results)) 202 203 return results 204 } 205 206 func (suite *ReadResultsSuite) TestHandleFinalBlock() { 207 results := suite.getResults(map[string]interface{}{ 208 "block": "final", 209 }) 210 require.Len(suite.T(), results, 1) 211 require.EqualValues(suite.T(), results[0], suite.finalResult) 212 } 213 214 func (suite *ReadResultsSuite) TestHandleSealedBlock() { 215 results := suite.getResults(map[string]interface{}{ 216 "block": "sealed", 217 }) 218 require.Len(suite.T(), results, 1) 219 require.EqualValues(suite.T(), results[0], suite.sealedResult) 220 } 221 222 func (suite *ReadResultsSuite) TestHandleBlockHeight() { 223 for i, result := range suite.allResults { 224 results := suite.getResults(map[string]interface{}{ 225 "block": float64(i), 226 }) 227 require.Len(suite.T(), results, 1) 228 require.EqualValues(suite.T(), results[0], result) 229 } 230 } 231 232 func (suite *ReadResultsSuite) TestHandleBlockID() { 233 for i, result := range suite.allResults { 234 results := suite.getResults(map[string]interface{}{ 235 "block": suite.allBlocks[i].ID().String(), 236 }) 237 require.Len(suite.T(), results, 1) 238 require.EqualValues(suite.T(), results[0], result) 239 } 240 } 241 242 func (suite *ReadResultsSuite) TestHandleID() { 243 for _, result := range suite.allResults { 244 results := suite.getResults(map[string]interface{}{ 245 "result": result.ID().String(), 246 }) 247 require.Len(suite.T(), results, 1) 248 require.EqualValues(suite.T(), results[0], result) 249 } 250 } 251 252 func (suite *ReadResultsSuite) TestHandleNExceedsRootBlock() { 253 // request by block 254 results := suite.getResults(map[string]interface{}{ 255 "block": "final", 256 "n": float64(len(suite.allResults) + 1), 257 }) 258 require.Len(suite.T(), results, len(suite.allResults)) 259 require.ElementsMatch(suite.T(), results, suite.allResults) 260 261 // request by result ID 262 results = suite.getResults(map[string]interface{}{ 263 "result": suite.finalResult.ID().String(), 264 "n": float64(len(suite.allResults) + 1), 265 }) 266 require.Len(suite.T(), results, len(suite.allResults)) 267 require.ElementsMatch(suite.T(), results, suite.allResults) 268 }