diff options
Diffstat (limited to 'tests/t_clean.c')
| -rw-r--r-- | tests/t_clean.c | 92 |
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 */ | ||
| 37 | static 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 | |||
| 36 | static size_t peers_in(ot_hash *hash) { | 50 | static 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 */ |
| 62 | static void step_clock_back(ot_torrent *torrent, int minutes) { | 76 | static 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 */ |
| 68 | static void age_by_a_minute(ot_torrent *torrent) { | 81 | static 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 | ||
| 73 | static void case_a_clock_that_went_back_keeps_the_swarm(void) { | 85 | static 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 | ||
| 139 | static 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 | |||
| 174 | static 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 | |||
| 127 | void test_clean(void) { | 207 | void 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 | } |
