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.IPv4(127, 0, 0, 1), Port: 4747},
19 &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 4748},
21 f = pp.PexOutgoingConn
24 func TestPexAdded(t *testing.T) {
25 t.Run("noHold", func(t *testing.T) {
27 s.Add(&PeerConn{peer: peer{RemoteAddr: addrs[0], outgoing: true}})
30 pexEvent{pexAdd, addrs[0], pp.PexOutgoingConn},
34 require.EqualValues(t, targ, s)
36 t.Run("belowTarg", func(t *testing.T) {
39 pexEvent{pexDrop, addrs[1], 0},
43 s.Add(&PeerConn{peer: peer{RemoteAddr: addrs[0]}})
46 pexEvent{pexDrop, addrs[1], 0},
49 pexEvent{pexAdd, addrs[0], 0},
53 require.EqualValues(t, targ, s)
55 t.Run("aboveTarg", func(t *testing.T) {
56 holdAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 4848}
59 pexEvent{pexDrop, holdAddr, 0},
63 s.Add(&PeerConn{peer: peer{RemoteAddr: addrs[0]}})
67 pexEvent{pexDrop, holdAddr, 0},
68 pexEvent{pexAdd, addrs[0], 0},
72 require.EqualValues(t, targ, s)
76 func TestPexDropped(t *testing.T) {
77 t.Run("belowTarg", func(t *testing.T) {
79 s.Drop(&PeerConn{peer: peer{RemoteAddr: addrs[0]}, pex: pexConnState{Listed: true}})
81 hold: []pexEvent{pexEvent{pexDrop, addrs[0], 0}},
84 require.EqualValues(t, targ, s)
86 t.Run("aboveTarg", func(t *testing.T) {
87 s := &pexState{nc: pexTargAdded + 1}
88 s.Drop(&PeerConn{peer: peer{RemoteAddr: addrs[0]}, pex: pexConnState{Listed: true}})
90 ev: []pexEvent{pexEvent{pexDrop, addrs[0], 0}},
93 require.EqualValues(t, targ, s)
95 t.Run("aboveTargNotListed", func(t *testing.T) {
96 s := &pexState{nc: pexTargAdded + 1}
97 s.Drop(&PeerConn{peer: peer{RemoteAddr: addrs[0]}, pex: pexConnState{Listed: false}})
98 targ := &pexState{nc: pexTargAdded + 1}
99 require.EqualValues(t, targ, s)
103 func TestPexReset(t *testing.T) {
105 hold: []pexEvent{pexEvent{pexDrop, addrs[0], 0}},
106 ev: []pexEvent{pexEvent{pexAdd, addrs[1], 0}},
110 targ := new(pexState)
111 require.EqualValues(t, targ, s)
114 var testcases = []struct {
132 pexEvent{pexAdd, addrs[0], f},
133 pexEvent{pexAdd, addrs[1], f},
134 pexEvent{pexAdd, addrs[2], f},
135 pexEvent{pexAdd, addrs[3], f},
140 Added: krpc.CompactIPv4NodeAddrs{
141 mustNodeAddr(addrs[2]),
142 mustNodeAddr(addrs[3]),
144 AddedFlags: []pp.PexPeerFlags{f, f},
145 Added6: krpc.CompactIPv6NodeAddrs{
146 mustNodeAddr(addrs[0]),
147 mustNodeAddr(addrs[1]),
149 Added6Flags: []pp.PexPeerFlags{f, f},
158 pexEvent{pexDrop, addrs[0], f},
159 pexEvent{pexDrop, addrs[2], f},
163 Dropped: krpc.CompactIPv4NodeAddrs{
164 mustNodeAddr(addrs[2]),
166 Dropped6: krpc.CompactIPv6NodeAddrs{
167 mustNodeAddr(addrs[0]),
177 pexEvent{pexAdd, addrs[0], f},
178 pexEvent{pexAdd, addrs[1], f},
179 pexEvent{pexDrop, addrs[0], f},
183 Added6: krpc.CompactIPv6NodeAddrs{
184 mustNodeAddr(addrs[1]),
186 Added6Flags: []pp.PexPeerFlags{f},
195 pexEvent{pexAdd, addrs[0], f},
196 pexEvent{pexAdd, addrs[1], f},
197 pexEvent{pexAdd, addrs[2], f},
200 pexEvent{pexDrop, addrs[0], f},
201 pexEvent{pexDrop, addrs[2], f},
202 pexEvent{pexDrop, addrs[1], f},
206 Added: krpc.CompactIPv4NodeAddrs{
207 mustNodeAddr(addrs[2]),
209 AddedFlags: []pp.PexPeerFlags{f},
210 Added6: krpc.CompactIPv6NodeAddrs{
211 mustNodeAddr(addrs[0]),
212 mustNodeAddr(addrs[1]),
214 Added6Flags: []pp.PexPeerFlags{f, f},
223 pexEvent{pexAdd, addrs[0], f},
224 pexEvent{pexAdd, addrs[1], f},
228 Added6: krpc.CompactIPv6NodeAddrs{
229 mustNodeAddr(addrs[1]),
231 Added6Flags: []pp.PexPeerFlags{f},
237 // Represents the contents of a PexMsg in a way that supports equivalence checking in tests. This is
238 // necessary because pexMsgFactory uses maps and so ordering of the resultant PexMsg isn't
239 // deterministic. Because the flags are in a different array, we can't just use testify's
240 // ElementsMatch because the ordering *does* still matter between an added addr and its flags.
241 type comparablePexMsg struct {
242 added, added6 []pexMsgAdded
243 dropped, dropped6 []krpc.NodeAddr
246 func (me *comparablePexMsg) makeAdded(addrs []krpc.NodeAddr, flags []pp.PexPeerFlags) (ret []pexMsgAdded) {
247 for i, addr := range addrs {
248 ret = append(ret, pexMsgAdded{
250 PexPeerFlags: flags[i],
256 // Such Rust-inspired.
257 func (me *comparablePexMsg) From(f pp.PexMsg) {
258 me.added = me.makeAdded(f.Added, f.AddedFlags)
259 me.added6 = me.makeAdded(f.Added6, f.Added6Flags)
260 me.dropped = f.Dropped
261 me.dropped6 = f.Dropped6
264 // For PexMsg created by pexMsgFactory, this is as good as it can get without using data structures
265 // in pexMsgFactory that preserve insert ordering.
266 func (actual comparablePexMsg) AssertEqual(t *testing.T, expected comparablePexMsg) {
267 assert.ElementsMatch(t, expected.added, actual.added)
268 assert.ElementsMatch(t, expected.added6, actual.added6)
269 assert.ElementsMatch(t, expected.dropped, actual.dropped)
270 assert.ElementsMatch(t, expected.dropped6, actual.dropped6)
273 func assertPexMsgsEqual(t *testing.T, expected, actual pp.PexMsg) {
274 var ec, ac comparablePexMsg
277 ac.AssertEqual(t, ec)
280 func TestPexGenmsg(t *testing.T) {
281 for _, tc := range testcases {
282 t.Run(tc.name, func(t *testing.T) {
284 m, seen := s.Genmsg(tc.arg)
285 assertPexMsgsEqual(t, tc.targM, m)
286 require.EqualValues(t, tc.targS, seen)
291 // generate 𝑛 distinct values of net.Addr
292 func addrgen(n int) chan net.Addr {
293 c := make(chan net.Addr)
295 for i := 4747; i < 65535 && n > 0; i++ {
296 c <- &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: i}
304 func TestPexInitialNoCutoff(t *testing.T) {
305 const n = 2 * pexMaxDelta
309 for addr := range c {
310 s.Add(&PeerConn{peer: peer{RemoteAddr: addr}})
312 m, seq := s.Genmsg(0)
314 require.EqualValues(t, n, seq)
315 require.EqualValues(t, n, len(m.Added))
316 require.EqualValues(t, n, len(m.AddedFlags))
317 require.EqualValues(t, 0, len(m.Added6))
318 require.EqualValues(t, 0, len(m.Added6Flags))
319 require.EqualValues(t, 0, len(m.Dropped))
320 require.EqualValues(t, 0, len(m.Dropped6))
323 func TestPexAdd(t *testing.T) {
324 addrs4 := []krpc.NodeAddr{
325 krpc.NodeAddr{IP: net.IPv4(127, 0, 0, 1), Port: 4747}, // 0
326 krpc.NodeAddr{IP: net.IPv4(127, 0, 0, 1), Port: 4748}, // 1
327 krpc.NodeAddr{IP: net.IPv4(127, 0, 0, 2), Port: 4747}, // 2
328 krpc.NodeAddr{IP: net.IPv4(127, 0, 0, 2), Port: 4748}, // 3
330 addrs6 := []krpc.NodeAddr{
331 krpc.NodeAddr{IP: net.IPv6loopback, Port: 4747}, // 0
332 krpc.NodeAddr{IP: net.IPv6loopback, Port: 4748}, // 1
333 krpc.NodeAddr{IP: net.IPv6loopback, Port: 4749}, // 2
334 krpc.NodeAddr{IP: net.IPv6loopback, Port: 4750}, // 3
336 f := pp.PexPrefersEncryption | pp.PexOutgoingConn
338 t.Run("ipv4", func(t *testing.T) {
343 for _, addr := range addrs {
347 Added: krpc.CompactIPv4NodeAddrs{
352 AddedFlags: []pp.PexPeerFlags{f, f, f},
354 assertPexMsgsEqual(t, targ, m.PexMsg())
356 t.Run("ipv6", func(t *testing.T) {
361 for _, addr := range addrs {
365 Added6: krpc.CompactIPv6NodeAddrs{
370 Added6Flags: []pp.PexPeerFlags{f, f, f},
372 assertPexMsgsEqual(t, targ, m.PexMsg())
374 t.Run("empty", func(t *testing.T) {
375 addr := krpc.NodeAddr{}
377 assert.Panics(t, func() { xm.Add(addr, f) })
379 require.EqualValues(t, 0, len(m.Added))
380 require.EqualValues(t, 0, len(m.AddedFlags))
381 require.EqualValues(t, 0, len(m.Added6))
382 require.EqualValues(t, 0, len(m.Added6Flags))
386 func TestPexDrop(t *testing.T) {
387 addrs4 := []krpc.NodeAddr{
388 krpc.NodeAddr{IP: net.IPv4(127, 0, 0, 1), Port: 4747}, // 0
389 krpc.NodeAddr{IP: net.IPv4(127, 0, 0, 1), Port: 4748}, // 1
390 krpc.NodeAddr{IP: net.IPv4(127, 0, 0, 2), Port: 4747}, // 2
391 krpc.NodeAddr{IP: net.IPv4(127, 0, 0, 2), Port: 4748}, // 3
393 addrs6 := []krpc.NodeAddr{
394 krpc.NodeAddr{IP: net.IPv6loopback, Port: 4747}, // 0
395 krpc.NodeAddr{IP: net.IPv6loopback, Port: 4748}, // 1
396 krpc.NodeAddr{IP: net.IPv6loopback, Port: 4749}, // 2
397 krpc.NodeAddr{IP: net.IPv6loopback, Port: 4750}, // 3
399 f := pp.PexPrefersEncryption | pp.PexOutgoingConn
401 t.Run("ipv4", func(t *testing.T) {
406 for _, addr := range addrs {
410 Dropped: krpc.CompactIPv4NodeAddrs{
416 assertPexMsgsEqual(t, targ, m.PexMsg())
418 t.Run("ipv6", func(t *testing.T) {
423 for _, addr := range addrs {
427 Dropped6: krpc.CompactIPv6NodeAddrs{
433 assertPexMsgsEqual(t, targ, m.PexMsg())
435 t.Run("empty", func(t *testing.T) {
436 addr := krpc.NodeAddr{}
438 require.Panics(t, func() { xm.Drop(addr) })
440 require.EqualValues(t, 0, len(m.Dropped))
441 require.EqualValues(t, 0, len(m.Dropped6))