github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/p2p/testing/protocolsession.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:45</date> 10 //</624342661968433152> 11 12 13 package testing 14 15 import ( 16 "errors" 17 "fmt" 18 "sync" 19 "time" 20 21 "github.com/ethereum/go-ethereum/log" 22 "github.com/ethereum/go-ethereum/p2p" 23 "github.com/ethereum/go-ethereum/p2p/discover" 24 "github.com/ethereum/go-ethereum/p2p/simulations/adapters" 25 ) 26 27 var errTimedOut = errors.New("timed out") 28 29 //ProtocolSession是对运行的枢轴节点的准模拟。 30 //可以发送(触发器)或 31 //接收(预期)消息 32 type ProtocolSession struct { 33 Server *p2p.Server 34 IDs []discover.NodeID 35 adapter *adapters.SimAdapter 36 events chan *p2p.PeerEvent 37 } 38 39 //交换是协议测试的基本单元 40 //数组中的触发器和预期将立即异步运行 41 //因此,对于具有不同消息类型的同一对等端,不能有多个预期值 42 //因为它是不可预测的,哪个期望会收到哪个消息 43 //(对于Expect 1和2,可能会发送消息2和1,两个Expect都会抱怨错误的消息代码) 44 //在会话上定义交换 45 type Exchange struct { 46 Label string 47 Triggers []Trigger 48 Expects []Expect 49 Timeout time.Duration 50 } 51 52 //触发器是交换的一部分,透视节点的传入消息 53 //同行发送 54 type Trigger struct { 55 Msg interface{} //要发送的消息类型 56 Code uint64 //给出报文代码 57 Peer discover.NodeID //向其发送消息的对等方 58 Timeout time.Duration //发送超时时间 59 } 60 61 //Expect是来自透视节点的交换传出消息的一部分 62 //由对等方接收 63 type Expect struct { 64 Msg interface{} //预期的消息类型 65 Code uint64 //现在给出了消息代码 66 Peer discover.NodeID //期望消息的对等机 67 Timeout time.Duration //接收超时时间 68 } 69 70 //disconnect表示一个disconnect事件,由testdisconnected使用并检查 71 type Disconnect struct { 72 Peer discover.NodeID //DiscConnected对等 73 Error error //断开连接原因 74 } 75 76 //触发器从对等方发送消息 77 func (s *ProtocolSession) trigger(trig Trigger) error { 78 simNode, ok := s.adapter.GetNode(trig.Peer) 79 if !ok { 80 return fmt.Errorf("trigger: peer %v does not exist (1- %v)", trig.Peer, len(s.IDs)) 81 } 82 mockNode, ok := simNode.Services()[0].(*mockNode) 83 if !ok { 84 return fmt.Errorf("trigger: peer %v is not a mock", trig.Peer) 85 } 86 87 errc := make(chan error) 88 89 go func() { 90 log.Trace(fmt.Sprintf("trigger %v (%v)....", trig.Msg, trig.Code)) 91 errc <- mockNode.Trigger(&trig) 92 log.Trace(fmt.Sprintf("triggered %v (%v)", trig.Msg, trig.Code)) 93 }() 94 95 t := trig.Timeout 96 if t == time.Duration(0) { 97 t = 1000 * time.Millisecond 98 } 99 select { 100 case err := <-errc: 101 return err 102 case <-time.After(t): 103 return fmt.Errorf("timout expecting %v to send to peer %v", trig.Msg, trig.Peer) 104 } 105 } 106 107 //Expect检查透视节点发送的消息的期望值 108 func (s *ProtocolSession) expect(exps []Expect) error { 109 //构建每个节点的期望图 110 peerExpects := make(map[discover.NodeID][]Expect) 111 for _, exp := range exps { 112 if exp.Msg == nil { 113 return errors.New("no message to expect") 114 } 115 peerExpects[exp.Peer] = append(peerExpects[exp.Peer], exp) 116 } 117 118 //为每个节点构造一个mocknode映射 119 mockNodes := make(map[discover.NodeID]*mockNode) 120 for nodeID := range peerExpects { 121 simNode, ok := s.adapter.GetNode(nodeID) 122 if !ok { 123 return fmt.Errorf("trigger: peer %v does not exist (1- %v)", nodeID, len(s.IDs)) 124 } 125 mockNode, ok := simNode.Services()[0].(*mockNode) 126 if !ok { 127 return fmt.Errorf("trigger: peer %v is not a mock", nodeID) 128 } 129 mockNodes[nodeID] = mockNode 130 } 131 132 //done chanell在函数返回时取消所有创建的goroutine 133 done := make(chan struct{}) 134 defer close(done) 135 //errc从中捕获第一个错误 136 errc := make(chan error) 137 138 wg := &sync.WaitGroup{} 139 wg.Add(len(mockNodes)) 140 for nodeID, mockNode := range mockNodes { 141 nodeID := nodeID 142 mockNode := mockNode 143 go func() { 144 defer wg.Done() 145 146 //求和所有期望超时值以给出最大值 147 //完成所有期望的时间。 148 //mocknode.expect检查所有接收到的消息 149 //每个消息的预期消息和超时列表 150 //其中不能单独检查。 151 var t time.Duration 152 for _, exp := range peerExpects[nodeID] { 153 if exp.Timeout == time.Duration(0) { 154 t += 2000 * time.Millisecond 155 } else { 156 t += exp.Timeout 157 } 158 } 159 alarm := time.NewTimer(t) 160 defer alarm.Stop() 161 162 //expecterrc用于检查是否返回错误 163 //从mocknode.expect不是nil并将其发送到 164 //只有在这种情况下才是errc。 165 //完成通道将在功能关闭时关闭 166 expectErrc := make(chan error) 167 go func() { 168 select { 169 case expectErrc <- mockNode.Expect(peerExpects[nodeID]...): 170 case <-done: 171 case <-alarm.C: 172 } 173 }() 174 175 select { 176 case err := <-expectErrc: 177 if err != nil { 178 select { 179 case errc <- err: 180 case <-done: 181 case <-alarm.C: 182 errc <- errTimedOut 183 } 184 } 185 case <-done: 186 case <-alarm.C: 187 errc <- errTimedOut 188 } 189 190 }() 191 } 192 193 go func() { 194 wg.Wait() 195 //当所有Goroutine完成时关闭errc,从errc返回nill err 196 close(errc) 197 }() 198 199 return <-errc 200 } 201 202 //测试交换测试一系列针对会话的交换 203 func (s *ProtocolSession) TestExchanges(exchanges ...Exchange) error { 204 for i, e := range exchanges { 205 if err := s.testExchange(e); err != nil { 206 return fmt.Errorf("exchange #%d %q: %v", i, e.Label, err) 207 } 208 log.Trace(fmt.Sprintf("exchange #%d %q: run successfully", i, e.Label)) 209 } 210 return nil 211 } 212 213 //测试交换测试单个交换。 214 //默认超时值为2秒。 215 func (s *ProtocolSession) testExchange(e Exchange) error { 216 errc := make(chan error) 217 done := make(chan struct{}) 218 defer close(done) 219 220 go func() { 221 for _, trig := range e.Triggers { 222 err := s.trigger(trig) 223 if err != nil { 224 errc <- err 225 return 226 } 227 } 228 229 select { 230 case errc <- s.expect(e.Expects): 231 case <-done: 232 } 233 }() 234 235 //全球超时或在所有期望都满足时结束 236 t := e.Timeout 237 if t == 0 { 238 t = 2000 * time.Millisecond 239 } 240 alarm := time.NewTimer(t) 241 select { 242 case err := <-errc: 243 return err 244 case <-alarm.C: 245 return errTimedOut 246 } 247 } 248 249 //testDisconnected测试作为参数提供的断开 250 //disconnect结构描述了在哪个对等机上预期出现的断开连接错误 251 func (s *ProtocolSession) TestDisconnected(disconnects ...*Disconnect) error { 252 expects := make(map[discover.NodeID]error) 253 for _, disconnect := range disconnects { 254 expects[disconnect.Peer] = disconnect.Error 255 } 256 257 timeout := time.After(time.Second) 258 for len(expects) > 0 { 259 select { 260 case event := <-s.events: 261 if event.Type != p2p.PeerEventTypeDrop { 262 continue 263 } 264 expectErr, ok := expects[event.Peer] 265 if !ok { 266 continue 267 } 268 269 if !(expectErr == nil && event.Error == "" || expectErr != nil && expectErr.Error() == event.Error) { 270 return fmt.Errorf("unexpected error on peer %v. expected '%v', got '%v'", event.Peer, expectErr, event.Error) 271 } 272 delete(expects, event.Peer) 273 case <-timeout: 274 return fmt.Errorf("timed out waiting for peers to disconnect") 275 } 276 } 277 return nil 278 } 279