github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/peer_test.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 19:16:41</date> 10 //</624450105675616256> 11 12 13 package p2p 14 15 import ( 16 "errors" 17 "fmt" 18 "math/rand" 19 "net" 20 "reflect" 21 "testing" 22 "time" 23 ) 24 25 var discard = Protocol{ 26 Name: "discard", 27 Length: 1, 28 Run: func(p *Peer, rw MsgReadWriter) error { 29 for { 30 msg, err := rw.ReadMsg() 31 if err != nil { 32 return err 33 } 34 fmt.Printf("discarding %d\n", msg.Code) 35 if err = msg.Discard(); err != nil { 36 return err 37 } 38 } 39 }, 40 } 41 42 func testPeer(protos []Protocol) (func(), *conn, *Peer, <-chan error) { 43 fd1, fd2 := net.Pipe() 44 c1 := &conn{fd: fd1, node: newNode(randomID(), nil), transport: newTestTransport(&newkey().PublicKey, fd1)} 45 c2 := &conn{fd: fd2, node: newNode(randomID(), nil), transport: newTestTransport(&newkey().PublicKey, fd2)} 46 for _, p := range protos { 47 c1.caps = append(c1.caps, p.cap()) 48 c2.caps = append(c2.caps, p.cap()) 49 } 50 51 peer := newPeer(c1, protos) 52 errc := make(chan error, 1) 53 go func() { 54 _, err := peer.run() 55 errc <- err 56 }() 57 58 closer := func() { c2.close(errors.New("close func called")) } 59 return closer, c2, peer, errc 60 } 61 62 func TestPeerProtoReadMsg(t *testing.T) { 63 proto := Protocol{ 64 Name: "a", 65 Length: 5, 66 Run: func(peer *Peer, rw MsgReadWriter) error { 67 if err := ExpectMsg(rw, 2, []uint{1}); err != nil { 68 t.Error(err) 69 } 70 if err := ExpectMsg(rw, 3, []uint{2}); err != nil { 71 t.Error(err) 72 } 73 if err := ExpectMsg(rw, 4, []uint{3}); err != nil { 74 t.Error(err) 75 } 76 return nil 77 }, 78 } 79 80 closer, rw, _, errc := testPeer([]Protocol{proto}) 81 defer closer() 82 83 Send(rw, baseProtocolLength+2, []uint{1}) 84 Send(rw, baseProtocolLength+3, []uint{2}) 85 Send(rw, baseProtocolLength+4, []uint{3}) 86 87 select { 88 case err := <-errc: 89 if err != errProtocolReturned { 90 t.Errorf("peer returned error: %v", err) 91 } 92 case <-time.After(2 * time.Second): 93 t.Errorf("receive timeout") 94 } 95 } 96 97 func TestPeerProtoEncodeMsg(t *testing.T) { 98 proto := Protocol{ 99 Name: "a", 100 Length: 2, 101 Run: func(peer *Peer, rw MsgReadWriter) error { 102 if err := SendItems(rw, 2); err == nil { 103 t.Error("expected error for out-of-range msg code, got nil") 104 } 105 if err := SendItems(rw, 1, "foo", "bar"); err != nil { 106 t.Errorf("write error: %v", err) 107 } 108 return nil 109 }, 110 } 111 closer, rw, _, _ := testPeer([]Protocol{proto}) 112 defer closer() 113 114 if err := ExpectMsg(rw, 17, []string{"foo", "bar"}); err != nil { 115 t.Error(err) 116 } 117 } 118 119 func TestPeerPing(t *testing.T) { 120 closer, rw, _, _ := testPeer(nil) 121 defer closer() 122 if err := SendItems(rw, pingMsg); err != nil { 123 t.Fatal(err) 124 } 125 if err := ExpectMsg(rw, pongMsg, nil); err != nil { 126 t.Error(err) 127 } 128 } 129 130 func TestPeerDisconnect(t *testing.T) { 131 closer, rw, _, disc := testPeer(nil) 132 defer closer() 133 if err := SendItems(rw, discMsg, DiscQuitting); err != nil { 134 t.Fatal(err) 135 } 136 select { 137 case reason := <-disc: 138 if reason != DiscQuitting { 139 t.Errorf("run returned wrong reason: got %v, want %v", reason, DiscQuitting) 140 } 141 case <-time.After(500 * time.Millisecond): 142 t.Error("peer did not return") 143 } 144 } 145 146 //此测试旨在验证对等端是否能够可靠地处理 147 //同时发生多个断开原因。 148 func TestPeerDisconnectRace(t *testing.T) { 149 maybe := func() bool { return rand.Intn(1) == 1 } 150 151 for i := 0; i < 1000; i++ { 152 protoclose := make(chan error) 153 protodisc := make(chan DiscReason) 154 closer, rw, p, disc := testPeer([]Protocol{ 155 { 156 Name: "closereq", 157 Run: func(p *Peer, rw MsgReadWriter) error { return <-protoclose }, 158 Length: 1, 159 }, 160 { 161 Name: "disconnect", 162 Run: func(p *Peer, rw MsgReadWriter) error { p.Disconnect(<-protodisc); return nil }, 163 Length: 1, 164 }, 165 }) 166 167 //模拟传入消息。 168 go SendItems(rw, baseProtocolLength+1) 169 go SendItems(rw, baseProtocolLength+2) 170 //关闭网络连接。 171 go closer() 172 //使协议“closereq”返回。 173 protoclose <- errors.New("protocol closed") 174 //使协议“断开”呼叫对等方。断开连接 175 protodisc <- DiscAlreadyConnected 176 //在某些情况下,模拟调用peer.disconnect的其他内容。 177 if maybe() { 178 go p.Disconnect(DiscInvalidIdentity) 179 } 180 //在某些情况下,模拟远程请求断开连接。 181 if maybe() { 182 go SendItems(rw, discMsg, DiscQuitting) 183 } 184 185 select { 186 case <-disc: 187 case <-time.After(2 * time.Second): 188 //peer.run应该很快返回。如果不是同伴 189 //Goroutines可能陷入了僵局。呼叫恐慌以便 190 //显示堆栈。 191 panic("Peer.run took to long to return.") 192 } 193 } 194 } 195 196 func TestNewPeer(t *testing.T) { 197 name := "nodename" 198 caps := []Cap{{"foo", 2}, {"bar", 3}} 199 id := randomID() 200 p := NewPeer(id, name, caps) 201 if p.ID() != id { 202 t.Errorf("ID mismatch: got %v, expected %v", p.ID(), id) 203 } 204 if p.Name() != name { 205 t.Errorf("Name mismatch: got %v, expected %v", p.Name(), name) 206 } 207 if !reflect.DeepEqual(p.Caps(), caps) { 208 t.Errorf("Caps mismatch: got %v, expected %v", p.Caps(), caps) 209 } 210 211 p.Disconnect(DiscAlreadyConnected) //不应该挂 212 } 213 214 func TestMatchProtocols(t *testing.T) { 215 tests := []struct { 216 Remote []Cap 217 Local []Protocol 218 Match map[string]protoRW 219 }{ 220 { 221 //无远程功能 222 Local: []Protocol{{Name: "a"}}, 223 }, 224 { 225 //没有本地协议 226 Remote: []Cap{{Name: "a"}}, 227 }, 228 { 229 //没有相互协议 230 Remote: []Cap{{Name: "a"}}, 231 Local: []Protocol{{Name: "b"}}, 232 }, 233 { 234 //一些匹配,一些差异 235 Remote: []Cap{{Name: "local"}, {Name: "match1"}, {Name: "match2"}}, 236 Local: []Protocol{{Name: "match1"}, {Name: "match2"}, {Name: "remote"}}, 237 Match: map[string]protoRW{"match1": {Protocol: Protocol{Name: "match1"}}, "match2": {Protocol: Protocol{Name: "match2"}}}, 238 }, 239 { 240 //各种字母顺序 241 Remote: []Cap{{Name: "aa"}, {Name: "ab"}, {Name: "bb"}, {Name: "ba"}}, 242 Local: []Protocol{{Name: "ba"}, {Name: "bb"}, {Name: "ab"}, {Name: "aa"}}, 243 Match: map[string]protoRW{"aa": {Protocol: Protocol{Name: "aa"}}, "ab": {Protocol: Protocol{Name: "ab"}}, "ba": {Protocol: Protocol{Name: "ba"}}, "bb": {Protocol: Protocol{Name: "bb"}}}, 244 }, 245 { 246 //没有相互的版本 247 Remote: []Cap{{Version: 1}}, 248 Local: []Protocol{{Version: 2}}, 249 }, 250 { 251 //多版本,单通用 252 Remote: []Cap{{Version: 1}, {Version: 2}}, 253 Local: []Protocol{{Version: 2}, {Version: 3}}, 254 Match: map[string]protoRW{"": {Protocol: Protocol{Version: 2}}}, 255 }, 256 { 257 //多版本,多公共 258 Remote: []Cap{{Version: 1}, {Version: 2}, {Version: 3}, {Version: 4}}, 259 Local: []Protocol{{Version: 2}, {Version: 3}}, 260 Match: map[string]protoRW{"": {Protocol: Protocol{Version: 3}}}, 261 }, 262 { 263 //各种版本订单 264 Remote: []Cap{{Version: 4}, {Version: 1}, {Version: 3}, {Version: 2}}, 265 Local: []Protocol{{Version: 2}, {Version: 3}, {Version: 1}}, 266 Match: map[string]protoRW{"": {Protocol: Protocol{Version: 3}}}, 267 }, 268 { 269 //覆盖子协议长度的版本 270 Remote: []Cap{{Version: 1}, {Version: 2}, {Version: 3}, {Name: "a"}}, 271 Local: []Protocol{{Version: 1, Length: 1}, {Version: 2, Length: 2}, {Version: 3, Length: 3}, {Name: "a"}}, 272 Match: map[string]protoRW{"": {Protocol: Protocol{Version: 3}}, "a": {Protocol: Protocol{Name: "a"}, offset: 3}}, 273 }, 274 } 275 276 for i, tt := range tests { 277 result := matchProtocols(tt.Local, tt.Remote, nil) 278 if len(result) != len(tt.Match) { 279 t.Errorf("test %d: negotiation mismatch: have %v, want %v", i, len(result), len(tt.Match)) 280 continue 281 } 282 //确保所有协商的协议都是必要的和正确的 283 for name, proto := range result { 284 match, ok := tt.Match[name] 285 if !ok { 286 t.Errorf("test %d, proto '%s': negotiated but shouldn't have", i, name) 287 continue 288 } 289 if proto.Name != match.Name { 290 t.Errorf("test %d, proto '%s': name mismatch: have %v, want %v", i, name, proto.Name, match.Name) 291 } 292 if proto.Version != match.Version { 293 t.Errorf("test %d, proto '%s': version mismatch: have %v, want %v", i, name, proto.Version, match.Version) 294 } 295 if proto.offset-baseProtocolLength != match.offset { 296 t.Errorf("test %d, proto '%s': offset mismatch: have %v, want %v", i, name, proto.offset-baseProtocolLength, match.offset) 297 } 298 } 299 //确保没有协议错过协商 300 for name := range tt.Match { 301 if _, ok := result[name]; !ok { 302 t.Errorf("test %d, proto '%s': not negotiated, should have", i, name) 303 continue 304 } 305 } 306 } 307 } 308