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.

157 lines
5.7 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. t.Cleanup(func() {
  60. if err := r.Stop(); err != nil {
  61. t.Error(err)
  62. }
  63. })
  64. r.Receive(ChunkChannel, peer, mustEncodeMsg(tc.request))
  65. time.Sleep(100 * time.Millisecond)
  66. assert.Equal(t, tc.expectResponse, response)
  67. conn.AssertExpectations(t)
  68. peer.AssertExpectations(t)
  69. })
  70. }
  71. }
  72. func TestReactor_Receive_SnapshotsRequest(t *testing.T) {
  73. testcases := map[string]struct {
  74. snapshots []*abci.Snapshot
  75. expectResponses []*ssproto.SnapshotsResponse
  76. }{
  77. "no snapshots": {nil, []*ssproto.SnapshotsResponse{}},
  78. ">10 unordered snapshots": {
  79. []*abci.Snapshot{
  80. {Height: 1, Format: 2, Chunks: 7, Hash: []byte{1, 2}, Metadata: []byte{1}},
  81. {Height: 2, Format: 2, Chunks: 7, Hash: []byte{2, 2}, Metadata: []byte{2}},
  82. {Height: 3, Format: 2, Chunks: 7, Hash: []byte{3, 2}, Metadata: []byte{3}},
  83. {Height: 1, Format: 1, Chunks: 7, Hash: []byte{1, 1}, Metadata: []byte{4}},
  84. {Height: 2, Format: 1, Chunks: 7, Hash: []byte{2, 1}, Metadata: []byte{5}},
  85. {Height: 3, Format: 1, Chunks: 7, Hash: []byte{3, 1}, Metadata: []byte{6}},
  86. {Height: 1, Format: 4, Chunks: 7, Hash: []byte{1, 4}, Metadata: []byte{7}},
  87. {Height: 2, Format: 4, Chunks: 7, Hash: []byte{2, 4}, Metadata: []byte{8}},
  88. {Height: 3, Format: 4, Chunks: 7, Hash: []byte{3, 4}, Metadata: []byte{9}},
  89. {Height: 1, Format: 3, Chunks: 7, Hash: []byte{1, 3}, Metadata: []byte{10}},
  90. {Height: 2, Format: 3, Chunks: 7, Hash: []byte{2, 3}, Metadata: []byte{11}},
  91. {Height: 3, Format: 3, Chunks: 7, Hash: []byte{3, 3}, Metadata: []byte{12}},
  92. },
  93. []*ssproto.SnapshotsResponse{
  94. {Height: 3, Format: 4, Chunks: 7, Hash: []byte{3, 4}, Metadata: []byte{9}},
  95. {Height: 3, Format: 3, Chunks: 7, Hash: []byte{3, 3}, Metadata: []byte{12}},
  96. {Height: 3, Format: 2, Chunks: 7, Hash: []byte{3, 2}, Metadata: []byte{3}},
  97. {Height: 3, Format: 1, Chunks: 7, Hash: []byte{3, 1}, Metadata: []byte{6}},
  98. {Height: 2, Format: 4, Chunks: 7, Hash: []byte{2, 4}, Metadata: []byte{8}},
  99. {Height: 2, Format: 3, Chunks: 7, Hash: []byte{2, 3}, Metadata: []byte{11}},
  100. {Height: 2, Format: 2, Chunks: 7, Hash: []byte{2, 2}, Metadata: []byte{2}},
  101. {Height: 2, Format: 1, Chunks: 7, Hash: []byte{2, 1}, Metadata: []byte{5}},
  102. {Height: 1, Format: 4, Chunks: 7, Hash: []byte{1, 4}, Metadata: []byte{7}},
  103. {Height: 1, Format: 3, Chunks: 7, Hash: []byte{1, 3}, Metadata: []byte{10}},
  104. },
  105. },
  106. }
  107. for name, tc := range testcases {
  108. tc := tc
  109. t.Run(name, func(t *testing.T) {
  110. // Mock ABCI connection to return local snapshots
  111. conn := &proxymocks.AppConnSnapshot{}
  112. conn.On("ListSnapshotsSync", abci.RequestListSnapshots{}).Return(&abci.ResponseListSnapshots{
  113. Snapshots: tc.snapshots,
  114. }, nil)
  115. // Mock peer to catch responses and store them in a slice
  116. responses := []*ssproto.SnapshotsResponse{}
  117. peer := &p2pmocks.Peer{}
  118. if len(tc.expectResponses) > 0 {
  119. peer.On("ID").Return(p2p.ID("id"))
  120. peer.On("Send", SnapshotChannel, mock.Anything).Run(func(args mock.Arguments) {
  121. msg, err := decodeMsg(args[1].([]byte))
  122. require.NoError(t, err)
  123. responses = append(responses, msg.(*ssproto.SnapshotsResponse))
  124. }).Return(true)
  125. }
  126. // Start a reactor and send a SnapshotsRequestMessage, then wait for and check responses
  127. r := NewReactor(conn, nil, "")
  128. err := r.Start()
  129. require.NoError(t, err)
  130. t.Cleanup(func() {
  131. if err := r.Stop(); err != nil {
  132. t.Error(err)
  133. }
  134. })
  135. r.Receive(SnapshotChannel, peer, mustEncodeMsg(&ssproto.SnapshotsRequest{}))
  136. time.Sleep(100 * time.Millisecond)
  137. assert.Equal(t, tc.expectResponses, responses)
  138. conn.AssertExpectations(t)
  139. peer.AssertExpectations(t)
  140. })
  141. }
  142. }