github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/peer_test.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2014 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package p2p 26 27 import ( 28 "errors" 29 "fmt" 30 "math/rand" 31 "net" 32 "reflect" 33 "testing" 34 "time" 35 ) 36 37 var discard = Protocol{ 38 Name: "discard", 39 Length: 1, 40 Run: func(p *Peer, rw MsgReadWriter) error { 41 for { 42 msg, err := rw.ReadMsg() 43 if err != nil { 44 return err 45 } 46 fmt.Printf("discarding %d\n", msg.Code) 47 if err = msg.Discard(); err != nil { 48 return err 49 } 50 } 51 }, 52 } 53 54 func testPeer(protos []Protocol) (func(), *conn, *Peer, <-chan error) { 55 fd1, fd2 := net.Pipe() 56 c1 := &conn{fd: fd1, transport: newTestTransport(randomID(), fd1)} 57 c2 := &conn{fd: fd2, transport: newTestTransport(randomID(), fd2)} 58 for _, p := range protos { 59 c1.caps = append(c1.caps, p.cap()) 60 c2.caps = append(c2.caps, p.cap()) 61 } 62 63 peer := newPeer(c1, protos) 64 errc := make(chan error, 1) 65 go func() { 66 _, err := peer.run() 67 errc <- err 68 }() 69 70 closer := func() { c2.close(errors.New("close func called")) } 71 return closer, c2, peer, errc 72 } 73 74 func TestPeerProtoReadMsg(t *testing.T) { 75 proto := Protocol{ 76 Name: "a", 77 Length: 5, 78 Run: func(peer *Peer, rw MsgReadWriter) error { 79 if err := ExpectMsg(rw, 2, []uint{1}); err != nil { 80 t.Error(err) 81 } 82 if err := ExpectMsg(rw, 3, []uint{2}); err != nil { 83 t.Error(err) 84 } 85 if err := ExpectMsg(rw, 4, []uint{3}); err != nil { 86 t.Error(err) 87 } 88 return nil 89 }, 90 } 91 92 closer, rw, _, errc := testPeer([]Protocol{proto}) 93 defer closer() 94 95 Send(rw, baseProtocolLength+2, []uint{1}) 96 Send(rw, baseProtocolLength+3, []uint{2}) 97 Send(rw, baseProtocolLength+4, []uint{3}) 98 99 select { 100 case err := <-errc: 101 if err != errProtocolReturned { 102 t.Errorf("peer returned error: %v", err) 103 } 104 case <-time.After(2 * time.Second): 105 t.Errorf("receive timeout") 106 } 107 } 108 109 func TestPeerProtoEncodeMsg(t *testing.T) { 110 proto := Protocol{ 111 Name: "a", 112 Length: 2, 113 Run: func(peer *Peer, rw MsgReadWriter) error { 114 if err := SendItems(rw, 2); err == nil { 115 t.Error("expected error for out-of-range msg code, got nil") 116 } 117 if err := SendItems(rw, 1, "foo", "bar"); err != nil { 118 t.Errorf("write error: %v", err) 119 } 120 return nil 121 }, 122 } 123 closer, rw, _, _ := testPeer([]Protocol{proto}) 124 defer closer() 125 126 if err := ExpectMsg(rw, 17, []string{"foo", "bar"}); err != nil { 127 t.Error(err) 128 } 129 } 130 131 func TestPeerPing(t *testing.T) { 132 closer, rw, _, _ := testPeer(nil) 133 defer closer() 134 if err := SendItems(rw, pingMsg); err != nil { 135 t.Fatal(err) 136 } 137 if err := ExpectMsg(rw, pongMsg, nil); err != nil { 138 t.Error(err) 139 } 140 } 141 142 func TestPeerDisconnect(t *testing.T) { 143 closer, rw, _, disc := testPeer(nil) 144 defer closer() 145 if err := SendItems(rw, discMsg, DiscQuitting); err != nil { 146 t.Fatal(err) 147 } 148 select { 149 case reason := <-disc: 150 if reason != DiscQuitting { 151 t.Errorf("run returned wrong reason: got %v, want %v", reason, DiscQuitting) 152 } 153 case <-time.After(500 * time.Millisecond): 154 t.Error("peer did not return") 155 } 156 } 157 158 //此测试旨在验证对等端是否能够可靠地处理 159 //同时发生多个断开原因。 160 func TestPeerDisconnectRace(t *testing.T) { 161 maybe := func() bool { return rand.Intn(1) == 1 } 162 163 for i := 0; i < 1000; i++ { 164 protoclose := make(chan error) 165 protodisc := make(chan DiscReason) 166 closer, rw, p, disc := testPeer([]Protocol{ 167 { 168 Name: "closereq", 169 Run: func(p *Peer, rw MsgReadWriter) error { return <-protoclose }, 170 Length: 1, 171 }, 172 { 173 Name: "disconnect", 174 Run: func(p *Peer, rw MsgReadWriter) error { p.Disconnect(<-protodisc); return nil }, 175 Length: 1, 176 }, 177 }) 178 179 //模拟传入消息。 180 go SendItems(rw, baseProtocolLength+1) 181 go SendItems(rw, baseProtocolLength+2) 182 //关闭网络连接。 183 go closer() 184 //使协议“closereq”返回。 185 protoclose <- errors.New("protocol closed") 186 //使协议“断开”呼叫对等方。断开连接 187 protodisc <- DiscAlreadyConnected 188 //在某些情况下,模拟调用peer.disconnect的其他内容。 189 if maybe() { 190 go p.Disconnect(DiscInvalidIdentity) 191 } 192 //在某些情况下,模拟远程请求断开连接。 193 if maybe() { 194 go SendItems(rw, discMsg, DiscQuitting) 195 } 196 197 select { 198 case <-disc: 199 case <-time.After(2 * time.Second): 200 //peer.run应该很快返回。如果不是同伴 201 // 202 //显示堆栈。 203 panic("Peer.run took to long to return.") 204 } 205 } 206 } 207 208 func TestNewPeer(t *testing.T) { 209 name := "nodename" 210 caps := []Cap{{"foo", 2}, {"bar", 3}} 211 id := randomID() 212 p := NewPeer(id, name, caps) 213 if p.ID() != id { 214 t.Errorf("ID mismatch: got %v, expected %v", p.ID(), id) 215 } 216 if p.Name() != name { 217 t.Errorf("Name mismatch: got %v, expected %v", p.Name(), name) 218 } 219 if !reflect.DeepEqual(p.Caps(), caps) { 220 t.Errorf("Caps mismatch: got %v, expected %v", p.Caps(), caps) 221 } 222 223 p.Disconnect(DiscAlreadyConnected) //不应该挂 224 } 225 226 func TestMatchProtocols(t *testing.T) { 227 tests := []struct { 228 Remote []Cap 229 Local []Protocol 230 Match map[string]protoRW 231 }{ 232 { 233 //无远程功能 234 Local: []Protocol{{Name: "a"}}, 235 }, 236 { 237 //没有本地协议 238 Remote: []Cap{{Name: "a"}}, 239 }, 240 { 241 //没有相互协议 242 Remote: []Cap{{Name: "a"}}, 243 Local: []Protocol{{Name: "b"}}, 244 }, 245 { 246 //一些匹配,一些差异 247 Remote: []Cap{{Name: "local"}, {Name: "match1"}, {Name: "match2"}}, 248 Local: []Protocol{{Name: "match1"}, {Name: "match2"}, {Name: "remote"}}, 249 Match: map[string]protoRW{"match1": {Protocol: Protocol{Name: "match1"}}, "match2": {Protocol: Protocol{Name: "match2"}}}, 250 }, 251 { 252 //各种字母顺序 253 Remote: []Cap{{Name: "aa"}, {Name: "ab"}, {Name: "bb"}, {Name: "ba"}}, 254 Local: []Protocol{{Name: "ba"}, {Name: "bb"}, {Name: "ab"}, {Name: "aa"}}, 255 Match: map[string]protoRW{"aa": {Protocol: Protocol{Name: "aa"}}, "ab": {Protocol: Protocol{Name: "ab"}}, "ba": {Protocol: Protocol{Name: "ba"}}, "bb": {Protocol: Protocol{Name: "bb"}}}, 256 }, 257 { 258 //没有相互的版本 259 Remote: []Cap{{Version: 1}}, 260 Local: []Protocol{{Version: 2}}, 261 }, 262 { 263 //多版本,单通用 264 Remote: []Cap{{Version: 1}, {Version: 2}}, 265 Local: []Protocol{{Version: 2}, {Version: 3}}, 266 Match: map[string]protoRW{"": {Protocol: Protocol{Version: 2}}}, 267 }, 268 { 269 //多版本,多公共 270 Remote: []Cap{{Version: 1}, {Version: 2}, {Version: 3}, {Version: 4}}, 271 Local: []Protocol{{Version: 2}, {Version: 3}}, 272 Match: map[string]protoRW{"": {Protocol: Protocol{Version: 3}}}, 273 }, 274 { 275 //各种版本订单 276 Remote: []Cap{{Version: 4}, {Version: 1}, {Version: 3}, {Version: 2}}, 277 Local: []Protocol{{Version: 2}, {Version: 3}, {Version: 1}}, 278 Match: map[string]protoRW{"": {Protocol: Protocol{Version: 3}}}, 279 }, 280 { 281 //覆盖子协议长度的版本 282 Remote: []Cap{{Version: 1}, {Version: 2}, {Version: 3}, {Name: "a"}}, 283 Local: []Protocol{{Version: 1, Length: 1}, {Version: 2, Length: 2}, {Version: 3, Length: 3}, {Name: "a"}}, 284 Match: map[string]protoRW{"": {Protocol: Protocol{Version: 3}}, "a": {Protocol: Protocol{Name: "a"}, offset: 3}}, 285 }, 286 } 287 288 for i, tt := range tests { 289 result := matchProtocols(tt.Local, tt.Remote, nil) 290 if len(result) != len(tt.Match) { 291 t.Errorf("test %d: negotiation mismatch: have %v, want %v", i, len(result), len(tt.Match)) 292 continue 293 } 294 //确保所有协商的协议都是必要的和正确的 295 for name, proto := range result { 296 match, ok := tt.Match[name] 297 if !ok { 298 t.Errorf("test %d, proto '%s': negotiated but shouldn't have", i, name) 299 continue 300 } 301 if proto.Name != match.Name { 302 t.Errorf("test %d, proto '%s': name mismatch: have %v, want %v", i, name, proto.Name, match.Name) 303 } 304 if proto.Version != match.Version { 305 t.Errorf("test %d, proto '%s': version mismatch: have %v, want %v", i, name, proto.Version, match.Version) 306 } 307 if proto.offset-baseProtocolLength != match.offset { 308 t.Errorf("test %d, proto '%s': offset mismatch: have %v, want %v", i, name, proto.offset-baseProtocolLength, match.offset) 309 } 310 } 311 //确保没有协议错过协商 312 for name := range tt.Match { 313 if _, ok := result[name]; !ok { 314 t.Errorf("test %d, proto '%s': not negotiated, should have", i, name) 315 continue 316 } 317 } 318 } 319 }