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 }