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 pexEvent{pexAdd, addrs[0], pp.PexOutgoingConn},
46 require.EqualValues(t, targ, s)
48 t.Run("belowTarg", func(t *testing.T) {
51 pexEvent{pexDrop, addrs[1], 0},
55 s.Add(&PeerConn{peer: peer{RemoteAddr: addrs[0]}})
58 pexEvent{pexDrop, addrs[1], 0},
61 pexEvent{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 pexEvent{pexDrop, holdAddr, 0},
75 s.Add(&PeerConn{peer: peer{RemoteAddr: addrs[0]}})
79 pexEvent{pexDrop, holdAddr, 0},
80 pexEvent{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{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{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{pexEvent{pexDrop, addrs[0], 0}},
118 ev: []pexEvent{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 pexEvent{pexAdd, addrs[0], f},
153 pexEvent{pexAdd, addrs[1], f},
154 pexEvent{pexAdd, addrs[2], f},
155 pexEvent{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 pexEvent{pexDrop, addrs[0], f},
179 pexEvent{pexDrop, addrs[2], f},
183 Dropped: krpc.CompactIPv4NodeAddrs{
184 mustNodeAddr(addrs[2]),
186 Dropped6: krpc.CompactIPv6NodeAddrs{
187 mustNodeAddr(addrs[0]),
197 pexEvent{pexAdd, addrs[0], f},
198 pexEvent{pexAdd, addrs[1], f},
199 pexEvent{pexDrop, addrs[0], f},
203 Added6: krpc.CompactIPv6NodeAddrs{
204 mustNodeAddr(addrs[1]),
206 Added6Flags: []pp.PexPeerFlags{f},
215 pexEvent{pexAdd, addrs[0], f},
216 pexEvent{pexAdd, addrs[1], f},
217 pexEvent{pexAdd, addrs[2], f},
220 pexEvent{pexDrop, addrs[0], f},
221 pexEvent{pexDrop, addrs[2], f},
222 pexEvent{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 pexEvent{pexAdd, addrs[0], f},
244 pexEvent{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)
310 for i := 4747; i < 65535 && n > 0; i++ {
311 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 TestPexAdd(t *testing.T) {
339 t.Run("ipv4", func(t *testing.T) {
342 m.addEvent(pexEvent{pexDrop, addrs[0], 0})
343 m.addEvent(pexEvent{pexAdd, addrs[1], f})
344 for _, addr := range addrs {
345 m.addEvent(pexEvent{pexAdd, addr, f})
348 Added: krpc.CompactIPv4NodeAddrs{
349 mustNodeAddr(addrs[1]),
350 mustNodeAddr(addrs[2]),
351 mustNodeAddr(addrs[3]),
353 AddedFlags: []pp.PexPeerFlags{f, f, f},
356 assertPexMsgsEqual(t, targ, out)
358 t.Run("ipv6", func(t *testing.T) {
361 m.addEvent(pexEvent{pexDrop, addrs[0], 0})
362 m.addEvent(pexEvent{pexAdd, addrs[1], f})
363 for _, addr := range addrs {
364 m.addEvent(pexEvent{pexAdd, addr, f})
367 Added6: krpc.CompactIPv6NodeAddrs{
368 mustNodeAddr(addrs[1]),
369 mustNodeAddr(addrs[2]),
370 mustNodeAddr(addrs[3]),
372 Added6Flags: []pp.PexPeerFlags{f, f, f},
374 assertPexMsgsEqual(t, targ, m.PexMsg())
376 t.Run("empty", func(t *testing.T) {
377 nullAddr := &net.TCPAddr{}
379 xm.addEvent(pexEvent{pexAdd, nullAddr, f})
381 require.EqualValues(t, 0, len(m.Added))
382 require.EqualValues(t, 0, len(m.AddedFlags))
383 require.EqualValues(t, 0, len(m.Added6))
384 require.EqualValues(t, 0, len(m.Added6Flags))
388 func TestPexDrop(t *testing.T) {
389 t.Run("ipv4", func(t *testing.T) {
392 m.addEvent(pexEvent{pexAdd, addrs[0], f})
393 m.addEvent(pexEvent{pexDrop, addrs[1], 0})
394 for _, addr := range addrs {
395 m.addEvent(pexEvent{pexDrop, addr, 0})
398 Dropped: krpc.CompactIPv4NodeAddrs{
399 mustNodeAddr(addrs[1]),
400 mustNodeAddr(addrs[2]),
401 mustNodeAddr(addrs[3]),
404 assertPexMsgsEqual(t, targ, m.PexMsg())
406 t.Run("ipv6", func(t *testing.T) {
409 m.addEvent(pexEvent{pexAdd, addrs[0], f})
410 m.addEvent(pexEvent{pexDrop, addrs[1], 0})
411 for _, addr := range addrs {
412 m.addEvent(pexEvent{pexDrop, addr, 0})
415 Dropped6: krpc.CompactIPv6NodeAddrs{
416 mustNodeAddr(addrs[1]),
417 mustNodeAddr(addrs[2]),
418 mustNodeAddr(addrs[3]),
421 assertPexMsgsEqual(t, targ, m.PexMsg())
423 t.Run("empty", func(t *testing.T) {
424 nullAddr := &net.TCPAddr{}
426 xm.addEvent(pexEvent{pexDrop, nullAddr, f})
428 require.EqualValues(t, 0, len(m.Dropped))
429 require.EqualValues(t, 0, len(m.Dropped6))