7 "github.com/stretchr/testify/assert"
8 "github.com/stretchr/testify/require"
10 "github.com/anacrolix/dht/v2/krpc"
11 pp "github.com/anacrolix/torrent/peer_protocol"
16 &net.TCPAddr{IP: net.IPv6loopback, Port: 4747},
17 &net.TCPAddr{IP: net.IPv6loopback, Port: 4748},
18 &net.TCPAddr{IP: net.IPv6loopback, Port: 4749},
19 &net.TCPAddr{IP: net.IPv6loopback, Port: 4750},
22 &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 4747},
23 &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 4748},
24 &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 4749},
25 &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 4750},
33 f = pp.PexOutgoingConn
36 func TestPexAdded(t *testing.T) {
37 t.Run("noHold", func(t *testing.T) {
39 s.Add(&PeerConn{Peer: Peer{RemoteAddr: addrs[0], outgoing: true}})
42 {pexAdd, addrs[0], pp.PexOutgoingConn},
46 require.EqualValues(t, targ, s)
48 t.Run("belowTarg", func(t *testing.T) {
51 {pexDrop, addrs[1], 0},
55 s.Add(&PeerConn{Peer: Peer{RemoteAddr: addrs[0]}})
58 {pexDrop, addrs[1], 0},
61 {pexAdd, addrs[0], 0},
65 require.EqualValues(t, targ, s)
67 t.Run("aboveTarg", func(t *testing.T) {
68 holdAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 4848}
71 {pexDrop, holdAddr, 0},
75 s.Add(&PeerConn{Peer: Peer{RemoteAddr: addrs[0]}})
79 {pexDrop, holdAddr, 0},
80 {pexAdd, addrs[0], 0},
84 require.EqualValues(t, targ, s)
88 func TestPexDropped(t *testing.T) {
89 t.Run("belowTarg", func(t *testing.T) {
91 s.Drop(&PeerConn{Peer: Peer{RemoteAddr: addrs[0]}, pex: pexConnState{Listed: true}})
93 hold: []pexEvent{{pexDrop, addrs[0], 0}},
96 require.EqualValues(t, targ, s)
98 t.Run("aboveTarg", func(t *testing.T) {
99 s := &pexState{nc: pexTargAdded + 1}
100 s.Drop(&PeerConn{Peer: Peer{RemoteAddr: addrs[0]}, pex: pexConnState{Listed: true}})
102 ev: []pexEvent{{pexDrop, addrs[0], 0}},
105 require.EqualValues(t, targ, s)
107 t.Run("aboveTargNotListed", func(t *testing.T) {
108 s := &pexState{nc: pexTargAdded + 1}
109 s.Drop(&PeerConn{Peer: Peer{RemoteAddr: addrs[0]}, pex: pexConnState{Listed: false}})
110 targ := &pexState{nc: pexTargAdded + 1}
111 require.EqualValues(t, targ, s)
115 func TestPexReset(t *testing.T) {
117 hold: []pexEvent{{pexDrop, addrs[0], 0}},
118 ev: []pexEvent{{pexAdd, addrs[1], 0}},
122 targ := new(pexState)
123 require.EqualValues(t, targ, s)
126 func mustNodeAddr(addr net.Addr) krpc.NodeAddr {
127 ret, ok := nodeAddr(addr)
134 var testcases = []struct {
152 {pexAdd, addrs[0], f},
153 {pexAdd, addrs[1], f},
154 {pexAdd, addrs[2], f},
155 {pexAdd, addrs[3], f},
160 Added: krpc.CompactIPv4NodeAddrs{
161 mustNodeAddr(addrs[2]),
162 mustNodeAddr(addrs[3]),
164 AddedFlags: []pp.PexPeerFlags{f, f},
165 Added6: krpc.CompactIPv6NodeAddrs{
166 mustNodeAddr(addrs[0]),
167 mustNodeAddr(addrs[1]),
169 Added6Flags: []pp.PexPeerFlags{f, f},
178 {pexDrop, addrs[0], f},
179 {pexDrop, addrs[2], f},
183 Dropped: krpc.CompactIPv4NodeAddrs{
184 mustNodeAddr(addrs[2]),
186 Dropped6: krpc.CompactIPv6NodeAddrs{
187 mustNodeAddr(addrs[0]),
197 {pexAdd, addrs[0], f},
198 {pexAdd, addrs[1], f},
199 {pexDrop, addrs[0], f},
203 Added6: krpc.CompactIPv6NodeAddrs{
204 mustNodeAddr(addrs[1]),
206 Added6Flags: []pp.PexPeerFlags{f},
215 {pexAdd, addrs[0], f},
216 {pexAdd, addrs[1], f},
217 {pexAdd, addrs[2], f},
220 {pexDrop, addrs[0], f},
221 {pexDrop, addrs[2], f},
222 {pexDrop, addrs[1], f},
226 Added: krpc.CompactIPv4NodeAddrs{
227 mustNodeAddr(addrs[2]),
229 AddedFlags: []pp.PexPeerFlags{f},
230 Added6: krpc.CompactIPv6NodeAddrs{
231 mustNodeAddr(addrs[0]),
232 mustNodeAddr(addrs[1]),
234 Added6Flags: []pp.PexPeerFlags{f, f},
243 {pexAdd, addrs[0], f},
244 {pexAdd, addrs[1], f},
248 Added6: krpc.CompactIPv6NodeAddrs{
249 mustNodeAddr(addrs[1]),
251 Added6Flags: []pp.PexPeerFlags{f},
257 // Represents the contents of a PexMsg in a way that supports equivalence checking in tests. This is
258 // necessary because pexMsgFactory uses maps and so ordering of the resultant PexMsg isn't
259 // deterministic. Because the flags are in a different array, we can't just use testify's
260 // ElementsMatch because the ordering *does* still matter between an added addr and its flags.
261 type comparablePexMsg struct {
262 added, added6 []krpc.NodeAddr
263 addedFlags, added6Flags []pp.PexPeerFlags
264 dropped, dropped6 []krpc.NodeAddr
267 // Such Rust-inspired.
268 func (me *comparablePexMsg) From(f pp.PexMsg) {
270 me.addedFlags = f.AddedFlags
272 me.added6Flags = f.Added6Flags
273 me.dropped = f.Dropped
274 me.dropped6 = f.Dropped6
277 // For PexMsg created by pexMsgFactory, this is as good as it can get without using data structures
278 // in pexMsgFactory that preserve insert ordering.
279 func (actual comparablePexMsg) AssertEqual(t *testing.T, expected comparablePexMsg) {
280 assert.ElementsMatch(t, expected.added, actual.added)
281 assert.ElementsMatch(t, expected.addedFlags, actual.addedFlags)
282 assert.ElementsMatch(t, expected.added6, actual.added6)
283 assert.ElementsMatch(t, expected.added6Flags, actual.added6Flags)
284 assert.ElementsMatch(t, expected.dropped, actual.dropped)
285 assert.ElementsMatch(t, expected.dropped6, actual.dropped6)
288 func assertPexMsgsEqual(t *testing.T, expected, actual pp.PexMsg) {
289 var ec, ac comparablePexMsg
292 ac.AssertEqual(t, ec)
295 func TestPexGenmsg(t *testing.T) {
296 for _, tc := range testcases {
297 t.Run(tc.name, func(t *testing.T) {
299 m, seen := s.Genmsg(tc.arg)
300 assertPexMsgsEqual(t, tc.targM, m)
301 require.EqualValues(t, tc.targS, seen)
306 // generate 𝑛 distinct values of net.Addr
307 func addrgen(n int) chan net.Addr {
308 c := make(chan net.Addr)
311 for i := 4747; i < 65535 && n > 0; i++ {
312 c <- &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: i}
319 func TestPexInitialNoCutoff(t *testing.T) {
320 const n = 2 * pexMaxDelta
324 for addr := range c {
325 s.Add(&PeerConn{Peer: Peer{RemoteAddr: addr}})
327 m, seq := s.Genmsg(0)
329 require.EqualValues(t, n, seq)
330 require.EqualValues(t, n, len(m.Added))
331 require.EqualValues(t, n, len(m.AddedFlags))
332 require.EqualValues(t, 0, len(m.Added6))
333 require.EqualValues(t, 0, len(m.Added6Flags))
334 require.EqualValues(t, 0, len(m.Dropped))
335 require.EqualValues(t, 0, len(m.Dropped6))
338 func benchmarkPexInitialN(b *testing.B, npeers int) {
339 for i := 0; i < b.N; i++ {
342 for addr := range c {
343 s.Add(&PeerConn{Peer: Peer{RemoteAddr: addr}})
349 // obtain at least 5 points, e.g. to plot a graph
350 func BenchmarkPexInitial4(b *testing.B) { benchmarkPexInitialN(b, 4) }
351 func BenchmarkPexInitial50(b *testing.B) { benchmarkPexInitialN(b, 50) }
352 func BenchmarkPexInitial100(b *testing.B) { benchmarkPexInitialN(b, 100) }
353 func BenchmarkPexInitial200(b *testing.B) { benchmarkPexInitialN(b, 200) }
354 func BenchmarkPexInitial400(b *testing.B) { benchmarkPexInitialN(b, 400) }
356 func TestPexAdd(t *testing.T) {
357 t.Run("ipv4", func(t *testing.T) {
360 m.addEvent(pexEvent{pexDrop, addrs[0], 0})
361 m.addEvent(pexEvent{pexAdd, addrs[1], f})
362 for _, addr := range addrs {
363 m.addEvent(pexEvent{pexAdd, addr, f})
366 Added: krpc.CompactIPv4NodeAddrs{
367 mustNodeAddr(addrs[1]),
368 mustNodeAddr(addrs[2]),
369 mustNodeAddr(addrs[3]),
371 AddedFlags: []pp.PexPeerFlags{f, f, f},
374 assertPexMsgsEqual(t, targ, out)
376 t.Run("ipv6", func(t *testing.T) {
379 m.addEvent(pexEvent{pexDrop, addrs[0], 0})
380 m.addEvent(pexEvent{pexAdd, addrs[1], f})
381 for _, addr := range addrs {
382 m.addEvent(pexEvent{pexAdd, addr, f})
385 Added6: krpc.CompactIPv6NodeAddrs{
386 mustNodeAddr(addrs[1]),
387 mustNodeAddr(addrs[2]),
388 mustNodeAddr(addrs[3]),
390 Added6Flags: []pp.PexPeerFlags{f, f, f},
392 assertPexMsgsEqual(t, targ, m.PexMsg())
394 t.Run("empty", func(t *testing.T) {
395 nullAddr := &net.TCPAddr{}
397 xm.addEvent(pexEvent{pexAdd, nullAddr, f})
399 require.EqualValues(t, 0, len(m.Added))
400 require.EqualValues(t, 0, len(m.AddedFlags))
401 require.EqualValues(t, 0, len(m.Added6))
402 require.EqualValues(t, 0, len(m.Added6Flags))
406 func TestPexDrop(t *testing.T) {
407 t.Run("ipv4", func(t *testing.T) {
410 m.addEvent(pexEvent{pexAdd, addrs[0], f})
411 m.addEvent(pexEvent{pexDrop, addrs[1], 0})
412 for _, addr := range addrs {
413 m.addEvent(pexEvent{pexDrop, addr, 0})
416 Dropped: krpc.CompactIPv4NodeAddrs{
417 mustNodeAddr(addrs[1]),
418 mustNodeAddr(addrs[2]),
419 mustNodeAddr(addrs[3]),
422 assertPexMsgsEqual(t, targ, m.PexMsg())
424 t.Run("ipv6", func(t *testing.T) {
427 m.addEvent(pexEvent{pexAdd, addrs[0], f})
428 m.addEvent(pexEvent{pexDrop, addrs[1], 0})
429 for _, addr := range addrs {
430 m.addEvent(pexEvent{pexDrop, addr, 0})
433 Dropped6: krpc.CompactIPv6NodeAddrs{
434 mustNodeAddr(addrs[1]),
435 mustNodeAddr(addrs[2]),
436 mustNodeAddr(addrs[3]),
439 assertPexMsgsEqual(t, targ, m.PexMsg())
441 t.Run("empty", func(t *testing.T) {
442 nullAddr := &net.TCPAddr{}
444 xm.addEvent(pexEvent{pexDrop, nullAddr, f})
446 require.EqualValues(t, 0, len(m.Dropped))
447 require.EqualValues(t, 0, len(m.Dropped6))