summaryrefslogtreecommitdiff
path: root/tests/t_clean.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/t_clean.c')
-rw-r--r--tests/t_clean.c92
1 files changed, 87 insertions, 5 deletions
diff --git a/tests/t_clean.c b/tests/t_clean.c
index 7eca9aa..ce17bc3 100644
--- a/tests/t_clean.c
+++ b/tests/t_clean.c
@@ -11,7 +11,7 @@
11#include "trackerlogic.h" 11#include "trackerlogic.h"
12#include "test.h" 12#include "test.h"
13 13
14/* A clock stepped backwards used to leave peer_list->base in the future, so 14/* A clock stepped backwards used to leave the torrent's base in the future, so
15 the span the cleaner works from came out negative. It was then added to a 15 the span the cleaner works from came out negative. It was then added to a
16 peer's age and stored in the single byte that age lives in, where -1 reads 16 peer's age and stored in the single byte that age lives in, where -1 reads
17 as 255 and the next pass threw the whole swarm away. */ 17 as 255 and the next pass threw the whole swarm away. */
@@ -33,6 +33,20 @@ static void announce(struct ot_workstruct *ws, ot_hash *hash, uint8_t last_octet
33 add_peer_to_torrent_and_return_peers(FLAG_TCP, ws, 0); 33 add_peer_to_torrent_and_return_peers(FLAG_TCP, ws, 0);
34} 34}
35 35
36/* A distinct v4 peer addressed by two octets, to build swarms past 256 */
37static size_t announce_wide(struct ot_workstruct *ws, ot_hash *hash, unsigned int which, size_t amount) {
38 static const uint8_t v4mapped[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
39
40 ws->reply = ws->outbuf;
41 memset(&ws->peer, 0, sizeof(ws->peer));
42 memcpy(&ws->peer, v4mapped, sizeof(v4mapped));
43 ((uint8_t *)&ws->peer)[14] = (uint8_t)(which >> 8);
44 ((uint8_t *)&ws->peer)[15] = (uint8_t)which;
45 OT_SETPORT(&ws->peer, &(uint16_t){6881});
46 ws->hash = hash;
47 return add_peer_to_torrent_and_return_peers(FLAG_TCP, ws, amount);
48}
49
36static size_t peers_in(ot_hash *hash) { 50static size_t peers_in(ot_hash *hash) {
37 char reply[1024]; 51 char reply[1024];
38 size_t len = return_udp_scrape_for_torrent(*hash, reply); 52 size_t len = return_udp_scrape_for_torrent(*hash, reply);
@@ -60,14 +74,12 @@ static ot_torrent *torrent_of(ot_hash *hash) {
60 74
61/* What a clock stepped back by `minutes` leaves behind */ 75/* What a clock stepped back by `minutes` leaves behind */
62static void step_clock_back(ot_torrent *torrent, int minutes) { 76static void step_clock_back(ot_torrent *torrent, int minutes) {
63 torrent->peer_list6->base += minutes; 77 torrent->base += minutes;
64 torrent->peer_list4->base += minutes;
65} 78}
66 79
67/* What the next minute of a well behaved clock looks like */ 80/* What the next minute of a well behaved clock looks like */
68static void age_by_a_minute(ot_torrent *torrent) { 81static void age_by_a_minute(ot_torrent *torrent) {
69 torrent->peer_list6->base -= 1; 82 torrent->base -= 1;
70 torrent->peer_list4->base -= 1;
71} 83}
72 84
73static void case_a_clock_that_went_back_keeps_the_swarm(void) { 85static void case_a_clock_that_went_back_keeps_the_swarm(void) {
@@ -124,6 +136,74 @@ static void case_an_idle_swarm_still_ages_out(void) {
124 workstruct_deinit(&ws); 136 workstruct_deinit(&ws);
125} 137}
126 138
139static void case_empty_torrent_timeout_bounds_a_counter_only_torrent(void) {
140 struct ot_workstruct ws;
141 ot_hash hash;
142 ot_torrent *torrent;
143 ot_time saved = g_empty_torrent_timeout;
144
145 test_case("the empty torrent timeout bounds a counter-only torrent's life");
146 memset(hash, 0x33, sizeof(hash));
147 CHECK_INT(workstruct_init(&ws, G_INBUF_SIZE), 0);
148
149 announce(&ws, &hash, 7, 1);
150 torrent = torrent_of(&hash);
151 CHECK(torrent != NULL);
152 torrent->down_count = 1; /* one completed download to remember it by */
153
154 /* Age the only peer out: the torrent falls empty but keeps its count */
155 step_clock_back(torrent, -OT_PEER_TIMEOUT);
156 CHECK_INT(clean_single_torrent(torrent), 0);
157 CHECK_INT(peers_in(&hash), 0);
158
159 /* Carry it a little past a short empty-torrent timeout */
160 step_clock_back(torrent, -10);
161
162 /* The default, matching the torrent timeout, still holds it for the count */
163 g_empty_torrent_timeout = OT_TORRENT_TIMEOUT;
164 CHECK_INT(clean_single_torrent(torrent), 0);
165
166 /* A timeout it has now exceeded lets the next sweep drop it */
167 g_empty_torrent_timeout = OT_PEER_TIMEOUT + 5;
168 CHECK_INT(clean_single_torrent(torrent), 1);
169
170 g_empty_torrent_timeout = saved;
171 workstruct_deinit(&ws);
172}
173
174static void case_a_bucketed_swarm_survives_clean_and_serves(void) {
175 struct ot_workstruct ws;
176 ot_hash hash;
177 ot_torrent *torrent;
178 unsigned int i;
179 const unsigned int n = 600; /* past OT_PEER_BUCKET_MINCOUNT (512) */
180
181 test_case("a swarm large enough to be bucketed cleans, splits and serves without loss");
182 memset(hash, 0x34, sizeof(hash));
183 CHECK_INT(workstruct_init(&ws, G_INBUF_SIZE), 0);
184
185 for (i = 0; i < n; ++i)
186 announce_wide(&ws, &hash, i, 0);
187 CHECK_INT(peers_in(&hash), n);
188
189 torrent = torrent_of(&hash);
190 CHECK(torrent != NULL);
191 CHECK(torrent->peer_list != NULL);
192
193 /* A clean with a minute elapsed splits the flat vector into buckets */
194 step_clock_back(torrent, -1);
195 CHECK_INT(clean_single_torrent(torrent), 0);
196 CHECK(torrent->peer_list != NULL);
197 CHECK_INT(OT_VECTOR_HASBUCKETS(&torrent->peer_list->peers4), 1);
198 CHECK_INT(peers_in(&hash), n);
199
200 /* Serve a selection back, which walks the bucket list */
201 CHECK(announce_wide(&ws, &hash, 1, 200) > 0);
202 CHECK_INT(peers_in(&hash), n);
203
204 workstruct_deinit(&ws);
205}
206
127void test_clean(void) { 207void test_clean(void) {
128 sigset_t hup; 208 sigset_t hup;
129 209
@@ -136,5 +216,7 @@ void test_clean(void) {
136 trackerlogic_init(); 216 trackerlogic_init();
137 case_a_clock_that_went_back_keeps_the_swarm(); 217 case_a_clock_that_went_back_keeps_the_swarm();
138 case_an_idle_swarm_still_ages_out(); 218 case_an_idle_swarm_still_ages_out();
219 case_empty_torrent_timeout_bounds_a_counter_only_torrent();
220 case_a_bucketed_swarm_survives_clean_and_serves();
139 trackerlogic_deinit(); 221 trackerlogic_deinit();
140} 222}