improve http_connection simulation test and extend it

This commit is contained in:
arvidn 2015-11-01 17:22:40 -05:00
parent f4a2b4d949
commit c6e46ae305
1 changed files with 126 additions and 41 deletions

View File

@ -62,25 +62,25 @@ struct sim_config : sim::default_config
return duration_cast<chrono::high_resolution_clock::duration>(chrono::milliseconds(100));
}
if (hostname == "try-next.com")
{
result.push_back(address_v4::from_string("10.0.0.10"));
result.push_back(address_v4::from_string("10.0.0.9"));
result.push_back(address_v4::from_string("10.0.0.8"));
result.push_back(address_v4::from_string("10.0.0.7"));
result.push_back(address_v4::from_string("10.0.0.6"));
result.push_back(address_v4::from_string("10.0.0.5"));
result.push_back(address_v4::from_string("10.0.0.4"));
result.push_back(address_v4::from_string("10.0.0.3"));
result.push_back(address_v4::from_string("10.0.0.2"));
return duration_cast<chrono::high_resolution_clock::duration>(chrono::milliseconds(100));
}
return default_config::hostname_lookup(requestor, hostname, result, ec);
}
};
void on_alert_notify(lt::session* ses)
{
std::vector<lt::alert*> alerts;
ses->pop_alerts(&alerts);
for (lt::alert* a : alerts)
{
lt::time_duration d = a->timestamp().time_since_epoch();
boost::uint32_t millis = lt::duration_cast<lt::milliseconds>(d).count();
printf("%4d.%03d: %s\n", millis / 1000, millis % 1000,
a->message().c_str());
}
}
boost::shared_ptr<http_connection> run_test(io_service& ios
boost::shared_ptr<http_connection> test_request(io_service& ios
, resolver& res
, std::string const& url
, char const* expected_data
@ -99,20 +99,22 @@ boost::shared_ptr<http_connection> run_test(io_service& ios
, [=](error_code const& ec, http_parser const& parser
, char const* data, const int size, http_connection& c)
{
fprintf(stderr, "RESPONSE: %s\n", url.c_str());
printf("RESPONSE: %s\n", url.c_str());
++*handler_called;
if (ec != expected_ec)
{
printf("ERROR: %s (expected: %s)\n"
, ec.message().c_str()
, expected_ec.message().c_str());
}
const int http_status = parser.status_code();
if (expected_size != -1)
{
TEST_EQUAL(size, expected_size);
}
TEST_EQUAL(ec, expected_ec);
if (ec != expected_ec)
{
fprintf(stderr, "ERROR: %s (expected: %s)\n"
, ec.message().c_str()
, expected_ec.message().c_str());
}
if (expected_status != -1)
{
TEST_EQUAL(http_status, expected_status);
@ -129,7 +131,7 @@ boost::shared_ptr<http_connection> run_test(io_service& ios
{
++*connect_handler_called;
TEST_CHECK(c.socket().is_open());
fprintf(stderr, "CONNECTED: %s\n", url.c_str());
printf("CONNECTED: %s\n", url.c_str());
});
h->get(url, seconds(1), 0, &ps, 5, "test/user-agent", address_v4::any()
@ -142,39 +144,123 @@ void print_http_header(std::map<std::string, std::string> const& headers)
for (std::map<std::string, std::string>::const_iterator i
= headers.begin(), end(headers.end()); i != end; ++i)
{
std::cerr << i->first << ": " << i->second << std::endl;
printf("%s: %s\n", i->first.c_str(), i->second.c_str());
}
}
void run_test(std::string url, int expect_size, int expect_status
, boost::system::error_code expect_error, std::vector<int> expect_counters);
enum expect_counters
{
connect_handler = 0,
handler = 1,
test_file_req = 2,
redirect_req = 3,
rel_redirect_req = 4,
inf_redirect_req = 5,
num_counters
};
TORRENT_TEST(http_connection)
{
std::string url_base = "http://10.0.0.2:8080";
run_test(url_base + "/non-existent", 0, 404, error_code(), { 1, 1 });
run_test(url_base + "/test_file", 1337, 200, error_code(), { 1, 1, 1});
run_test(url_base + "/redirect", 1337, 200, error_code(), { 2, 1, 1, 1 });
run_test(url_base + "/relative/redirect", 1337, 200, error_code(), {2, 1, 1, 0, 1});
run_test(url_base + "/infinite/redirect", 0, 301, error_code(asio::error::eof), {6, 1, 0, 0, 0, 6});
// we are on an IPv4 host, we can't connect to IPv6 addresses, make sure that
// error is correctly propagated
run_test("http://[ff::dead:beef]:8080/test_file", 0, -1, error_code(asio::error::address_family_not_supported)
, {0,1});
// this hostname will resolve to multiple IPs, all but one that we cannot
// connect to and the second one where we'll get the test file response. Make
// sure the http_connection correcly tries the second IP if the first one
// fails.
run_test("http://try-next.com:8080/test_file", 1337, 200, error_code(), { 1, 1, 1});
// make sure hostname lookup failures are passed through correctly
run_test("http://non-existent.com/test_file", 0, -1, asio::error::host_not_found, { 0, 1});
// run_test(url_base + "/password_protected", 1337, 200, error_code(), { 1, 1, 1});
// run_test(url_base + "/test_file.gz", 1337, 200, error_code(), { 1, 1, 1});
//#error test all proxies
//#error test https
//#error test chunked encoding
}
void run_test(std::string url, int expect_size, int expect_status
, boost::system::error_code expect_error, std::vector<int> expect_counters)
{
using sim::asio::ip::address_v4;
sim_config network_cfg;
sim::simulation sim{network_cfg};
// allow sparse expected counters
expect_counters.resize(num_counters, 0);
sim::asio::io_service web_server(sim, address_v4::from_string("10.0.0.2"));
sim::asio::io_service ios(sim, address_v4::from_string("10.0.0.1"));
sim::asio::io_service ipv6_host(sim, address_v6::from_string("ff::dead:beef"));
lt::resolver res(ios);
sim::http_server http(web_server, 8080);
sim::http_server http_v6(ipv6_host, 8080);
char data_buffer[4000];
std::generate(data_buffer, data_buffer + sizeof(data_buffer), &std::rand);
std::vector<int> counters(num_counters, 0);
http.register_handler("/test_file"
, [data_buffer](std::string method, std::string req
, [data_buffer,&counters](std::string method, std::string req
, std::map<std::string, std::string>& headers)
{
++counters[test_file_req];
print_http_header(headers);
TEST_EQUAL(headers["user-agent"], "test/user-agent");
TEST_EQUAL(method, "GET");
return sim::send_response(200, "OK", 1337).append(data_buffer, 1337);
});
int connect_handler_called = 0;
int handler_called = 0;
http.register_handler("/redirect"
, [data_buffer,&counters](std::string method, std::string req
, std::map<std::string, std::string>& headers)
{
++counters[redirect_req];
TEST_EQUAL(method, "GET");
return "HTTP/1.1 301 Moved Temporarily\r\n"
"Location: /test_file\r\n"
"\r\n";
});
int expect_connect_handler_called = 0;
int expect_handler_called = 0;
http.register_handler("/relative/redirect"
, [data_buffer,&counters](std::string method, std::string req
, std::map<std::string, std::string>& headers)
{
++counters[rel_redirect_req];
TEST_EQUAL(method, "GET");
return "HTTP/1.1 301 Moved Temporarily\r\n"
"Location: ../test_file\r\n"
"\r\n";
});
http.register_handler("/infinite/redirect"
, [data_buffer,&counters](std::string method, std::string req
, std::map<std::string, std::string>& headers)
{
++counters[inf_redirect_req];
TEST_EQUAL(method, "GET");
return "HTTP/1.1 301 Moved Temporarily\r\n"
"Location: /infinite/redirect\r\n"
"\r\n";
});
lt::aux::proxy_settings ps;
ps.hostname = "127.0.0.1";
@ -182,22 +268,21 @@ TORRENT_TEST(http_connection)
ps.password = "testpass";
ps.type = settings_pack::none;
auto c1 = run_test(ios, res, "http://10.0.0.2:8080/non-existent", NULL, 0, 404, error_code()
, ps, &connect_handler_called, &handler_called);
++expect_connect_handler_called;
++expect_handler_called;
auto c2 = run_test(ios, res, "http://10.0.0.2:8080/test_file", data_buffer, 1337, 200, error_code()
, ps, &connect_handler_called, &handler_called);
++expect_connect_handler_called;
++expect_handler_called;
auto c = test_request(ios, res, url, data_buffer, expect_size
, expect_status, expect_error, ps, &counters[connect_handler]
, &counters[handler]);
error_code e;
sim.run(e);
if (e) std::cerr << " run failed: " << e.message() << std::endl;
TEST_EQUAL(e, error_code());
TEST_EQUAL(connect_handler_called, expect_connect_handler_called);
TEST_EQUAL(handler_called, expect_handler_called);
TEST_EQUAL(counters.size(), expect_counters.size());
for (int i = 0; i < counters.size(); ++i)
{
if (counters[i] != expect_counters[i]) fprintf(stderr, "i=%d\n", i);
TEST_EQUAL(counters[i], expect_counters[i]);
}
}