convert tracker try-next test to be a simulation (and deterministic)
This commit is contained in:
parent
7070492a5f
commit
d3df16cd12
|
@ -363,8 +363,17 @@ TORRENT_TEST(ipv6_support)
|
||||||
TEST_EQUAL(v6_announces, 2);
|
TEST_EQUAL(v6_announces, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Announce, typename Test1, typename Test2>
|
// this runs a simulation of a torrent with tracker(s), making sure the request
|
||||||
void tracker_test(Announce a, Test1 test1, Test2 test2, char const* url_path = "/announce")
|
// received by the tracker matches the expectation.
|
||||||
|
// The Setup function is run first, giving the test an opportunity to add
|
||||||
|
// trackers to the torrent. It's expected to return the number of seconds to
|
||||||
|
// wait until test2 is called.
|
||||||
|
// The Announce function is called on http requests. Test1 is run on the session
|
||||||
|
// 5 seconds after startup. The tracker is running at 10.0.0.2 (or tracker.com)
|
||||||
|
// port 8080.
|
||||||
|
template <typename Setup, typename Announce, typename Test1, typename Test2>
|
||||||
|
void tracker_test(Setup setup, Announce a, Test1 test1, Test2 test2
|
||||||
|
, char const* url_path = "/announce")
|
||||||
{
|
{
|
||||||
using sim::asio::ip::address_v4;
|
using sim::asio::ip::address_v4;
|
||||||
sim_config network_cfg;
|
sim_config network_cfg;
|
||||||
|
@ -390,7 +399,7 @@ void tracker_test(Announce a, Test1 test1, Test2 test2, char const* url_path = "
|
||||||
p.name = "test-torrent";
|
p.name = "test-torrent";
|
||||||
p.save_path = ".";
|
p.save_path = ".";
|
||||||
p.info_hash.assign("abababababababababab");
|
p.info_hash.assign("abababababababababab");
|
||||||
p.trackers.push_back("http://tracker.com:8080/announce");
|
int const delay = setup(p);
|
||||||
ses->async_add_torrent(p);
|
ses->async_add_torrent(p);
|
||||||
|
|
||||||
// run the test 5 seconds in
|
// run the test 5 seconds in
|
||||||
|
@ -405,7 +414,7 @@ void tracker_test(Announce a, Test1 test1, Test2 test2, char const* url_path = "
|
||||||
});
|
});
|
||||||
|
|
||||||
asio::high_resolution_timer t2(ios);
|
asio::high_resolution_timer t2(ios);
|
||||||
t2.expires_from_now(chrono::seconds(9));
|
t2.expires_from_now(chrono::seconds(5 + delay));
|
||||||
t2.async_wait([&ses,&test2](boost::system::error_code const& ec)
|
t2.async_wait([&ses,&test2](boost::system::error_code const& ec)
|
||||||
{
|
{
|
||||||
std::vector<lt::torrent_handle> torrents = ses->get_torrents();
|
std::vector<lt::torrent_handle> torrents = ses->get_torrents();
|
||||||
|
@ -416,7 +425,7 @@ void tracker_test(Announce a, Test1 test1, Test2 test2, char const* url_path = "
|
||||||
|
|
||||||
// then shut down 10 seconds in
|
// then shut down 10 seconds in
|
||||||
asio::high_resolution_timer t3(ios);
|
asio::high_resolution_timer t3(ios);
|
||||||
t3.expires_from_now(chrono::seconds(10));
|
t3.expires_from_now(chrono::seconds(10 + delay));
|
||||||
t3.async_wait([&ses,&zombie](boost::system::error_code const& ec)
|
t3.async_wait([&ses,&zombie](boost::system::error_code const& ec)
|
||||||
{
|
{
|
||||||
zombie = ses->abort();
|
zombie = ses->abort();
|
||||||
|
@ -427,6 +436,16 @@ void tracker_test(Announce a, Test1 test1, Test2 test2, char const* url_path = "
|
||||||
sim.run();
|
sim.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Announce, typename Test1, typename Test2>
|
||||||
|
void tracker_test(Announce a, Test1 test1, Test2 test2, char const* url_path = "/announce")
|
||||||
|
{
|
||||||
|
tracker_test([](lt::add_torrent_params& p) {
|
||||||
|
p.trackers.push_back("http://tracker.com:8080/announce");
|
||||||
|
return 5;
|
||||||
|
},
|
||||||
|
a, test1, test2, url_path);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Announce, typename Test>
|
template <typename Announce, typename Test>
|
||||||
void announce_entry_test(Announce a, Test t, char const* url_path = "/announce")
|
void announce_entry_test(Announce a, Test t, char const* url_path = "/announce")
|
||||||
{
|
{
|
||||||
|
@ -609,6 +628,74 @@ TORRENT_TEST(test_invalid_bencoding)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TORRENT_TEST(try_next)
|
||||||
|
{
|
||||||
|
// test that we move on to try the next tier if the first one fails
|
||||||
|
|
||||||
|
bool got_announce = false;
|
||||||
|
tracker_test(
|
||||||
|
[](lt::add_torrent_params& p)
|
||||||
|
{
|
||||||
|
// TODO: 3 use tracker_tiers here to put the trackers in different tiers
|
||||||
|
p.trackers.push_back("udp://failing-tracker.com/announce");
|
||||||
|
p.trackers.push_back("http://failing-tracker.com/announce");
|
||||||
|
|
||||||
|
// this is the working tracker
|
||||||
|
p.trackers.push_back("http://tracker.com:8080/announce");
|
||||||
|
return 60;
|
||||||
|
},
|
||||||
|
[&](std::string method, std::string req
|
||||||
|
, std::map<std::string, std::string>& headers)
|
||||||
|
{
|
||||||
|
got_announce = true;
|
||||||
|
TEST_EQUAL(method, "GET");
|
||||||
|
|
||||||
|
char response[500];
|
||||||
|
// respond with an empty peer list
|
||||||
|
int size = snprintf(response, sizeof(response), "d5:peers0:e");
|
||||||
|
return sim::send_response(200, "OK", size) + response;
|
||||||
|
}
|
||||||
|
, [](torrent_handle h) {}
|
||||||
|
, [](torrent_handle h)
|
||||||
|
{
|
||||||
|
torrent_status st = h.status();
|
||||||
|
TEST_EQUAL(st.current_tracker, "http://tracker.com:8080/announce");
|
||||||
|
|
||||||
|
std::vector<announce_entry> tr = h.trackers();
|
||||||
|
|
||||||
|
TEST_EQUAL(tr.size(), 3);
|
||||||
|
|
||||||
|
for (int i = 0; i < tr.size(); ++i)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "tracker \"%s\"\n", tr[i].url.c_str());
|
||||||
|
if (tr[i].url == "http://tracker.com:8080/announce")
|
||||||
|
{
|
||||||
|
TEST_EQUAL(tr[i].fails, 0);
|
||||||
|
TEST_EQUAL(tr[i].verified, true);
|
||||||
|
}
|
||||||
|
else if (tr[i].url == "http://failing-tracker.com/announce")
|
||||||
|
{
|
||||||
|
TEST_CHECK(tr[i].fails >= 1);
|
||||||
|
TEST_EQUAL(tr[i].verified, false);
|
||||||
|
TEST_EQUAL(tr[i].last_error
|
||||||
|
, error_code(boost::asio::error::host_not_found));
|
||||||
|
}
|
||||||
|
else if (tr[i].url == "udp://failing-tracker.com/announce")
|
||||||
|
{
|
||||||
|
TEST_CHECK(tr[i].fails >= 1);
|
||||||
|
TEST_EQUAL(tr[i].verified, false);
|
||||||
|
TEST_EQUAL(tr[i].last_error
|
||||||
|
, error_code(boost::asio::error::host_not_found));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TEST_ERROR(("unexpected tracker URL: " + tr[i].url).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
TEST_EQUAL(got_announce, true);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: test external IP
|
// TODO: test external IP
|
||||||
// TODO: test with different queuing settings
|
// TODO: test with different queuing settings
|
||||||
// TODO: test when a torrent transitions from downloading to finished and
|
// TODO: test when a torrent transitions from downloading to finished and
|
||||||
|
|
|
@ -387,121 +387,6 @@ TORRENT_TEST(udp_tracker)
|
||||||
TEST_EQUAL(num_udp_announces(), prev_udp_announces + 2);
|
TEST_EQUAL(num_udp_announces(), prev_udp_announces + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_TEST(try_next)
|
|
||||||
{
|
|
||||||
// ========================================
|
|
||||||
// test that we move on to try the next tier if the first one fails
|
|
||||||
// ========================================
|
|
||||||
|
|
||||||
int http_port = start_web_server();
|
|
||||||
int udp_port = start_udp_tracker();
|
|
||||||
|
|
||||||
int prev_udp_announces = num_udp_announces();
|
|
||||||
|
|
||||||
settings_pack pack = settings();
|
|
||||||
pack.set_bool(settings_pack::announce_to_all_trackers, true);
|
|
||||||
pack.set_bool(settings_pack::announce_to_all_tiers, false);
|
|
||||||
pack.set_int(settings_pack::tracker_completion_timeout, 2);
|
|
||||||
pack.set_int(settings_pack::tracker_receive_timeout, 1);
|
|
||||||
pack.set_str(settings_pack::listen_interfaces, "0.0.0.0:39775");
|
|
||||||
|
|
||||||
boost::scoped_ptr<lt::session> s(new lt::session(pack));
|
|
||||||
|
|
||||||
error_code ec;
|
|
||||||
remove_all("tmp2_tracker", ec);
|
|
||||||
create_directory("tmp2_tracker", ec);
|
|
||||||
std::ofstream file(combine_path("tmp2_tracker", "temporary").c_str());
|
|
||||||
boost::shared_ptr<torrent_info> t = ::create_torrent(&file, "temporary", 16 * 1024, 13, false);
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
// this should fail
|
|
||||||
char tracker_url[200];
|
|
||||||
snprintf(tracker_url, sizeof(tracker_url), "udp://www1.non-existent.com:80/announce");
|
|
||||||
t->add_tracker(tracker_url, 0);
|
|
||||||
|
|
||||||
// and this should fail
|
|
||||||
snprintf(tracker_url, sizeof(tracker_url), "http://127.0.0.2:3/announce");
|
|
||||||
t->add_tracker(tracker_url, 1);
|
|
||||||
|
|
||||||
// this should be announced to
|
|
||||||
// udp trackers are prioritized if they're on the same host as an http one
|
|
||||||
// so this must be before the http one on 127.0.0.1
|
|
||||||
snprintf(tracker_url, sizeof(tracker_url), "udp://127.0.0.1:%d/announce", udp_port);
|
|
||||||
t->add_tracker(tracker_url, 2);
|
|
||||||
|
|
||||||
// and this should not be announced to (since the one before it succeeded)
|
|
||||||
snprintf(tracker_url, sizeof(tracker_url), "http://127.0.0.1:%d/announce", http_port);
|
|
||||||
t->add_tracker(tracker_url, 3);
|
|
||||||
|
|
||||||
prev_udp_announces = num_udp_announces();
|
|
||||||
|
|
||||||
add_torrent_params addp;
|
|
||||||
addp.flags &= ~add_torrent_params::flag_paused;
|
|
||||||
addp.flags &= ~add_torrent_params::flag_auto_managed;
|
|
||||||
addp.flags |= add_torrent_params::flag_seed_mode;
|
|
||||||
addp.ti = t;
|
|
||||||
addp.save_path = "tmp2_tracker";
|
|
||||||
torrent_handle h = s->add_torrent(addp);
|
|
||||||
|
|
||||||
for (int i = 0; i < 50; ++i)
|
|
||||||
{
|
|
||||||
print_alerts(*s, "s");
|
|
||||||
if (num_udp_announces() == prev_udp_announces + 1) break;
|
|
||||||
|
|
||||||
fprintf(stderr, "UDP: %d / %d\n", int(num_udp_announces())
|
|
||||||
, int(prev_udp_announces) + 1);
|
|
||||||
test_sleep(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
// we expect the first two trackers to have failed (because the hostname
|
|
||||||
// doesn't exist and the port isn't open),
|
|
||||||
// the second tracker to have succeeded and the third to not have been used
|
|
||||||
std::vector<announce_entry> tr = h.trackers();
|
|
||||||
|
|
||||||
TEST_EQUAL(tr.size(), 4);
|
|
||||||
|
|
||||||
if (tr.size() == 4)
|
|
||||||
{
|
|
||||||
// this tracker may not have failed yet, but just timed out (if the
|
|
||||||
// hostname lookup is slow)
|
|
||||||
if (tr[0].fails == 1)
|
|
||||||
{
|
|
||||||
TEST_EQUAL(tr[0].verified, false);
|
|
||||||
TEST_EQUAL(tr[0].last_error
|
|
||||||
, error_code(boost::asio::error::host_not_found));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_EQUAL(tr[1].fails, 1);
|
|
||||||
TEST_EQUAL(tr[1].verified, false);
|
|
||||||
const bool tracker_error = tr[1].last_error == boost::asio::error::timed_out
|
|
||||||
|| tr[1].last_error == boost::system::error_condition(boost::system::errc::connection_refused)
|
|
||||||
#ifdef TORRENT_WINDOWS
|
|
||||||
|| tr[1].last_error == boost::system::error_code(ERROR_CONNECTION_REFUSED, boost::system::system_category())
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
TEST_EQUAL(tracker_error, true);
|
|
||||||
|
|
||||||
TEST_EQUAL(tr[2].fails, 0);
|
|
||||||
TEST_EQUAL(tr[2].verified, true);
|
|
||||||
|
|
||||||
TEST_EQUAL(tr[3].fails, 0);
|
|
||||||
TEST_EQUAL(tr[3].verified, false);
|
|
||||||
}
|
|
||||||
test_sleep(1000);
|
|
||||||
|
|
||||||
TEST_EQUAL(num_udp_announces(), prev_udp_announces + 1);
|
|
||||||
|
|
||||||
fprintf(stderr, "destructing session\n");
|
|
||||||
s.reset();
|
|
||||||
fprintf(stderr, "done\n");
|
|
||||||
|
|
||||||
fprintf(stderr, "stop_tracker\n");
|
|
||||||
stop_udp_tracker();
|
|
||||||
fprintf(stderr, "stop_web_server\n");
|
|
||||||
stop_web_server();
|
|
||||||
fprintf(stderr, "done\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
TORRENT_TEST(http_peers)
|
TORRENT_TEST(http_peers)
|
||||||
{
|
{
|
||||||
int http_port = start_web_server();
|
int http_port = start_web_server();
|
||||||
|
|
Loading…
Reference in New Issue