// // Copyright (C) 2012 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include "shill/link_monitor.h" #include #include #include #include "shill/logging.h" #include "shill/mock_active_link_monitor.h" #include "shill/mock_connection.h" #include "shill/mock_control.h" #include "shill/mock_device_info.h" #include "shill/mock_event_dispatcher.h" #include "shill/mock_log.h" #include "shill/mock_metrics.h" #include "shill/mock_passive_link_monitor.h" #include "shill/net/byte_string.h" #include "shill/net/mock_time.h" using base::Bind; using base::Unretained; using std::string; using testing::_; using testing::AnyNumber; using testing::HasSubstr; using testing::Invoke; using testing::Mock; using testing::NiceMock; using testing::Return; using testing::ReturnRef; using testing::SetArgumentPointee; using testing::StrictMock; using testing::Test; namespace shill { namespace { const uint8_t kGatewayMACAddress[] = { 0, 1, 2, 3, 4, 5 }; } // namespace class LinkMonitorObserver { public: LinkMonitorObserver() : failure_callback_( Bind(&LinkMonitorObserver::OnFailureCallback, Unretained(this))), gateway_change_callback_( Bind(&LinkMonitorObserver::OnGatewayChangeCallback, Unretained(this))) {} virtual ~LinkMonitorObserver() {} MOCK_METHOD0(OnFailureCallback, void()); MOCK_METHOD0(OnGatewayChangeCallback, void()); const LinkMonitor::FailureCallback failure_callback() { return failure_callback_; } const LinkMonitor::GatewayChangeCallback gateway_change_callback() { return gateway_change_callback_; } private: LinkMonitor::FailureCallback failure_callback_; LinkMonitor::GatewayChangeCallback gateway_change_callback_; DISALLOW_COPY_AND_ASSIGN(LinkMonitorObserver); }; class LinkMonitorTest : public Test { public: LinkMonitorTest() : metrics_(&dispatcher_), device_info_(&control_, nullptr, nullptr, nullptr), connection_(new StrictMock(&device_info_)), active_link_monitor_(new MockActiveLinkMonitor()), passive_link_monitor_(new MockPassiveLinkMonitor()), monitor_(connection_, &dispatcher_, &metrics_, &device_info_, observer_.failure_callback(), observer_.gateway_change_callback()) {} virtual ~LinkMonitorTest() {} virtual void SetUp() { monitor_.active_link_monitor_.reset(active_link_monitor_); monitor_.passive_link_monitor_.reset(passive_link_monitor_); monitor_.time_ = &time_; time_val_.tv_sec = 0; time_val_.tv_usec = 0; EXPECT_CALL(time_, GetTimeMonotonic(_)) .WillRepeatedly(DoAll(SetArgumentPointee<0>(time_val_), Return(0))); EXPECT_CALL(*connection_, technology()) .WillRepeatedly(Return(Technology::kEthernet)); } void AdvanceTime(int time_ms) { struct timeval adv_time = { static_cast(time_ms/1000), static_cast((time_ms % 1000) * 1000) }; timeradd(&time_val_, &adv_time, &time_val_); EXPECT_CALL(time_, GetTimeMonotonic(_)) .WillRepeatedly(DoAll(SetArgumentPointee<0>(time_val_), Return(0))); } void SetGatewayMacAddress(const ByteString& gateway_mac_address) { monitor_.gateway_mac_address_ = gateway_mac_address; } void VerifyGatewayMacAddress(const ByteString& gateway_mac_address) { EXPECT_TRUE(monitor_.gateway_mac_address_.Equals(gateway_mac_address)); } void TriggerActiveLinkMonitorFailure(Metrics::LinkMonitorFailure failure, int broadcast_failure_count, int unicast_failure_count) { monitor_.OnActiveLinkMonitorFailure(failure, broadcast_failure_count, unicast_failure_count); } void TriggerActiveLinkMonitorSuccess() { monitor_.OnActiveLinkMonitorSuccess(); } void TriggerPassiveLinkMonitorResultCallback(bool status) { monitor_.OnPassiveLinkMonitorResultCallback(status); } protected: MockEventDispatcher dispatcher_; StrictMock metrics_; MockControl control_; NiceMock device_info_; scoped_refptr connection_; MockTime time_; struct timeval time_val_; MockActiveLinkMonitor* active_link_monitor_; MockPassiveLinkMonitor* passive_link_monitor_; LinkMonitorObserver observer_; LinkMonitor monitor_; }; MATCHER_P(IsMacAddress, mac_address, "") { return mac_address.Equals(arg); } TEST_F(LinkMonitorTest, Start) { EXPECT_CALL(*active_link_monitor_, Start(ActiveLinkMonitor::kDefaultTestPeriodMilliseconds)) .WillOnce(Return(false)); EXPECT_FALSE(monitor_.Start()); Mock::VerifyAndClearExpectations(active_link_monitor_); EXPECT_CALL(*active_link_monitor_, Start(ActiveLinkMonitor::kDefaultTestPeriodMilliseconds)) .WillOnce(Return(true)); EXPECT_TRUE(monitor_.Start()); Mock::VerifyAndClearExpectations(active_link_monitor_); } TEST_F(LinkMonitorTest, OnAfterResume) { ByteString gateway_mac(kGatewayMACAddress, arraysize(kGatewayMACAddress)); const bool kGatewayUnicastArpSupport = true; SetGatewayMacAddress(gateway_mac); // Verify gateway settings persist when link monitor is restarted, and // active link monitor is started with fast test period. EXPECT_CALL(*active_link_monitor_, Stop()).Times(1); EXPECT_CALL(*passive_link_monitor_, Stop()).Times(1); EXPECT_CALL(*active_link_monitor_, gateway_supports_unicast_arp()) .WillOnce(Return(kGatewayUnicastArpSupport)); EXPECT_CALL(*active_link_monitor_, set_gateway_mac_address(IsMacAddress(gateway_mac))); EXPECT_CALL(*active_link_monitor_, set_gateway_supports_unicast_arp(kGatewayUnicastArpSupport)); EXPECT_CALL(*active_link_monitor_, Start(ActiveLinkMonitor::kFastTestPeriodMilliseconds)); monitor_.OnAfterResume(); VerifyGatewayMacAddress(gateway_mac); Mock::VerifyAndClearExpectations(active_link_monitor_); Mock::VerifyAndClearExpectations(passive_link_monitor_); } TEST_F(LinkMonitorTest, OnActiveLinkMonitorFailure) { // Start link monitor. EXPECT_CALL(*active_link_monitor_, Start(ActiveLinkMonitor::kDefaultTestPeriodMilliseconds)) .WillOnce(Return(true)); EXPECT_TRUE(monitor_.Start()); Mock::VerifyAndClearExpectations(active_link_monitor_); const int kBroadcastFailureCount = 5; const int kUnicastFailureCount = 3; const int kElapsedTimeMilliseconds = 5000; // Active monitor failed after 5 seconds. EXPECT_CALL(observer_, OnFailureCallback()).Times(1); EXPECT_CALL(metrics_, SendEnumToUMA( HasSubstr("LinkMonitorFailure"), Metrics::kLinkMonitorFailureThresholdReached, _)); EXPECT_CALL(metrics_, SendToUMA( HasSubstr("LinkMonitorSecondsToFailure"), kElapsedTimeMilliseconds / 1000, _, _, _)); EXPECT_CALL(metrics_, SendToUMA( HasSubstr("BroadcastErrorsAtFailure"), kBroadcastFailureCount, _, _, _)); EXPECT_CALL(metrics_, SendToUMA( HasSubstr("UnicastErrorsAtFailure"), kUnicastFailureCount, _, _, _)); AdvanceTime(kElapsedTimeMilliseconds); TriggerActiveLinkMonitorFailure(Metrics::kLinkMonitorFailureThresholdReached, kBroadcastFailureCount, kUnicastFailureCount); } TEST_F(LinkMonitorTest, OnActiveLinkMonitorSuccess) { ByteString gateway_mac(kGatewayMACAddress, arraysize(kGatewayMACAddress)); EXPECT_CALL(*active_link_monitor_, gateway_mac_address()) .WillRepeatedly(ReturnRef(gateway_mac)); // Active link monitor succeed for the first time, gateway MAC address will be // updated. EXPECT_CALL(observer_, OnGatewayChangeCallback()).Times(1); EXPECT_CALL(*passive_link_monitor_, Start( PassiveLinkMonitor::kDefaultMonitorCycles)).Times(1); TriggerActiveLinkMonitorSuccess(); VerifyGatewayMacAddress(gateway_mac); Mock::VerifyAndClearExpectations(&observer_); Mock::VerifyAndClearExpectations(passive_link_monitor_); // Active link monitor succeed again, gateway MAC address not changed. EXPECT_CALL(observer_, OnGatewayChangeCallback()).Times(0); EXPECT_CALL(*passive_link_monitor_, Start( PassiveLinkMonitor::kDefaultMonitorCycles)).Times(1); TriggerActiveLinkMonitorSuccess(); VerifyGatewayMacAddress(gateway_mac); Mock::VerifyAndClearExpectations(&observer_); Mock::VerifyAndClearExpectations(passive_link_monitor_); } TEST_F(LinkMonitorTest, OnPassiveLinkMonitorResultCallback) { // Active link monitor should start regardless of the result of the passive // link monitor. EXPECT_CALL(*active_link_monitor_, Start(ActiveLinkMonitor::kDefaultTestPeriodMilliseconds)); TriggerPassiveLinkMonitorResultCallback(true); Mock::VerifyAndClearExpectations(active_link_monitor_); EXPECT_CALL(*active_link_monitor_, Start(ActiveLinkMonitor::kDefaultTestPeriodMilliseconds)); TriggerPassiveLinkMonitorResultCallback(false); Mock::VerifyAndClearExpectations(active_link_monitor_); } } // namespace shill