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  }