github.com/aergoio/aergo@v1.3.1/p2p/raftsupport/clusterreceiver_test.go (about) 1 /* 2 * @file 3 * @copyright defined in aergo/LICENSE.txt 4 */ 5 6 package raftsupport 7 8 import ( 9 "bytes" 10 "sync/atomic" 11 "testing" 12 "time" 13 14 "github.com/aergoio/aergo/message" 15 "github.com/aergoio/aergo/p2p/p2pcommon" 16 "github.com/aergoio/aergo/p2p/p2pmock" 17 "github.com/aergoio/aergo/types" 18 "github.com/golang/mock/gomock" 19 ) 20 21 func TestStartGet(t *testing.T) { 22 ctrl := gomock.NewController(t) 23 defer ctrl.Finish() 24 25 type args struct { 26 peerCnt int 27 timeout time.Duration 28 } 29 tests := []struct { 30 name string 31 args args 32 33 wantSentCnt int // count of sent to remote peers 34 wantTimeout bool // whether receiver returns result or not (=timeout) 35 wantErrResp bool // result with error or not 36 }{ 37 {"TTimeout", args{peerCnt: 1}, 1, true, false}, 38 {"TNoPeers", args{peerCnt: 0}, 0, false, true}, 39 } 40 for _, tt := range tests { 41 t.Run(tt.name, func(t *testing.T) { 42 mockActor := p2pmock.NewMockActorService(ctrl) 43 mockMF := p2pmock.NewMockMoFactory(ctrl) 44 mockMo := createDummyMo(ctrl) 45 mockMF.EXPECT().NewMsgBlockRequestOrder(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockMo).Times(tt.wantSentCnt) 46 peers := make([]p2pcommon.RemotePeer, 0, tt.args.peerCnt) 47 for i := 0; i < tt.args.peerCnt; i++ { 48 dummyPeerID, _ := types.IDB58Decode("16Uiu2HAmFqptXPfcdaCdwipB2fhHATgKGVFVPehDAPZsDKSU7jRm") 49 peers = append(peers, createDummyPeer(ctrl, dummyPeerID, types.RUNNING)) 50 } 51 replyChan := make(chan *message.GetClusterRsp) 52 dummyReq := &message.GetCluster{ReplyC: replyChan} 53 target := NewClusterInfoReceiver(mockActor, mockMF, peers, time.Millisecond, dummyReq) 54 target.StartGet() 55 56 if !tt.wantTimeout { 57 timer := time.NewTimer(time.Second * 2) 58 select { 59 case resp := <-replyChan: 60 if (resp.Err != nil) != tt.wantErrResp { 61 t.Errorf("resp error %v, wantErr %v ", resp.Err, tt.wantErrResp) 62 } 63 case <-timer.C: 64 t.Errorf("timeout occurred, want no time") 65 } 66 } else { 67 timer := time.NewTimer(time.Millisecond * 100) 68 select { 69 case resp := <-replyChan: 70 t.Errorf("unexpected response (%d mems, err:%v), want timeout", len(resp.Members), resp.Err) 71 case <-timer.C: 72 // expected timeout 73 } 74 } 75 }) 76 } 77 } 78 79 func createDummyPeer(ctrl *gomock.Controller, pid types.PeerID, state types.PeerState) *p2pmock.MockRemotePeer { 80 mockPeer := p2pmock.NewMockRemotePeer(ctrl) 81 mockPeer.EXPECT().State().Return(state).AnyTimes() 82 mockPeer.EXPECT().ID().Return(pid).AnyTimes() 83 mockPeer.EXPECT().ConsumeRequest(gomock.Any()).AnyTimes() 84 mockPeer.EXPECT().SendMessage(gomock.Any()).AnyTimes() 85 return mockPeer 86 } 87 88 func createDummyMo(ctrl *gomock.Controller) *p2pmock.MockMsgOrder { 89 dummyMo := p2pmock.NewMockMsgOrder(ctrl) 90 dummyMo.EXPECT().IsNeedSign().Return(true).AnyTimes() 91 dummyMo.EXPECT().IsRequest().Return(true).AnyTimes() 92 dummyMo.EXPECT().GetProtocolID().Return(p2pcommon.NewTxNotice).AnyTimes() 93 dummyMo.EXPECT().GetMsgID().Return(p2pcommon.NewMsgID()).AnyTimes() 94 return dummyMo 95 } 96 97 func TestClusterInfoReceiver_trySendNextPeer(t *testing.T) { 98 ctrl := gomock.NewController(t) 99 defer ctrl.Finish() 100 101 type args struct { 102 stats []int 103 } 104 tests := []struct { 105 name string 106 args args 107 108 wantSentCnt int 109 }{ 110 {"TAllRunning", args{[]int{1, 1, 1, 1, 1}}, 5}, 111 {"TNoPeers", args{[]int{}}, 0}, 112 {"TNoRunning", args{[]int{0, 0, 0, 0, 0}}, 0}, 113 {"TMixed", args{[]int{0, 0, 1, 1, 1}}, 3}, 114 {"TMixed2", args{[]int{1, 1, 0, 0, 0}}, 2}, 115 {"TMixed3", args{[]int{1, 0, 1, 0, 0, 1}}, 3}, 116 {"TMixed4", args{[]int{0, 1, 0, 1, 0, 1, 0}}, 3}, 117 } 118 for _, tt := range tests { 119 t.Run(tt.name, func(t *testing.T) { 120 mockActor := p2pmock.NewMockActorService(ctrl) 121 mockMF := p2pmock.NewMockMoFactory(ctrl) 122 mockMo := createDummyMo(ctrl) 123 mockMF.EXPECT().NewMsgBlockRequestOrder(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockMo).Times(tt.wantSentCnt) 124 peers := make([]p2pcommon.RemotePeer, 0, len(tt.args.stats)) 125 for _, run := range tt.args.stats { 126 dummyPeerID, _ := types.IDB58Decode("16Uiu2HAmFqptXPfcdaCdwipB2fhHATgKGVFVPehDAPZsDKSU7jRm") 127 stat := types.RUNNING 128 if run == 0 { 129 stat = types.STOPPING 130 } 131 peers = append(peers, createDummyPeer(ctrl, dummyPeerID, stat)) 132 } 133 134 sentCnt := 0 135 replyChan := make(chan *message.GetClusterRsp) 136 dummyReq := &message.GetCluster{ReplyC: replyChan} 137 target := NewClusterInfoReceiver(mockActor, mockMF, peers, time.Millisecond, dummyReq) 138 for target.trySendNextPeer() { 139 sentCnt++ 140 } 141 142 if sentCnt != tt.wantSentCnt { 143 t.Errorf("resp error %v, wantErr %v ", sentCnt, tt.wantSentCnt) 144 } 145 }) 146 } 147 } 148 149 func TestClusterInfoReceiver_ReceiveResp(t *testing.T) { 150 sampleChainID := []byte("testChain") 151 members := make([]*types.MemberAttr,4) 152 ctrl := gomock.NewController(t) 153 defer ctrl.Finish() 154 155 type args struct { 156 stats []int 157 } 158 tests := []struct { 159 name string 160 args args 161 162 wantSentCnt int // count of sent to remote peers 163 wantTimeout bool // whether receiver returns result or not (=timeout) 164 wantErrResp bool // result with error or not 165 }{ 166 {"TAllRet", args{[]int{1, 1, 1, 1, 1}}, 1, false,false}, 167 {"TErrRet", args{[]int{0, 0, 0, 0, 0}}, 5, false, true}, 168 {"TMixed", args{[]int{0, 0, 1, 1, 1}}, 3, false, false}, 169 {"TTimeout", args{[]int{0, 0}}, 3, true, true}, 170 } 171 for _, tt := range tests { 172 t.Run(tt.name, func(t *testing.T) { 173 peers := make([]p2pcommon.RemotePeer, 0, len(tt.args.stats)) 174 175 mockActor := p2pmock.NewMockActorService(ctrl) 176 mockMF := p2pmock.NewMockMoFactory(ctrl) 177 mockMo := createDummyMo(ctrl) 178 mockMF.EXPECT().NewMsgBlockRequestOrder(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockMo).Times(tt.wantSentCnt) 179 180 replyChan := make(chan *message.GetClusterRsp) 181 dummyReq := &message.GetCluster{ReplyC: replyChan} 182 target := NewClusterInfoReceiver(mockActor, mockMF, peers, time.Second, dummyReq) 183 184 seq := int32(0) 185 for i:=0; i<5; i++ { 186 dummyPeerID, _ := types.IDB58Decode("16Uiu2HAmFqptXPfcdaCdwipB2fhHATgKGVFVPehDAPZsDKSU7jRm") 187 stat := types.RUNNING 188 mockPeer := p2pmock.NewMockRemotePeer(ctrl) 189 mockPeer.EXPECT().State().Return(stat).AnyTimes() 190 mockPeer.EXPECT().ID().Return(dummyPeerID).AnyTimes() 191 mockPeer.EXPECT().ConsumeRequest(gomock.Any()).AnyTimes() 192 mockPeer.EXPECT().SendMessage(gomock.Any()).Do(func(mo p2pcommon.MsgOrder) { 193 time.Sleep(time.Millisecond*5) 194 callSeq := atomic.LoadInt32(&seq) 195 msg := p2pmock.NewMockMessage(ctrl) 196 msg.EXPECT().ID().Return(p2pcommon.NewMsgID()).AnyTimes() 197 msg.EXPECT().OriginalID().Return(p2pcommon.NewMsgID()).AnyTimes() 198 msg.EXPECT().Timestamp().Return(time.Now().UnixNano()).AnyTimes() 199 msg.EXPECT().Subprotocol().Return(p2pcommon.GetClusterResponse).AnyTimes() 200 if callSeq < int32(len(tt.args.stats)) { 201 err := "" 202 if tt.args.stats[callSeq] == 0 { 203 err = "getCluster failed" 204 } 205 body := &types.GetClusterInfoResponse{ChainID:sampleChainID, MbrAttrs:members, Error:err} 206 atomic.AddInt32(&seq, 1) 207 go target.ReceiveResp(msg, body) 208 } else { 209 atomic.AddInt32(&seq, 1) 210 } 211 }).MaxTimes(1) 212 peers = append(peers, mockPeer) 213 } 214 // force inject peers 215 target.peers = peers 216 217 target.StartGet() 218 219 if !tt.wantTimeout { 220 timer := time.NewTimer(time.Second * 2) 221 select { 222 case resp := <-replyChan: 223 if (resp.Err != nil) != tt.wantErrResp { 224 t.Errorf("resp error %v, wantErr %v ", resp.Err, tt.wantErrResp) 225 } 226 // receiver return valid result 227 if !tt.wantErrResp { 228 if !bytes.Equal(resp.ChainID, sampleChainID) { 229 t.Errorf("resp chainid %v, want %v ",resp.ChainID, sampleChainID) 230 } 231 if len(resp.Members) != len(members) { 232 t.Errorf("resp members %v, want %v ",resp.Members, len(members)) 233 } 234 } 235 case <-timer.C: 236 t.Errorf("timeout occurred, want no time") 237 } 238 } else { 239 timer := time.NewTimer(time.Millisecond * 100) 240 select { 241 case resp := <-replyChan: 242 t.Errorf("unexpected response (%d mems, err:%v), want timeout", len(resp.Members), resp.Err) 243 case <-timer.C: 244 // expected timeout 245 } 246 } 247 248 }) 249 } 250 }