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