github.com/aergoio/aergo@v1.3.1/p2p/raftsupport/rafttransport_test.go (about) 1 /* 2 * @file 3 * @copyright defined in aergo/LICENSE.txt 4 */ 5 6 package raftsupport 7 8 import ( 9 "io" 10 "reflect" 11 "testing" 12 "time" 13 14 "github.com/aergoio/aergo-lib/log" 15 "github.com/aergoio/aergo/consensus" 16 "github.com/aergoio/aergo/consensus/impl/raftv2" 17 "github.com/aergoio/aergo/p2p/p2pcommon" 18 "github.com/aergoio/aergo/p2p/p2pmock" 19 "github.com/aergoio/aergo/p2p/p2putil" 20 "github.com/aergoio/aergo/types" 21 "github.com/aergoio/etcd/raft" 22 "github.com/aergoio/etcd/raft/raftpb" 23 "github.com/aergoio/etcd/snap" 24 "github.com/golang/mock/gomock" 25 "github.com/pkg/errors" 26 ) 27 28 func TestAergoRaftTransport_SendSnapshot(t *testing.T) { 29 // SendSnapshot acquire snap.Message, which must be closed after using. 30 31 logger := log.NewLogger("raft.support.test") 32 dummyChainID := make([]byte, 32) 33 dummyPeerID := p2putil.RandomPeerID() 34 dummyPeerMeta := p2pcommon.PeerMeta{ID: dummyPeerID} 35 dummyMemID := uint64(112345531252) 36 dummyMember := &consensus.Member{types.MemberAttr{ID: dummyMemID, PeerID: []byte(dummyPeerID)}} 37 38 type mockOPs struct { 39 toID uint64 40 raMem *consensus.Member 41 pmGetPeer bool 42 sr error // snapshotSender result 43 } 44 tests := []struct { 45 name string 46 47 mOP mockOPs 48 49 wantResult bool 50 }{ 51 {"TSucc", mockOPs{toID: dummyMemID, raMem: dummyMember, pmGetPeer: true}, true}, 52 {"TWrongID", mockOPs{toID: 0, raMem: dummyMember, pmGetPeer: true}, false}, 53 {"TInvalidMemberID", mockOPs{toID: dummyMemID, raMem: nil, pmGetPeer: true}, false}, 54 {"TNotConnPeer", mockOPs{toID: dummyMemID, raMem: dummyMember, pmGetPeer: false}, false}, 55 {"TTransportErr", mockOPs{toID: dummyMemID, raMem: dummyMember, pmGetPeer: true, sr: errors.New("transport error")}, false}, 56 } 57 for _, tt := range tests { 58 t.Run(tt.name, func(t *testing.T) { 59 ctrl := gomock.NewController(t) 60 defer ctrl.Finish() 61 62 mockNT := p2pmock.NewMockNetworkTransport(ctrl) 63 mockPM := p2pmock.NewMockPeerManager(ctrl) 64 mockMF := p2pmock.NewMockMoFactory(ctrl) 65 mockCA := p2pmock.NewMockConsensusAccessor(ctrl) 66 mockRA := p2pmock.NewMockAergoRaftAccessor(ctrl) 67 mockRC := p2pmock.NewMockReadCloser(ctrl) 68 mockPeer := p2pmock.NewMockRemotePeer(ctrl) 69 dummyCl := raftv2.NewCluster(dummyChainID, nil, "test", dummyPeerID, 0, nil) 70 71 // not checked mock operations 72 mockCA.EXPECT().RaftAccessor().Return(mockRA).AnyTimes() 73 mockPM.EXPECT().AddPeerEventListener(gomock.Any()).AnyTimes() 74 mockPeer.EXPECT().ID().Return(dummyPeerID).AnyTimes() 75 mockPeer.EXPECT().Name().Return(dummyPeerID.ShortString()).AnyTimes() 76 mockPeer.EXPECT().Meta().Return(dummyPeerMeta).AnyTimes() 77 mockRC.EXPECT().Read(gomock.Any()).DoAndReturn(func(buf []byte) (int, error) { 78 return len(buf), nil 79 }).AnyTimes() 80 81 // checked mock operations 82 // close must be called in any cases 83 mockRC.EXPECT().Close().Times(1) 84 if tt.mOP.toID != 0 { 85 mockRA.EXPECT().GetMemberByID(tt.mOP.toID).Return(tt.mOP.raMem).Times(1) 86 if tt.mOP.raMem != nil { 87 if tt.mOP.pmGetPeer { 88 mockPM.EXPECT().GetPeer(dummyPeerID).Return(mockPeer, true).Times(1) 89 } else { 90 mockPM.EXPECT().GetPeer(dummyPeerID).Return(nil, false).Times(1) 91 mockRA.EXPECT().ReportUnreachable(dummyPeerID) 92 mockRA.EXPECT().ReportSnapshot(dummyPeerID, raft.SnapshotFailure) 93 } 94 } 95 } 96 // emulate snapshotSender 97 rs := raftpb.Message{To: tt.mOP.toID} 98 msg := snap.NewMessage(rs, mockRC, 1000) 99 ssf := &snapStubFactory{serr: tt.mOP.sr, rsize: rs.Size() + 1000} 100 101 target := NewAergoRaftTransport(logger, mockNT, mockPM, mockMF, mockCA, dummyCl) 102 target.snapF = ssf 103 104 target.SendSnapshot(*msg) 105 106 timer := time.NewTimer(time.Millisecond * 100) 107 select { 108 case r := <-msg.CloseNotify(): 109 if r != tt.wantResult { 110 t.Errorf("close result %v , want %v", r, tt.wantResult) 111 } 112 case <-timer.C: 113 t.Error("unexpected timeout") 114 } 115 }) 116 } 117 } 118 119 func TestAergoRaftTransport_NewSnapshotSender(t *testing.T) { 120 logger := log.NewLogger("raft.support.test") 121 dummyChainID := make([]byte, 32) 122 dummyPeerID := p2putil.RandomPeerID() 123 124 ctrl := gomock.NewController(t) 125 defer ctrl.Finish() 126 127 mockNT := p2pmock.NewMockNetworkTransport(ctrl) 128 mockPM := p2pmock.NewMockPeerManager(ctrl) 129 mockMF := p2pmock.NewMockMoFactory(ctrl) 130 mockCA := p2pmock.NewMockConsensusAccessor(ctrl) 131 mockRA := p2pmock.NewMockAergoRaftAccessor(ctrl) 132 mockRWC := p2pmock.NewMockReadWriteCloser(ctrl) 133 mockPeer := p2pmock.NewMockRemotePeer(ctrl) 134 dummyCl := raftv2.NewCluster(dummyChainID, nil, "test", dummyPeerID, 0, nil) 135 // not checked mock operations 136 mockCA.EXPECT().RaftAccessor().Return(mockRA).AnyTimes() 137 mockPM.EXPECT().AddPeerEventListener(gomock.Any()).AnyTimes() 138 139 target := NewAergoRaftTransport(logger, mockNT, mockPM, mockMF, mockCA, dummyCl) 140 got := target.NewSnapshotSender(mockPeer) 141 if _, ok := got.(*snapshotSender); !ok { 142 t.Errorf("AergoRaftTransport.NewSnapshotSender() type is differ: %v", reflect.TypeOf(got).Name()) 143 } else { 144 if got.(*snapshotSender).peer != mockPeer { 145 t.Errorf("AergoRaftTransport.NewSnapshotSender() assign failed") 146 } 147 } 148 149 got2 := target.NewSnapshotReceiver(mockPeer, mockRWC) 150 if _, ok := got2.(*snapshotReceiver); !ok { 151 t.Errorf("AergoRaftTransport.NewSnapshotSender() type is differ: %v", reflect.TypeOf(got).Name()) 152 } else { 153 if got2.(*snapshotReceiver).peer != mockPeer { 154 t.Errorf("AergoRaftTransport.NewSnapshotSender() assign failed") 155 } 156 } 157 } 158 159 type snapStubFactory struct { 160 rsize int 161 serr error 162 } 163 164 func (f snapStubFactory) NewSnapshotSender(peer p2pcommon.RemotePeer) SnapshotSender { 165 return &snapSenderStub{f.rsize, f.serr} 166 } 167 168 func (snapStubFactory) NewSnapshotReceiver(peer p2pcommon.RemotePeer, rwc io.ReadWriteCloser) SnapshotReceiver { 169 return &snapReceiverStub{} 170 } 171 172 type snapSenderStub struct { 173 rsize int 174 err error 175 } 176 177 func (s snapSenderStub) Send(snapMsg *snap.Message) { 178 if s.rsize > 0 { 179 buf := make([]byte, s.rsize) 180 snapMsg.ReadCloser.Read(buf) 181 } 182 snapMsg.CloseWithError(s.err) 183 } 184 185 type snapReceiverStub struct { 186 } 187 188 func (r snapReceiverStub) Receive() { 189 } 190 191 func TestAergoRaftTransport_Send(t *testing.T) { 192 // SendSnapshot acquire snap.Message, which must be closed after using. 193 194 logger := log.NewLogger("raft.support.test") 195 dummyChainID := make([]byte, 32) 196 dummyPeerID := p2putil.RandomPeerID() 197 dummyPeerMeta := p2pcommon.PeerMeta{ID: dummyPeerID} 198 dummyMemID := uint64(11111) 199 dummyMember := &consensus.Member{types.MemberAttr{ID: dummyMemID, PeerID: []byte(dummyPeerID)}} 200 unreachableMemID := uint64(33333) 201 unreachablePeerID := p2putil.RandomPeerID() 202 unreachableMember := &consensus.Member{types.MemberAttr{ID:unreachableMemID , PeerID: []byte(unreachablePeerID)}} 203 204 zeroM := raftpb.Message{To:0, Type:raftpb.MsgApp} 205 notM := raftpb.Message{To:98767, Type:raftpb.MsgApp} 206 memM := raftpb.Message{To:dummyMemID, Type:raftpb.MsgApp} 207 unM := raftpb.Message{To:unreachableMemID, Type:raftpb.MsgApp} 208 type args struct { 209 toID uint64 210 raMem *consensus.Member 211 pmGetPeer bool 212 sr error // snapshotSender result 213 } 214 tests := []struct { 215 name string 216 msgs []raftpb.Message 217 218 wantChkMemCnt int 219 wantGetPeerCnt int 220 wantSendCnt int 221 wantUnreachCnt int 222 wantResult bool 223 }{ 224 {"TSingle", ToM(memM), 1,1,1, 0, true}, 225 {"TMulti", ToM(memM,memM,memM), 3,3,3, 0, true}, 226 {"TWZero", ToM(memM,zeroM,zeroM,memM), 2,2, 2,0, true}, 227 {"TInvalidM", ToM(notM,notM), 2,0,0, 0,true}, 228 {"TUnreachable", ToM(unM, unM, memM), 3,3,1, 2,true}, 229 230 //{"TWrongID", args{toID: 0, raMem: dummyMember, pmGetPeer: true}, false}, 231 //{"TInvalidMemberID", args{toID: dummyMemID, raMem: nil, pmGetPeer: true}, false}, 232 //{"TNotConnPeer", args{toID: dummyMemID, raMem: dummyMember, pmGetPeer: false}, false}, 233 //{"TTransportErr", args{toID: dummyMemID, raMem: dummyMember, pmGetPeer: true, sr: errors.New("transport error")}, false}, 234 } 235 for _, tt := range tests { 236 t.Run(tt.name, func(t *testing.T) { 237 ctrl := gomock.NewController(t) 238 defer ctrl.Finish() 239 240 mockNT := p2pmock.NewMockNetworkTransport(ctrl) 241 mockPM := p2pmock.NewMockPeerManager(ctrl) 242 mockMF := p2pmock.NewMockMoFactory(ctrl) 243 mockCA := p2pmock.NewMockConsensusAccessor(ctrl) 244 mockRA := p2pmock.NewMockAergoRaftAccessor(ctrl) 245 mockRC := p2pmock.NewMockReadCloser(ctrl) 246 mockPeer := p2pmock.NewMockRemotePeer(ctrl) 247 dummyCl := raftv2.NewCluster(dummyChainID, nil, "test", dummyPeerID, 0, nil) 248 dummyMO := p2pmock.NewMockMsgOrder(ctrl) 249 250 // not checked mock operations 251 mockCA.EXPECT().RaftAccessor().Return(mockRA).AnyTimes() 252 mockPM.EXPECT().AddPeerEventListener(gomock.Any()).AnyTimes() 253 mockPeer.EXPECT().ID().Return(dummyPeerID).AnyTimes() 254 mockPeer.EXPECT().Name().Return(dummyPeerID.ShortString()).AnyTimes() 255 mockPeer.EXPECT().Meta().Return(dummyPeerMeta).AnyTimes() 256 mockRC.EXPECT().Read(gomock.Any()).DoAndReturn(func(buf []byte) (int, error) { 257 return len(buf), nil 258 }).AnyTimes() 259 260 // checked mock operations 261 mockRA.EXPECT().GetMemberByID(gomock.Any()).DoAndReturn(func(id uint64) *consensus.Member { 262 if id == dummyMemID { 263 return dummyMember 264 } else if id == unreachableMemID { 265 return unreachableMember 266 } else { 267 return nil 268 } 269 }).Times(tt.wantChkMemCnt) 270 mockPM.EXPECT().GetPeer(gomock.Any()).DoAndReturn(func(pid types.PeerID) (p2pcommon.RemotePeer, bool) { 271 if pid == dummyPeerID { 272 return mockPeer, true 273 } else { 274 return nil, false 275 } 276 }).MaxTimes(tt.wantGetPeerCnt) 277 mockMF.EXPECT().NewRaftMsgOrder(gomock.Any(), gomock.Any()).Return(dummyMO).Times(tt.wantSendCnt) 278 mockPeer.EXPECT().SendMessage(gomock.Any()).Times(tt.wantSendCnt) 279 mockRA.EXPECT().ReportUnreachable(unreachablePeerID).Times(tt.wantUnreachCnt) 280 281 282 target := NewAergoRaftTransport(logger, mockNT, mockPM, mockMF, mockCA, dummyCl) 283 284 target.Send(tt.msgs) 285 286 }) 287 } 288 } 289 290 func ToM(ms ...raftpb.Message) []raftpb.Message { 291 return ms 292 }