1 #include "config.h"
2
3 #include "test_request_list.h"
4
5 #include "torrent/exceptions.h"
6 #include "torrent/peer/peer_info.h"
7 #include "download/delegator.h"
8 #include "protocol/peer_chunks.h"
9 #include "protocol/request_list.h"
10 #include "rak/socket_address.h"
11
12 CPPUNIT_TEST_SUITE_REGISTRATION(TestRequestList);
13
14 static uint32_t
chunk_index_size(uint32_t index)15 chunk_index_size(uint32_t index) {
16 return 1 << 10;
17 }
18
19 static void
transfer_list_void()20 transfer_list_void() {
21 // std::cout << "list_void" << std::endl;
22 }
23
24 static void
transfer_list_completed(torrent::TransferList * transfer_list,uint32_t index)25 transfer_list_completed(torrent::TransferList* transfer_list, uint32_t index) {
26 torrent::TransferList::iterator itr = transfer_list->find(index);
27
28 // std::cout << "list_completed:" << index << " found: " << (itr != transfer_list->end()) << std::endl;
29
30 CPPUNIT_ASSERT(itr != transfer_list->end());
31
32 transfer_list->erase(itr);
33 }
34
35 // Move to support header:
36 #define SETUP_DELEGATOR(fpc_prefix) \
37 torrent::Delegator* delegator = new torrent::Delegator; \
38 delegator->slot_chunk_find() = std::bind(&fpc_prefix ## _find_peer_chunk, std::placeholders::_1, std::placeholders::_2); \
39 delegator->slot_chunk_size() = std::bind(&chunk_index_size, std::placeholders::_1); \
40 delegator->transfer_list()->slot_canceled() = std::bind(&transfer_list_void); \
41 delegator->transfer_list()->slot_queued() = std::bind(&transfer_list_void); \
42 delegator->transfer_list()->slot_completed() = std::bind(&transfer_list_completed, delegator->transfer_list(), std::placeholders::_1); \
43 delegator->transfer_list()->slot_corrupt() = std::bind(&transfer_list_void);
44
45 // Set bitfield size...
46 #define SETUP_PEER_CHUNKS() \
47 rak::socket_address peer_info_address; \
48 torrent::PeerInfo* peer_info = new torrent::PeerInfo(peer_info_address.c_sockaddr()); \
49 torrent::PeerChunks* peer_chunks = new torrent::PeerChunks; \
50 peer_chunks->set_peer_info(peer_info);
51
52 #define CLEANUP_PEER_CHUNKS() \
53 delete peer_chunks; \
54 delete peer_info;
55
56 #define SETUP_REQUEST_LIST() \
57 torrent::RequestList* request_list = new torrent::RequestList; \
58 request_list->set_delegator(delegator); \
59 request_list->set_peer_chunks(peer_chunks);
60
61 #define SETUP_ALL(fpc_prefix) \
62 SET_CACHED_TIME(0); \
63 SETUP_DELEGATOR(basic); \
64 SETUP_PEER_CHUNKS(); \
65 SETUP_REQUEST_LIST();
66
67 #define SETUP_ALL_WITH_3(fpc_prefix) \
68 SETUP_ALL(fpc_prefix); \
69 const torrent::Piece* piece_1 = request_list->delegate(); \
70 const torrent::Piece* piece_2 = request_list->delegate(); \
71 const torrent::Piece* piece_3 = request_list->delegate(); \
72 CPPUNIT_ASSERT(piece_1 && piece_2 && piece_3);
73
74 #define CLEANUP_ALL(fpc_prefix) \
75 CLEANUP_PEER_CHUNKS(); \
76 delete delegator; \
77 delete request_list;
78
79 #define CLEAR_TRANSFERS(fpc_prefix) \
80 delegator->transfer_list()->clear();
81
82 //
83 //
84 //
85
86 #define VERIFY_QUEUE_SIZES(s_0, s_1, s_2, s_3) \
87 CPPUNIT_ASSERT(request_list->queued_size() == s_0); \
88 CPPUNIT_ASSERT(request_list->unordered_size() == s_1); \
89 CPPUNIT_ASSERT(request_list->stalled_size() == s_2); \
90 CPPUNIT_ASSERT(request_list->choked_size() == s_3);
91
92 #define VERIFY_PIECE_IS_LEADER(piece) \
93 CPPUNIT_ASSERT(request_list->transfer() != NULL); \
94 CPPUNIT_ASSERT(request_list->transfer()->is_leader()); \
95 CPPUNIT_ASSERT(request_list->transfer()->peer_info() != NULL); \
96 CPPUNIT_ASSERT(request_list->transfer()->peer_info() == peer_info);
97
98 #define VERIFY_TRANSFER_COUNTER(transfer, count) \
99 CPPUNIT_ASSERT(transfer != NULL); \
100 CPPUNIT_ASSERT(transfer->peer_info() != NULL); \
101 CPPUNIT_ASSERT(transfer->peer_info()->transfer_counter() == count);
102
103 #define SET_CACHED_TIME(seconds) \
104 torrent::cachedTime = rak::timer::from_seconds(1000 + seconds); \
105 rak::priority_queue_perform(&torrent::taskScheduler, torrent::cachedTime);
106
107
108 //
109 // Basic tests:
110 //
111
112 static uint32_t
basic_find_peer_chunk(torrent::PeerChunks * peerChunk,bool highPriority)113 basic_find_peer_chunk(torrent::PeerChunks* peerChunk, bool highPriority) {
114 static int next_index = 0;
115
116 return next_index++;
117 }
118
119 void
test_basic()120 TestRequestList::test_basic() {
121 SETUP_ALL(basic);
122
123 CPPUNIT_ASSERT(!request_list->is_downloading());
124 CPPUNIT_ASSERT(!request_list->is_interested_in_active());
125
126 VERIFY_QUEUE_SIZES(0, 0, 0, 0);
127
128 CPPUNIT_ASSERT(request_list->calculate_pipe_size(1024 * 0) == 2);
129 CPPUNIT_ASSERT(request_list->calculate_pipe_size(1024 * 10) == 12);
130
131 CPPUNIT_ASSERT(request_list->transfer() == NULL);
132
133 CLEANUP_ALL();
134 }
135
136 void
test_single_request()137 TestRequestList::test_single_request() {
138 SETUP_ALL(basic);
139
140 const torrent::Piece* piece = request_list->delegate();
141 // std::cout << piece->index() << ' ' << piece->offset() << ' ' << piece->length() << std::endl;
142 // std::cout << peer_info->transfer_counter() << std::endl;
143
144 CPPUNIT_ASSERT(request_list->downloading(*piece));
145
146 VERIFY_PIECE_IS_LEADER(*piece);
147 VERIFY_TRANSFER_COUNTER(request_list->transfer(), 1);
148
149 request_list->transfer()->adjust_position(piece->length());
150
151 CPPUNIT_ASSERT(request_list->transfer()->is_finished());
152
153 request_list->finished();
154
155 CPPUNIT_ASSERT(peer_info->transfer_counter() == 0);
156
157 CLEANUP_ALL();
158 }
159
160 void
test_single_canceled()161 TestRequestList::test_single_canceled() {
162 SETUP_ALL(basic);
163
164 const torrent::Piece* piece = request_list->delegate();
165 // std::cout << piece->index() << ' ' << piece->offset() << ' ' << piece->length() << std::endl;
166 // std::cout << peer_info->transfer_counter() << std::endl;
167
168 CPPUNIT_ASSERT(request_list->downloading(*piece));
169
170 VERIFY_PIECE_IS_LEADER(*piece); // REMOVE
171 VERIFY_TRANSFER_COUNTER(request_list->transfer(), 1); // REMOVE
172
173 request_list->transfer()->adjust_position(piece->length() / 2);
174
175 CPPUNIT_ASSERT(!request_list->transfer()->is_finished());
176
177 request_list->skipped();
178
179 // The transfer remains in Block until it gets the block has a
180 // transfer trigger finished.
181
182 // TODO: We need to have a way of clearing disowned transfers, then
183 // make transfer list delete Block's(?) with those before dtor...
184
185 CPPUNIT_ASSERT(peer_info->transfer_counter() == 0);
186
187 CLEAR_TRANSFERS();
188 CLEANUP_ALL();
189 }
190
191 void
test_choke_normal()192 TestRequestList::test_choke_normal() {
193 SETUP_ALL_WITH_3(basic);
194 VERIFY_QUEUE_SIZES(3, 0, 0, 0);
195
196 request_list->choked();
197
198 SET_CACHED_TIME(1);
199 VERIFY_QUEUE_SIZES(0, 0, 0, 3);
200
201 SET_CACHED_TIME(6);
202 VERIFY_QUEUE_SIZES(0, 0, 0, 0);
203
204 CLEAR_TRANSFERS();
205 CLEANUP_ALL();
206 }
207
208 void
test_choke_unchoke_discard()209 TestRequestList::test_choke_unchoke_discard() {
210 SETUP_ALL_WITH_3(basic);
211
212 request_list->choked();
213
214 SET_CACHED_TIME(5);
215 request_list->unchoked();
216
217 SET_CACHED_TIME(10);
218 VERIFY_QUEUE_SIZES(0, 0, 0, 3);
219
220 SET_CACHED_TIME(65);
221 VERIFY_QUEUE_SIZES(0, 0, 0, 0);
222
223 CLEAR_TRANSFERS();
224 CLEANUP_ALL();
225 }
226
227 void
test_choke_unchoke_transfer()228 TestRequestList::test_choke_unchoke_transfer() {
229 SETUP_ALL_WITH_3(basic);
230
231 request_list->choked();
232 SET_CACHED_TIME(5);
233 request_list->unchoked();
234
235 SET_CACHED_TIME(10);
236 CPPUNIT_ASSERT(request_list->downloading(*piece_1));
237 request_list->transfer()->adjust_position(piece_1->length());
238 request_list->finished();
239
240 SET_CACHED_TIME(60);
241 CPPUNIT_ASSERT(request_list->downloading(*piece_2));
242 request_list->transfer()->adjust_position(piece_2->length());
243 request_list->finished();
244
245 SET_CACHED_TIME(110);
246 CPPUNIT_ASSERT(request_list->downloading(*piece_3));
247 request_list->transfer()->adjust_position(piece_3->length());
248 request_list->finished();
249
250 VERIFY_QUEUE_SIZES(0, 0, 0, 0);
251
252 CLEAR_TRANSFERS();
253 CLEANUP_ALL();
254 }
255