1//
2// Copyright (C) 2012 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "shill/link_monitor.h"
18
19#include <string>
20
21#include <base/bind.h>
22#include <gtest/gtest.h>
23
24#include "shill/logging.h"
25#include "shill/mock_active_link_monitor.h"
26#include "shill/mock_connection.h"
27#include "shill/mock_control.h"
28#include "shill/mock_device_info.h"
29#include "shill/mock_event_dispatcher.h"
30#include "shill/mock_log.h"
31#include "shill/mock_metrics.h"
32#include "shill/mock_passive_link_monitor.h"
33#include "shill/net/byte_string.h"
34#include "shill/net/mock_time.h"
35
36using base::Bind;
37using base::Unretained;
38using std::string;
39using testing::_;
40using testing::AnyNumber;
41using testing::HasSubstr;
42using testing::Invoke;
43using testing::Mock;
44using testing::NiceMock;
45using testing::Return;
46using testing::ReturnRef;
47using testing::SetArgumentPointee;
48using testing::StrictMock;
49using testing::Test;
50
51namespace shill {
52
53namespace {
54const uint8_t kGatewayMACAddress[] = { 0, 1, 2, 3, 4, 5 };
55}  // namespace
56
57class LinkMonitorObserver {
58 public:
59  LinkMonitorObserver()
60      : failure_callback_(
61            Bind(&LinkMonitorObserver::OnFailureCallback, Unretained(this))),
62        gateway_change_callback_(
63            Bind(&LinkMonitorObserver::OnGatewayChangeCallback,
64                 Unretained(this))) {}
65  virtual ~LinkMonitorObserver() {}
66
67  MOCK_METHOD0(OnFailureCallback, void());
68  MOCK_METHOD0(OnGatewayChangeCallback, void());
69
70  const LinkMonitor::FailureCallback failure_callback() {
71    return failure_callback_;
72  }
73
74  const LinkMonitor::GatewayChangeCallback gateway_change_callback() {
75    return gateway_change_callback_;
76  }
77
78 private:
79  LinkMonitor::FailureCallback failure_callback_;
80  LinkMonitor::GatewayChangeCallback gateway_change_callback_;
81
82  DISALLOW_COPY_AND_ASSIGN(LinkMonitorObserver);
83};
84
85class LinkMonitorTest : public Test {
86 public:
87  LinkMonitorTest()
88      : metrics_(&dispatcher_),
89        device_info_(&control_, nullptr, nullptr, nullptr),
90        connection_(new StrictMock<MockConnection>(&device_info_)),
91        active_link_monitor_(new MockActiveLinkMonitor()),
92        passive_link_monitor_(new MockPassiveLinkMonitor()),
93        monitor_(connection_,
94                 &dispatcher_,
95                 &metrics_,
96                 &device_info_,
97                 observer_.failure_callback(),
98                 observer_.gateway_change_callback()) {}
99  virtual ~LinkMonitorTest() {}
100
101  virtual void SetUp() {
102    monitor_.active_link_monitor_.reset(active_link_monitor_);
103    monitor_.passive_link_monitor_.reset(passive_link_monitor_);
104    monitor_.time_ = &time_;
105
106    time_val_.tv_sec = 0;
107    time_val_.tv_usec = 0;
108    EXPECT_CALL(time_, GetTimeMonotonic(_))
109        .WillRepeatedly(DoAll(SetArgumentPointee<0>(time_val_), Return(0)));
110    EXPECT_CALL(*connection_, technology())
111        .WillRepeatedly(Return(Technology::kEthernet));
112  }
113
114  void AdvanceTime(int time_ms) {
115    struct timeval adv_time = {
116      static_cast<time_t>(time_ms/1000),
117      static_cast<time_t>((time_ms % 1000) * 1000) };
118    timeradd(&time_val_, &adv_time, &time_val_);
119    EXPECT_CALL(time_, GetTimeMonotonic(_))
120        .WillRepeatedly(DoAll(SetArgumentPointee<0>(time_val_), Return(0)));
121  }
122
123  void SetGatewayMacAddress(const ByteString& gateway_mac_address) {
124    monitor_.gateway_mac_address_ = gateway_mac_address;
125  }
126
127  void VerifyGatewayMacAddress(const ByteString& gateway_mac_address) {
128    EXPECT_TRUE(monitor_.gateway_mac_address_.Equals(gateway_mac_address));
129  }
130
131  void TriggerActiveLinkMonitorFailure(Metrics::LinkMonitorFailure failure,
132                                       int broadcast_failure_count,
133                                       int unicast_failure_count) {
134    monitor_.OnActiveLinkMonitorFailure(failure,
135                                    broadcast_failure_count,
136                                    unicast_failure_count);
137  }
138
139  void TriggerActiveLinkMonitorSuccess() {
140    monitor_.OnActiveLinkMonitorSuccess();
141  }
142
143  void TriggerPassiveLinkMonitorResultCallback(bool status) {
144    monitor_.OnPassiveLinkMonitorResultCallback(status);
145  }
146
147 protected:
148  MockEventDispatcher dispatcher_;
149  StrictMock<MockMetrics> metrics_;
150  MockControl control_;
151  NiceMock<MockDeviceInfo> device_info_;
152  scoped_refptr<MockConnection> connection_;
153  MockTime time_;
154  struct timeval time_val_;
155  MockActiveLinkMonitor* active_link_monitor_;
156  MockPassiveLinkMonitor* passive_link_monitor_;
157  LinkMonitorObserver observer_;
158  LinkMonitor monitor_;
159};
160
161MATCHER_P(IsMacAddress, mac_address, "") {
162  return mac_address.Equals(arg);
163}
164
165TEST_F(LinkMonitorTest, Start) {
166  EXPECT_CALL(*active_link_monitor_,
167              Start(ActiveLinkMonitor::kDefaultTestPeriodMilliseconds))
168      .WillOnce(Return(false));
169  EXPECT_FALSE(monitor_.Start());
170  Mock::VerifyAndClearExpectations(active_link_monitor_);
171
172  EXPECT_CALL(*active_link_monitor_,
173              Start(ActiveLinkMonitor::kDefaultTestPeriodMilliseconds))
174      .WillOnce(Return(true));
175  EXPECT_TRUE(monitor_.Start());
176  Mock::VerifyAndClearExpectations(active_link_monitor_);
177}
178
179TEST_F(LinkMonitorTest, OnAfterResume) {
180  ByteString gateway_mac(kGatewayMACAddress, arraysize(kGatewayMACAddress));
181  const bool kGatewayUnicastArpSupport = true;
182  SetGatewayMacAddress(gateway_mac);
183  // Verify gateway settings persist when link monitor is restarted, and
184  // active link monitor is started with fast test period.
185  EXPECT_CALL(*active_link_monitor_, Stop()).Times(1);
186  EXPECT_CALL(*passive_link_monitor_, Stop()).Times(1);
187  EXPECT_CALL(*active_link_monitor_, gateway_supports_unicast_arp())
188      .WillOnce(Return(kGatewayUnicastArpSupport));
189  EXPECT_CALL(*active_link_monitor_,
190              set_gateway_mac_address(IsMacAddress(gateway_mac)));
191  EXPECT_CALL(*active_link_monitor_,
192              set_gateway_supports_unicast_arp(kGatewayUnicastArpSupport));
193  EXPECT_CALL(*active_link_monitor_,
194              Start(ActiveLinkMonitor::kFastTestPeriodMilliseconds));
195  monitor_.OnAfterResume();
196  VerifyGatewayMacAddress(gateway_mac);
197  Mock::VerifyAndClearExpectations(active_link_monitor_);
198  Mock::VerifyAndClearExpectations(passive_link_monitor_);
199}
200
201TEST_F(LinkMonitorTest, OnActiveLinkMonitorFailure) {
202  // Start link monitor.
203  EXPECT_CALL(*active_link_monitor_,
204              Start(ActiveLinkMonitor::kDefaultTestPeriodMilliseconds))
205      .WillOnce(Return(true));
206  EXPECT_TRUE(monitor_.Start());
207  Mock::VerifyAndClearExpectations(active_link_monitor_);
208
209  const int kBroadcastFailureCount = 5;
210  const int kUnicastFailureCount = 3;
211  const int kElapsedTimeMilliseconds = 5000;
212
213  // Active monitor failed after 5 seconds.
214  EXPECT_CALL(observer_, OnFailureCallback()).Times(1);
215  EXPECT_CALL(metrics_, SendEnumToUMA(
216      HasSubstr("LinkMonitorFailure"),
217      Metrics::kLinkMonitorFailureThresholdReached, _));
218  EXPECT_CALL(metrics_, SendToUMA(
219      HasSubstr("LinkMonitorSecondsToFailure"), kElapsedTimeMilliseconds / 1000,
220      _, _, _));
221  EXPECT_CALL(metrics_, SendToUMA(
222      HasSubstr("BroadcastErrorsAtFailure"), kBroadcastFailureCount,
223      _, _, _));
224  EXPECT_CALL(metrics_, SendToUMA(
225      HasSubstr("UnicastErrorsAtFailure"), kUnicastFailureCount,
226      _, _, _));
227  AdvanceTime(kElapsedTimeMilliseconds);
228  TriggerActiveLinkMonitorFailure(Metrics::kLinkMonitorFailureThresholdReached,
229                                  kBroadcastFailureCount,
230                                  kUnicastFailureCount);
231}
232
233TEST_F(LinkMonitorTest, OnActiveLinkMonitorSuccess) {
234  ByteString gateway_mac(kGatewayMACAddress,
235                               arraysize(kGatewayMACAddress));
236  EXPECT_CALL(*active_link_monitor_, gateway_mac_address())
237      .WillRepeatedly(ReturnRef(gateway_mac));
238
239  // Active link monitor succeed for the first time, gateway MAC address will be
240  // updated.
241  EXPECT_CALL(observer_, OnGatewayChangeCallback()).Times(1);
242  EXPECT_CALL(*passive_link_monitor_, Start(
243      PassiveLinkMonitor::kDefaultMonitorCycles)).Times(1);
244  TriggerActiveLinkMonitorSuccess();
245  VerifyGatewayMacAddress(gateway_mac);
246  Mock::VerifyAndClearExpectations(&observer_);
247  Mock::VerifyAndClearExpectations(passive_link_monitor_);
248
249  // Active link monitor succeed again, gateway MAC address not changed.
250  EXPECT_CALL(observer_, OnGatewayChangeCallback()).Times(0);
251  EXPECT_CALL(*passive_link_monitor_, Start(
252      PassiveLinkMonitor::kDefaultMonitorCycles)).Times(1);
253  TriggerActiveLinkMonitorSuccess();
254  VerifyGatewayMacAddress(gateway_mac);
255  Mock::VerifyAndClearExpectations(&observer_);
256  Mock::VerifyAndClearExpectations(passive_link_monitor_);
257}
258
259TEST_F(LinkMonitorTest, OnPassiveLinkMonitorResultCallback) {
260  // Active link monitor should start regardless of the result of the passive
261  // link monitor.
262
263  EXPECT_CALL(*active_link_monitor_,
264              Start(ActiveLinkMonitor::kDefaultTestPeriodMilliseconds));
265  TriggerPassiveLinkMonitorResultCallback(true);
266  Mock::VerifyAndClearExpectations(active_link_monitor_);
267
268  EXPECT_CALL(*active_link_monitor_,
269              Start(ActiveLinkMonitor::kDefaultTestPeriodMilliseconds));
270  TriggerPassiveLinkMonitorResultCallback(false);
271  Mock::VerifyAndClearExpectations(active_link_monitor_);
272}
273
274}  // namespace shill
275