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 func TestPexAdd(t *testing.T) {
292 addrs4 := []krpc.NodeAddr{
293 krpc.NodeAddr{IP: net.IPv4(127, 0, 0, 1), Port: 4747}, // 0
294 krpc.NodeAddr{IP: net.IPv4(127, 0, 0, 1), Port: 4748}, // 1
295 krpc.NodeAddr{IP: net.IPv4(127, 0, 0, 2), Port: 4747}, // 2
296 krpc.NodeAddr{IP: net.IPv4(127, 0, 0, 2), Port: 4748}, // 3
298 addrs6 := []krpc.NodeAddr{
299 krpc.NodeAddr{IP: net.IPv6loopback, Port: 4747}, // 0
300 krpc.NodeAddr{IP: net.IPv6loopback, Port: 4748}, // 1
301 krpc.NodeAddr{IP: net.IPv6loopback, Port: 4749}, // 2
302 krpc.NodeAddr{IP: net.IPv6loopback, Port: 4750}, // 3
304 f := pp.PexPrefersEncryption | pp.PexOutgoingConn
306 t.Run("ipv4", func(t *testing.T) {
311 for _, addr := range addrs {
315 Added: krpc.CompactIPv4NodeAddrs{
320 AddedFlags: []pp.PexPeerFlags{f, f, f},
322 assertPexMsgsEqual(t, targ, m.PexMsg())
324 t.Run("ipv6", func(t *testing.T) {
329 for _, addr := range addrs {
333 Added6: krpc.CompactIPv6NodeAddrs{
338 Added6Flags: []pp.PexPeerFlags{f, f, f},
340 assertPexMsgsEqual(t, targ, m.PexMsg())
342 t.Run("empty", func(t *testing.T) {
343 addr := krpc.NodeAddr{}
345 assert.Panics(t, func() { xm.Add(addr, f) })
347 require.EqualValues(t, 0, len(m.Added))
348 require.EqualValues(t, 0, len(m.AddedFlags))
349 require.EqualValues(t, 0, len(m.Added6))
350 require.EqualValues(t, 0, len(m.Added6Flags))
354 func TestPexDrop(t *testing.T) {
355 addrs4 := []krpc.NodeAddr{
356 krpc.NodeAddr{IP: net.IPv4(127, 0, 0, 1), Port: 4747}, // 0
357 krpc.NodeAddr{IP: net.IPv4(127, 0, 0, 1), Port: 4748}, // 1
358 krpc.NodeAddr{IP: net.IPv4(127, 0, 0, 2), Port: 4747}, // 2
359 krpc.NodeAddr{IP: net.IPv4(127, 0, 0, 2), Port: 4748}, // 3
361 addrs6 := []krpc.NodeAddr{
362 krpc.NodeAddr{IP: net.IPv6loopback, Port: 4747}, // 0
363 krpc.NodeAddr{IP: net.IPv6loopback, Port: 4748}, // 1
364 krpc.NodeAddr{IP: net.IPv6loopback, Port: 4749}, // 2
365 krpc.NodeAddr{IP: net.IPv6loopback, Port: 4750}, // 3
367 f := pp.PexPrefersEncryption | pp.PexOutgoingConn
369 t.Run("ipv4", func(t *testing.T) {
374 for _, addr := range addrs {
378 Dropped: krpc.CompactIPv4NodeAddrs{
384 assertPexMsgsEqual(t, targ, m.PexMsg())
386 t.Run("ipv6", func(t *testing.T) {
391 for _, addr := range addrs {
395 Dropped6: krpc.CompactIPv6NodeAddrs{
401 assertPexMsgsEqual(t, targ, m.PexMsg())
403 t.Run("empty", func(t *testing.T) {
404 addr := krpc.NodeAddr{}
406 require.Panics(t, func() { xm.Drop(addr) })
408 require.EqualValues(t, 0, len(m.Dropped))
409 require.EqualValues(t, 0, len(m.Dropped6))