| // Copyright 2018 The Chromium OS 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 "shill/connection_diagnostics.h" |
| |
| #include <linux/rtnetlink.h> |
| #include <net/if_arp.h> |
| |
| #include <memory> |
| #include <utility> |
| |
| #include <gtest/gtest.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/arp_client.h" |
| #include "shill/net/mock_io_handler_factory.h" |
| #include "shill/net/mock_rtnl_handler.h" |
| #include "shill/routing_table_entry.h" |
| |
| using base::Bind; |
| using base::Callback; |
| using base::Unretained; |
| using std::string; |
| using std::vector; |
| using testing::_; |
| using testing::ByMove; |
| using testing::DoAll; |
| using testing::NiceMock; |
| using testing::Return; |
| using testing::ReturnRef; |
| using testing::ReturnRefOfCopy; |
| using testing::SetArgPointee; |
| using testing::Test; |
| |
| namespace { |
| const char kInterfaceName[] = "int0"; |
| const char kDNSServer0[] = "8.8.8.8"; |
| const char kDNSServer1[] = "8.8.4.4"; |
| const char kHttpUrl[] = "http://www.gstatic.com/generate_204"; |
| const char kHttpsUrl[] = "https://www.google.com/generate_204"; |
| const vector<string> kFallbackHttpUrls{ |
| "http://www.google.com/gen_204", |
| "http://play.googleapis.com/generate_204", |
| }; |
| const char kLocalMacAddressASCIIString[] = "123456"; |
| const char kArpReplySenderMacAddressASCIIString[] = "345678"; |
| const char* const 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 shill::IPAddress kIPv4ZeroAddress("0.0.0.0"); |
| const vector<base::TimeDelta> kEmptyResult; |
| const vector<base::TimeDelta> kNonEmptyResult{ |
| base::TimeDelta::FromMilliseconds(10)}; |
| const uint8_t kMacZeroAddress[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| } // 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), |
| manager_(&control_, &dispatcher_, &metrics_), |
| device_info_(&manager_), |
| connection_(new NiceMock<MockConnection>(&device_info_)), |
| connection_diagnostics_(connection_, |
| &dispatcher_, |
| &metrics_, |
| &device_info_, |
| callback_target_.result_callback()), |
| portal_detector_(new NiceMock<MockPortalDetector>(connection_)) { |
| connection_diagnostics_.io_handler_factory_ = &io_handler_factory_; |
| } |
| |
| ~ConnectionDiagnosticsTest() override = default; |
| |
| void SetUp() override { |
| 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_, interface_name()) |
| .WillByDefault(ReturnRef(interface_name_)); |
| ON_CALL(*connection_, dns_servers()).WillByDefault(ReturnRef(dns_servers_)); |
| ON_CALL(*connection_, gateway()) |
| .WillByDefault(ReturnRef(gateway_ipv4_address_)); |
| ON_CALL(*connection_, local()).WillByDefault(ReturnRef(local_ip_address_)); |
| connection_diagnostics_.dns_client_factory_ = |
| MockDnsClientFactory::GetInstance(); |
| connection_diagnostics_.icmp_session_factory_ = |
| MockIcmpSessionFactory::GetInstance(); |
| } |
| |
| void TearDown() override {} |
| |
| protected: |
| class CallbackTarget { |
| public: |
| CallbackTarget() |
| : result_callback_( |
| Bind(&CallbackTarget::ResultCallback, Unretained(this))) {} |
| |
| MOCK_METHOD(void, |
| ResultCallback, |
| (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_, 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 PortalDetector::Properties& props) { |
| return connection_diagnostics_.Start(props); |
| } |
| |
| void VerifyStopped() { |
| EXPECT_FALSE(connection_diagnostics_.running()); |
| EXPECT_EQ(0, connection_diagnostics_.num_dns_attempts_); |
| EXPECT_TRUE(connection_diagnostics_.diagnostic_events_.empty()); |
| EXPECT_EQ(nullptr, connection_diagnostics_.dns_client_); |
| EXPECT_FALSE(connection_diagnostics_.arp_client_->IsStarted()); |
| EXPECT_FALSE(connection_diagnostics_.icmp_session_->IsStarted()); |
| EXPECT_EQ(nullptr, connection_diagnostics_.portal_detector_); |
| EXPECT_EQ(nullptr, connection_diagnostics_.receive_response_handler_); |
| EXPECT_EQ(nullptr, connection_diagnostics_.neighbor_msg_listener_); |
| EXPECT_TRUE( |
| connection_diagnostics_.id_to_pending_dns_server_icmp_session_.empty()); |
| EXPECT_EQ(nullptr, connection_diagnostics_.target_url_); |
| 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(PortalDetector::Properties props) { |
| AddExpectedEvent(ConnectionDiagnostics::kTypePortalDetection, |
| ConnectionDiagnostics::kPhaseStart, |
| ConnectionDiagnostics::kResultSuccess); |
| EXPECT_CALL(*portal_detector_, StartAfterDelay(props, 0)) |
| .WillOnce(Return(true)); |
| EXPECT_FALSE(connection_diagnostics_.running()); |
| EXPECT_TRUE(connection_diagnostics_.diagnostic_events_.empty()); |
| EXPECT_TRUE(Start(props)); |
| EXPECT_TRUE(connection_diagnostics_.running()); |
| } |
| |
| void ExpectPortalDetectionEndContentPhaseSuccess() { |
| ExpectPortalDetectionEnd( |
| ConnectionDiagnostics::kPhasePortalDetectionEndContent, |
| ConnectionDiagnostics::kResultSuccess, PortalDetector::Phase::kContent, |
| PortalDetector::Status::kSuccess); |
| } |
| |
| void ExpectPortalDetectionEndContentPhaseFailure() { |
| ExpectPortalDetectionEnd( |
| ConnectionDiagnostics::kPhasePortalDetectionEndContent, |
| ConnectionDiagnostics::kResultFailure, PortalDetector::Phase::kContent, |
| PortalDetector::Status::kFailure); |
| } |
| |
| void ExpectPortalDetectionEndDNSPhaseFailure() { |
| ExpectPortalDetectionEnd(ConnectionDiagnostics::kPhasePortalDetectionEndDNS, |
| ConnectionDiagnostics::kResultFailure, |
| PortalDetector::Phase::kDNS, |
| PortalDetector::Status::kFailure); |
| } |
| |
| void ExpectPortalDetectionEndDNSPhaseTimeout() { |
| ExpectPortalDetectionEnd(ConnectionDiagnostics::kPhasePortalDetectionEndDNS, |
| ConnectionDiagnostics::kResultTimeout, |
| PortalDetector::Phase::kDNS, |
| PortalDetector::Status::kTimeout); |
| } |
| |
| void ExpectPortalDetectionEndHTTPPhaseFailure() { |
| ExpectPortalDetectionEnd( |
| ConnectionDiagnostics::kPhasePortalDetectionEndOther, |
| ConnectionDiagnostics::kResultFailure, PortalDetector::Phase::kHTTP, |
| PortalDetector::Status::kFailure); |
| } |
| |
| 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_, PostDelayedTask(_, _, 0)); |
| connection_diagnostics_.OnPingDNSServerComplete(1, kEmptyResult); |
| } |
| |
| void ExpectResolveTargetServerIPAddressStartSuccess( |
| IPAddress::Family family) { |
| AddExpectedEvent(ConnectionDiagnostics::kTypeResolveTargetServerIP, |
| ConnectionDiagnostics::kPhaseStart, |
| ConnectionDiagnostics::kResultSuccess); |
| ASSERT_FALSE(family == IPAddress::kFamilyUnknown); |
| |
| auto dns_client = std::make_unique<NiceMock<MockDnsClient>>(); |
| EXPECT_CALL(*dns_client, |
| Start(connection_diagnostics_.target_url_->host(), _)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*connection_, IsIPv6()) |
| .WillOnce(Return(family == IPAddress::kFamilyIPv6)); |
| EXPECT_CALL( |
| *MockDnsClientFactory::GetInstance(), |
| CreateDnsClient(family, kInterfaceName, dns_servers_, |
| DnsClient::kDnsTimeoutMilliseconds, &dispatcher_, _)) |
| .WillOnce(Return(ByMove(std::move(dns_client)))); |
| 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_, PostDelayedTask(_, _, 0)); |
| 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_, PostDelayedTask(_, _, 0)); |
| auto entry = |
| RoutingTableEntry::Create(address_queried, |
| IPAddress(address_queried.family()), gateway) |
| .SetTable(connection_->table_id()); |
| 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(SetArgPointee<1>(local_mac_address_), Return(true))); |
| EXPECT_CALL(*arp_client_, StartReplyListener()).WillOnce(Return(true)); |
| // We should send an ARP probe request for our own local IP address. |
| EXPECT_CALL(*arp_client_, |
| TransmitRequest(IsArpRequest( |
| kIPv4ZeroAddress, local_ip_address_, local_mac_address_, |
| ByteString(kMacZeroAddress, sizeof(kMacZeroAddress))))) |
| .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, |
| PortalDetector::Phase trial_phase, |
| PortalDetector::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_, PostDelayedTask(_, _, 0)); |
| } |
| connection_diagnostics_.StartAfterPortalDetectionInternal( |
| PortalDetector::Result(trial_phase, trial_status), |
| PortalDetector::Result(PortalDetector::Phase::kContent, |
| PortalDetector::Status::kSuccess)); |
| } |
| |
| // |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); |
| 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_, dns_servers()) |
| .WillRepeatedly(ReturnRefOfCopy(vector<string>{"110.2.3", "1.5"})); |
| } 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); |
| |
| auto dns_server_icmp_session_0 = |
| std::make_unique<NiceMock<MockIcmpSession>>(&dispatcher_); |
| auto dns_server_icmp_session_1 = |
| std::make_unique<NiceMock<MockIcmpSession>>(&dispatcher_); |
| |
| 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)); |
| |
| EXPECT_CALL(*MockIcmpSessionFactory::GetInstance(), |
| CreateIcmpSession(&dispatcher_)) |
| .WillOnce(Return(ByMove(std::move(dns_server_icmp_session_0)))) |
| .WillOnce(Return(ByMove(std::move(dns_server_icmp_session_1)))); |
| } |
| |
| 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_, PostDelayedTask(_, _, 0)); |
| } else if (result == ConnectionDiagnostics::kResultTimeout) { |
| error.Populate(Error::kOperationTimeout); |
| EXPECT_CALL(dispatcher_, PostDelayedTask(_, _, 0)); |
| } 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_, PostDelayedTask(_, _, 0)); |
| EXPECT_CALL(metrics_, NotifyConnectionDiagnosticsIssue(_)).Times(0); |
| EXPECT_CALL(callback_target(), ResultCallback(_, _)).Times(0); |
| } else { |
| EXPECT_CALL(dispatcher_, PostDelayedTask(_, _, 0)).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_, PostDelayedTask(_, _, 0)); |
| } |
| 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_; |
| MockIOHandlerFactory io_handler_factory_; |
| 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<MockIcmpSession>* icmp_session_; |
| 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) { |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); // Start diagnostics; |
| EXPECT_FALSE(Start(props)); |
| } |
| |
| 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(); |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kBadURL, kHttpsUrl, kFallbackHttpUrls); |
| EXPECT_FALSE(Start(props)); |
| // 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| ExpectPortalDetectionEndContentPhaseSuccess(); |
| VerifyStopped(); |
| } |
| |
| TEST_F(ConnectionDiagnosticsTest, EndWith_PortalDetectionContentPhase_Failure) { |
| // Portal detection ends unsuccessfully in content phase, so we end |
| // diagnostics. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| ExpectPortalDetectionEndContentPhaseFailure(); |
| VerifyStopped(); |
| } |
| |
| TEST_F(ConnectionDiagnosticsTest, EndWith_DNSFailure_1) { |
| // Portal detection ends with a DNS failure (not timeout), so we end |
| // diagnostics. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| ExpectPortalDetectionEndDNSPhaseFailure(); |
| VerifyStopped(); |
| } |
| |
| TEST_F(ConnectionDiagnosticsTest, EndWith_DNSFailure_2) { |
| // Portal detection ends in HTTP phase, DNS resolution fails (not timeout), so |
| // we end diagnostics. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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(); |
| |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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. |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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(); |
| |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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(); |
| |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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(); |
| |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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(); |
| |
| PortalDetector::Properties props = |
| PortalDetector::Properties(kHttpUrl, kHttpsUrl, kFallbackHttpUrls); |
| ExpectPortalDetectionStartSuccess(props); |
| 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 |