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