]> Sergey Matveev's repositories - btrtrc.git/blob - request-strategy/order_test.go
8c518b5032cfe16eea78558fc9e96446090f2b4d
[btrtrc.git] / request-strategy / order_test.go
1 package request_strategy
2
3 import (
4         "math"
5         "testing"
6
7         pp "github.com/anacrolix/torrent/peer_protocol"
8         "github.com/bradfitz/iter"
9         qt "github.com/frankban/quicktest"
10 )
11
12 func r(i pieceIndex, begin int) Request {
13         return Request{pp.Integer(i), ChunkSpec{pp.Integer(begin), 1}}
14 }
15
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})
20                 }
21         }
22 }
23
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})
28                 }
29         }
30 }
31
32 func requestSetFromSlice(rs ...Request) (ret map[Request]struct{}) {
33         ret = make(map[Request]struct{}, len(rs))
34         for _, r := range rs {
35                 ret[r] = struct{}{}
36         }
37         return
38 }
39
40 type intPeerId int
41
42 func (i intPeerId) Uintptr() uintptr {
43         return uintptr(i)
44 }
45
46 func TestStealingFromSlowerPeer(t *testing.T) {
47         c := qt.New(t)
48         order := ClientPieceOrder{}
49         basePeer := Peer{
50                 HasPiece: func(i pieceIndex) bool {
51                         return true
52                 },
53                 MaxRequests:  math.MaxInt16,
54                 DownloadRate: 2,
55         }
56         // Slower than the stealers, but has all requests already.
57         stealee := basePeer
58         stealee.DownloadRate = 1
59         stealee.HasExistingRequest = func(r Request) bool {
60                 return true
61         }
62         stealee.Id = intPeerId(1)
63         firstStealer := basePeer
64         firstStealer.Id = intPeerId(2)
65         secondStealer := basePeer
66         secondStealer.Id = intPeerId(3)
67         results := order.DoRequests([]*Torrent{{
68                 Pieces: []Piece{{
69                         Request:           true,
70                         NumPendingChunks:  5,
71                         IterPendingChunks: chunkIterRange(5),
72                 }},
73                 Peers: []Peer{
74                         stealee,
75                         firstStealer,
76                         secondStealer,
77                 },
78         }})
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)
83         }
84         check(stealee.Id, 1)
85         check(firstStealer.Id, 2)
86         check(secondStealer.Id, 2)
87 }
88
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)
92 }
93
94 func TestStealingFromSlowerPeersBasic(t *testing.T) {
95         c := qt.New(t)
96         order := ClientPieceOrder{}
97         basePeer := Peer{
98                 HasPiece: func(i pieceIndex) bool {
99                         return true
100                 },
101                 MaxRequests:  math.MaxInt16,
102                 DownloadRate: 2,
103         }
104         stealee := basePeer
105         stealee.DownloadRate = 1
106         stealee.HasExistingRequest = func(r Request) bool {
107                 return true
108         }
109         stealee.Id = intPeerId(1)
110         firstStealer := basePeer
111         firstStealer.Id = intPeerId(2)
112         secondStealer := basePeer
113         secondStealer.Id = intPeerId(3)
114         results := order.DoRequests([]*Torrent{{
115                 Pieces: []Piece{{
116                         Request:           true,
117                         NumPendingChunks:  2,
118                         IterPendingChunks: chunkIter(0, 1),
119                 }},
120                 Peers: []Peer{
121                         stealee,
122                         firstStealer,
123                         secondStealer,
124                 },
125         }})
126         checkNumRequestsAndInterest(c, results[firstStealer.Id], 1, true)
127         checkNumRequestsAndInterest(c, results[secondStealer.Id], 1, true)
128         checkNumRequestsAndInterest(c, results[stealee.Id], 0, false)
129 }
130
131 func TestPeerKeepsExistingIfReasonable(t *testing.T) {
132         c := qt.New(t)
133         order := ClientPieceOrder{}
134         basePeer := Peer{
135                 HasPiece: func(i pieceIndex) bool {
136                         return true
137                 },
138                 MaxRequests:  math.MaxInt16,
139                 DownloadRate: 2,
140         }
141         // Slower than the stealers, but has all requests already.
142         stealee := basePeer
143         stealee.DownloadRate = 1
144         keepReq := r(0, 0)
145         stealee.HasExistingRequest = func(r Request) bool {
146                 return r == keepReq
147         }
148         stealee.Id = intPeerId(1)
149         firstStealer := basePeer
150         firstStealer.Id = intPeerId(2)
151         secondStealer := basePeer
152         secondStealer.Id = intPeerId(3)
153         results := order.DoRequests([]*Torrent{{
154                 Pieces: []Piece{{
155                         Request:           true,
156                         NumPendingChunks:  4,
157                         IterPendingChunks: chunkIter(0, 1, 3, 4),
158                 }},
159                 Peers: []Peer{
160                         stealee,
161                         firstStealer,
162                         secondStealer,
163                 },
164         }})
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)
169         }
170         check(firstStealer.Id, 2)
171         check(secondStealer.Id, 1)
172         c.Check(results[stealee.Id], qt.ContentEquals, PeerNextRequestState{
173                 Interested: true,
174                 Requests:   requestSetFromSlice(keepReq),
175         })
176 }
177
178 func TestDontStealUnnecessarily(t *testing.T) {
179         c := qt.New(t)
180         order := ClientPieceOrder{}
181         basePeer := Peer{
182                 HasPiece: func(i pieceIndex) bool {
183                         return true
184                 },
185                 MaxRequests:  math.MaxInt16,
186                 DownloadRate: 2,
187         }
188         // Slower than the stealers, but has all requests already.
189         stealee := basePeer
190         stealee.DownloadRate = 1
191         keepReqs := requestSetFromSlice(r(0, 0), r(0, 1), r(0, 2))
192         stealee.HasExistingRequest = func(r Request) bool {
193                 _, ok := keepReqs[r]
194                 return ok
195         }
196         stealee.Id = intPeerId(1)
197         firstStealer := basePeer
198         firstStealer.Id = intPeerId(2)
199         secondStealer := basePeer
200         secondStealer.Id = intPeerId(3)
201         results := order.DoRequests([]*Torrent{{
202                 Pieces: []Piece{{
203                         Request:           true,
204                         NumPendingChunks:  9,
205                         IterPendingChunks: chunkIterRange(9),
206                 }},
207                 Peers: []Peer{
208                         firstStealer,
209                         stealee,
210                         secondStealer,
211                 },
212         }})
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)
217         }
218         check(firstStealer.Id, 3)
219         check(secondStealer.Id, 3)
220         c.Check(results[stealee.Id], qt.ContentEquals, PeerNextRequestState{
221                 Interested: true,
222                 Requests:   keepReqs,
223         })
224 }