"net"
"testing"
+ "github.com/anacrolix/dht/v2/krpc"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "github.com/anacrolix/dht/v2/krpc"
pp "github.com/anacrolix/torrent/peer_protocol"
)
addrs4[0],
addrs4[1],
}
- f = pp.PexOutgoingConn
)
-func TestPexAdded(t *testing.T) {
- t.Run("noHold", func(t *testing.T) {
- s := new(pexState)
- s.Add(&PeerConn{peer: peer{RemoteAddr: addrs[0], outgoing: true}})
- targ := &pexState{
- ev: []pexEvent{
- pexEvent{pexAdd, addrs[0], pp.PexOutgoingConn},
- },
- nc: 1,
- }
- require.EqualValues(t, targ, s)
- })
- t.Run("belowTarg", func(t *testing.T) {
- s := &pexState{
- hold: []pexEvent{
- pexEvent{pexDrop, addrs[1], 0},
- },
- nc: 0,
- }
- s.Add(&PeerConn{peer: peer{RemoteAddr: addrs[0]}})
- targ := &pexState{
- hold: []pexEvent{
- pexEvent{pexDrop, addrs[1], 0},
- },
- ev: []pexEvent{
- pexEvent{pexAdd, addrs[0], 0},
- },
- nc: 1,
- }
- require.EqualValues(t, targ, s)
- })
- t.Run("aboveTarg", func(t *testing.T) {
- holdAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 4848}
- s := &pexState{
- hold: []pexEvent{
- pexEvent{pexDrop, holdAddr, 0},
- },
- nc: pexTargAdded,
- }
- s.Add(&PeerConn{peer: peer{RemoteAddr: addrs[0]}})
- targ := &pexState{
- hold: []pexEvent{},
- ev: []pexEvent{
- pexEvent{pexDrop, holdAddr, 0},
- pexEvent{pexAdd, addrs[0], 0},
- },
- nc: pexTargAdded + 1,
- }
- require.EqualValues(t, targ, s)
- })
-}
-
-func TestPexDropped(t *testing.T) {
- t.Run("belowTarg", func(t *testing.T) {
- s := &pexState{nc: 1}
- s.Drop(&PeerConn{peer: peer{RemoteAddr: addrs[0]}, pex: pexConnState{Listed: true}})
- targ := &pexState{
- hold: []pexEvent{pexEvent{pexDrop, addrs[0], 0}},
- nc: 0,
- }
- require.EqualValues(t, targ, s)
- })
- t.Run("aboveTarg", func(t *testing.T) {
- s := &pexState{nc: pexTargAdded + 1}
- s.Drop(&PeerConn{peer: peer{RemoteAddr: addrs[0]}, pex: pexConnState{Listed: true}})
- targ := &pexState{
- ev: []pexEvent{pexEvent{pexDrop, addrs[0], 0}},
- nc: pexTargAdded,
- }
- require.EqualValues(t, targ, s)
- })
- t.Run("aboveTargNotListed", func(t *testing.T) {
- s := &pexState{nc: pexTargAdded + 1}
- s.Drop(&PeerConn{peer: peer{RemoteAddr: addrs[0]}, pex: pexConnState{Listed: false}})
- targ := &pexState{nc: pexTargAdded + 1}
- require.EqualValues(t, targ, s)
- })
-}
-
func TestPexReset(t *testing.T) {
- s := &pexState{
- hold: []pexEvent{pexEvent{pexDrop, addrs[0], 0}},
- ev: []pexEvent{pexEvent{pexAdd, addrs[1], 0}},
- nc: 1,
+ s := &pexState{}
+ conns := []PeerConn{
+ {Peer: Peer{RemoteAddr: addrs[0]}},
+ {Peer: Peer{RemoteAddr: addrs[1]}},
+ {Peer: Peer{RemoteAddr: addrs[2]}},
}
+ s.Add(&conns[0])
+ s.Add(&conns[1])
+ s.Drop(&conns[0])
s.Reset()
targ := new(pexState)
require.EqualValues(t, targ, s)
}
-func mustNodeAddr(addr net.Addr) krpc.NodeAddr {
- ret, ok := nodeAddr(addr)
- if !ok {
- panic(addr)
+func krpcNodeAddrFromNetAddr(addr net.Addr) krpc.NodeAddr {
+ addrPort, err := addrPortFromPeerRemoteAddr(addr)
+ if err != nil {
+ panic(err)
}
- return ret
+ return krpcNodeAddrFromAddrPort(addrPort)
}
var testcases = []struct {
- name string
- in *pexState
- arg int
- targM pp.PexMsg
- targS int
+ name string
+ in *pexState
+ targ pp.PexMsg
+ update func(*pexState)
+ targ1 pp.PexMsg
}{
{
- name: "empty",
- in: &pexState{},
- arg: 0,
- targM: pp.PexMsg{},
- targS: 0,
+ name: "empty",
+ in: &pexState{},
+ targ: pp.PexMsg{},
+ },
+ {
+ name: "add0",
+ in: func() *pexState {
+ s := new(pexState)
+ nullAddr := &net.TCPAddr{}
+ s.Add(&PeerConn{Peer: Peer{RemoteAddr: nullAddr}})
+ return s
+ }(),
+ targ: pp.PexMsg{},
+ },
+ {
+ name: "drop0",
+ in: func() *pexState {
+ nullAddr := &net.TCPAddr{}
+ s := new(pexState)
+ s.Drop(&PeerConn{Peer: Peer{RemoteAddr: nullAddr}, pex: pexConnState{Listed: true}})
+ return s
+ }(),
+ targ: pp.PexMsg{},
},
{
name: "add4",
- in: &pexState{
- ev: []pexEvent{
- pexEvent{pexAdd, addrs[0], f},
- pexEvent{pexAdd, addrs[1], f},
- pexEvent{pexAdd, addrs[2], f},
- pexEvent{pexAdd, addrs[3], f},
- },
- },
- arg: 0,
- targM: pp.PexMsg{
+ in: func() *pexState {
+ s := new(pexState)
+ s.Add(&PeerConn{Peer: Peer{RemoteAddr: addrs[0]}})
+ s.Add(&PeerConn{Peer: Peer{RemoteAddr: addrs[1], outgoing: true}})
+ s.Add(&PeerConn{Peer: Peer{RemoteAddr: addrs[2], outgoing: true}})
+ s.Add(&PeerConn{Peer: Peer{RemoteAddr: addrs[3]}})
+ return s
+ }(),
+ targ: pp.PexMsg{
Added: krpc.CompactIPv4NodeAddrs{
- mustNodeAddr(addrs[2]),
- mustNodeAddr(addrs[3]),
+ krpcNodeAddrFromNetAddr(addrs[2]),
+ krpcNodeAddrFromNetAddr(addrs[3]),
},
- AddedFlags: []pp.PexPeerFlags{f, f},
+ AddedFlags: []pp.PexPeerFlags{pp.PexOutgoingConn, 0},
Added6: krpc.CompactIPv6NodeAddrs{
- mustNodeAddr(addrs[0]),
- mustNodeAddr(addrs[1]),
+ krpcNodeAddrFromNetAddr(addrs[0]),
+ krpcNodeAddrFromNetAddr(addrs[1]),
},
- Added6Flags: []pp.PexPeerFlags{f, f},
+ Added6Flags: []pp.PexPeerFlags{0, pp.PexOutgoingConn},
},
- targS: 4,
},
{
name: "drop2",
- arg: 0,
- in: &pexState{
- ev: []pexEvent{
- pexEvent{pexDrop, addrs[0], f},
- pexEvent{pexDrop, addrs[2], f},
- },
- },
- targM: pp.PexMsg{
+ in: func() *pexState {
+ s := &pexState{nc: pexTargAdded + 2}
+ s.Drop(&PeerConn{Peer: Peer{RemoteAddr: addrs[0]}, pex: pexConnState{Listed: true}})
+ s.Drop(&PeerConn{Peer: Peer{RemoteAddr: addrs[2]}, pex: pexConnState{Listed: true}})
+ return s
+ }(),
+ targ: pp.PexMsg{
Dropped: krpc.CompactIPv4NodeAddrs{
- mustNodeAddr(addrs[2]),
+ krpcNodeAddrFromNetAddr(addrs[2]),
},
Dropped6: krpc.CompactIPv6NodeAddrs{
- mustNodeAddr(addrs[0]),
+ krpcNodeAddrFromNetAddr(addrs[0]),
},
},
- targS: 2,
},
{
name: "add2drop1",
- arg: 0,
- in: &pexState{
- ev: []pexEvent{
- pexEvent{pexAdd, addrs[0], f},
- pexEvent{pexAdd, addrs[1], f},
- pexEvent{pexDrop, addrs[0], f},
- },
- },
- targM: pp.PexMsg{
+ in: func() *pexState {
+ conns := []PeerConn{
+ {Peer: Peer{RemoteAddr: addrs[0]}},
+ {Peer: Peer{RemoteAddr: addrs[1]}},
+ {Peer: Peer{RemoteAddr: addrs[2]}},
+ }
+ s := &pexState{nc: pexTargAdded}
+ s.Add(&conns[0])
+ s.Add(&conns[1])
+ s.Drop(&conns[0])
+ s.Drop(&conns[2]) // to be ignored: it wasn't added
+ return s
+ }(),
+ targ: pp.PexMsg{
Added6: krpc.CompactIPv6NodeAddrs{
- mustNodeAddr(addrs[1]),
+ krpcNodeAddrFromNetAddr(addrs[1]),
},
- Added6Flags: []pp.PexPeerFlags{f},
+ Added6Flags: []pp.PexPeerFlags{0},
},
- targS: 3,
},
{
name: "delayed",
- arg: 0,
- in: &pexState{
- ev: []pexEvent{
- pexEvent{pexAdd, addrs[0], f},
- pexEvent{pexAdd, addrs[1], f},
- pexEvent{pexAdd, addrs[2], f},
+ in: func() *pexState {
+ conns := []PeerConn{
+ {Peer: Peer{RemoteAddr: addrs[0]}},
+ {Peer: Peer{RemoteAddr: addrs[1]}},
+ {Peer: Peer{RemoteAddr: addrs[2]}},
+ }
+ s := new(pexState)
+ s.Add(&conns[0])
+ s.Add(&conns[1])
+ s.Add(&conns[2])
+ s.Drop(&conns[0]) // on hold: s.nc < pexTargAdded
+ s.Drop(&conns[2])
+ s.Drop(&conns[1])
+ return s
+ }(),
+ targ: pp.PexMsg{
+ Added: krpc.CompactIPv4NodeAddrs{
+ krpcNodeAddrFromNetAddr(addrs[2]),
},
- hold: []pexEvent{
- pexEvent{pexDrop, addrs[0], f},
- pexEvent{pexDrop, addrs[2], f},
- pexEvent{pexDrop, addrs[1], f},
+ AddedFlags: []pp.PexPeerFlags{0},
+ Added6: krpc.CompactIPv6NodeAddrs{
+ krpcNodeAddrFromNetAddr(addrs[0]),
+ krpcNodeAddrFromNetAddr(addrs[1]),
},
+ Added6Flags: []pp.PexPeerFlags{0, 0},
},
- targM: pp.PexMsg{
- Added: krpc.CompactIPv4NodeAddrs{
- mustNodeAddr(addrs[2]),
- },
- AddedFlags: []pp.PexPeerFlags{f},
+ },
+ {
+ name: "unheld",
+ in: func() *pexState {
+ conns := []PeerConn{
+ {Peer: Peer{RemoteAddr: addrs[0]}},
+ {Peer: Peer{RemoteAddr: addrs[1]}},
+ }
+ s := &pexState{nc: pexTargAdded - 1}
+ s.Add(&conns[0])
+ s.Drop(&conns[0]) // on hold: s.nc < pexTargAdded
+ s.Add(&conns[1]) // unholds the above
+ return s
+ }(),
+ targ: pp.PexMsg{
Added6: krpc.CompactIPv6NodeAddrs{
- mustNodeAddr(addrs[0]),
- mustNodeAddr(addrs[1]),
+ krpcNodeAddrFromNetAddr(addrs[1]),
},
- Added6Flags: []pp.PexPeerFlags{f, f},
+ Added6Flags: []pp.PexPeerFlags{0},
},
- targS: 3,
},
{
name: "followup",
- arg: 1,
- in: &pexState{
- ev: []pexEvent{
- pexEvent{pexAdd, addrs[0], f},
- pexEvent{pexAdd, addrs[1], f},
+ in: func() *pexState {
+ s := new(pexState)
+ s.Add(&PeerConn{Peer: Peer{RemoteAddr: addrs[0]}})
+ return s
+ }(),
+ targ: pp.PexMsg{
+ Added6: krpc.CompactIPv6NodeAddrs{
+ krpcNodeAddrFromNetAddr(addrs[0]),
},
+ Added6Flags: []pp.PexPeerFlags{0},
},
- targM: pp.PexMsg{
+ update: func(s *pexState) {
+ s.Add(&PeerConn{Peer: Peer{RemoteAddr: addrs[1]}})
+ },
+ targ1: pp.PexMsg{
Added6: krpc.CompactIPv6NodeAddrs{
- mustNodeAddr(addrs[1]),
+ krpcNodeAddrFromNetAddr(addrs[1]),
},
- Added6Flags: []pp.PexPeerFlags{f},
+ Added6Flags: []pp.PexPeerFlags{0},
},
- targS: 2,
},
}
ac.AssertEqual(t, ec)
}
-func TestPexGenmsg(t *testing.T) {
+func TestPexGenmsg0(t *testing.T) {
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
- s := tc.in
- m, seen := s.Genmsg(tc.arg)
- assertPexMsgsEqual(t, tc.targM, m)
- require.EqualValues(t, tc.targS, seen)
+ s := *tc.in
+ m, last := s.Genmsg(nil)
+ assertPexMsgsEqual(t, tc.targ, m)
+ if tc.update != nil {
+ tc.update(&s)
+ m1, last := s.Genmsg(last)
+ assertPexMsgsEqual(t, tc.targ1, m1)
+ assert.NotNil(t, last)
+ }
})
}
}
func addrgen(n int) chan net.Addr {
c := make(chan net.Addr)
go func() {
+ defer close(c)
for i := 4747; i < 65535 && n > 0; i++ {
c <- &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: i}
n--
}
- close(c)
}()
return c
}
c := addrgen(n)
for addr := range c {
- s.Add(&PeerConn{peer: peer{RemoteAddr: addr}})
+ s.Add(&PeerConn{Peer: Peer{RemoteAddr: addr}})
}
- m, seq := s.Genmsg(0)
+ m, _ := s.Genmsg(nil)
- require.EqualValues(t, n, seq)
require.EqualValues(t, n, len(m.Added))
require.EqualValues(t, n, len(m.AddedFlags))
require.EqualValues(t, 0, len(m.Added6))
require.EqualValues(t, 0, len(m.Dropped6))
}
-func TestPexAdd(t *testing.T) {
- t.Run("ipv4", func(t *testing.T) {
- addrs := addrs4
- var m pexMsgFactory
- m.addEvent(pexEvent{pexDrop, addrs[0], 0})
- m.addEvent(pexEvent{pexAdd, addrs[1], f})
- for _, addr := range addrs {
- m.addEvent(pexEvent{pexAdd, addr, f})
- }
- targ := pp.PexMsg{
- Added: krpc.CompactIPv4NodeAddrs{
- mustNodeAddr(addrs[1]),
- mustNodeAddr(addrs[2]),
- mustNodeAddr(addrs[3]),
- },
- AddedFlags: []pp.PexPeerFlags{f, f, f},
- }
- out := m.PexMsg()
- assertPexMsgsEqual(t, targ, out)
- })
- t.Run("ipv6", func(t *testing.T) {
- addrs := addrs6
- var m pexMsgFactory
- m.addEvent(pexEvent{pexDrop, addrs[0], 0})
- m.addEvent(pexEvent{pexAdd, addrs[1], f})
- for _, addr := range addrs {
- m.addEvent(pexEvent{pexAdd, addr, f})
+func benchmarkPexInitialN(b *testing.B, npeers int) {
+ for i := 0; i < b.N; i++ {
+ var s pexState
+ c := addrgen(npeers)
+ for addr := range c {
+ s.Add(&PeerConn{Peer: Peer{RemoteAddr: addr}})
+ s.Genmsg(nil)
}
- targ := pp.PexMsg{
- Added6: krpc.CompactIPv6NodeAddrs{
- mustNodeAddr(addrs[1]),
- mustNodeAddr(addrs[2]),
- mustNodeAddr(addrs[3]),
- },
- Added6Flags: []pp.PexPeerFlags{f, f, f},
- }
- assertPexMsgsEqual(t, targ, m.PexMsg())
- })
- t.Run("empty", func(t *testing.T) {
- nullAddr := &net.TCPAddr{}
- var xm pexMsgFactory
- xm.addEvent(pexEvent{pexAdd, nullAddr, f})
- m := xm.PexMsg()
- require.EqualValues(t, 0, len(m.Added))
- require.EqualValues(t, 0, len(m.AddedFlags))
- require.EqualValues(t, 0, len(m.Added6))
- require.EqualValues(t, 0, len(m.Added6Flags))
- })
+ }
}
-func TestPexDrop(t *testing.T) {
- t.Run("ipv4", func(t *testing.T) {
- addrs := addrs4
- var m pexMsgFactory
- m.addEvent(pexEvent{pexAdd, addrs[0], f})
- m.addEvent(pexEvent{pexDrop, addrs[1], 0})
- for _, addr := range addrs {
- m.addEvent(pexEvent{pexDrop, addr, 0})
- }
- targ := pp.PexMsg{
- Dropped: krpc.CompactIPv4NodeAddrs{
- mustNodeAddr(addrs[1]),
- mustNodeAddr(addrs[2]),
- mustNodeAddr(addrs[3]),
- },
- }
- assertPexMsgsEqual(t, targ, m.PexMsg())
- })
- t.Run("ipv6", func(t *testing.T) {
- addrs := addrs6
- var m pexMsgFactory
- m.addEvent(pexEvent{pexAdd, addrs[0], f})
- m.addEvent(pexEvent{pexDrop, addrs[1], 0})
- for _, addr := range addrs {
- m.addEvent(pexEvent{pexDrop, addr, 0})
- }
- targ := pp.PexMsg{
- Dropped6: krpc.CompactIPv6NodeAddrs{
- mustNodeAddr(addrs[1]),
- mustNodeAddr(addrs[2]),
- mustNodeAddr(addrs[3]),
- },
- }
- assertPexMsgsEqual(t, targ, m.PexMsg())
- })
- t.Run("empty", func(t *testing.T) {
- nullAddr := &net.TCPAddr{}
- var xm pexMsgFactory
- xm.addEvent(pexEvent{pexDrop, nullAddr, f})
- m := xm.PexMsg()
- require.EqualValues(t, 0, len(m.Dropped))
- require.EqualValues(t, 0, len(m.Dropped6))
- })
-}
+// obtain at least 5 points, e.g. to plot a graph
+func BenchmarkPexInitial4(b *testing.B) { benchmarkPexInitialN(b, 4) }
+func BenchmarkPexInitial50(b *testing.B) { benchmarkPexInitialN(b, 50) }
+func BenchmarkPexInitial100(b *testing.B) { benchmarkPexInitialN(b, 100) }
+func BenchmarkPexInitial200(b *testing.B) { benchmarkPexInitialN(b, 200) }
+func BenchmarkPexInitial400(b *testing.B) { benchmarkPexInitialN(b, 400) }