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