You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
5.6 KiB

  1. package statesync
  2. import (
  3. "testing"
  4. "time"
  5. "github.com/stretchr/testify/assert"
  6. "github.com/stretchr/testify/mock"
  7. "github.com/stretchr/testify/require"
  8. abci "github.com/tendermint/tendermint/abci/types"
  9. "github.com/tendermint/tendermint/p2p"
  10. p2pmocks "github.com/tendermint/tendermint/p2p/mocks"
  11. ssproto "github.com/tendermint/tendermint/proto/tendermint/statesync"
  12. proxymocks "github.com/tendermint/tendermint/proxy/mocks"
  13. )
  14. func TestReactor_Receive_ChunkRequest(t *testing.T) {
  15. testcases := map[string]struct {
  16. request *ssproto.ChunkRequest
  17. chunk []byte
  18. expectResponse *ssproto.ChunkResponse
  19. }{
  20. "chunk is returned": {
  21. &ssproto.ChunkRequest{Height: 1, Format: 1, Index: 1},
  22. []byte{1, 2, 3},
  23. &ssproto.ChunkResponse{Height: 1, Format: 1, Index: 1, Chunk: []byte{1, 2, 3}}},
  24. "empty chunk is returned, as nil": {
  25. &ssproto.ChunkRequest{Height: 1, Format: 1, Index: 1},
  26. []byte{},
  27. &ssproto.ChunkResponse{Height: 1, Format: 1, Index: 1, Chunk: nil}},
  28. "nil (missing) chunk is returned as missing": {
  29. &ssproto.ChunkRequest{Height: 1, Format: 1, Index: 1},
  30. nil,
  31. &ssproto.ChunkResponse{Height: 1, Format: 1, Index: 1, Missing: true},
  32. },
  33. }
  34. for name, tc := range testcases {
  35. tc := tc
  36. t.Run(name, func(t *testing.T) {
  37. // Mock ABCI connection to return local snapshots
  38. conn := &proxymocks.AppConnSnapshot{}
  39. conn.On("LoadSnapshotChunkSync", abci.RequestLoadSnapshotChunk{
  40. Height: tc.request.Height,
  41. Format: tc.request.Format,
  42. Chunk: tc.request.Index,
  43. }).Return(&abci.ResponseLoadSnapshotChunk{Chunk: tc.chunk}, nil)
  44. // Mock peer to store response, if found
  45. peer := &p2pmocks.Peer{}
  46. peer.On("ID").Return(p2p.ID("id"))
  47. var response *ssproto.ChunkResponse
  48. if tc.expectResponse != nil {
  49. peer.On("Send", ChunkChannel, mock.Anything).Run(func(args mock.Arguments) {
  50. msg, err := decodeMsg(args[1].([]byte))
  51. require.NoError(t, err)
  52. response = msg.(*ssproto.ChunkResponse)
  53. }).Return(true)
  54. }
  55. // Start a reactor and send a ssproto.ChunkRequest, then wait for and check response
  56. r := NewReactor(conn, nil, "")
  57. err := r.Start()
  58. require.NoError(t, err)
  59. defer r.Stop()
  60. r.Receive(ChunkChannel, peer, mustEncodeMsg(tc.request))
  61. time.Sleep(100 * time.Millisecond)
  62. assert.Equal(t, tc.expectResponse, response)
  63. conn.AssertExpectations(t)
  64. peer.AssertExpectations(t)
  65. })
  66. }
  67. }
  68. func TestReactor_Receive_SnapshotsRequest(t *testing.T) {
  69. testcases := map[string]struct {
  70. snapshots []*abci.Snapshot
  71. expectResponses []*ssproto.SnapshotsResponse
  72. }{
  73. "no snapshots": {nil, []*ssproto.SnapshotsResponse{}},
  74. ">10 unordered snapshots": {
  75. []*abci.Snapshot{
  76. {Height: 1, Format: 2, Chunks: 7, Hash: []byte{1, 2}, Metadata: []byte{1}},
  77. {Height: 2, Format: 2, Chunks: 7, Hash: []byte{2, 2}, Metadata: []byte{2}},
  78. {Height: 3, Format: 2, Chunks: 7, Hash: []byte{3, 2}, Metadata: []byte{3}},
  79. {Height: 1, Format: 1, Chunks: 7, Hash: []byte{1, 1}, Metadata: []byte{4}},
  80. {Height: 2, Format: 1, Chunks: 7, Hash: []byte{2, 1}, Metadata: []byte{5}},
  81. {Height: 3, Format: 1, Chunks: 7, Hash: []byte{3, 1}, Metadata: []byte{6}},
  82. {Height: 1, Format: 4, Chunks: 7, Hash: []byte{1, 4}, Metadata: []byte{7}},
  83. {Height: 2, Format: 4, Chunks: 7, Hash: []byte{2, 4}, Metadata: []byte{8}},
  84. {Height: 3, Format: 4, Chunks: 7, Hash: []byte{3, 4}, Metadata: []byte{9}},
  85. {Height: 1, Format: 3, Chunks: 7, Hash: []byte{1, 3}, Metadata: []byte{10}},
  86. {Height: 2, Format: 3, Chunks: 7, Hash: []byte{2, 3}, Metadata: []byte{11}},
  87. {Height: 3, Format: 3, Chunks: 7, Hash: []byte{3, 3}, Metadata: []byte{12}},
  88. },
  89. []*ssproto.SnapshotsResponse{
  90. {Height: 3, Format: 4, Chunks: 7, Hash: []byte{3, 4}, Metadata: []byte{9}},
  91. {Height: 3, Format: 3, Chunks: 7, Hash: []byte{3, 3}, Metadata: []byte{12}},
  92. {Height: 3, Format: 2, Chunks: 7, Hash: []byte{3, 2}, Metadata: []byte{3}},
  93. {Height: 3, Format: 1, Chunks: 7, Hash: []byte{3, 1}, Metadata: []byte{6}},
  94. {Height: 2, Format: 4, Chunks: 7, Hash: []byte{2, 4}, Metadata: []byte{8}},
  95. {Height: 2, Format: 3, Chunks: 7, Hash: []byte{2, 3}, Metadata: []byte{11}},
  96. {Height: 2, Format: 2, Chunks: 7, Hash: []byte{2, 2}, Metadata: []byte{2}},
  97. {Height: 2, Format: 1, Chunks: 7, Hash: []byte{2, 1}, Metadata: []byte{5}},
  98. {Height: 1, Format: 4, Chunks: 7, Hash: []byte{1, 4}, Metadata: []byte{7}},
  99. {Height: 1, Format: 3, Chunks: 7, Hash: []byte{1, 3}, Metadata: []byte{10}},
  100. },
  101. },
  102. }
  103. for name, tc := range testcases {
  104. tc := tc
  105. t.Run(name, func(t *testing.T) {
  106. // Mock ABCI connection to return local snapshots
  107. conn := &proxymocks.AppConnSnapshot{}
  108. conn.On("ListSnapshotsSync", abci.RequestListSnapshots{}).Return(&abci.ResponseListSnapshots{
  109. Snapshots: tc.snapshots,
  110. }, nil)
  111. // Mock peer to catch responses and store them in a slice
  112. responses := []*ssproto.SnapshotsResponse{}
  113. peer := &p2pmocks.Peer{}
  114. if len(tc.expectResponses) > 0 {
  115. peer.On("ID").Return(p2p.ID("id"))
  116. peer.On("Send", SnapshotChannel, mock.Anything).Run(func(args mock.Arguments) {
  117. msg, err := decodeMsg(args[1].([]byte))
  118. require.NoError(t, err)
  119. responses = append(responses, msg.(*ssproto.SnapshotsResponse))
  120. }).Return(true)
  121. }
  122. // Start a reactor and send a SnapshotsRequestMessage, then wait for and check responses
  123. r := NewReactor(conn, nil, "")
  124. err := r.Start()
  125. require.NoError(t, err)
  126. defer r.Stop()
  127. r.Receive(SnapshotChannel, peer, mustEncodeMsg(&ssproto.SnapshotsRequest{}))
  128. time.Sleep(100 * time.Millisecond)
  129. assert.Equal(t, tc.expectResponses, responses)
  130. conn.AssertExpectations(t)
  131. peer.AssertExpectations(t)
  132. })
  133. }
  134. }