github.com/Finschia/finschia-sdk@v0.48.1/store/streaming/file/service_test.go (about)

     1  package file
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"sync"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/require"
    12  	abci "github.com/tendermint/tendermint/abci/types"
    13  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    14  
    15  	ocabci "github.com/Finschia/ostracon/abci/types"
    16  
    17  	"github.com/Finschia/finschia-sdk/codec"
    18  	codecTypes "github.com/Finschia/finschia-sdk/codec/types"
    19  	"github.com/Finschia/finschia-sdk/store/types"
    20  	sdk "github.com/Finschia/finschia-sdk/types"
    21  )
    22  
    23  var (
    24  	interfaceRegistry            = codecTypes.NewInterfaceRegistry()
    25  	testMarshaller               = codec.NewProtoCodec(interfaceRegistry)
    26  	testStreamingService         *StreamingService
    27  	testListener1, testListener2 types.WriteListener
    28  	emptyContext                 = sdk.Context{}
    29  
    30  	// test abci message types
    31  	mockHash          = []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}
    32  	testBeginBlockReq = ocabci.RequestBeginBlock{
    33  		Header: tmproto.Header{
    34  			Height: 1,
    35  		},
    36  		ByzantineValidators: []abci.Evidence{},
    37  		Hash:                mockHash,
    38  		LastCommitInfo: abci.LastCommitInfo{
    39  			Round: 1,
    40  			Votes: []abci.VoteInfo{},
    41  		},
    42  	}
    43  	testBeginBlockRes = abci.ResponseBeginBlock{
    44  		Events: []abci.Event{
    45  			{
    46  				Type: "testEventType1",
    47  			},
    48  			{
    49  				Type: "testEventType2",
    50  			},
    51  		},
    52  	}
    53  	testEndBlockReq = abci.RequestEndBlock{
    54  		Height: 1,
    55  	}
    56  	testEndBlockRes = abci.ResponseEndBlock{
    57  		Events:                []abci.Event{},
    58  		ConsensusParamUpdates: &abci.ConsensusParams{},
    59  		ValidatorUpdates:      []abci.ValidatorUpdate{},
    60  	}
    61  	mockTxBytes1      = []byte{9, 8, 7, 6, 5, 4, 3, 2, 1}
    62  	testDeliverTxReq1 = abci.RequestDeliverTx{
    63  		Tx: mockTxBytes1,
    64  	}
    65  	mockTxBytes2      = []byte{8, 7, 6, 5, 4, 3, 2}
    66  	testDeliverTxReq2 = abci.RequestDeliverTx{
    67  		Tx: mockTxBytes2,
    68  	}
    69  	mockTxResponseData1 = []byte{1, 3, 5, 7, 9}
    70  	testDeliverTxRes1   = abci.ResponseDeliverTx{
    71  		Events:    []abci.Event{},
    72  		Code:      1,
    73  		Codespace: "mockCodeSpace",
    74  		Data:      mockTxResponseData1,
    75  		GasUsed:   2,
    76  		GasWanted: 3,
    77  		Info:      "mockInfo",
    78  		Log:       "mockLog",
    79  	}
    80  	mockTxResponseData2 = []byte{1, 3, 5, 7, 9}
    81  	testDeliverTxRes2   = abci.ResponseDeliverTx{
    82  		Events:    []abci.Event{},
    83  		Code:      1,
    84  		Codespace: "mockCodeSpace",
    85  		Data:      mockTxResponseData2,
    86  		GasUsed:   2,
    87  		GasWanted: 3,
    88  		Info:      "mockInfo",
    89  		Log:       "mockLog",
    90  	}
    91  
    92  	// mock store keys
    93  	mockStoreKey1 = sdk.NewKVStoreKey("mockStore1")
    94  	mockStoreKey2 = sdk.NewKVStoreKey("mockStore2")
    95  
    96  	// file stuff
    97  	testPrefix = "testPrefix"
    98  	testDir    = "./.test"
    99  
   100  	// mock state changes
   101  	mockKey1   = []byte{1, 2, 3}
   102  	mockValue1 = []byte{3, 2, 1}
   103  	mockKey2   = []byte{2, 3, 4}
   104  	mockValue2 = []byte{4, 3, 2}
   105  	mockKey3   = []byte{3, 4, 5}
   106  	mockValue3 = []byte{5, 4, 3}
   107  )
   108  
   109  func TestIntermediateWriter(t *testing.T) {
   110  	outChan := make(chan []byte, 0)
   111  	iw := NewIntermediateWriter(outChan)
   112  	require.IsType(t, &IntermediateWriter{}, iw)
   113  	testBytes := []byte{1, 2, 3, 4, 5}
   114  	var length int
   115  	var err error
   116  	waitChan := make(chan struct{}, 0)
   117  	go func() {
   118  		length, err = iw.Write(testBytes)
   119  		waitChan <- struct{}{}
   120  	}()
   121  	receivedBytes := <-outChan
   122  	<-waitChan
   123  	require.Equal(t, len(testBytes), length)
   124  	require.Equal(t, testBytes, receivedBytes)
   125  	require.Nil(t, err)
   126  }
   127  
   128  func TestFileStreamingService(t *testing.T) {
   129  	if os.Getenv("CI") != "" {
   130  		t.Skip("Skipping TestFileStreamingService in CI environment")
   131  	}
   132  	err := os.Mkdir(testDir, 0700)
   133  	require.Nil(t, err)
   134  	defer os.RemoveAll(testDir)
   135  
   136  	testKeys := []types.StoreKey{mockStoreKey1, mockStoreKey2}
   137  	testStreamingService, err = NewStreamingService(testDir, testPrefix, testKeys, testMarshaller)
   138  	require.Nil(t, err)
   139  	require.IsType(t, &StreamingService{}, testStreamingService)
   140  	require.Equal(t, testPrefix, testStreamingService.filePrefix)
   141  	require.Equal(t, testDir, testStreamingService.writeDir)
   142  	require.Equal(t, testMarshaller, testStreamingService.codec)
   143  	testListener1 = testStreamingService.listeners[mockStoreKey1][0]
   144  	testListener2 = testStreamingService.listeners[mockStoreKey2][0]
   145  	wg := new(sync.WaitGroup)
   146  	testStreamingService.Stream(wg)
   147  	testListenBeginBlock(t)
   148  	testListenDeliverTx1(t)
   149  	testListenDeliverTx2(t)
   150  	testListenEndBlock(t)
   151  	testStreamingService.Close()
   152  	wg.Wait()
   153  }
   154  
   155  func testListenBeginBlock(t *testing.T) {
   156  	expectedBeginBlockReqBytes, err := testMarshaller.Marshal(&testBeginBlockReq)
   157  	require.Nil(t, err)
   158  	expectedBeginBlockResBytes, err := testMarshaller.Marshal(&testBeginBlockRes)
   159  	require.Nil(t, err)
   160  
   161  	// write state changes
   162  	testListener1.OnWrite(mockStoreKey1, mockKey1, mockValue1, false)
   163  	testListener2.OnWrite(mockStoreKey2, mockKey2, mockValue2, false)
   164  	testListener1.OnWrite(mockStoreKey1, mockKey3, mockValue3, false)
   165  
   166  	// expected KV pairs
   167  	expectedKVPair1, err := testMarshaller.Marshal(&types.StoreKVPair{
   168  		StoreKey: mockStoreKey1.Name(),
   169  		Key:      mockKey1,
   170  		Value:    mockValue1,
   171  		Delete:   false,
   172  	})
   173  	require.Nil(t, err)
   174  	expectedKVPair2, err := testMarshaller.Marshal(&types.StoreKVPair{
   175  		StoreKey: mockStoreKey2.Name(),
   176  		Key:      mockKey2,
   177  		Value:    mockValue2,
   178  		Delete:   false,
   179  	})
   180  	require.Nil(t, err)
   181  	expectedKVPair3, err := testMarshaller.Marshal(&types.StoreKVPair{
   182  		StoreKey: mockStoreKey1.Name(),
   183  		Key:      mockKey3,
   184  		Value:    mockValue3,
   185  		Delete:   false,
   186  	})
   187  	require.Nil(t, err)
   188  
   189  	// send the ABCI messages
   190  	err = testStreamingService.ListenBeginBlock(emptyContext, testBeginBlockReq, testBeginBlockRes)
   191  	require.Nil(t, err)
   192  
   193  	// load the file, checking that it was created with the expected name
   194  	fileName := fmt.Sprintf("%s-block-%d-begin", testPrefix, testBeginBlockReq.GetHeader().Height)
   195  	fileBytes, err := readInFile(fileName)
   196  	require.Nil(t, err)
   197  
   198  	// segment the file into the separate gRPC messages and check the correctness of each
   199  	segments, err := segmentBytes(fileBytes)
   200  	require.Nil(t, err)
   201  	require.Equal(t, 5, len(segments))
   202  	require.Equal(t, expectedBeginBlockReqBytes, segments[0])
   203  	require.Equal(t, expectedKVPair1, segments[1])
   204  	require.Equal(t, expectedKVPair2, segments[2])
   205  	require.Equal(t, expectedKVPair3, segments[3])
   206  	require.Equal(t, expectedBeginBlockResBytes, segments[4])
   207  }
   208  
   209  func testListenDeliverTx1(t *testing.T) {
   210  	expectedDeliverTxReq1Bytes, err := testMarshaller.Marshal(&testDeliverTxReq1)
   211  	require.Nil(t, err)
   212  	expectedDeliverTxRes1Bytes, err := testMarshaller.Marshal(&testDeliverTxRes1)
   213  	require.Nil(t, err)
   214  
   215  	// write state changes
   216  	testListener1.OnWrite(mockStoreKey1, mockKey1, mockValue1, false)
   217  	testListener2.OnWrite(mockStoreKey2, mockKey2, mockValue2, false)
   218  	testListener1.OnWrite(mockStoreKey2, mockKey3, mockValue3, false)
   219  
   220  	// expected KV pairs
   221  	expectedKVPair1, err := testMarshaller.Marshal(&types.StoreKVPair{
   222  		StoreKey: mockStoreKey1.Name(),
   223  		Key:      mockKey1,
   224  		Value:    mockValue1,
   225  		Delete:   false,
   226  	})
   227  	require.Nil(t, err)
   228  	expectedKVPair2, err := testMarshaller.Marshal(&types.StoreKVPair{
   229  		StoreKey: mockStoreKey2.Name(),
   230  		Key:      mockKey2,
   231  		Value:    mockValue2,
   232  		Delete:   false,
   233  	})
   234  	require.Nil(t, err)
   235  	expectedKVPair3, err := testMarshaller.Marshal(&types.StoreKVPair{
   236  		StoreKey: mockStoreKey2.Name(),
   237  		Key:      mockKey3,
   238  		Value:    mockValue3,
   239  		Delete:   false,
   240  	})
   241  	require.Nil(t, err)
   242  
   243  	// send the ABCI messages
   244  	err = testStreamingService.ListenDeliverTx(emptyContext, testDeliverTxReq1, testDeliverTxRes1)
   245  	require.Nil(t, err)
   246  
   247  	// load the file, checking that it was created with the expected name
   248  	fileName := fmt.Sprintf("%s-block-%d-tx-%d", testPrefix, testBeginBlockReq.GetHeader().Height, 0)
   249  	fileBytes, err := readInFile(fileName)
   250  	require.Nil(t, err)
   251  
   252  	// segment the file into the separate gRPC messages and check the correctness of each
   253  	segments, err := segmentBytes(fileBytes)
   254  	require.Nil(t, err)
   255  	require.Equal(t, 5, len(segments))
   256  	require.Equal(t, expectedDeliverTxReq1Bytes, segments[0])
   257  	require.Equal(t, expectedKVPair1, segments[1])
   258  	require.Equal(t, expectedKVPair2, segments[2])
   259  	require.Equal(t, expectedKVPair3, segments[3])
   260  	require.Equal(t, expectedDeliverTxRes1Bytes, segments[4])
   261  }
   262  
   263  func testListenDeliverTx2(t *testing.T) {
   264  	expectedDeliverTxReq2Bytes, err := testMarshaller.Marshal(&testDeliverTxReq2)
   265  	require.Nil(t, err)
   266  	expectedDeliverTxRes2Bytes, err := testMarshaller.Marshal(&testDeliverTxRes2)
   267  	require.Nil(t, err)
   268  
   269  	// write state changes
   270  	testListener1.OnWrite(mockStoreKey2, mockKey1, mockValue1, false)
   271  	testListener2.OnWrite(mockStoreKey1, mockKey2, mockValue2, false)
   272  	testListener1.OnWrite(mockStoreKey2, mockKey3, mockValue3, false)
   273  
   274  	// expected KV pairs
   275  	expectedKVPair1, err := testMarshaller.Marshal(&types.StoreKVPair{
   276  		StoreKey: mockStoreKey2.Name(),
   277  		Key:      mockKey1,
   278  		Value:    mockValue1,
   279  		Delete:   false,
   280  	})
   281  	require.Nil(t, err)
   282  	expectedKVPair2, err := testMarshaller.Marshal(&types.StoreKVPair{
   283  		StoreKey: mockStoreKey1.Name(),
   284  		Key:      mockKey2,
   285  		Value:    mockValue2,
   286  		Delete:   false,
   287  	})
   288  	require.Nil(t, err)
   289  	expectedKVPair3, err := testMarshaller.Marshal(&types.StoreKVPair{
   290  		StoreKey: mockStoreKey2.Name(),
   291  		Key:      mockKey3,
   292  		Value:    mockValue3,
   293  		Delete:   false,
   294  	})
   295  	require.Nil(t, err)
   296  
   297  	// send the ABCI messages
   298  	err = testStreamingService.ListenDeliverTx(emptyContext, testDeliverTxReq2, testDeliverTxRes2)
   299  	require.Nil(t, err)
   300  
   301  	// load the file, checking that it was created with the expected name
   302  	fileName := fmt.Sprintf("%s-block-%d-tx-%d", testPrefix, testBeginBlockReq.GetHeader().Height, 1)
   303  	fileBytes, err := readInFile(fileName)
   304  	require.Nil(t, err)
   305  
   306  	// segment the file into the separate gRPC messages and check the correctness of each
   307  	segments, err := segmentBytes(fileBytes)
   308  	require.Nil(t, err)
   309  	require.Equal(t, 5, len(segments))
   310  	require.Equal(t, expectedDeliverTxReq2Bytes, segments[0])
   311  	require.Equal(t, expectedKVPair1, segments[1])
   312  	require.Equal(t, expectedKVPair2, segments[2])
   313  	require.Equal(t, expectedKVPair3, segments[3])
   314  	require.Equal(t, expectedDeliverTxRes2Bytes, segments[4])
   315  }
   316  
   317  func testListenEndBlock(t *testing.T) {
   318  	expectedEndBlockReqBytes, err := testMarshaller.Marshal(&testEndBlockReq)
   319  	require.Nil(t, err)
   320  	expectedEndBlockResBytes, err := testMarshaller.Marshal(&testEndBlockRes)
   321  	require.Nil(t, err)
   322  
   323  	// write state changes
   324  	testListener1.OnWrite(mockStoreKey1, mockKey1, mockValue1, false)
   325  	testListener2.OnWrite(mockStoreKey1, mockKey2, mockValue2, false)
   326  	testListener1.OnWrite(mockStoreKey2, mockKey3, mockValue3, false)
   327  
   328  	// expected KV pairs
   329  	expectedKVPair1, err := testMarshaller.Marshal(&types.StoreKVPair{
   330  		StoreKey: mockStoreKey1.Name(),
   331  		Key:      mockKey1,
   332  		Value:    mockValue1,
   333  		Delete:   false,
   334  	})
   335  	require.Nil(t, err)
   336  	expectedKVPair2, err := testMarshaller.Marshal(&types.StoreKVPair{
   337  		StoreKey: mockStoreKey1.Name(),
   338  		Key:      mockKey2,
   339  		Value:    mockValue2,
   340  		Delete:   false,
   341  	})
   342  	require.Nil(t, err)
   343  	expectedKVPair3, err := testMarshaller.Marshal(&types.StoreKVPair{
   344  		StoreKey: mockStoreKey2.Name(),
   345  		Key:      mockKey3,
   346  		Value:    mockValue3,
   347  		Delete:   false,
   348  	})
   349  	require.Nil(t, err)
   350  
   351  	// send the ABCI messages
   352  	err = testStreamingService.ListenEndBlock(emptyContext, testEndBlockReq, testEndBlockRes)
   353  	require.Nil(t, err)
   354  
   355  	// load the file, checking that it was created with the expected name
   356  	fileName := fmt.Sprintf("%s-block-%d-end", testPrefix, testEndBlockReq.Height)
   357  	fileBytes, err := readInFile(fileName)
   358  	require.Nil(t, err)
   359  
   360  	// segment the file into the separate gRPC messages and check the correctness of each
   361  	segments, err := segmentBytes(fileBytes)
   362  	require.Nil(t, err)
   363  	require.Equal(t, 5, len(segments))
   364  	require.Equal(t, expectedEndBlockReqBytes, segments[0])
   365  	require.Equal(t, expectedKVPair1, segments[1])
   366  	require.Equal(t, expectedKVPair2, segments[2])
   367  	require.Equal(t, expectedKVPair3, segments[3])
   368  	require.Equal(t, expectedEndBlockResBytes, segments[4])
   369  }
   370  
   371  func readInFile(name string) ([]byte, error) {
   372  	path := filepath.Join(testDir, name)
   373  	return os.ReadFile(path)
   374  }
   375  
   376  // Returns all of the protobuf messages contained in the byte array as an array of byte arrays
   377  // The messages have their length prefix removed
   378  func segmentBytes(bz []byte) ([][]byte, error) {
   379  	var err error
   380  	segments := make([][]byte, 0)
   381  	for len(bz) > 0 {
   382  		var segment []byte
   383  		segment, bz, err = getHeadSegment(bz)
   384  		if err != nil {
   385  			return nil, err
   386  		}
   387  		segments = append(segments, segment)
   388  	}
   389  	return segments, nil
   390  }
   391  
   392  // Returns the bytes for the leading protobuf object in the byte array (removing the length prefix) and returns the remainder of the byte array
   393  func getHeadSegment(bz []byte) ([]byte, []byte, error) {
   394  	size, prefixSize := binary.Uvarint(bz)
   395  	if prefixSize < 0 {
   396  		return nil, nil, fmt.Errorf("invalid number of bytes read from length-prefixed encoding: %d", prefixSize)
   397  	}
   398  	if size > uint64(len(bz)-prefixSize) {
   399  		return nil, nil, fmt.Errorf("not enough bytes to read; want: %v, got: %v", size, len(bz)-prefixSize)
   400  	}
   401  	return bz[prefixSize:(uint64(prefixSize) + size)], bz[uint64(prefixSize)+size:], nil
   402  }