| // Copyright 2018 The ChromiumOS Authors |
| // 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 <memory> |
| #include <set> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include <base/time/time.h> |
| #include <gtest/gtest.h> |
| #include <net-base/http_url.h> |
| #include <net-base/ip_address.h> |
| |
| #include "shill/icmp_session.h" |
| #include "shill/manager.h" |
| #include "shill/mock_control.h" |
| #include "shill/mock_dns_client.h" |
| #include "shill/mock_event_dispatcher.h" |
| #include "shill/mock_icmp_session.h" |
| #include "shill/mock_metrics.h" |
| |
| 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 shill { |
| |
| namespace { |
| constexpr const char kInterfaceName[] = "int0"; |
| constexpr const int kInterfaceIndex = 4; |
| constexpr net_base::IPAddress kIPv4DNSServer0( |
| net_base::IPv4Address(8, 8, 8, 8)); |
| constexpr net_base::IPAddress kIPv4DNSServer1( |
| net_base::IPv4Address(8, 8, 4, 4)); |
| constexpr net_base::IPAddress kIPv6DNSServer0(net_base::IPv6Address( |
| 0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0, 0, 0, 0, 0, 0, 0, 0, 0x88, 0x88)); |
| constexpr net_base::IPAddress kIPv6DNSServer1(net_base::IPv6Address( |
| 0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0, 0, 0, 0, 0, 0, 0, 0, 0x88, 0x44)); |
| constexpr const char kHttpUrl[] = "http://www.gstatic.com/generate_204"; |
| const auto kIPv4DeviceAddress = |
| *net_base::IPAddress::CreateFromString("100.200.43.22"); |
| const auto kIPv6DeviceAddress = |
| *net_base::IPAddress::CreateFromString("2001:db8::3333:4444:5555"); |
| const auto kIPv4ServerAddress = |
| *net_base::IPAddress::CreateFromString("8.8.8.8"); |
| const auto kIPv6ServerAddress = |
| *net_base::IPAddress::CreateFromString("fe80::1aa9:5ff:7ebf:14c5"); |
| const auto kIPv4GatewayAddress = |
| *net_base::IPAddress::CreateFromString("192.168.1.1"); |
| const auto kIPv6GatewayAddress = |
| *net_base::IPAddress::CreateFromString("fee2::11b2:53f:13be:125e"); |
| const std::vector<base::TimeDelta> kEmptyResult; |
| const std::vector<base::TimeDelta> kNonEmptyResult{base::Milliseconds(10)}; |
| } // namespace |
| |
| 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 << "Device 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 << "Device 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() |
| : gateway_(kIPv4GatewayAddress), |
| dns_list_({kIPv4DNSServer0, kIPv4DNSServer1}), |
| connection_diagnostics_(kInterfaceName, |
| kInterfaceIndex, |
| kIPv4DeviceAddress, |
| kIPv4GatewayAddress, |
| {kIPv4DNSServer0, kIPv4DNSServer1}, |
| &dispatcher_, |
| &metrics_, |
| callback_target_.result_callback()) {} |
| |
| ~ConnectionDiagnosticsTest() override = default; |
| |
| void SetUp() override { |
| ASSERT_EQ(net_base::IPFamily::kIPv4, kIPv4DeviceAddress.GetFamily()); |
| ASSERT_EQ(net_base::IPFamily::kIPv4, kIPv4ServerAddress.GetFamily()); |
| ASSERT_EQ(net_base::IPFamily::kIPv4, kIPv4GatewayAddress.GetFamily()); |
| ASSERT_EQ(net_base::IPFamily::kIPv6, kIPv6ServerAddress.GetFamily()); |
| ASSERT_EQ(net_base::IPFamily::kIPv6, kIPv6GatewayAddress.GetFamily()); |
| |
| dns_client_ = new NiceMock<MockDnsClient>(); |
| icmp_session_ = new NiceMock<MockIcmpSession>(&dispatcher_); |
| connection_diagnostics_.dns_client_.reset(dns_client_); // Passes ownership |
| connection_diagnostics_.icmp_session_.reset( |
| icmp_session_); // Passes ownership |
| } |
| |
| void TearDown() override {} |
| |
| protected: |
| class CallbackTarget { |
| public: |
| CallbackTarget() {} |
| |
| MOCK_METHOD(void, |
| ResultCallback, |
| (const std::string&, |
| const std::vector<ConnectionDiagnostics::Event>&)); |
| |
| base::OnceCallback<void(const std::string&, |
| const std::vector<ConnectionDiagnostics::Event>&)> |
| result_callback() { |
| return base::BindOnce(&CallbackTarget::ResultCallback, |
| base::Unretained(this)); |
| } |
| }; |
| |
| CallbackTarget& callback_target() { return callback_target_; } |
| net_base::IPAddress gateway() { return gateway_; } |
| |
| void UseIPv6() { |
| gateway_ = kIPv6GatewayAddress; |
| dns_list_ = {kIPv6DNSServer0, kIPv6DNSServer1}; |
| connection_diagnostics_.ip_address_ = kIPv6DeviceAddress; |
| connection_diagnostics_.gateway_ = kIPv6GatewayAddress; |
| connection_diagnostics_.dns_list_ = {kIPv6DNSServer0, kIPv6DNSServer1}; |
| } |
| |
| 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); |
| } |
| |
| bool Start(const std::string& url) { |
| return connection_diagnostics_.Start( |
| *net_base::HttpUrl::CreateFromString(url)); |
| } |
| |
| 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_.icmp_session_->IsStarted()); |
| EXPECT_TRUE( |
| connection_diagnostics_.id_to_pending_dns_server_icmp_session_.empty()); |
| EXPECT_EQ(std::nullopt, connection_diagnostics_.target_url_); |
| } |
| |
| void ExpectIcmpSessionStop() { EXPECT_CALL(*icmp_session_, Stop()); } |
| |
| void ExpectSuccessfulStart() { |
| EXPECT_FALSE(connection_diagnostics_.running()); |
| EXPECT_TRUE(connection_diagnostics_.diagnostic_events_.empty()); |
| EXPECT_TRUE(Start(kHttpUrl)); |
| EXPECT_TRUE(connection_diagnostics_.running()); |
| } |
| |
| void ExpectPingDNSServersStartSuccess() { |
| ExpectPingDNSSeversStart(true, ""); |
| } |
| |
| 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(_, _, base::TimeDelta())); |
| connection_diagnostics_.OnPingDNSServerComplete(1, kEmptyResult); |
| } |
| |
| void ExpectResolveTargetServerIPAddressStartSuccess() { |
| AddExpectedEvent(ConnectionDiagnostics::kTypeResolveTargetServerIP, |
| ConnectionDiagnostics::kPhaseStart, |
| ConnectionDiagnostics::kResultSuccess); |
| std::vector<std::string> pingable_dns_servers; |
| for (const auto& dns : dns_list_) { |
| pingable_dns_servers.push_back(dns.ToString()); |
| } |
| EXPECT_CALL(*dns_client_, |
| Start(pingable_dns_servers, |
| connection_diagnostics_.target_url_->host(), _)) |
| .WillOnce(Return(true)); |
| connection_diagnostics_.ResolveTargetServerIPAddress(pingable_dns_servers); |
| } |
| |
| void ExpectResolveTargetServerIPAddressEndSuccess( |
| const net_base::IPAddress& resolved_address) { |
| ExpectResolveTargetServerIPAddressEnd(ConnectionDiagnostics::kResultSuccess, |
| resolved_address); |
| } |
| |
| void ExpectResolveTargetServerIPAddressEndTimeout() { |
| ExpectResolveTargetServerIPAddressEnd( |
| ConnectionDiagnostics::kResultTimeout, |
| net_base::IPAddress(net_base::IPFamily::kIPv4)); |
| } |
| |
| void ExpectResolveTargetServerIPAddressEndFailure() { |
| ExpectResolveTargetServerIPAddressEnd( |
| ConnectionDiagnostics::kResultFailure, |
| net_base::IPAddress(net_base::IPFamily::kIPv4)); |
| } |
| |
| void ExpectPingHostStartSuccess(ConnectionDiagnostics::Type ping_event_type, |
| const net_base::IPAddress& address) { |
| AddExpectedEvent(ping_event_type, ConnectionDiagnostics::kPhaseStart, |
| ConnectionDiagnostics::kResultSuccess); |
| EXPECT_CALL(*icmp_session_, Start(address, _, _)).WillOnce(Return(true)); |
| connection_diagnostics_.PingHost(address); |
| } |
| |
| void ExpectPingHostStartFailure(ConnectionDiagnostics::Type ping_event_type, |
| const net_base::IPAddress& address) { |
| AddExpectedEvent(ping_event_type, ConnectionDiagnostics::kPhaseStart, |
| ConnectionDiagnostics::kResultFailure); |
| EXPECT_CALL(*icmp_session_, Start(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 net_base::IPAddress& address) { |
| AddExpectedEvent(ping_event_type, ConnectionDiagnostics::kPhaseEnd, |
| ConnectionDiagnostics::kResultSuccess); |
| const auto& issue = |
| ping_event_type == ConnectionDiagnostics::kTypePingGateway |
| ? ConnectionDiagnostics::kIssueGatewayUpstream |
| : ConnectionDiagnostics::kIssueHTTP; |
| 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 net_base::IPAddress& address) { |
| AddExpectedEvent(ping_event_type, ConnectionDiagnostics::kPhaseEnd, |
| ConnectionDiagnostics::kResultFailure); |
| // If the ping destination was not the gateway, the next action is to try |
| // to ping the gateway. |
| if (ping_event_type == ConnectionDiagnostics::kTypePingTargetServer) { |
| EXPECT_CALL(dispatcher_, PostDelayedTask(_, _, base::TimeDelta())); |
| } |
| connection_diagnostics_.OnPingHostComplete(ping_event_type, address, |
| kEmptyResult); |
| } |
| |
| private: |
| // |expected_issue| only used if |is_success| is false. |
| void ExpectPingDNSSeversStart(bool is_success, |
| const std::string& expected_issue) { |
| AddExpectedEvent(ConnectionDiagnostics::kTypePingDNSServers, |
| ConnectionDiagnostics::kPhaseStart, |
| is_success ? ConnectionDiagnostics::kResultSuccess |
| : ConnectionDiagnostics::kResultFailure); |
| if (!is_success && |
| // If the DNS server addresses are invalid, we will not even attempt to |
| // start any ICMP sessions. |
| expected_issue == ConnectionDiagnostics::kIssueDNSServersInvalid) { |
| connection_diagnostics_.dns_list_ = {}; |
| } 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(kIPv4DNSServer0, _, _)) |
| .WillOnce(Return(is_success)); |
| EXPECT_CALL(*dns_server_icmp_session_1, Start(kIPv4DNSServer1, _, _)) |
| .WillOnce(Return(is_success)); |
| |
| connection_diagnostics_.id_to_pending_dns_server_icmp_session_.clear(); |
| connection_diagnostics_.id_to_pending_dns_server_icmp_session_[0] = |
| std::move(dns_server_icmp_session_0); |
| connection_diagnostics_.id_to_pending_dns_server_icmp_session_[1] = |
| 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 net_base::IPAddress& resolved_address) { |
| AddExpectedEvent(ConnectionDiagnostics::kTypeResolveTargetServerIP, |
| ConnectionDiagnostics::kPhaseEnd, result); |
| Error error; |
| if (result == ConnectionDiagnostics::kResultSuccess) { |
| error.Populate(Error::kSuccess); |
| EXPECT_CALL(dispatcher_, PostDelayedTask(_, _, base::TimeDelta())); |
| } else if (result == ConnectionDiagnostics::kResultTimeout) { |
| error.Populate(Error::kOperationTimeout); |
| EXPECT_CALL(dispatcher_, PostDelayedTask(_, _, base::TimeDelta())); |
| } else { |
| error.Populate(Error::kOperationFailed); |
| EXPECT_CALL(metrics_, |
| NotifyConnectionDiagnosticsIssue( |
| ConnectionDiagnostics::kIssueDNSServerMisconfig)); |
| EXPECT_CALL( |
| callback_target(), |
| ResultCallback(ConnectionDiagnostics::kIssueDNSServerMisconfig, |
| IsEventList(expected_events_))); |
| } |
| if (error.IsSuccess()) { |
| connection_diagnostics_.OnDNSResolutionComplete(resolved_address); |
| } else { |
| connection_diagnostics_.OnDNSResolutionComplete(base::unexpected(error)); |
| } |
| } |
| |
| 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(_, _, base::TimeDelta())); |
| EXPECT_CALL(metrics_, NotifyConnectionDiagnosticsIssue(_)).Times(0); |
| EXPECT_CALL(callback_target(), ResultCallback(_, _)).Times(0); |
| } else { |
| EXPECT_CALL(dispatcher_, PostDelayedTask(_, _, base::TimeDelta())) |
| .Times(0); |
| EXPECT_CALL(metrics_, |
| NotifyConnectionDiagnosticsIssue( |
| ConnectionDiagnostics::kIssueDNSServerNoResponse)); |
| EXPECT_CALL( |
| callback_target(), |
| ResultCallback(ConnectionDiagnostics::kIssueDNSServerNoResponse, |
| IsEventList(expected_events_))); |
| } |
| connection_diagnostics_.OnPingDNSServerComplete(1, kNonEmptyResult); |
| } |
| |
| net_base::IPAddress gateway_; |
| std::vector<net_base::IPAddress> dns_list_; |
| CallbackTarget callback_target_; |
| NiceMock<MockMetrics> metrics_; |
| ConnectionDiagnostics connection_diagnostics_; |
| NiceMock<MockEventDispatcher> dispatcher_; |
| |
| // Used only for EXPECT_CALL(). Objects are owned by |
| // |connection_diagnostics_|. |
| NiceMock<MockDnsClient>* dns_client_; |
| NiceMock<MockIcmpSession>* icmp_session_; |
| |
| // For each test, all events we expect to appear in the final result are |
| // accumulated in this vector. |
| std::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::kTypePingDNSServers, |
| ConnectionDiagnostics::kPhaseStart, |
| ConnectionDiagnostics::kResultSuccess, 0)); |
| EXPECT_FALSE( |
| DoesPreviousEventMatch(ConnectionDiagnostics::kTypePingDNSServers, |
| ConnectionDiagnostics::kPhaseStart, |
| ConnectionDiagnostics::kResultSuccess, 2)); |
| |
| AddActualEvent(ConnectionDiagnostics::kTypeResolveTargetServerIP, |
| ConnectionDiagnostics::kPhaseStart, |
| ConnectionDiagnostics::kResultSuccess); |
| AddActualEvent(ConnectionDiagnostics::kTypeResolveTargetServerIP, |
| ConnectionDiagnostics::kPhaseEnd, |
| ConnectionDiagnostics::kResultSuccess); |
| |
| // Matching out of bounds should fail. (2 events total, so 2 events before the |
| // last event is out of bounds). |
| EXPECT_FALSE( |
| DoesPreviousEventMatch(ConnectionDiagnostics::kTypeResolveTargetServerIP, |
| ConnectionDiagnostics::kPhaseStart, |
| ConnectionDiagnostics::kResultSuccess, 2)); |
| |
| // Valid matches. |
| EXPECT_TRUE( |
| DoesPreviousEventMatch(ConnectionDiagnostics::kTypeResolveTargetServerIP, |
| ConnectionDiagnostics::kPhaseStart, |
| ConnectionDiagnostics::kResultSuccess, 1)); |
| EXPECT_TRUE( |
| DoesPreviousEventMatch(ConnectionDiagnostics::kTypeResolveTargetServerIP, |
| ConnectionDiagnostics::kPhaseEnd, |
| ConnectionDiagnostics::kResultSuccess, 0)); |
| } |
| |
| TEST_F(ConnectionDiagnosticsTest, EndWith_InternalError) { |
| // DNS resolution succeeds, and we attempt to ping the target web server but |
| // fail because of an internal error. |
| ExpectSuccessfulStart(); |
| ExpectResolveTargetServerIPAddressStartSuccess(); |
| ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress); |
| ExpectPingHostStartFailure(ConnectionDiagnostics::kTypePingTargetServer, |
| kIPv4ServerAddress); |
| VerifyStopped(); |
| } |
| |
| TEST_F(ConnectionDiagnosticsTest, EndWith_DNSFailure) { |
| // DNS resolution fails (not timeout), so we end diagnostics. |
| ExpectSuccessfulStart(); |
| ExpectResolveTargetServerIPAddressStartSuccess(); |
| ExpectResolveTargetServerIPAddressEndFailure(); |
| VerifyStopped(); |
| } |
| |
| TEST_F(ConnectionDiagnosticsTest, EndWith_PingDNSServerStartFailure_1) { |
| // we attempt to pinging DNS servers, but fail to start any IcmpSessions, so |
| // end diagnostics. |
| ExpectSuccessfulStart(); |
| ExpectPingDNSSeversStartFailureAllIcmpSessionsFailed(); |
| VerifyStopped(); |
| } |
| |
| TEST_F(ConnectionDiagnosticsTest, EndWith_PingDNSServerEndSuccess_NoRetries_1) { |
| // 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. |
| ExpectSuccessfulStart(); |
| ExpectPingDNSServersStartSuccess(); |
| ExpectPingDNSServersEndSuccessRetriesLeft(); |
| ExpectResolveTargetServerIPAddressStartSuccess(); |
| ExpectResolveTargetServerIPAddressEndTimeout(); |
| ExpectPingDNSServersStartSuccess(); |
| ExpectPingDNSServersEndSuccessRetriesLeft(); |
| ExpectResolveTargetServerIPAddressStartSuccess(); |
| ExpectResolveTargetServerIPAddressEndTimeout(); |
| ExpectPingDNSServersStartSuccess(); |
| ExpectPingDNSServersEndSuccessNoRetriesLeft(); |
| VerifyStopped(); |
| } |
| |
| TEST_F(ConnectionDiagnosticsTest, EndWith_PingDNSServerEndSuccess_NoRetries_2) { |
| // 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. |
| ExpectSuccessfulStart(); |
| ExpectResolveTargetServerIPAddressStartSuccess(); |
| ExpectResolveTargetServerIPAddressEndTimeout(); |
| ExpectPingDNSServersStartSuccess(); |
| ExpectPingDNSServersEndSuccessRetriesLeft(); |
| ExpectResolveTargetServerIPAddressStartSuccess(); |
| ExpectResolveTargetServerIPAddressEndTimeout(); |
| ExpectPingDNSServersStartSuccess(); |
| ExpectPingDNSServersEndSuccessNoRetriesLeft(); |
| VerifyStopped(); |
| } |
| |
| TEST_F(ConnectionDiagnosticsTest, EndWith_PingTargetIPSuccess_1) { |
| // DNS resolution succeeds, and pinging the resolved IP address succeeds, so |
| // we end diagnostics. |
| ExpectSuccessfulStart(); |
| ExpectResolveTargetServerIPAddressStartSuccess(); |
| ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress); |
| ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer, |
| kIPv4ServerAddress); |
| ExpectPingHostEndSuccess(ConnectionDiagnostics::kTypePingTargetServer, |
| kIPv4ServerAddress); |
| VerifyStopped(); |
| } |
| |
| TEST_F(ConnectionDiagnosticsTest, EndWith_PingTargetIPSuccess_2) { |
| // pinging DNS servers succeeds, DNS resolution succeeds, and pinging the |
| // resolved IP address succeeds, so we end diagnostics. |
| ExpectSuccessfulStart(); |
| ExpectPingDNSServersStartSuccess(); |
| ExpectPingDNSServersEndSuccessRetriesLeft(); |
| ExpectResolveTargetServerIPAddressStartSuccess(); |
| ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress); |
| ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer, |
| kIPv4ServerAddress); |
| ExpectPingHostEndSuccess(ConnectionDiagnostics::kTypePingTargetServer, |
| kIPv4ServerAddress); |
| VerifyStopped(); |
| } |
| |
| TEST_F(ConnectionDiagnosticsTest, EndWith_PingTargetIPSuccess_3) { |
| // DNS resolution times out, pinging DNS servers succeeds, DNS resolution |
| // succeeds, and pinging the resolved IP address succeeds, so we end |
| // diagnostics. |
| ExpectSuccessfulStart(); |
| ExpectResolveTargetServerIPAddressStartSuccess(); |
| ExpectResolveTargetServerIPAddressEndTimeout(); |
| ExpectPingDNSServersStartSuccess(); |
| ExpectPingDNSServersEndSuccessRetriesLeft(); |
| ExpectResolveTargetServerIPAddressStartSuccess(); |
| ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress); |
| ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer, |
| kIPv4ServerAddress); |
| ExpectPingHostEndSuccess(ConnectionDiagnostics::kTypePingTargetServer, |
| kIPv4ServerAddress); |
| VerifyStopped(); |
| } |
| |
| TEST_F(ConnectionDiagnosticsTest, EndWith_PingGatewaySuccess_1_IPv4) { |
| // 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. |
| ExpectSuccessfulStart(); |
| ExpectResolveTargetServerIPAddressStartSuccess(); |
| ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress); |
| ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer, |
| kIPv4ServerAddress); |
| ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer, |
| kIPv4ServerAddress); |
| ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingGateway, |
| gateway()); |
| ExpectPingHostEndSuccess(ConnectionDiagnostics::kTypePingGateway, gateway()); |
| VerifyStopped(); |
| } |
| |
| TEST_F(ConnectionDiagnosticsTest, EndWith_PingGatewaySuccess_1_IPv6) { |
| // Same as above, but this time the resolved IP address of the target URL is |
| // IPv6. |
| UseIPv6(); |
| |
| ExpectSuccessfulStart(); |
| ExpectResolveTargetServerIPAddressStartSuccess(); |
| ExpectResolveTargetServerIPAddressEndSuccess(kIPv6ServerAddress); |
| ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer, |
| kIPv6ServerAddress); |
| ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer, |
| kIPv6ServerAddress); |
| ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingGateway, |
| gateway()); |
| ExpectPingHostEndSuccess(ConnectionDiagnostics::kTypePingGateway, gateway()); |
| VerifyStopped(); |
| } |
| |
| TEST_F(ConnectionDiagnosticsTest, EndWith_PingGatewaySuccess_2) { |
| // 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. |
| ExpectSuccessfulStart(); |
| ExpectPingDNSServersStartSuccess(); |
| ExpectPingDNSServersEndSuccessRetriesLeft(); |
| ExpectResolveTargetServerIPAddressStartSuccess(); |
| ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress); |
| ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer, |
| kIPv4ServerAddress); |
| ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingGateway, |
| gateway()); |
| ExpectPingHostEndSuccess(ConnectionDiagnostics::kTypePingGateway, gateway()); |
| VerifyStopped(); |
| } |
| |
| TEST_F(ConnectionDiagnosticsTest, EndWith_PingGatewaySuccess_3) { |
| // 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. |
| ExpectSuccessfulStart(); |
| ExpectResolveTargetServerIPAddressStartSuccess(); |
| ExpectResolveTargetServerIPAddressEndTimeout(); |
| ExpectPingDNSServersStartSuccess(); |
| ExpectPingDNSServersEndSuccessRetriesLeft(); |
| ExpectResolveTargetServerIPAddressStartSuccess(); |
| ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress); |
| ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer, |
| kIPv4ServerAddress); |
| ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer, |
| kIPv4ServerAddress); |
| ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingGateway, |
| gateway()); |
| ExpectPingHostEndSuccess(ConnectionDiagnostics::kTypePingGateway, gateway()); |
| VerifyStopped(); |
| } |
| |
| TEST_F(ConnectionDiagnosticsTest, EndWith_PingGatewayFailure) { |
| // DNS resolution succeeds, pinging the resolved IP address fails. Pinging |
| // the gateway also fails, so we end diagnostics. |
| ExpectSuccessfulStart(); |
| ExpectResolveTargetServerIPAddressStartSuccess(); |
| ExpectResolveTargetServerIPAddressEndSuccess(kIPv4ServerAddress); |
| ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingTargetServer, |
| kIPv4ServerAddress); |
| ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingTargetServer, |
| kIPv4ServerAddress); |
| ExpectPingHostStartSuccess(ConnectionDiagnostics::kTypePingGateway, |
| gateway()); |
| ExpectPingHostEndFailure(ConnectionDiagnostics::kTypePingGateway, gateway()); |
| VerifyStopped(); |
| } |
| |
| } // namespace shill |