github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/p2p/peer_test.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // +build !deterministic 18 19 package p2p 20 21 import ( 22 "errors" 23 "math/rand" 24 "reflect" 25 "testing" 26 "time" 27 ) 28 29 func TestPeerProtoReadMsg(t *testing.T) { 30 done := make(chan struct{}) 31 proto := Protocol{ 32 Name: "a", 33 Length: 5, 34 Run: func(peer *Peer, rw MsgReadWriter) error { 35 if err := ExpectMsg(rw, 2, []uint{1}); err != nil { 36 t.Error(err) 37 } 38 if err := ExpectMsg(rw, 3, []uint{2}); err != nil { 39 t.Error(err) 40 } 41 if err := ExpectMsg(rw, 4, []uint{3}); err != nil { 42 t.Error(err) 43 } 44 close(done) 45 return nil 46 }, 47 } 48 49 closer, rw, _, errc := testPeer([]Protocol{proto}) 50 defer closer() 51 52 Send(rw, baseProtocolLength+2, []uint{1}) 53 Send(rw, baseProtocolLength+3, []uint{2}) 54 Send(rw, baseProtocolLength+4, []uint{3}) 55 56 select { 57 case <-done: 58 case err := <-errc: 59 t.Errorf("peer returned: %v", err) 60 case <-time.After(2 * time.Second): 61 t.Errorf("receive timeout") 62 } 63 } 64 65 func TestPeerProtoEncodeMsg(t *testing.T) { 66 proto := Protocol{ 67 Name: "a", 68 Length: 2, 69 Run: func(peer *Peer, rw MsgReadWriter) error { 70 if err := SendItems(rw, 2); err == nil { 71 t.Error("expected error for out-of-range msg code, got nil") 72 } 73 if err := SendItems(rw, 1, "foo", "bar"); err != nil { 74 t.Errorf("write error: %v", err) 75 } 76 return nil 77 }, 78 } 79 closer, rw, _, _ := testPeer([]Protocol{proto}) 80 defer closer() 81 82 if err := ExpectMsg(rw, 17, []string{"foo", "bar"}); err != nil { 83 t.Error(err) 84 } 85 } 86 87 func TestPeerPing(t *testing.T) { 88 closer, rw, _, _ := testPeer(nil) 89 defer closer() 90 if err := SendItems(rw, pingMsg); err != nil { 91 t.Fatal(err) 92 } 93 if err := ExpectMsg(rw, pongMsg, nil); err != nil { 94 t.Error(err) 95 } 96 } 97 98 func TestPeerDisconnect(t *testing.T) { 99 closer, rw, _, disc := testPeer(nil) 100 defer closer() 101 if err := SendItems(rw, discMsg, DiscQuitting); err != nil { 102 t.Fatal(err) 103 } 104 select { 105 case reason := <-disc: 106 if reason != DiscRequested { 107 t.Errorf("run returned wrong reason: got %v, want %v", reason, DiscRequested) 108 } 109 case <-time.After(500 * time.Millisecond): 110 t.Error("peer did not return") 111 } 112 } 113 114 // This test is supposed to verify that Peer can reliably handle 115 // multiple causes of disconnection occurring at the same time. 116 func TestPeerDisconnectRace(t *testing.T) { 117 maybe := func() bool { return rand.Intn(1) == 1 } 118 119 for i := 0; i < 1000; i++ { 120 protoclose := make(chan error) 121 protodisc := make(chan DiscReason) 122 closer, rw, p, disc := testPeer([]Protocol{ 123 { 124 Name: "closereq", 125 Run: func(p *Peer, rw MsgReadWriter) error { return <-protoclose }, 126 Length: 1, 127 }, 128 { 129 Name: "disconnect", 130 Run: func(p *Peer, rw MsgReadWriter) error { p.Disconnect(<-protodisc); return nil }, 131 Length: 1, 132 }, 133 }) 134 135 // Simulate incoming messages. 136 go SendItems(rw, baseProtocolLength+1) 137 go SendItems(rw, baseProtocolLength+2) 138 // Close the network connection. 139 go closer() 140 // Make protocol "closereq" return. 141 protoclose <- errors.New("protocol closed") 142 // Make protocol "disconnect" call peer.Disconnect 143 protodisc <- DiscAlreadyConnected 144 // In some cases, simulate something else calling peer.Disconnect. 145 if maybe() { 146 go p.Disconnect(DiscInvalidIdentity) 147 } 148 // In some cases, simulate remote requesting a disconnect. 149 if maybe() { 150 go SendItems(rw, discMsg, DiscQuitting) 151 } 152 153 select { 154 case <-disc: 155 case <-time.After(2 * time.Second): 156 // Peer.run should return quickly. If it doesn't the Peer 157 // goroutines are probably deadlocked. Call panic in order to 158 // show the stacks. 159 panic("Peer.run took to long to return.") 160 } 161 } 162 } 163 164 func TestNewPeer(t *testing.T) { 165 name := "nodename" 166 caps := []Cap{{"foo", 2}, {"bar", 3}} 167 id := randomID() 168 p := NewPeer(id, name, caps) 169 if p.ID() != id { 170 t.Errorf("ID mismatch: got %v, expected %v", p.ID(), id) 171 } 172 if p.Name() != name { 173 t.Errorf("Name mismatch: got %v, expected %v", p.Name(), name) 174 } 175 if !reflect.DeepEqual(p.Caps(), caps) { 176 t.Errorf("Caps mismatch: got %v, expected %v", p.Caps(), caps) 177 } 178 179 p.Disconnect(DiscAlreadyConnected) // Should not hang 180 } 181 182 func TestMatchProtocols(t *testing.T) { 183 tests := []struct { 184 Remote []Cap 185 Local []Protocol 186 Match map[string]protoRW 187 }{ 188 { 189 // No remote capabilities 190 Local: []Protocol{{Name: "a"}}, 191 }, 192 { 193 // No local protocols 194 Remote: []Cap{{Name: "a"}}, 195 }, 196 { 197 // No mutual protocols 198 Remote: []Cap{{Name: "a"}}, 199 Local: []Protocol{{Name: "b"}}, 200 }, 201 { 202 // Some matches, some differences 203 Remote: []Cap{{Name: "local"}, {Name: "match1"}, {Name: "match2"}}, 204 Local: []Protocol{{Name: "match1"}, {Name: "match2"}, {Name: "remote"}}, 205 Match: map[string]protoRW{"match1": {Protocol: Protocol{Name: "match1"}}, "match2": {Protocol: Protocol{Name: "match2"}}}, 206 }, 207 { 208 // Various alphabetical ordering 209 Remote: []Cap{{Name: "aa"}, {Name: "ab"}, {Name: "bb"}, {Name: "ba"}}, 210 Local: []Protocol{{Name: "ba"}, {Name: "bb"}, {Name: "ab"}, {Name: "aa"}}, 211 Match: map[string]protoRW{"aa": {Protocol: Protocol{Name: "aa"}}, "ab": {Protocol: Protocol{Name: "ab"}}, "ba": {Protocol: Protocol{Name: "ba"}}, "bb": {Protocol: Protocol{Name: "bb"}}}, 212 }, 213 { 214 // No mutual versions 215 Remote: []Cap{{Version: 1}}, 216 Local: []Protocol{{Version: 2}}, 217 }, 218 { 219 // Multiple versions, single common 220 Remote: []Cap{{Version: 1}, {Version: 2}}, 221 Local: []Protocol{{Version: 2}, {Version: 3}}, 222 Match: map[string]protoRW{"": {Protocol: Protocol{Version: 2}}}, 223 }, 224 { 225 // Multiple versions, multiple common 226 Remote: []Cap{{Version: 1}, {Version: 2}, {Version: 3}, {Version: 4}}, 227 Local: []Protocol{{Version: 2}, {Version: 3}}, 228 Match: map[string]protoRW{"": {Protocol: Protocol{Version: 3}}}, 229 }, 230 { 231 // Various version orderings 232 Remote: []Cap{{Version: 4}, {Version: 1}, {Version: 3}, {Version: 2}}, 233 Local: []Protocol{{Version: 2}, {Version: 3}, {Version: 1}}, 234 Match: map[string]protoRW{"": {Protocol: Protocol{Version: 3}}}, 235 }, 236 { 237 // Versions overriding sub-protocol lengths 238 Remote: []Cap{{Version: 1}, {Version: 2}, {Version: 3}, {Name: "a"}}, 239 Local: []Protocol{{Version: 1, Length: 1}, {Version: 2, Length: 2}, {Version: 3, Length: 3}, {Name: "a"}}, 240 Match: map[string]protoRW{"": {Protocol: Protocol{Version: 3}}, "a": {Protocol: Protocol{Name: "a"}, offset: 3}}, 241 }, 242 } 243 244 for i, tt := range tests { 245 result := matchProtocols(tt.Local, tt.Remote, nil) 246 if len(result) != len(tt.Match) { 247 t.Errorf("test %d: negotiation mismatch: have %v, want %v", i, len(result), len(tt.Match)) 248 continue 249 } 250 // Make sure all negotiated protocols are needed and correct 251 for name, proto := range result { 252 match, ok := tt.Match[name] 253 if !ok { 254 t.Errorf("test %d, proto '%s': negotiated but shouldn't have", i, name) 255 continue 256 } 257 if proto.Name != match.Name { 258 t.Errorf("test %d, proto '%s': name mismatch: have %v, want %v", i, name, proto.Name, match.Name) 259 } 260 if proto.Version != match.Version { 261 t.Errorf("test %d, proto '%s': version mismatch: have %v, want %v", i, name, proto.Version, match.Version) 262 } 263 if proto.offset-baseProtocolLength != match.offset { 264 t.Errorf("test %d, proto '%s': offset mismatch: have %v, want %v", i, name, proto.offset-baseProtocolLength, match.offset) 265 } 266 } 267 // Make sure no protocols missed negotiation 268 for name := range tt.Match { 269 if _, ok := result[name]; !ok { 270 t.Errorf("test %d, proto '%s': not negotiated, should have", i, name) 271 continue 272 } 273 } 274 } 275 }