1457 lines
66 KiB
C++
1457 lines
66 KiB
C++
//
|
|
// Copyright (C) 2015 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
#include "shill/connection_diagnostics.h"
|
|
|
|
#include <net/if_arp.h>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include "shill/arp_client.h"
|
|
#include "shill/arp_client_test_helper.h"
|
|
#include "shill/icmp_session.h"
|
|
#include "shill/mock_arp_client.h"
|
|
#include "shill/mock_connection.h"
|
|
#include "shill/mock_control.h"
|
|
#include "shill/mock_device_info.h"
|
|
#include "shill/mock_dns_client.h"
|
|
#include "shill/mock_dns_client_factory.h"
|
|
#include "shill/mock_event_dispatcher.h"
|
|
#include "shill/mock_icmp_session.h"
|
|
#include "shill/mock_icmp_session_factory.h"
|
|
#include "shill/mock_manager.h"
|
|
#include "shill/mock_metrics.h"
|
|
#include "shill/mock_portal_detector.h"
|
|
#include "shill/mock_routing_table.h"
|
|
#include "shill/net/mock_rtnl_handler.h"
|
|
|
|
using base::Bind;
|
|
using base::Callback;
|
|
using base::Unretained;
|
|
using std::string;
|
|
using std::vector;
|
|
using testing::_;
|
|
using testing::NiceMock;
|
|
using testing::Return;
|
|
using testing::ReturnRef;
|
|
using testing::SetArgumentPointee;
|
|
using testing::Test;
|
|
|
|
namespace {
|
|
const char kInterfaceName[] = "int0";
|
|
const char kDNSServer0[] = "8.8.8.8";
|
|
const char kDNSServer1[] = "8.8.4.4";
|
|
const char kURL[] = "http://www.gstatic.com/generate_204";
|
|
const char kLocalMacAddressASCIIString[] = "123456";
|
|
const char kArpReplySenderMacAddressASCIIString[] = "345678";
|
|
const char* kDNSServers[] = {kDNSServer0, kDNSServer1};
|
|
const shill::IPAddress kIPv4LocalAddress("100.200.43.22");
|
|
const shill::IPAddress kIPv4ServerAddress("8.8.8.8");
|
|
const shill::IPAddress kIPv6ServerAddress("fe80::1aa9:5ff:7ebf:14c5");
|
|
const shill::IPAddress kIPv4GatewayAddress("192.168.1.1");
|
|
const shill::IPAddress kIPv6GatewayAddress("fee2::11b2:53f:13be:125e");
|
|
const vector<base::TimeDelta> kEmptyResult;
|
|
const vector<base::TimeDelta> kNonEmptyResult{
|
|
base::TimeDelta::FromMilliseconds(10)};
|
|
} // namespace
|
|
|
|
namespace shill {
|
|
|
|
MATCHER_P(IsSameIPAddress, ip_addr, "") {
|
|
return arg.Equals(ip_addr);
|
|
}
|
|
|
|
MATCHER_P(IsEventList, expected_events, "") {
|
|
// Match on type, phase, and result, but not message.
|
|
if (arg.size() != expected_events.size()) {
|
|
return false;
|
|
}
|
|
for (size_t i = 0; i < expected_events.size(); ++i) {
|
|
if (expected_events[i].type != arg[i].type ||
|
|
expected_events[i].phase != arg[i].phase ||
|
|
expected_events[i].result != arg[i].result) {
|
|
*result_listener << "\n=== Mismatch found on expected event index " << i
|
|
<< " ===";
|
|
*result_listener << "\nExpected: "
|
|
<< ConnectionDiagnostics::EventToString(
|
|
expected_events[i]);
|
|
*result_listener << "\n Actual: "
|
|
<< ConnectionDiagnostics::EventToString(arg[i]);
|
|
*result_listener << "\nExpected connection diagnostics events:";
|
|
for (const auto& expected_event : expected_events) {
|
|
*result_listener << "\n" << ConnectionDiagnostics::EventToString(
|
|
expected_event);
|
|
}
|
|
*result_listener << "\nActual connection diagnostics events:";
|
|
for (const auto& actual_event : expected_events) {
|
|
*result_listener << "\n"
|
|
<< ConnectionDiagnostics::EventToString(actual_event);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
MATCHER_P4(IsArpRequest, local_ip, remote_ip, local_mac, remote_mac, "") {
|
|
if (local_ip.Equals(arg.local_ip_address()) &&
|
|
remote_ip.Equals(arg.remote_ip_address()) &&
|
|
local_mac.Equals(arg.local_mac_address()) &&
|
|
remote_mac.Equals(arg.remote_mac_address())) {
|
|
return true;
|
|
}
|
|
|
|
if (!local_ip.Equals(arg.local_ip_address())) {
|
|
*result_listener << "Local IP '" << arg.local_ip_address().ToString()
|
|
<< "' (expected '" << local_ip.ToString() << "').";
|
|
}
|
|
|
|
if (!remote_ip.Equals(arg.remote_ip_address())) {
|
|
*result_listener << "Remote IP '" << arg.remote_ip_address().ToString()
|
|
<< "' (expected '" << remote_ip.ToString() << "').";
|
|
}
|
|
|
|
if (!local_mac.Equals(arg.local_mac_address())) {
|
|
*result_listener << "Local MAC '" << arg.local_mac_address().HexEncode()
|
|
<< "' (expected " << local_mac.HexEncode() << ")'.";
|
|
}
|
|
|
|
if (!remote_mac.Equals(arg.remote_mac_address())) {
|
|
*result_listener << "Remote MAC '" << arg.remote_mac_address().HexEncode()
|
|
<< "' (expected " << remote_mac.HexEncode() << ")'.";
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
class ConnectionDiagnosticsTest : public Test {
|
|
public:
|
|
ConnectionDiagnosticsTest()
|
|
: interface_name_(kInterfaceName),
|
|
dns_servers_(kDNSServers, kDNSServers + 2),
|
|
local_ip_address_(kIPv4LocalAddress),
|
|
gateway_ipv4_address_(kIPv4GatewayAddress),
|
|
gateway_ipv6_address_(kIPv6GatewayAddress),
|
|
local_mac_address_(string(kLocalMacAddressASCIIString), false),
|
|
metrics_(&dispatcher_),
|
|
manager_(&control_, &dispatcher_, &metrics_),
|
|
device_info_(&control_, &dispatcher_, &metrics_, &manager_),
|
|
connection_(new NiceMock<MockConnection>(&device_info_)),
|
|
connection_diagnostics_(connection_, &dispatcher_, &metrics_,
|
|
&device_info_,
|
|
callback_target_.result_callback()),
|
|
portal_detector_(new NiceMock<MockPortalDetector>(connection_)) {}
|
|
virtual ~ConnectionDiagnosticsTest() {}
|
|
|
|
virtual void SetUp() {
|
|
ASSERT_EQ(IPAddress::kFamilyIPv4, kIPv4LocalAddress.family());
|
|
ASSERT_EQ(IPAddress::kFamilyIPv4, kIPv4ServerAddress.family());
|
|
ASSERT_EQ(IPAddress::kFamilyIPv4, kIPv4GatewayAddress.family());
|
|
ASSERT_EQ(IPAddress::kFamilyIPv6, kIPv6ServerAddress.family());
|
|
ASSERT_EQ(IPAddress::kFamilyIPv6, kIPv6GatewayAddress.family());
|
|
|
|
arp_client_ = new NiceMock<MockArpClient>();
|
|
client_test_helper_.reset(new ArpClientTestHelper(arp_client_));
|
|
icmp_session_ = new NiceMock<MockIcmpSession>(&dispatcher_);
|
|
connection_diagnostics_.arp_client_.reset(arp_client_); // Passes ownership
|
|
connection_diagnostics_.icmp_session_.reset(
|
|
icmp_session_); // Passes ownership
|
|
connection_diagnostics_.portal_detector_.reset(
|
|
portal_detector_); // Passes ownership
|
|
connection_diagnostics_.routing_table_ = &routing_table_;
|
|
connection_diagnostics_.rtnl_handler_ = &rtnl_handler_;
|
|
ON_CALL(*connection_.get(), interface_name())
|
|
.WillByDefault(ReturnRef(interface_name_));
|
|
ON_CALL(*connection_.get(), dns_servers())
|
|
.WillByDefault(ReturnRef(dns_servers_));
|
|
ON_CALL(*connection_.get(), gateway())
|
|
.WillByDefault(ReturnRef(gateway_ipv4_address_));
|
|
ON_CALL(*connection_.get(), local())
|
|
.WillByDefault(ReturnRef(local_ip_address_));
|
|
connection_diagnostics_.dns_client_factory_ =
|
|
MockDNSClientFactory::GetInstance();
|
|
connection_diagnostics_.icmp_session_factory_ =
|
|
MockIcmpSessionFactory::GetInstance();
|
|
}
|
|
|
|
virtual void TearDown() {}
|
|
|
|
protected:
|
|
class CallbackTarget {
|
|
public:
|
|
CallbackTarget()
|
|
: result_callback_(
|
|
Bind(&CallbackTarget::ResultCallback, Unretained(this))) {}
|
|
|
|
MOCK_METHOD2(ResultCallback,
|
|
void(const string&,
|
|
const vector<ConnectionDiagnostics::Event>&));
|
|
|
|
Callback<void(const string&, const vector<ConnectionDiagnostics::Event>&)>&
|
|
result_callback() {
|
|
return result_callback_;
|
|
}
|
|
|
|
private:
|
|
Callback<void(const string&, const vector<ConnectionDiagnostics::Event>&)>
|
|
result_callback_;
|
|
};
|
|
|
|
CallbackTarget& callback_target() {
|
|
return callback_target_;
|
|
}
|
|
|
|
void UseIPv6Gateway() {
|
|
EXPECT_CALL(*connection_.get(), gateway())
|
|
.WillRepeatedly(ReturnRef(gateway_ipv6_address_));
|
|
}
|
|
|
|
void AddExpectedEvent(ConnectionDiagnostics::Type type,
|
|
ConnectionDiagnostics::Phase phase,
|
|
ConnectionDiagnostics::Result result) {
|
|
expected_events_.push_back(
|
|
ConnectionDiagnostics::Event(type, phase, result, ""));
|
|
}
|
|
|
|
void AddActualEvent(ConnectionDiagnostics::Type type,
|
|
ConnectionDiagnostics::Phase phase,
|
|
ConnectionDiagnostics::Result result) {
|
|
connection_diagnostics_.diagnostic_events_.push_back(
|
|
ConnectionDiagnostics::Event(type, phase, result, ""));
|
|
}
|
|
|
|
bool DoesPreviousEventMatch(ConnectionDiagnostics::Type type,
|
|
ConnectionDiagnostics::Phase phase,
|
|
ConnectionDiagnostics::Result result,
|
|
size_t num_events_ago) {
|
|
return connection_diagnostics_.DoesPreviousEventMatch(type, phase, result,
|
|
num_events_ago);
|
|
}
|
|
|
|
// This direct call to ConnectionDiagnostics::Start does not mock the
|
|
// return
|
|
// value of MockPortalDetector::CreatePortalDetector, so this will crash
|
|
// the
|
|
// test if PortalDetector::Start is actually called. Use only for testing
|
|
// bad input to ConnectionDiagnostics::Start.
|
|
bool Start(const string& url_string) {
|
|
return connection_diagnostics_.Start(url_string);
|
|
}
|
|
|
|
void VerifyStopped() {
|
|
EXPECT_FALSE(connection_diagnostics_.running());
|
|
EXPECT_EQ(0, connection_diagnostics_.num_dns_attempts_);
|
|
EXPECT_TRUE(connection_diagnostics_.diagnostic_events_.empty());
|
|
EXPECT_FALSE(connection_diagnostics_.dns_client_.get());
|
|
EXPECT_FALSE(connection_diagnostics_.arp_client_->IsStarted());
|
|
EXPECT_FALSE(connection_diagnostics_.icmp_session_->IsStarted());
|
|
EXPECT_FALSE(connection_diagnostics_.portal_detector_.get());
|
|
EXPECT_FALSE(connection_diagnostics_.receive_response_handler_.get());
|
|
EXPECT_FALSE(connection_diagnostics_.neighbor_msg_listener_.get());
|
|
EXPECT_TRUE(
|
|
connection_diagnostics_.id_to_pending_dns_server_icmp_session_.empty());
|
|
EXPECT_FALSE(connection_diagnostics_.target_url_.get());
|
|
EXPECT_TRUE(connection_diagnostics_.route_query_callback_.IsCancelled());
|
|
EXPECT_TRUE(
|
|
connection_diagnostics_.route_query_timeout_callback_.IsCancelled());
|
|
EXPECT_TRUE(
|
|
connection_diagnostics_.arp_reply_timeout_callback_.IsCancelled());
|
|
EXPECT_TRUE(connection_diagnostics_.neighbor_request_timeout_callback_
|
|
.IsCancelled());
|
|
}
|
|
|
|
void ExpectIcmpSessionStop() {
|
|
EXPECT_CALL(*icmp_session_, Stop());
|
|
}
|
|
|
|
void ExpectPortalDetectionStartSuccess(const string& url_string) {
|
|
AddExpectedEvent(ConnectionDiagnostics::kTypePortalDetection,
|
|
ConnectionDiagnostics::kPhaseStart,
|
|
ConnectionDiagnostics::kResultSuccess);
|
|
EXPECT_CALL(*portal_detector_, Start(url_string)).WillOnce(Return(true));
|
|
EXPECT_FALSE(connection_diagnostics_.running());
|
|
EXPECT_TRUE(connection_diagnostics_.diagnostic_events_.empty());
|
|
EXPECT_TRUE(Start(url_string));
|
|
EXPECT_TRUE(connection_diagnostics_.running());
|
|
}
|
|
|
|
void ExpectPortalDetectionEndContentPhaseSuccess() {
|
|
ExpectPortalDetectionEnd(
|
|
ConnectionDiagnostics::kPhasePortalDetectionEndContent,
|
|
ConnectionDiagnostics::kResultSuccess,
|
|
ConnectivityTrial::kPhaseContent,
|
|
ConnectivityTrial::kStatusSuccess);
|
|
}
|
|
|
|
void ExpectPortalDetectionEndContentPhaseFailure() {
|
|
ExpectPortalDetectionEnd(
|
|
ConnectionDiagnostics::kPhasePortalDetectionEndContent,
|
|
ConnectionDiagnostics::kResultFailure,
|
|
ConnectivityTrial::kPhaseContent,
|
|
ConnectivityTrial::kStatusFailure);
|
|
}
|
|
|
|
void ExpectPortalDetectionEndDNSPhaseFailure() {
|
|
ExpectPortalDetectionEnd(ConnectionDiagnostics::kPhasePortalDetectionEndDNS,
|
|
ConnectionDiagnostics::kResultFailure,
|
|
ConnectivityTrial::kPhaseDNS,
|
|
ConnectivityTrial::kStatusFailure);
|
|
}
|
|
|
|
void ExpectPortalDetectionEndDNSPhaseTimeout() {
|
|
ExpectPortalDetectionEnd(ConnectionDiagnostics::kPhasePortalDetectionEndDNS,
|
|
ConnectionDiagnostics::kResultTimeout,
|
|
ConnectivityTrial::kPhaseDNS,
|
|
ConnectivityTrial::kStatusTimeout);
|
|
}
|
|
|
|
void ExpectPortalDetectionEndHTTPPhaseFailure() {
|
|
ExpectPortalDetectionEnd(
|
|
ConnectionDiagnostics::kPhasePortalDetectionEndOther,
|
|
ConnectionDiagnostics::kResultFailure,
|
|
ConnectivityTrial::kPhaseHTTP,
|
|
ConnectivityTrial::kStatusFailure);
|
|
}
|
|
|
|
void ExpectPingDNSServersStartSuccess() {
|
|
ExpectPingDNSSeversStart(true, "");
|
|
}
|
|
|
|
void ExpectPingDNSSeversStartFailureAllAddressesInvalid() {
|
|
ExpectPingDNSSeversStart(false,
|
|
ConnectionDiagnostics::kIssueDNSServersInvalid);
|
|
}
|
|
|
|
void ExpectPingDNSSeversStartFailureAllIcmpSessionsFailed() {
|
|
ExpectPingDNSSeversStart(false, ConnectionDiagnostics::kIssueInternalError);
|
|
}
|
|
|
|
void ExpectPingDNSServersEndSuccessRetriesLeft() {
|
|
ExpectPingDNSServersEndSuccess(true);
|
|
}
|
|
|
|
void ExpectPingDNSServersEndSuccessNoRetriesLeft() {
|
|
ExpectPingDNSServersEndSuccess(false);
|
|
}
|
|
|
|
void ExpectPingDNSServersEndFailure() {
|
|
AddExpectedEvent(ConnectionDiagnostics::kTypePingDNSServers,
|
|
ConnectionDiagnostics::kPhaseEnd,
|
|
ConnectionDiagnostics::kResultFailure);
|
|
// Post task to find DNS server route only after all (i.e. 2) pings are
|
|
// done.
|
|
connection_diagnostics_.OnPingDNSServerComplete(0, kEmptyResult);
|
|
EXPECT_CALL(dispatcher_, PostTask(_));
|
|
connection_diagnostics_.OnPingDNSServerComplete(1, kEmptyResult);
|
|
}
|
|
|
|
void ExpectResolveTargetServerIPAddressStartSuccess(
|
|
IPAddress::Family family) {
|
|
AddExpectedEvent(ConnectionDiagnostics::kTypeResolveTargetServerIP,
|
|
ConnectionDiagnostics::kPhaseStart,
|
|
ConnectionDiagnostics::kResultSuccess);
|
|
ASSERT_FALSE(family == IPAddress::kFamilyUnknown);
|
|
|
|
dns_client_ = new NiceMock<MockDNSClient>();
|
|
EXPECT_CALL(*connection_.get(), IsIPv6())
|
|
.WillOnce(Return(family == IPAddress::kFamilyIPv6));
|
|
EXPECT_CALL(
|
|
*MockDNSClientFactory::GetInstance(),
|
|
CreateDNSClient(family, kInterfaceName, dns_servers_,
|
|
ConnectionDiagnostics::kDNSTimeoutSeconds * 1000,
|
|
&dispatcher_, _))
|
|
.WillOnce(Return(dns_client_)); // Passes ownership
|
|
EXPECT_CALL(*dns_client_,
|
|
Start(connection_diagnostics_.target_url_->host(), _))
|
|
.WillOnce(Return(true));
|
|
connection_diagnostics_.ResolveTargetServerIPAddress(dns_servers_);
|
|
}
|
|
|
|
void ExpectResolveTargetServerIPAddressEndSuccess(
|
|
const IPAddress& resolved_address) {
|
|
ExpectResolveTargetServerIPAddressEnd(ConnectionDiagnostics::kResultSuccess,
|
|
resolved_address);
|
|
}
|
|
|
|
void ExpectResolveTargetServerIPAddressEndTimeout() {
|
|
ExpectResolveTargetServerIPAddressEnd(ConnectionDiagnostics::kResultTimeout,
|
|
IPAddress(IPAddress::kFamilyIPv4));
|
|
}
|
|
|
|
void ExpectResolveTargetServerIPAddressEndFailure() {
|
|
ExpectResolveTargetServerIPAddressEnd(ConnectionDiagnostics::kResultFailure,
|
|
IPAddress(IPAddress::kFamilyIPv4));
|
|
}
|
|
|
|
void ExpectPingHostStartSuccess(ConnectionDiagnostics::Type ping_event_type,
|
|
const IPAddress& address) {
|
|
AddExpectedEvent(ping_event_type, ConnectionDiagnostics::kPhaseStart,
|
|
ConnectionDiagnostics::kResultSuccess);
|
|
EXPECT_CALL(*icmp_session_, Start(IsSameIPAddress(address), _))
|
|
.WillOnce(Return(true));
|
|
connection_diagnostics_.PingHost(address);
|
|
}
|
|
|
|
void ExpectPingHostStartFailure(ConnectionDiagnostics::Type ping_event_type,
|
|
const IPAddress& address) {
|
|
AddExpectedEvent(ping_event_type, ConnectionDiagnostics::kPhaseStart,
|
|
ConnectionDiagnostics::kResultFailure);
|
|
EXPECT_CALL(*icmp_session_, Start(IsSameIPAddress(address), _))
|
|
.WillOnce(Return(false));
|
|
EXPECT_CALL(metrics_, NotifyConnectionDiagnosticsIssue(
|
|
ConnectionDiagnostics::kIssueInternalError));
|
|
EXPECT_CALL(callback_target(),
|
|
ResultCallback(ConnectionDiagnostics::kIssueInternalError,
|
|
IsEventList(expected_events_)));
|
|
connection_diagnostics_.PingHost(address);
|
|
}
|
|
|
|
void ExpectPingHostEndSuccess(ConnectionDiagnostics::Type ping_event_type,
|
|
const IPAddress& address) {
|
|
AddExpectedEvent(ping_event_type, ConnectionDiagnostics::kPhaseEnd,
|
|
ConnectionDiagnostics::kResultSuccess);
|
|
const string& issue =
|
|
ping_event_type == ConnectionDiagnostics::kTypePingGateway
|
|
? ConnectionDiagnostics::kIssueGatewayUpstream
|
|
: ConnectionDiagnostics::kIssueHTTPBrokenPortal;
|
|
EXPECT_CALL(metrics_, NotifyConnectionDiagnosticsIssue(issue));
|
|
EXPECT_CALL(callback_target(),
|
|
ResultCallback(issue, IsEventList(expected_events_)));
|
|
connection_diagnostics_.OnPingHostComplete(ping_event_type, address,
|
|
kNonEmptyResult);
|
|
}
|
|
|
|
void ExpectPingHostEndFailure(ConnectionDiagnostics::Type ping_event_type,
|
|
const IPAddress& address) {
|
|
AddExpectedEvent(ping_event_type, ConnectionDiagnostics::kPhaseEnd,
|
|
ConnectionDiagnostics::kResultFailure);
|
|
// Next action is either to find a route to the target web server, find an
|
|
// ARP entry for the IPv4 gateway, or find a neighbor table entry for the
|
|
// IPv6 gateway.
|
|
EXPECT_CALL(dispatcher_, PostTask(_));
|
|
connection_diagnostics_.OnPingHostComplete(ping_event_type, address,
|
|
kEmptyResult);
|
|
}
|
|
|
|
void ExpectFindRouteToHostStartSuccess(const IPAddress& address) {
|
|
AddExpectedEvent(ConnectionDiagnostics::kTypeFindRoute,
|
|
ConnectionDiagnostics::kPhaseStart,
|
|
ConnectionDiagnostics::kResultSuccess);
|
|
EXPECT_CALL(routing_table_,
|
|
RequestRouteToHost(IsSameIPAddress(address),
|
|
connection_->interface_index(), _, _,
|
|
connection_->table_id()))
|
|
.WillOnce(Return(true));
|
|
EXPECT_CALL(
|
|
dispatcher_,
|
|
PostDelayedTask(
|
|
_, ConnectionDiagnostics::kRouteQueryTimeoutSeconds * 1000));
|
|
connection_diagnostics_.FindRouteToHost(address);
|
|
EXPECT_FALSE(
|
|
connection_diagnostics_.route_query_timeout_callback_.IsCancelled());
|
|
}
|
|
|
|
void ExpectFindRouteToHostEndSuccess(const IPAddress& address_queried,
|
|
bool is_local_address) {
|
|
AddExpectedEvent(ConnectionDiagnostics::kTypeFindRoute,
|
|
ConnectionDiagnostics::kPhaseEnd,
|
|
ConnectionDiagnostics::kResultSuccess);
|
|
|
|
IPAddress gateway(IPAddress::kFamilyIPv4);
|
|
if (is_local_address) {
|
|
gateway.SetAddressToDefault();
|
|
} else {
|
|
// Could be an IPv6 address, but we instrument this later with the
|
|
// argument passed to ExpectPingHostStartSuccess.
|
|
gateway = gateway_ipv4_address_;
|
|
}
|
|
|
|
// Next action is either to ping the gateway, find an ARP table entry for
|
|
// the local IPv4 web server, or find a neighbor table entry for the local
|
|
// IPv6 web server.
|
|
EXPECT_CALL(dispatcher_, PostTask(_));
|
|
RoutingTableEntry entry(
|
|
address_queried, IPAddress(address_queried.family()), gateway, 0,
|
|
RT_SCOPE_UNIVERSE, true, connection_->table_id(), -1);
|
|
connection_diagnostics_.OnRouteQueryResponse(connection_->interface_index(),
|
|
entry);
|
|
}
|
|
|
|
void ExpectFindRouteToHostEndFailure() {
|
|
AddExpectedEvent(ConnectionDiagnostics::kTypeFindRoute,
|
|
ConnectionDiagnostics::kPhaseEnd,
|
|
ConnectionDiagnostics::kResultFailure);
|
|
EXPECT_CALL(metrics_, NotifyConnectionDiagnosticsIssue(
|
|
ConnectionDiagnostics::kIssueRouting));
|
|
EXPECT_CALL(callback_target(),
|
|
ResultCallback(ConnectionDiagnostics::kIssueRouting,
|
|
IsEventList(expected_events_)));
|
|
connection_diagnostics_.OnRouteQueryTimeout();
|
|
}
|
|
|
|
void ExpectArpTableLookupStartSuccessEndSuccess(const IPAddress& address,
|
|
bool is_gateway) {
|
|
ExpectArpTableLookup(address, true, is_gateway);
|
|
}
|
|
|
|
void ExpectArpTableLookupStartSuccessEndFailure(const IPAddress& address) {
|
|
ExpectArpTableLookup(address, false, false);
|
|
}
|
|
|
|
void ExpectNeighborTableLookupStartSuccess(const IPAddress& address) {
|
|
AddExpectedEvent(ConnectionDiagnostics::kTypeNeighborTableLookup,
|
|
ConnectionDiagnostics::kPhaseStart,
|
|
ConnectionDiagnostics::kResultSuccess);
|
|
EXPECT_CALL(rtnl_handler_, RequestDump(RTNLHandler::kRequestNeighbor));
|
|
EXPECT_CALL(
|
|
dispatcher_,
|
|
PostDelayedTask(
|
|
_,
|
|
ConnectionDiagnostics::kNeighborTableRequestTimeoutSeconds * 1000));
|
|
connection_diagnostics_.FindNeighborTableEntry(address);
|
|
}
|
|
|
|
void ExpectNeighborTableLookupEndSuccess(const IPAddress& address_queried,
|
|
bool is_gateway) {
|
|
AddExpectedEvent(ConnectionDiagnostics::kTypeNeighborTableLookup,
|
|
ConnectionDiagnostics::kPhaseEnd,
|
|
ConnectionDiagnostics::kResultSuccess);
|
|
RTNLMessage msg(RTNLMessage::kTypeNeighbor, RTNLMessage::kModeAdd, 0, 0, 0,
|
|
connection_->interface_index(), IPAddress::kFamilyIPv6);
|
|
msg.set_neighbor_status(
|
|
RTNLMessage::NeighborStatus(NUD_REACHABLE, 0, NDA_DST));
|
|
msg.SetAttribute(NDA_DST, address_queried.address());
|
|
const string& issue =
|
|
is_gateway ? ConnectionDiagnostics::kIssueGatewayNotResponding
|
|
: ConnectionDiagnostics::kIssueServerNotResponding;
|
|
EXPECT_CALL(metrics_, NotifyConnectionDiagnosticsIssue(issue));
|
|
EXPECT_CALL(callback_target(),
|
|
ResultCallback(issue, IsEventList(expected_events_)));
|
|
connection_diagnostics_.OnNeighborMsgReceived(address_queried, msg);
|
|
}
|
|
|
|
void ExpectNeighborTableLookupEndFailureNotReachable(
|
|
const IPAddress& address_queried, bool is_gateway) {
|
|
ExpectNeighborTableLookupEndFailure(address_queried, is_gateway, false);
|
|
}
|
|
|
|
void ExpectNeighborTableLookupEndFailureNoEntry(
|
|
const IPAddress& address_queried, bool is_gateway) {
|
|
ExpectNeighborTableLookupEndFailure(address_queried, is_gateway, true);
|
|
}
|
|
|
|
void ExpectCheckIPCollisionStartSuccess() {
|
|
AddExpectedEvent(ConnectionDiagnostics::kTypeIPCollisionCheck,
|
|
ConnectionDiagnostics::kPhaseStart,
|
|
ConnectionDiagnostics::kResultSuccess);
|
|
EXPECT_CALL(device_info_, GetMACAddress(connection_->interface_index(), _))
|
|
.WillOnce(
|
|
DoAll(SetArgumentPointee<1>(local_mac_address_), Return(true)));
|
|
EXPECT_CALL(*arp_client_, StartReplyListener()).WillOnce(Return(true));
|
|
// We should send an ARP request for our own local IP address.
|
|
EXPECT_CALL(*arp_client_, TransmitRequest(IsArpRequest(
|
|
local_ip_address_, local_ip_address_,
|
|
local_mac_address_, ByteString())))
|
|
.WillOnce(Return(true));
|
|
EXPECT_CALL(dispatcher_,
|
|
PostDelayedTask(
|
|
_, ConnectionDiagnostics::kArpReplyTimeoutSeconds * 1000));
|
|
connection_diagnostics_.CheckIpCollision();
|
|
}
|
|
|
|
void ExpectCheckIPCollisionEndSuccess() {
|
|
AddExpectedEvent(ConnectionDiagnostics::kTypeIPCollisionCheck,
|
|
ConnectionDiagnostics::kPhaseEnd,
|
|
ConnectionDiagnostics::kResultSuccess);
|
|
// Simulate ARP response from a sender with the same IP address as our
|
|
// connection, directed at our local IP address and local MAC address.
|
|
client_test_helper_->GeneratePacket(
|
|
ARPOP_REPLY, local_ip_address_,
|
|
ByteString(string(kArpReplySenderMacAddressASCIIString), false),
|
|
local_ip_address_, local_mac_address_);
|
|
EXPECT_CALL(metrics_, NotifyConnectionDiagnosticsIssue(
|
|
ConnectionDiagnostics::kIssueIPCollision));
|
|
EXPECT_CALL(callback_target(),
|
|
ResultCallback(ConnectionDiagnostics::kIssueIPCollision,
|
|
IsEventList(expected_events_)));
|
|
connection_diagnostics_.OnArpReplyReceived(1);
|
|
}
|
|
|
|
void ExpectCheckIPCollisionEndFailureGatewayArpFailed() {
|
|
ExpectCheckIPCollisionEndFailure(
|
|
ConnectionDiagnostics::kIssueGatewayArpFailed);
|
|
}
|
|
|
|
void ExpectCheckIPCollisionEndFailureServerArpFailed() {
|
|
ExpectCheckIPCollisionEndFailure(
|
|
ConnectionDiagnostics::kIssueServerArpFailed);
|
|
}
|
|
|
|
private:
|
|
void ExpectPortalDetectionEnd(ConnectionDiagnostics::Phase diag_phase,
|
|
ConnectionDiagnostics::Result diag_result,
|
|
ConnectivityTrial::Phase trial_phase,
|
|
ConnectivityTrial::Status trial_status) {
|
|
AddExpectedEvent(ConnectionDiagnostics::kTypePortalDetection, diag_phase,
|
|
diag_result);
|
|
if (diag_phase == ConnectionDiagnostics::kPhasePortalDetectionEndContent) {
|
|
const string& issue = diag_result == ConnectionDiagnostics::kResultSuccess
|
|
? ConnectionDiagnostics::kIssueNone
|
|
: ConnectionDiagnostics::kIssueCaptivePortal;
|
|
EXPECT_CALL(metrics_, NotifyConnectionDiagnosticsIssue(issue));
|
|
EXPECT_CALL(callback_target(),
|
|
ResultCallback(issue, IsEventList(expected_events_)));
|
|
|
|
} else if (diag_phase ==
|
|
ConnectionDiagnostics::kPhasePortalDetectionEndDNS &&
|
|
diag_result == ConnectionDiagnostics::kResultFailure) {
|
|
EXPECT_CALL(metrics_,
|
|
NotifyConnectionDiagnosticsIssue(
|
|
ConnectionDiagnostics::kIssueDNSServerMisconfig));
|
|
EXPECT_CALL(
|
|
callback_target(),
|
|
ResultCallback(ConnectionDiagnostics::kIssueDNSServerMisconfig,
|
|
IsEventList(expected_events_)));
|
|
} else {
|
|
// Otherwise, we end in DNS phase with a timeout, or a HTTP phase failure.
|
|
// Either of these cases warrant further diagnostic actions.
|
|
EXPECT_CALL(dispatcher_, PostTask(_));
|
|
}
|
|
connection_diagnostics_.StartAfterPortalDetectionInternal(
|
|
PortalDetector::Result(
|
|
ConnectivityTrial::Result(trial_phase, trial_status)));
|
|
}
|
|
|
|
// |expected_issue| only used if |is_success| is false.
|
|
void ExpectPingDNSSeversStart(bool is_success, const string& expected_issue) {
|
|
AddExpectedEvent(ConnectionDiagnostics::kTypePingDNSServers,
|
|
ConnectionDiagnostics::kPhaseStart,
|
|
is_success ? ConnectionDiagnostics::kResultSuccess
|
|
: ConnectionDiagnostics::kResultFailure);
|
|
const char* bad_addresses[] = {"110.2.3", "1.5"};
|
|
const vector<string> bad_dns_servers(bad_addresses, bad_addresses + 2);
|
|
if (!is_success &&
|
|
expected_issue == ConnectionDiagnostics::kIssueDNSServersInvalid) {
|
|
// If the DNS server addresses are invalid, we will not even attempt to
|
|
// start any ICMP sessions.
|
|
EXPECT_CALL(*connection_.get(), dns_servers())
|
|
.WillRepeatedly(ReturnRef(bad_dns_servers));
|
|
} else {
|
|
// We are either instrumenting the success case (started pinging all
|
|
// DNS servers successfully) or the failure case where we fail to start
|
|
// any pings.
|
|
ASSERT_TRUE(is_success ||
|
|
expected_issue == ConnectionDiagnostics::kIssueInternalError);
|
|
dns_server_icmp_session_0_ = new NiceMock<MockIcmpSession>(&dispatcher_);
|
|
dns_server_icmp_session_1_ = new NiceMock<MockIcmpSession>(&dispatcher_);
|
|
EXPECT_CALL(*MockIcmpSessionFactory::GetInstance(),
|
|
CreateIcmpSession(&dispatcher_))
|
|
.WillOnce(Return(dns_server_icmp_session_0_))
|
|
.WillOnce(Return(dns_server_icmp_session_1_));
|
|
EXPECT_CALL(*dns_server_icmp_session_0_,
|
|
Start(IsSameIPAddress(IPAddress(kDNSServer0)), _))
|
|
.WillOnce(Return(is_success));
|
|
EXPECT_CALL(*dns_server_icmp_session_1_,
|
|
Start(IsSameIPAddress(IPAddress(kDNSServer1)), _))
|
|
.WillOnce(Return(is_success));
|
|
}
|
|
|
|
if (is_success) {
|
|
EXPECT_CALL(metrics_, NotifyConnectionDiagnosticsIssue(_)).Times(0);
|
|
EXPECT_CALL(callback_target(), ResultCallback(_, _)).Times(0);
|
|
} else {
|
|
EXPECT_CALL(metrics_, NotifyConnectionDiagnosticsIssue(expected_issue));
|
|
EXPECT_CALL(
|
|
callback_target(),
|
|
ResultCallback(expected_issue, IsEventList(expected_events_)));
|
|
}
|
|
connection_diagnostics_.PingDNSServers();
|
|
if (is_success) {
|
|
EXPECT_EQ(2, connection_diagnostics_
|
|
.id_to_pending_dns_server_icmp_session_.size());
|
|
} else {
|
|
EXPECT_TRUE(connection_diagnostics_.id_to_pending_dns_server_icmp_session_
|
|
.empty());
|
|
}
|
|
}
|
|
|
|
void ExpectResolveTargetServerIPAddressEnd(
|
|
ConnectionDiagnostics::Result result, const IPAddress& resolved_address) {
|
|
AddExpectedEvent(ConnectionDiagnostics::kTypeResolveTargetServerIP,
|
|
ConnectionDiagnostics::kPhaseEnd, result);
|
|
Error error;
|
|
if (result == ConnectionDiagnostics::kResultSuccess) {
|
|
error.Populate(Error::kSuccess);
|
|
EXPECT_CALL(dispatcher_, PostTask(_));
|
|
} else if (result == ConnectionDiagnostics::kResultTimeout) {
|
|
error.Populate(Error::kOperationTimeout);
|
|
EXPECT_CALL(dispatcher_, PostTask(_));
|
|
} else {
|
|
error.Populate(Error::kOperationFailed);
|
|
EXPECT_CALL(metrics_,
|
|
NotifyConnectionDiagnosticsIssue(
|
|
ConnectionDiagnostics::kIssueDNSServerMisconfig));
|
|
EXPECT_CALL(
|
|
callback_target(),
|
|
ResultCallback(ConnectionDiagnostics::kIssueDNSServerMisconfig,
|
|
IsEventList(expected_events_)));
|
|
}
|
|
connection_diagnostics_.OnDNSResolutionComplete(error, resolved_address);
|
|
}
|
|
|
|
void ExpectPingDNSServersEndSuccess(bool retries_left) {
|
|
AddExpectedEvent(ConnectionDiagnostics::kTypePingDNSServers,
|
|
ConnectionDiagnostics::kPhaseEnd,
|
|
ConnectionDiagnostics::kResultSuccess);
|
|
if (retries_left) {
|
|
EXPECT_LT(connection_diagnostics_.num_dns_attempts_,
|
|
ConnectionDiagnostics::kMaxDNSRetries);
|
|
} else {
|
|
EXPECT_GE(connection_diagnostics_.num_dns_attempts_,
|
|
ConnectionDiagnostics::kMaxDNSRetries);
|
|
}
|
|
// Post retry task or report done only after all (i.e. 2) pings are done.
|
|
connection_diagnostics_.OnPingDNSServerComplete(0, kNonEmptyResult);
|
|
if (retries_left) {
|
|
EXPECT_CALL(dispatcher_, PostTask(_));
|
|
EXPECT_CALL(metrics_, NotifyConnectionDiagnosticsIssue(_)).Times(0);
|
|
EXPECT_CALL(callback_target(), ResultCallback(_, _)).Times(0);
|
|
} else {
|
|
EXPECT_CALL(dispatcher_, PostTask(_)).Times(0);
|
|
EXPECT_CALL(metrics_,
|
|
NotifyConnectionDiagnosticsIssue(
|
|
ConnectionDiagnostics::kIssueDNSServerNoResponse));
|
|
EXPECT_CALL(
|
|
callback_target(),
|
|
ResultCallback(ConnectionDiagnostics::kIssueDNSServerNoResponse,
|
|
IsEventList(expected_events_)));
|
|
}
|
|
connection_diagnostics_.OnPingDNSServerComplete(1, kNonEmptyResult);
|
|
}
|
|
|
|
void ExpectArpTableLookup(const IPAddress& address, bool success,
|
|
bool is_gateway) {
|
|
AddExpectedEvent(ConnectionDiagnostics::kTypeArpTableLookup,
|
|
ConnectionDiagnostics::kPhaseStart,
|
|
ConnectionDiagnostics::kResultSuccess);
|
|
AddExpectedEvent(ConnectionDiagnostics::kTypeArpTableLookup,
|
|
ConnectionDiagnostics::kPhaseEnd,
|
|
success ? ConnectionDiagnostics::kResultSuccess
|
|
: ConnectionDiagnostics::kResultFailure);
|
|
EXPECT_CALL(device_info_,
|
|
GetMACAddressOfPeer(connection_->interface_index(),
|
|
IsSameIPAddress(address), _))
|
|
.WillOnce(Return(success));
|
|
if (success) {
|
|
const string& issue =
|
|
is_gateway ? ConnectionDiagnostics::kIssueGatewayNotResponding
|
|
: ConnectionDiagnostics::kIssueServerNotResponding;
|
|
EXPECT_CALL(metrics_, NotifyConnectionDiagnosticsIssue(issue));
|
|
EXPECT_CALL(callback_target(),
|
|
ResultCallback(issue, IsEventList(expected_events_)));
|
|
} else {
|
|
// Checking for IP collision.
|
|
EXPECT_CALL(dispatcher_, PostTask(_));
|
|
}
|
|
connection_diagnostics_.FindArpTableEntry(address);
|
|
}
|
|
|
|
void ExpectCheckIPCollisionEndFailure(const string& expected_issue) {
|
|
AddExpectedEvent(ConnectionDiagnostics::kTypeIPCollisionCheck,
|
|
ConnectionDiagnostics::kPhaseEnd,
|
|
ConnectionDiagnostics::kResultFailure);
|
|
EXPECT_CALL(metrics_, NotifyConnectionDiagnosticsIssue(expected_issue));
|
|
EXPECT_CALL(callback_target(),
|
|
ResultCallback(expected_issue, IsEventList(expected_events_)));
|
|
connection_diagnostics_.OnArpRequestTimeout();
|
|
}
|
|
|
|
void ExpectNeighborTableLookupEndFailure(const IPAddress& address_queried,
|
|
bool is_gateway, bool is_timeout) {
|
|
AddExpectedEvent(ConnectionDiagnostics::kTypeNeighborTableLookup,
|
|
ConnectionDiagnostics::kPhaseEnd,
|
|
ConnectionDiagnostics::kResultFailure);
|
|
string issue;
|
|
if (is_timeout) {
|
|
issue = is_gateway ? ConnectionDiagnostics::kIssueGatewayNoNeighborEntry
|
|
: ConnectionDiagnostics::kIssueServerNoNeighborEntry;
|
|
EXPECT_CALL(metrics_, NotifyConnectionDiagnosticsIssue(issue));
|
|
EXPECT_CALL(callback_target(),
|
|
ResultCallback(issue, IsEventList(expected_events_)));
|
|
connection_diagnostics_.OnNeighborTableRequestTimeout(address_queried);
|
|
} else {
|
|
issue =
|
|
is_gateway
|
|
? ConnectionDiagnostics::kIssueGatewayNeighborEntryNotConnected
|
|
: ConnectionDiagnostics::kIssueServerNeighborEntryNotConnected;
|
|
EXPECT_CALL(metrics_, NotifyConnectionDiagnosticsIssue(issue));
|
|
EXPECT_CALL(
|
|
callback_target(),
|
|
ResultCallback(issue,
|
|
IsEventList(expected_events_)));
|
|
RTNLMessage msg(RTNLMessage::kTypeNeighbor, RTNLMessage::kModeAdd, 0, 0,
|
|
0, connection_->interface_index(),
|
|
IPAddress::kFamilyIPv6);
|
|
msg.set_neighbor_status(
|
|
RTNLMessage::NeighborStatus(NUD_FAILED, 0, NDA_DST));
|
|
msg.SetAttribute(NDA_DST, address_queried.address());
|
|
connection_diagnostics_.OnNeighborMsgReceived(address_queried, msg);
|
|
}
|
|
}
|
|
|
|
const string interface_name_;
|
|
const vector<string> dns_servers_;
|
|
const IPAddress local_ip_address_;
|
|
const IPAddress gateway_ipv4_address_;
|
|
const IPAddress gateway_ipv6_address_;
|
|
ByteString local_mac_address_;
|
|
CallbackTarget callback_target_;
|
|
MockControl control_;
|
|
NiceMock<MockMetrics> metrics_;
|
|
MockManager manager_;
|
|
NiceMock<MockDeviceInfo> device_info_;
|
|
scoped_refptr<NiceMock<MockConnection>> connection_;
|
|
ConnectionDiagnostics connection_diagnostics_;
|
|
NiceMock<MockEventDispatcher> dispatcher_;
|
|
NiceMock<MockRoutingTable> routing_table_;
|
|
NiceMock<MockRTNLHandler> rtnl_handler_;
|
|
std::unique_ptr<ArpClientTestHelper> client_test_helper_;
|
|
|
|
// Used only for EXPECT_CALL(). Objects are owned by
|
|
// |connection_diagnostics_|.
|
|
NiceMock<MockArpClient>* arp_client_;
|
|
NiceMock<MockDNSClient>* dns_client_;
|
|
NiceMock<MockIcmpSession>* icmp_session_;
|
|
NiceMock<MockIcmpSession>* dns_server_icmp_session_0_;
|
|
NiceMock<MockIcmpSession>* dns_server_icmp_session_1_;
|
|
NiceMock<MockPortalDetector>* portal_detector_;
|
|
|
|
// For each test, all events we expect to appear in the final result are
|
|
// accumulated in this vector.
|
|
vector<ConnectionDiagnostics::Event> expected_events_;
|
|
};
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, DoesPreviousEventMatch) {
|
|
// If |diagnostic_events| is empty, we should always fail to match an event.
|
|
EXPECT_FALSE(
|
|
DoesPreviousEventMatch(ConnectionDiagnostics::kTypePortalDetection,
|
|
ConnectionDiagnostics::kPhaseStart,
|
|
ConnectionDiagnostics::kResultSuccess, 0));
|
|
EXPECT_FALSE(
|
|
DoesPreviousEventMatch(ConnectionDiagnostics::kTypePortalDetection,
|
|
ConnectionDiagnostics::kPhaseStart,
|
|
ConnectionDiagnostics::kResultSuccess, 2));
|
|
|
|
AddActualEvent(ConnectionDiagnostics::kTypePortalDetection,
|
|
ConnectionDiagnostics::kPhaseStart,
|
|
ConnectionDiagnostics::kResultSuccess);
|
|
AddActualEvent(ConnectionDiagnostics::kTypePortalDetection,
|
|
ConnectionDiagnostics::kPhasePortalDetectionEndOther,
|
|
ConnectionDiagnostics::kResultFailure);
|
|
AddActualEvent(ConnectionDiagnostics::kTypeResolveTargetServerIP,
|
|
ConnectionDiagnostics::kPhaseStart,
|
|
ConnectionDiagnostics::kResultSuccess);
|
|
AddActualEvent(ConnectionDiagnostics::kTypeResolveTargetServerIP,
|
|
ConnectionDiagnostics::kPhaseEnd,
|
|
ConnectionDiagnostics::kResultSuccess);
|
|
|
|
// Matching out of bounds should fail. (4 events total, so 4 events before the
|
|
// last event is out of bounds).
|
|
EXPECT_FALSE(
|
|
DoesPreviousEventMatch(ConnectionDiagnostics::kTypePortalDetection,
|
|
ConnectionDiagnostics::kPhaseStart,
|
|
ConnectionDiagnostics::kResultSuccess, 4));
|
|
|
|
// Valid matches.
|
|
EXPECT_TRUE(
|
|
DoesPreviousEventMatch(ConnectionDiagnostics::kTypePortalDetection,
|
|
ConnectionDiagnostics::kPhaseStart,
|
|
ConnectionDiagnostics::kResultSuccess, 3));
|
|
EXPECT_TRUE(
|
|
DoesPreviousEventMatch(ConnectionDiagnostics::kTypeResolveTargetServerIP,
|
|
ConnectionDiagnostics::kPhaseStart,
|
|
ConnectionDiagnostics::kResultSuccess, 1));
|
|
EXPECT_TRUE(
|
|
DoesPreviousEventMatch(ConnectionDiagnostics::kTypeResolveTargetServerIP,
|
|
ConnectionDiagnostics::kPhaseEnd,
|
|
ConnectionDiagnostics::kResultSuccess, 0));
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, StartWhileRunning) {
|
|
ExpectPortalDetectionStartSuccess(kURL); // Start diagnostics;
|
|
EXPECT_FALSE(Start(kURL));
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, StartWithBadURL) {
|
|
const string kBadURL("http://www.foo.com:x"); // Colon but no port
|
|
// IcmpSession::Stop will be called once when the bad URL is rejected.
|
|
ExpectIcmpSessionStop();
|
|
EXPECT_FALSE(Start(kBadURL));
|
|
// IcmpSession::Stop will be called a second time when
|
|
// |connection_diagnostics_| is destructed.
|
|
ExpectIcmpSessionStop();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_InternalError) {
|
|
// Portal detection ends in HTTP phase, DNS resolution succeeds, and we
|
|
// attempt to ping the target web server but fail because of an internal
|
|
// error.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress);
|
|
ExpectPingHostStartFailure(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_PortalDetectionContentPhase_Success) {
|
|
// Portal detection ends successfully in content phase, so we end diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndContentPhaseSuccess();
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_PortalDetectionContentPhase_Failure) {
|
|
// Portal detection ends unsuccessfully in content phase, so we end
|
|
// diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndContentPhaseFailure();
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_DNSFailure_1) {
|
|
// Portal detection ends with a DNS failure (not timeout), so we end
|
|
// diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndDNSPhaseFailure();
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_DNSFailure_2) {
|
|
// Portal detection ends in HTTP phase, DNS resolution fails (not timeout), so
|
|
// we end diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndFailure();
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_PingDNSServerStartFailure_1) {
|
|
// Portal detection ends with a DNS timeout, and we attempt to pinging DNS
|
|
// servers, but fail to start any IcmpSessions, so end diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndDNSPhaseTimeout();
|
|
ExpectPingDNSSeversStartFailureAllIcmpSessionsFailed();
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_PingDNSServerStartFailure_2) {
|
|
// Portal detection ends with a DNS timeout, and we attempt to pinging DNS
|
|
// servers, but all DNS servers configured for this connection have invalid IP
|
|
// addresses, so we fail to start ping DNs servers, andend diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndDNSPhaseTimeout();
|
|
ExpectPingDNSSeversStartFailureAllAddressesInvalid();
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_PingDNSServerEndSuccess_NoRetries_1) {
|
|
// Portal detection ends with a DNS timeout, pinging DNS servers succeeds, DNS
|
|
// resolution times out, pinging DNS servers succeeds again, and DNS
|
|
// resolution times out again. End diagnostics because we have no more DNS
|
|
// retries left.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndDNSPhaseTimeout();
|
|
ExpectPingDNSServersStartSuccess();
|
|
ExpectPingDNSServersEndSuccessRetriesLeft();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndTimeout();
|
|
ExpectPingDNSServersStartSuccess();
|
|
ExpectPingDNSServersEndSuccessRetriesLeft();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndTimeout();
|
|
ExpectPingDNSServersStartSuccess();
|
|
ExpectPingDNSServersEndSuccessNoRetriesLeft();
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_PingDNSServerEndSuccess_NoRetries_2) {
|
|
// Portal detection ends in HTTP phase, DNS resolution times out, pinging DNS
|
|
// servers succeeds, DNS resolution times out again, pinging DNS servers
|
|
// succeeds. End diagnostics because we have no more DNS retries left.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndTimeout();
|
|
ExpectPingDNSServersStartSuccess();
|
|
ExpectPingDNSServersEndSuccessRetriesLeft();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndTimeout();
|
|
ExpectPingDNSServersStartSuccess();
|
|
ExpectPingDNSServersEndSuccessNoRetriesLeft();
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_PingTargetIPSuccess_1) {
|
|
// Portal detection ends in HTTP phase, DNS resolution succeeds, and pinging
|
|
// the resolved IP address succeeds, so we end diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectPingHostEndSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_PingTargetIPSuccess_2) {
|
|
// Portal detection ends with a DNS timeout, pinging DNS servers succeeds, DNS
|
|
// resolution succeeds, and pinging the resolved IP address succeeds, so we
|
|
// end diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndDNSPhaseTimeout();
|
|
ExpectPingDNSServersStartSuccess();
|
|
ExpectPingDNSServersEndSuccessRetriesLeft();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectPingHostEndSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_PingTargetIPSuccess_3) {
|
|
// Portal detection ends in HTTP phase, DNS resolution times out, pinging DNS
|
|
// servers succeeds, DNS resolution succeeds, and pinging the resolved IP
|
|
// address succeeds, so we end diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndTimeout();
|
|
ExpectPingDNSServersStartSuccess();
|
|
ExpectPingDNSServersEndSuccessRetriesLeft();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectPingHostEndSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_FindRouteFailure_1) {
|
|
// Portal detection ends in HTTP phase, DNS resolution succeeds, pinging the
|
|
// resolved IP address fails, and we fail to get a route for the IP address,
|
|
// so we end diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectFindRouteToHostStartSuccess(kIPv4ServerAddress);
|
|
ExpectFindRouteToHostEndFailure();
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_FindRoute_Failure_2) {
|
|
// Portal detection ends with a DNS timeout, pinging DNS servers succeeds, DNS
|
|
// resolution succeeds, pinging the resolved IP address fails, and we fail to
|
|
// get a route for the IP address, so we end diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndDNSPhaseTimeout();
|
|
ExpectPingDNSServersStartSuccess();
|
|
ExpectPingDNSServersEndSuccessRetriesLeft();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectFindRouteToHostStartSuccess(kIPv4ServerAddress);
|
|
ExpectFindRouteToHostEndFailure();
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_FindRouteFailure_3) {
|
|
// Portal detection ends in HTTP phase, DNS resolution times out, pinging DNS
|
|
// servers succeeds, DNS resolution succeeds, pinging the resolved IP address
|
|
// fails, and we fail to get a route for the IP address, so we end
|
|
// diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndTimeout();
|
|
ExpectPingDNSServersStartSuccess();
|
|
ExpectPingDNSServersEndSuccessRetriesLeft();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectFindRouteToHostStartSuccess(kIPv4ServerAddress);
|
|
ExpectFindRouteToHostEndFailure();
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_FindRouteFailure_4) {
|
|
// Portal detection ends with a DNS timeout, pinging DNS servers fails, get a
|
|
// route for the first DNS server, so we end diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndDNSPhaseTimeout();
|
|
ExpectPingDNSServersStartSuccess();
|
|
ExpectPingDNSServersEndFailure();
|
|
ExpectFindRouteToHostStartSuccess(kIPv4GatewayAddress);
|
|
ExpectFindRouteToHostEndFailure();
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_PingGatewaySuccess_1_IPv4) {
|
|
// Portal detection ends in HTTP phase, DNS resolution succeeds, pinging the
|
|
// resolved IP address fails, and we successfully get route for the IP
|
|
// address. This address is remote, so ping the local gateway and succeed, so
|
|
// we end diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectFindRouteToHostStartSuccess(kIPv4ServerAddress);
|
|
ExpectFindRouteToHostEndSuccess(kIPv4ServerAddress, false);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingGateway,
|
|
kIPv4GatewayAddress);
|
|
ExpectPingHostEndSuccess(ConnectionDiagnostics::kTypePingGateway,
|
|
kIPv4GatewayAddress);
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_PingGatewaySuccess_1_IPv6) {
|
|
// Same as above, but this time the resolved IP address of the target URL
|
|
// is IPv6.
|
|
UseIPv6Gateway();
|
|
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv6);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv6ServerAddress);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv6ServerAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv6ServerAddress);
|
|
ExpectFindRouteToHostStartSuccess(kIPv6ServerAddress);
|
|
ExpectFindRouteToHostEndSuccess(kIPv6ServerAddress, false);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingGateway,
|
|
kIPv6GatewayAddress);
|
|
ExpectPingHostEndSuccess(ConnectionDiagnostics::kTypePingGateway,
|
|
kIPv6GatewayAddress);
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_PingGatewaySuccess_2) {
|
|
// Portal detection ends with a DNS timeout, pinging DNS servers succeeds, DNS
|
|
// resolution succeeds, pinging the resolved IP address fails, and we
|
|
// successfully get route for the IP address. This address is remote, so ping
|
|
// the local gateway and succeed, so we end diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndDNSPhaseTimeout();
|
|
ExpectPingDNSServersStartSuccess();
|
|
ExpectPingDNSServersEndSuccessRetriesLeft();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectFindRouteToHostStartSuccess(kIPv4ServerAddress);
|
|
ExpectFindRouteToHostEndSuccess(kIPv4ServerAddress, false);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingGateway,
|
|
kIPv4GatewayAddress);
|
|
ExpectPingHostEndSuccess(ConnectionDiagnostics::kTypePingGateway,
|
|
kIPv4GatewayAddress);
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_PingGatewaySuccess_3) {
|
|
// Portal detection ends in HTTP phase, DNS resolution times out, pinging DNS
|
|
// servers succeeds, DNS resolution succeeds, pinging the resolved IP address
|
|
// fails, and we successfully get route for the IP address. This address is
|
|
// remote, so ping the local gateway. The ping succeeds, so we end
|
|
// diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndTimeout();
|
|
ExpectPingDNSServersStartSuccess();
|
|
ExpectPingDNSServersEndSuccessRetriesLeft();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectFindRouteToHostStartSuccess(kIPv4ServerAddress);
|
|
ExpectFindRouteToHostEndSuccess(kIPv4ServerAddress, false);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingGateway,
|
|
kIPv4GatewayAddress);
|
|
ExpectPingHostEndSuccess(ConnectionDiagnostics::kTypePingGateway,
|
|
kIPv4GatewayAddress);
|
|
VerifyStopped();
|
|
}
|
|
|
|
// Note: for the test below, several other possible paths through the diagnostic
|
|
// state machine that will lead us to end diagnostics at ARP table lookup or IP
|
|
// collision check are not explicitly tested. We do this to avoid redundancy
|
|
// since the above tests have already exercised these sub-paths extensively,
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_FindArpTableEntrySuccess_1) {
|
|
// Portal detection ends in HTTP phase, DNS resolution succeeds, pinging the
|
|
// resolved IP address fails, and we successfully get route for the IP
|
|
// address. This address is remote, pinging the local gateway fails, and we
|
|
// find an ARP table entry for the gateway address, so we end diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectFindRouteToHostStartSuccess(kIPv4ServerAddress);
|
|
ExpectFindRouteToHostEndSuccess(kIPv4ServerAddress, false);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingGateway,
|
|
kIPv4GatewayAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingGateway,
|
|
kIPv4GatewayAddress);
|
|
ExpectArpTableLookupStartSuccessEndSuccess(kIPv4GatewayAddress, true);
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_FindArpTableEntrySuccess_2) {
|
|
// Portal detection ends in HTTP phase, DNS resolution succeeds, pinging the
|
|
// resolved IP address fails, and we successfully get route for the IP
|
|
// address. This address is local, and we find an ARP table entry for this
|
|
// address, so we end diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectFindRouteToHostStartSuccess(kIPv4ServerAddress);
|
|
ExpectFindRouteToHostEndSuccess(kIPv4ServerAddress, true);
|
|
ExpectArpTableLookupStartSuccessEndSuccess(kIPv4ServerAddress, false);
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_IPCollisionSuccess_1) {
|
|
// Portal detection ends in HTTP phase, DNS resolution succeeds, pinging the
|
|
// resolved IP address fails, and we successfully get route for the IP
|
|
// address. This address is remote, pinging the local gateway fails, ARP table
|
|
// lookup fails, we check for IP collision and find one, so we end
|
|
// diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectFindRouteToHostStartSuccess(kIPv4ServerAddress);
|
|
ExpectFindRouteToHostEndSuccess(kIPv4ServerAddress, false);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingGateway,
|
|
kIPv4GatewayAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingGateway,
|
|
kIPv4GatewayAddress);
|
|
ExpectArpTableLookupStartSuccessEndFailure(kIPv4GatewayAddress);
|
|
ExpectCheckIPCollisionStartSuccess();
|
|
ExpectCheckIPCollisionEndSuccess();
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_IPCollisionSuccess_2) {
|
|
// Portal detection ends in HTTP phase, DNS resolution succeeds, pinging the
|
|
// resolved IP address fails, and we successfully get route for the IP
|
|
// address. This address is local, ARP table lookup fails, we check for IP
|
|
// collision and find one, so we end diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectFindRouteToHostStartSuccess(kIPv4ServerAddress);
|
|
ExpectFindRouteToHostEndSuccess(kIPv4ServerAddress, true);
|
|
ExpectArpTableLookupStartSuccessEndSuccess(kIPv4ServerAddress, false);
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_IPCollisionFailure_1) {
|
|
// Portal detection ends in HTTP phase, DNS resolution succeeds, pinging the
|
|
// resolved IP address fails, and we successfully get route for the IP
|
|
// address. This address is remote, pinging the local gateway fails, ARP table
|
|
// lookup fails, we check for IP collision and do not find one, so we end
|
|
// diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectFindRouteToHostStartSuccess(kIPv4ServerAddress);
|
|
ExpectFindRouteToHostEndSuccess(kIPv4ServerAddress, false);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingGateway,
|
|
kIPv4GatewayAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingGateway,
|
|
kIPv4GatewayAddress);
|
|
ExpectArpTableLookupStartSuccessEndFailure(kIPv4GatewayAddress);
|
|
ExpectCheckIPCollisionStartSuccess();
|
|
ExpectCheckIPCollisionEndFailureGatewayArpFailed();
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_IPCollisionFailure_2) {
|
|
// Portal detection ends in HTTP phase, DNS resolution succeeds, pinging the
|
|
// resolved IP address fails, and we successfully get route for the IP
|
|
// address. This address is local, ARP table lookup fails, we check for IP
|
|
// collision and do not find one, so we end diagnostics.
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv4);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv4ServerAddress);
|
|
ExpectFindRouteToHostStartSuccess(kIPv4ServerAddress);
|
|
ExpectFindRouteToHostEndSuccess(kIPv4ServerAddress, true);
|
|
ExpectArpTableLookupStartSuccessEndFailure(kIPv4ServerAddress);
|
|
ExpectCheckIPCollisionStartSuccess();
|
|
ExpectCheckIPCollisionEndFailureServerArpFailed();
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_kTypeNeighborTableLookupSuccess_1) {
|
|
// Portal detection ends in HTTP phase, DNS resolution succeeds, pinging the
|
|
// resolved IP address fails, and we successfully get route for the IP
|
|
// address. This address is remote, pinging the local IPv6 gateway fails,
|
|
// and we find a neighbor table entry for the gateway. End diagnostics.
|
|
UseIPv6Gateway();
|
|
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv6);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv6ServerAddress);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv6ServerAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv6ServerAddress);
|
|
ExpectFindRouteToHostStartSuccess(kIPv6ServerAddress);
|
|
ExpectFindRouteToHostEndSuccess(kIPv6ServerAddress, false);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingGateway,
|
|
kIPv6GatewayAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingGateway,
|
|
kIPv6GatewayAddress);
|
|
ExpectNeighborTableLookupStartSuccess(kIPv6GatewayAddress);
|
|
ExpectNeighborTableLookupEndSuccess(kIPv6GatewayAddress, true);
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_kTypeNeighborTableLookupSuccess_2) {
|
|
// Portal detection ends in HTTP phase, DNS resolution succeeds, pinging the
|
|
// resolved IP address fails, we succeed in getting a route for the IP
|
|
// address. This address is a local IPv6 address, and we find a neighbor table
|
|
// entry for it. End diagnostics.
|
|
UseIPv6Gateway();
|
|
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv6);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv6ServerAddress);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv6ServerAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv6ServerAddress);
|
|
ExpectFindRouteToHostStartSuccess(kIPv6ServerAddress);
|
|
ExpectFindRouteToHostEndSuccess(kIPv6ServerAddress, true);
|
|
ExpectNeighborTableLookupStartSuccess(kIPv6ServerAddress);
|
|
ExpectNeighborTableLookupEndSuccess(kIPv6ServerAddress, false);
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_kTypeNeighborTableLookupFailure_1) {
|
|
// Portal detection ends in HTTP phase, DNS resolution succeeds, pinging the
|
|
// resolved IP address fails, and we successfully get route for the IP
|
|
// address. This address is remote, pinging the local IPv6 gateway fails, and
|
|
// we find a neighbor table entry for the gateway, but it is not marked as
|
|
// reachable. End diagnostics.
|
|
UseIPv6Gateway();
|
|
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv6);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv6ServerAddress);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv6ServerAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv6ServerAddress);
|
|
ExpectFindRouteToHostStartSuccess(kIPv6ServerAddress);
|
|
ExpectFindRouteToHostEndSuccess(kIPv6ServerAddress, false);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingGateway,
|
|
kIPv6GatewayAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingGateway,
|
|
kIPv6GatewayAddress);
|
|
ExpectNeighborTableLookupStartSuccess(kIPv6GatewayAddress);
|
|
ExpectNeighborTableLookupEndFailureNotReachable(kIPv6GatewayAddress, true);
|
|
VerifyStopped();
|
|
}
|
|
|
|
TEST_F(ConnectionDiagnosticsTest, EndWith_kTypeNeighborTableLookupFailure_2) {
|
|
// Portal detection ends in HTTP phase, DNS resolution succeeds, pinging the
|
|
// resolved IP address fails, we succeed in getting a route for the IP
|
|
// address. This address is a local IPv6 address, and we do not find a
|
|
// neighbor table entry for it. End diagnostics.
|
|
UseIPv6Gateway();
|
|
|
|
ExpectPortalDetectionStartSuccess(kURL);
|
|
ExpectPortalDetectionEndHTTPPhaseFailure();
|
|
ExpectResolveTargetServerIPAddressStartSuccess(IPAddress::kFamilyIPv6);
|
|
ExpectResolveTargetServerIPAddressEndSuccess(kIPv6ServerAddress);
|
|
ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv6ServerAddress);
|
|
ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer,
|
|
kIPv6ServerAddress);
|
|
ExpectFindRouteToHostStartSuccess(kIPv6ServerAddress);
|
|
ExpectFindRouteToHostEndSuccess(kIPv6ServerAddress, true);
|
|
ExpectNeighborTableLookupStartSuccess(kIPv6ServerAddress);
|
|
ExpectNeighborTableLookupEndFailureNoEntry(kIPv6ServerAddress, false);
|
|
VerifyStopped();
|
|
}
|
|
|
|
} // namespace shill
|