blob: 3ae88b05032f5a8eda1102d39e50b71ce5c41b06 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/basictypes.h"
#include "base/message_loop/message_loop.h"
#include "chrome/browser/net/network_stats.h"
#include "net/base/net_errors.h"
#include "net/base/network_change_notifier.h"
#include "net/base/test_completion_callback.h"
#include "net/dns/host_resolver.h"
#include "net/dns/mock_host_resolver.h"
#include "net/socket/socket_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
namespace chrome_browser_net {
class NetworkStatsTest : public PlatformTest {
public:
NetworkStatsTest() {}
protected:
virtual void SetUp() {
net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
base::MessageLoop::current()->RunUntilIdle();
mock_writes_.clear();
mock_reads_.clear();
}
virtual void TearDown() {
net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
// Empty the current queue.
base::MessageLoop::current()->RunUntilIdle();
PlatformTest::TearDown();
}
void CreateToken(uint64 timestamp_micros,
const string& hash,
ProbePacket_Token* token) {
token->set_timestamp_micros(timestamp_micros);
token->mutable_hash()->assign(hash);
}
// DeterministicMockData defines the exact sequence of the read/write
// operations (specified by the last parameter of MockRead/MockWrite).
// |io_mode_write| is the IO mode for writing only. Reading is always async.
void MakeDeterministicMockData(uint32 max_tests,
uint32 max_probe_packets,
uint32 probe_bytes,
net::IoMode io_mode_write) {
// Only allow 0 or 1 test because the test 2 in NetworkStats is random.
DCHECK_LT(max_tests, 2U);
outputs_.resize(10);
ProbePacket probe_packet;
ProbeMessage probe_message;
probe_message.SetPacketHeader(ProbePacket_Type_HELLO_REQUEST,
&probe_packet);
probe_packet.set_group_id(0);
outputs_[0] = probe_message.MakeEncodedPacket(probe_packet);
mock_writes_.clear();
mock_writes_.push_back(net::MockWrite(
io_mode_write, &outputs_[0][0], outputs_[0].size(), 0));
// Add one probe_request.
probe_packet = ProbePacket(); // Clear all content.
ProbePacket_Token token;
CreateToken(1L, "1010", &token);
probe_message.GenerateProbeRequest(
token, 1, probe_bytes, 0, max_probe_packets, &probe_packet);
outputs_[1] = probe_message.MakeEncodedPacket(probe_packet);
mock_writes_.push_back(net::MockWrite(
io_mode_write, &outputs_[1][0], outputs_[1].size(), 2));
inputs_.resize(10);
mock_reads_.clear();
// Add a hello reply.
probe_packet = ProbePacket(); // Clear all content.
probe_message.SetPacketHeader(ProbePacket_Type_HELLO_REPLY, &probe_packet);
probe_packet.set_group_id(0);
CreateToken(1L, "1010", probe_packet.mutable_token());
inputs_[0] = probe_message.MakeEncodedPacket(probe_packet);
mock_reads_.push_back(
net::MockRead(net::ASYNC, &inputs_[0][0], inputs_[0].size(), 1));
for (uint32 i = 0; i < max_probe_packets; ++i) {
// Add a probe reply.
probe_packet = ProbePacket(); // Clear all content.
probe_message.SetPacketHeader(ProbePacket_Type_PROBE_REPLY,
&probe_packet);
int padding_size = probe_bytes - probe_packet.ByteSize() - 8;
probe_packet.mutable_padding()->append(
std::string(std::max(0, padding_size), 0));
probe_packet.mutable_header()->set_checksum(0);
probe_packet.set_group_id(1);
probe_packet.set_packet_index(i);
inputs_[1 + i] = probe_message.MakeEncodedPacket(probe_packet);
mock_reads_.push_back(net::MockRead(
net::ASYNC, &inputs_[1 + i][0], inputs_[1 + i].size(), 3 + i));
}
}
// Test NetworkStats::Start(...) method.
void TestStart(bool has_proxy,
uint32 max_tests,
uint32 max_probe_packets,
uint32 bytes,
net::IoMode io_mode) {
net::DeterministicMockClientSocketFactory mock_socket_factory;
MakeDeterministicMockData(max_tests, max_probe_packets, bytes, io_mode);
net::DeterministicSocketData test_data(
&mock_reads_[0], mock_reads_.size(),
&mock_writes_[0], mock_writes_.size());
mock_socket_factory.AddSocketDataProvider(&test_data);
NetworkStats* udp_stats_client = new NetworkStats(&mock_socket_factory);
udp_stats_client->maximum_tests_ = max_tests;
udp_stats_client->maximum_sequential_packets_ = max_probe_packets;
net::TestCompletionCallback cb;
scoped_ptr<net::MockHostResolver> host_resolver(
new net::MockHostResolver());
net::HostPortPair host_port_pair;
EXPECT_TRUE(udp_stats_client->Start(host_resolver.get(),
host_port_pair,
9999,
has_proxy,
bytes,
cb.callback()));
int num_packets_run = (max_tests + 1) * 2 + max_probe_packets - 1;
test_data.RunFor(num_packets_run);
int rv = cb.WaitForResult();
// Check there were no errors during connect/write/read to echo UDP server.
EXPECT_EQ(0, rv);
}
// Make one write and then |max_probe_packets| reads.
void MakeDelayedMockData(NetworkStats::TestType test_type,
uint32 probe_bytes,
uint32 pacing_interval_micros,
uint32 max_probe_packets,
net::IoMode io_mode) {
outputs_.resize(1);
ProbePacket probe_packet;
ProbeMessage probe_message;
mock_writes_.clear();
ProbePacket_Token token;
CreateToken(2L, "2a2b", &token);
switch (test_type) {
case NetworkStats::NON_PACED_PACKET_TEST:
pacing_interval_micros = 0;
break;
case NetworkStats::NAT_BIND_TEST:
// For NAT_BIND_TEST, we always set this to 1000000 to avoid the
// randomness in NetworkStats::SendProbeRequest() and to match
// the value chosen in TestStartOneTest() below.
pacing_interval_micros = 1000000;
break;
default: {} // Do nothing here.
}
probe_message.GenerateProbeRequest(token,
1, // current_test_index_ = 1.
probe_bytes,
pacing_interval_micros,
max_probe_packets,
&probe_packet);
outputs_[0] = probe_message.MakeEncodedPacket(probe_packet);
mock_writes_.push_back(
net::MockWrite(io_mode, &outputs_[0][0], outputs_[0].size()));
inputs_.resize(max_probe_packets);
mock_reads_.clear();
for (uint32 i = 0; i < max_probe_packets; ++i) {
// Add a probe reply.
probe_packet = ProbePacket(); // Clear all content.
probe_message.SetPacketHeader(ProbePacket_Type_PROBE_REPLY,
&probe_packet);
int padding_size = probe_bytes - probe_packet.ByteSize() - 8;
probe_packet.mutable_padding()->append(
std::string(std::max(0, padding_size), 0));
probe_packet.mutable_header()->set_checksum(0);
probe_packet.set_group_id(1);
probe_packet.set_packet_index(i);
inputs_[i] = probe_message.MakeEncodedPacket(probe_packet);
mock_reads_.push_back(
net::MockRead(io_mode, &inputs_[i][0], inputs_[i].size()));
}
}
// Test NetworkStats::StartOneTest(...) method.
void TestStartOneTest(bool has_proxy,
NetworkStats::TestType test_type,
uint32 bytes,
uint32 interval_micros,
uint32 max_probe_packets,
net::IoMode io_mode) {
net::MockClientSocketFactory mock_socket_factory;
MakeDelayedMockData(
test_type, bytes, interval_micros, max_probe_packets, io_mode);
net::DelayedSocketData test_data(1,
&mock_reads_[0],
mock_reads_.size(),
&mock_writes_[0],
mock_writes_.size());
mock_socket_factory.AddSocketDataProvider(&test_data);
NetworkStats* udp_stats_client = new NetworkStats(&mock_socket_factory);
udp_stats_client->maximum_tests_ = 1; // Only do one probe at a time.
udp_stats_client->maximum_sequential_packets_ = max_probe_packets;
udp_stats_client->maximum_NAT_packets_ = max_probe_packets;
// For NAT_BIND_TEST, we always set this to 1 (second) to avoid the
// randomness in NetworkStats::SendProbeRequest().
udp_stats_client->maximum_NAT_idle_seconds_ = 1;
udp_stats_client->start_test_after_connect_ = false;
udp_stats_client->inter_arrival_time_ =
base::TimeDelta::FromMicroseconds(interval_micros);
CreateToken(2L, "2a2b", &udp_stats_client->token_);
net::TestCompletionCallback cb;
scoped_ptr<net::MockHostResolver> host_resolver(
new net::MockHostResolver());
net::HostPortPair host_port_pair;
EXPECT_TRUE(udp_stats_client->Start(host_resolver.get(),
host_port_pair,
9999,
has_proxy,
bytes,
cb.callback()));
// Test need to be added after Start() because Start() will reset
// test_sequence_
udp_stats_client->test_sequence_.push_back(test_type);
udp_stats_client->current_test_index_ = 1;
// Wait for host resolving and check if there were no errors during
// connect/write/read to UDP server.
int rv = cb.WaitForResult();
EXPECT_EQ(0, rv);
udp_stats_client->ReadData();
udp_stats_client->StartOneTest();
rv = cb.WaitForResult();
EXPECT_EQ(0, rv);
}
base::MessageLoopForIO message_loop_;
std::vector<std::string> inputs_;
std::vector<std::string> outputs_;
std::vector<net::MockRead> mock_reads_;
std::vector<net::MockWrite> mock_writes_;
};
TEST_F(NetworkStatsTest, ProbeTest100BHasProxyGetToken) {
TestStart(true, 0, 1, 100, net::ASYNC);
}
TEST_F(NetworkStatsTest, ProbeTest500BHasNoProxyGetTokenSync) {
TestStart(false, 0, 1, 500, net::SYNCHRONOUS);
}
TEST_F(NetworkStatsTest, ProbeTest100BHasNoProxyOneTest) {
TestStart(false, 1, 1, 100, net::ASYNC);
}
TEST_F(NetworkStatsTest, ProbeTest100BHasNoProxyOneTestSync) {
TestStart(false, 1, 1, 100, net::SYNCHRONOUS);
}
TEST_F(NetworkStatsTest, ProbeTest100BHasProxyOneTest) {
TestStart(true, 1, 1, 100, net::ASYNC);
}
TEST_F(NetworkStatsTest, ProbeTest100BHasProxyOneTestSync) {
TestStart(true, 1, 1, 100, net::SYNCHRONOUS);
}
TEST_F(NetworkStatsTest, ProbeTest500BHasProxyOneTest) {
TestStart(true, 1, 1, 500, net::ASYNC);
}
TEST_F(NetworkStatsTest, ProbeTest500BHasNoProxyOneTestSync) {
TestStart(false, 1, 1, 500, net::SYNCHRONOUS);
}
TEST_F(NetworkStatsTest, ProbeTest500BHasNoProxyOneTest) {
TestStart(false, 1, 1, 500, net::ASYNC);
}
TEST_F(NetworkStatsTest, ProbeTest500BHasProxyOneTestSync) {
TestStart(true, 1, 1, 500, net::SYNCHRONOUS);
}
TEST_F(NetworkStatsTest, ProbeTest1200BHasProxyOneTest) {
TestStart(true, 1, 1, 1200, net::ASYNC);
}
TEST_F(NetworkStatsTest, ProbeTest1200BHasNoProxyOneTestSync) {
TestStart(false, 1, 1, 1200, net::SYNCHRONOUS);
}
TEST_F(NetworkStatsTest, ProbeTest1200BHasNoProxyOneTest) {
TestStart(false, 1, 1, 1200, net::ASYNC);
}
TEST_F(NetworkStatsTest, ProbeTest1200BHasProxyOneTestSync) {
TestStart(true, 1, 1, 1200, net::SYNCHRONOUS);
}
TEST_F(NetworkStatsTest, ProbeTest100BHasNoProxyOneTestMultiPackets) {
TestStart(false, 1, 4, 100, net::ASYNC);
}
TEST_F(NetworkStatsTest, ProbeTest1200BHasProxyOneTestMultiPacketsSync) {
TestStart(true, 1, 4, 1200, net::SYNCHRONOUS);
}
TEST_F(NetworkStatsTest, StartNonPacedTest100BHasProxy) {
TestStartOneTest(
true, NetworkStats::NON_PACED_PACKET_TEST, 100, 0, 1, net::ASYNC);
}
TEST_F(NetworkStatsTest, StartNonPacedTest100BHasNoProxySync) {
TestStartOneTest(
false, NetworkStats::NON_PACED_PACKET_TEST, 100, 0, 1, net::SYNCHRONOUS);
}
TEST_F(NetworkStatsTest, StartNonPacedTest500BHasNoProxy) {
TestStartOneTest(
false, NetworkStats::NON_PACED_PACKET_TEST, 500, 3, 1, net::ASYNC);
}
TEST_F(NetworkStatsTest, StartNonPacedTest1200BHasProxySync) {
TestStartOneTest(
true, NetworkStats::NON_PACED_PACKET_TEST, 1200, 1, 1, net::SYNCHRONOUS);
}
TEST_F(NetworkStatsTest, StartNonPacedTest500BHasNoProxyMulti) {
TestStartOneTest(
false, NetworkStats::NON_PACED_PACKET_TEST, 500, 2, 3, net::ASYNC);
}
TEST_F(NetworkStatsTest, StartNonPacedTest1200BHasProxySyncMulti) {
TestStartOneTest(
true, NetworkStats::NON_PACED_PACKET_TEST, 1200, 1, 4, net::SYNCHRONOUS);
}
TEST_F(NetworkStatsTest, StartPacedTest100BHasProxy) {
TestStartOneTest(
true, NetworkStats::PACED_PACKET_TEST, 100, 0, 1, net::ASYNC);
}
TEST_F(NetworkStatsTest, StartPacedTest100BHasNoProxySync) {
TestStartOneTest(
false, NetworkStats::PACED_PACKET_TEST, 100, 0, 1, net::SYNCHRONOUS);
}
TEST_F(NetworkStatsTest, StartPacedTest500BHasNoProxy) {
TestStartOneTest(
false, NetworkStats::PACED_PACKET_TEST, 500, 3, 1, net::ASYNC);
}
TEST_F(NetworkStatsTest, StartPacedTest1200BHasProxySync) {
TestStartOneTest(
true, NetworkStats::PACED_PACKET_TEST, 1200, 1, 1, net::SYNCHRONOUS);
}
TEST_F(NetworkStatsTest, StartPacedTest500BHasNoProxyMulti) {
TestStartOneTest(
false, NetworkStats::PACED_PACKET_TEST, 500, 2, 3, net::ASYNC);
}
TEST_F(NetworkStatsTest, StartPacedTest1200BHasProxySyncMulti) {
TestStartOneTest(
true, NetworkStats::PACED_PACKET_TEST, 1200, 1, 4, net::SYNCHRONOUS);
}
TEST_F(NetworkStatsTest, StartNATBindTest100BHasProxy) {
TestStartOneTest(true, NetworkStats::NAT_BIND_TEST, 100, 0, 1, net::ASYNC);
}
TEST_F(NetworkStatsTest, StartNATBindTest100BHasNoProxySync) {
TestStartOneTest(
false, NetworkStats::NAT_BIND_TEST, 100, 3, 1, net::SYNCHRONOUS);
}
TEST_F(NetworkStatsTest, StartNATBindTest500BHasNoProxy) {
TestStartOneTest(false, NetworkStats::NAT_BIND_TEST, 500, 0, 2, net::ASYNC);
}
TEST_F(NetworkStatsTest, StartNATBindTest1200BHasProxySync) {
TestStartOneTest(
true, NetworkStats::NAT_BIND_TEST, 1200, 3, 2, net::SYNCHRONOUS);
}
} // namespace chrome_browser_net