1 package request_strategy
7 pp "github.com/anacrolix/torrent/peer_protocol"
8 "github.com/bradfitz/iter"
9 qt "github.com/frankban/quicktest"
12 func r(i pieceIndex, begin int) Request {
13 return Request{pp.Integer(i), ChunkSpec{pp.Integer(begin), 1}}
16 func chunkIterRange(end int) func(func(ChunkSpec)) {
17 return func(f func(ChunkSpec)) {
18 for offset := range iter.N(end) {
19 f(ChunkSpec{pp.Integer(offset), 1})
24 func chunkIter(offsets ...int) func(func(ChunkSpec)) {
25 return func(f func(ChunkSpec)) {
26 for _, offset := range offsets {
27 f(ChunkSpec{pp.Integer(offset), 1})
32 func requestSetFromSlice(rs ...Request) (ret map[Request]struct{}) {
33 ret = make(map[Request]struct{}, len(rs))
34 for _, r := range rs {
42 func (i intPeerId) Uintptr() uintptr {
46 func TestStealingFromSlowerPeer(t *testing.T) {
49 HasPiece: func(i pieceIndex) bool {
52 MaxRequests: math.MaxInt16,
55 // Slower than the stealers, but has all requests already.
57 stealee.DownloadRate = 1
58 stealee.HasExistingRequest = func(r Request) bool {
61 stealee.Id = intPeerId(1)
62 firstStealer := basePeer
63 firstStealer.Id = intPeerId(2)
64 secondStealer := basePeer
65 secondStealer.Id = intPeerId(3)
66 results := Run(Input{Torrents: []Torrent{{
70 IterPendingChunks: chunkIterRange(5),
79 c.Assert(results, qt.HasLen, 3)
80 check := func(p PeerId, l int) {
81 c.Check(results[p].Requests, qt.HasLen, l)
82 c.Check(results[p].Interested, qt.Equals, l > 0)
85 check(firstStealer.Id, 2)
86 check(secondStealer.Id, 2)
89 func checkNumRequestsAndInterest(c *qt.C, next PeerNextRequestState, num int, interest bool) {
90 c.Check(next.Requests, qt.HasLen, num)
91 c.Check(next.Interested, qt.Equals, interest)
94 func TestStealingFromSlowerPeersBasic(t *testing.T) {
97 HasPiece: func(i pieceIndex) bool {
100 MaxRequests: math.MaxInt16,
104 stealee.DownloadRate = 1
105 stealee.HasExistingRequest = func(r Request) bool {
108 stealee.Id = intPeerId(1)
109 firstStealer := basePeer
110 firstStealer.Id = intPeerId(2)
111 secondStealer := basePeer
112 secondStealer.Id = intPeerId(3)
113 results := Run(Input{Torrents: []Torrent{{
117 IterPendingChunks: chunkIter(0, 1),
126 checkNumRequestsAndInterest(c, results[firstStealer.Id], 1, true)
127 checkNumRequestsAndInterest(c, results[secondStealer.Id], 1, true)
128 checkNumRequestsAndInterest(c, results[stealee.Id], 0, false)
131 func TestPeerKeepsExistingIfReasonable(t *testing.T) {
134 HasPiece: func(i pieceIndex) bool {
137 MaxRequests: math.MaxInt16,
140 // Slower than the stealers, but has all requests already.
142 stealee.DownloadRate = 1
144 stealee.HasExistingRequest = func(r Request) bool {
147 stealee.Id = intPeerId(1)
148 firstStealer := basePeer
149 firstStealer.Id = intPeerId(2)
150 secondStealer := basePeer
151 secondStealer.Id = intPeerId(3)
152 results := Run(Input{Torrents: []Torrent{{
156 IterPendingChunks: chunkIter(0, 1, 3, 4),
165 c.Assert(results, qt.HasLen, 3)
166 check := func(p PeerId, l int) {
167 c.Check(results[p].Requests, qt.HasLen, l)
168 c.Check(results[p].Interested, qt.Equals, l > 0)
170 check(firstStealer.Id, 2)
171 check(secondStealer.Id, 1)
172 c.Check(results[stealee.Id], qt.ContentEquals, PeerNextRequestState{
174 Requests: requestSetFromSlice(keepReq),
178 func TestDontStealUnnecessarily(t *testing.T) {
181 HasPiece: func(i pieceIndex) bool {
184 MaxRequests: math.MaxInt16,
187 // Slower than the stealers, but has all requests already.
189 stealee.DownloadRate = 1
190 keepReqs := requestSetFromSlice(r(0, 0), r(0, 1), r(0, 2))
191 stealee.HasExistingRequest = func(r Request) bool {
195 stealee.Id = intPeerId(1)
196 firstStealer := basePeer
197 firstStealer.Id = intPeerId(2)
198 secondStealer := basePeer
199 secondStealer.Id = intPeerId(3)
200 results := Run(Input{Torrents: []Torrent{{
204 IterPendingChunks: chunkIterRange(9),
213 c.Assert(results, qt.HasLen, 3)
214 check := func(p PeerId, l int) {
215 c.Check(results[p].Requests, qt.HasLen, l)
216 c.Check(results[p].Interested, qt.Equals, l > 0)
218 check(firstStealer.Id, 3)
219 check(secondStealer.Id, 3)
220 c.Check(results[stealee.Id], qt.ContentEquals, PeerNextRequestState{