1 //
2 // Copyright (C) 2013 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/cellular/active_passive_out_of_credits_detector.h"
18
19 #include <string>
20 #include <vector>
21
22 #include <gtest/gtest.h>
23
24 #include "shill/cellular/mock_cellular.h"
25 #include "shill/cellular/mock_cellular_service.h"
26 #include "shill/cellular/mock_modem_info.h"
27 #include "shill/mock_connection.h"
28 #include "shill/mock_connection_health_checker.h"
29 #include "shill/mock_device_info.h"
30 #include "shill/mock_manager.h"
31 #include "shill/mock_traffic_monitor.h"
32 #include "shill/test_event_dispatcher.h"
33
34 using base::Bind;
35 using base::Unretained;
36 using std::string;
37 using std::vector;
38 using testing::_;
39 using testing::AnyNumber;
40 using testing::Mock;
41 using testing::NiceMock;
42 using testing::Return;
43 using testing::ReturnPointee;
44 using testing::ReturnRef;
45 using testing::StrictMock;
46
47 namespace shill {
48
49 class ActivePassiveOutOfCreditsDetectorTest : public testing::Test {
50 public:
ActivePassiveOutOfCreditsDetectorTest()51 ActivePassiveOutOfCreditsDetectorTest()
52 : modem_info_(nullptr, &dispatcher_, &metrics_, &manager_),
53 device_info_(modem_info_.control_interface(), modem_info_.dispatcher(),
54 modem_info_.metrics(), modem_info_.manager()),
55 manager_(modem_info_.control_interface(), modem_info_.dispatcher(),
56 modem_info_.metrics()),
57 metrics_(modem_info_.dispatcher()),
58 cellular_(new NiceMock<MockCellular>(&modem_info_,
59 "usb0",
60 kAddress,
61 3,
62 Cellular::kTypeCDMA,
63 "",
64 "")),
65 service_(new NiceMock<MockCellularService>(&modem_info_, cellular_)),
66 connection_(new NiceMock<MockConnection>(&device_info_)),
67 out_of_credits_detector_(
68 new ActivePassiveOutOfCreditsDetector(
69 modem_info_.dispatcher(), modem_info_.manager(),
70 modem_info_.metrics(), service_.get())) {}
71
SetUp()72 virtual void SetUp() {
73 service_->connection_ = connection_;
74 cellular_->service_ = service_;
75 service_->SetRoamingState(kRoamingStateHome);
76 ON_CALL(*connection_, interface_name())
77 .WillByDefault(ReturnRef(interface_name_));
78 ON_CALL(*connection_, dns_servers())
79 .WillByDefault(ReturnRef(dns_servers_));
80 ON_CALL(manager_, GetPortalCheckURL())
81 .WillByDefault(ReturnRef(portal_check_url_));
82 ON_CALL(*service_, explicitly_disconnected()).WillByDefault(Return(false));
83 ON_CALL(*service_, resume_start_time())
84 .WillByDefault(ReturnRef(resume_start_time_));
85 }
86
TearDown()87 virtual void TearDown() {
88 cellular_->service_ = nullptr; // Break circular reference.
89 }
90
OnConnectionHealthCheckerResult(ConnectionHealthChecker::Result result)91 void OnConnectionHealthCheckerResult(
92 ConnectionHealthChecker::Result result) {}
93
94 protected:
95 static const char kAddress[];
96
SetMockServiceState(Service::ConnectState old_state,Service::ConnectState new_state)97 void SetMockServiceState(Service::ConnectState old_state,
98 Service::ConnectState new_state) {
99 out_of_credits_detector_->NotifyServiceStateChanged(old_state, new_state);
100 }
101
SetTrafficMonitor(TrafficMonitor * traffic_monitor)102 void SetTrafficMonitor(TrafficMonitor* traffic_monitor) {
103 out_of_credits_detector_->set_traffic_monitor(traffic_monitor);
104 }
105
SetConnectionHealthChecker(ConnectionHealthChecker * health_checker)106 void SetConnectionHealthChecker(ConnectionHealthChecker* health_checker) {
107 out_of_credits_detector_->set_connection_health_checker(health_checker);
108 }
109
110 EventDispatcherForTest dispatcher_;
111 MockModemInfo modem_info_;
112 NiceMock<MockDeviceInfo> device_info_;
113 NiceMock<MockManager> manager_;
114 NiceMock<MockMetrics> metrics_;
115 scoped_refptr<NiceMock<MockCellular>> cellular_;
116 scoped_refptr<NiceMock<MockCellularService>> service_;
117 scoped_refptr<NiceMock<MockConnection>> connection_;
118 string interface_name_;
119 vector<string> dns_servers_;
120 string portal_check_url_;
121 base::Time resume_start_time_;
122 std::unique_ptr<ActivePassiveOutOfCreditsDetector> out_of_credits_detector_;
123 };
124
125 const char ActivePassiveOutOfCreditsDetectorTest::kAddress[] = "000102030405";
126
TEST_F(ActivePassiveOutOfCreditsDetectorTest,ConnectDisconnectLoopOutOfCreditsDetected)127 TEST_F(ActivePassiveOutOfCreditsDetectorTest,
128 ConnectDisconnectLoopOutOfCreditsDetected) {
129 EXPECT_CALL(*service_, Connect(_, _)).Times(2);
130 SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
131 SetMockServiceState(Service::kStateAssociating, Service::kStateConnected);
132 SetMockServiceState(Service::kStateConnected, Service::kStateFailure);
133 EXPECT_TRUE(out_of_credits_detector_->IsDetecting());
134 dispatcher_.DispatchPendingEvents();
135 SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
136 SetMockServiceState(Service::kStateAssociating, Service::kStateConfiguring);
137 SetMockServiceState(Service::kStateConfiguring, Service::kStateIdle);
138 EXPECT_TRUE(out_of_credits_detector_->IsDetecting());
139 dispatcher_.DispatchPendingEvents();
140 SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
141 SetMockServiceState(Service::kStateAssociating, Service::kStateConnected);
142 SetMockServiceState(Service::kStateConnected, Service::kStateIdle);
143 EXPECT_TRUE(out_of_credits_detector_->out_of_credits());
144 EXPECT_FALSE(out_of_credits_detector_->IsDetecting());
145 }
146
TEST_F(ActivePassiveOutOfCreditsDetectorTest,ConnectDisconnectLoopDetectionNotSkippedAfterSlowResume)147 TEST_F(ActivePassiveOutOfCreditsDetectorTest,
148 ConnectDisconnectLoopDetectionNotSkippedAfterSlowResume) {
149 resume_start_time_ =
150 base::Time::Now() -
151 base::TimeDelta::FromSeconds(
152 ActivePassiveOutOfCreditsDetector::kOutOfCreditsResumeIgnoreSeconds + 1);
153 EXPECT_CALL(*service_, Connect(_, _)).Times(2);
154 SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
155 SetMockServiceState(Service::kStateAssociating, Service::kStateFailure);
156 EXPECT_TRUE(out_of_credits_detector_->IsDetecting());
157 dispatcher_.DispatchPendingEvents();
158 SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
159 SetMockServiceState(Service::kStateAssociating, Service::kStateConfiguring);
160 SetMockServiceState(Service::kStateConfiguring, Service::kStateIdle);
161 EXPECT_TRUE(out_of_credits_detector_->IsDetecting());
162 dispatcher_.DispatchPendingEvents();
163 SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
164 SetMockServiceState(Service::kStateAssociating, Service::kStateConnected);
165 SetMockServiceState(Service::kStateConnected, Service::kStateIdle);
166 EXPECT_TRUE(out_of_credits_detector_->out_of_credits());
167 EXPECT_FALSE(out_of_credits_detector_->IsDetecting());
168 }
169
TEST_F(ActivePassiveOutOfCreditsDetectorTest,ConnectDisconnectLoopDetectionSkippedAfterResume)170 TEST_F(ActivePassiveOutOfCreditsDetectorTest,
171 ConnectDisconnectLoopDetectionSkippedAfterResume) {
172 resume_start_time_ = base::Time::Now();
173 ON_CALL(*service_, resume_start_time())
174 .WillByDefault(ReturnRef(resume_start_time_));
175 EXPECT_CALL(*service_, Connect(_, _)).Times(0);
176 SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
177 SetMockServiceState(Service::kStateAssociating, Service::kStateConnected);
178 SetMockServiceState(Service::kStateConnected, Service::kStateIdle);
179 EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
180 EXPECT_FALSE(out_of_credits_detector_->IsDetecting());
181 // There should not be any pending connect requests but dispatch pending
182 // events anyway to be sure.
183 dispatcher_.DispatchPendingEvents();
184 }
185
TEST_F(ActivePassiveOutOfCreditsDetectorTest,ConnectDisconnectLoopDetectionSkippedAlreadyOutOfCredits)186 TEST_F(ActivePassiveOutOfCreditsDetectorTest,
187 ConnectDisconnectLoopDetectionSkippedAlreadyOutOfCredits) {
188 EXPECT_CALL(*service_, Connect(_, _)).Times(0);
189 out_of_credits_detector_->ReportOutOfCredits(true);
190 SetMockServiceState(Service::kStateAssociating, Service::kStateConnected);
191 SetMockServiceState(Service::kStateConnected, Service::kStateIdle);
192 EXPECT_FALSE(out_of_credits_detector_->IsDetecting());
193 // There should not be any pending connect requests but dispatch pending
194 // events anyway to be sure.
195 dispatcher_.DispatchPendingEvents();
196 }
197
TEST_F(ActivePassiveOutOfCreditsDetectorTest,ConnectDisconnectLoopDetectionSkippedExplicitDisconnect)198 TEST_F(ActivePassiveOutOfCreditsDetectorTest,
199 ConnectDisconnectLoopDetectionSkippedExplicitDisconnect) {
200 EXPECT_CALL(*service_, Connect(_, _)).Times(0);
201 SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
202 SetMockServiceState(Service::kStateAssociating, Service::kStateConnected);
203 EXPECT_CALL(*service_, explicitly_disconnected()).WillOnce(Return(true));
204 SetMockServiceState(Service::kStateConnected, Service::kStateIdle);
205 EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
206 EXPECT_FALSE(out_of_credits_detector_->IsDetecting());
207 // There should not be any pending connect requests but dispatch pending
208 // events anyway to be sure.
209 dispatcher_.DispatchPendingEvents();
210 }
211
TEST_F(ActivePassiveOutOfCreditsDetectorTest,ConnectDisconnectLoopDetectionConnectionNotDropped)212 TEST_F(ActivePassiveOutOfCreditsDetectorTest,
213 ConnectDisconnectLoopDetectionConnectionNotDropped) {
214 EXPECT_CALL(*service_, Connect(_, _)).Times(0);
215 SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
216 SetMockServiceState(Service::kStateAssociating, Service::kStateConfiguring);
217 SetMockServiceState(Service::kStateConfiguring, Service::kStateConnected);
218 EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
219 EXPECT_FALSE(out_of_credits_detector_->IsDetecting());
220 // There should not be any pending connect requests but dispatch pending
221 // events anyway to be sure.
222 dispatcher_.DispatchPendingEvents();
223 }
224
TEST_F(ActivePassiveOutOfCreditsDetectorTest,ConnectDisconnectLoopDetectionIntermittentNetwork)225 TEST_F(ActivePassiveOutOfCreditsDetectorTest,
226 ConnectDisconnectLoopDetectionIntermittentNetwork) {
227 EXPECT_CALL(*service_, Connect(_, _)).Times(0);
228 SetMockServiceState(Service::kStateAssociating, Service::kStateConnected);
229 out_of_credits_detector_->connect_start_time_ =
230 base::Time::Now() -
231 base::TimeDelta::FromSeconds(
232 ActivePassiveOutOfCreditsDetector::
233 kOutOfCreditsConnectionDropSeconds + 1);
234 SetMockServiceState(Service::kStateConnected, Service::kStateIdle);
235 EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
236 EXPECT_FALSE(out_of_credits_detector_->IsDetecting());
237 // There should not be any pending connect requests but dispatch pending
238 // events anyway to be sure.
239 dispatcher_.DispatchPendingEvents();
240 }
241
TEST_F(ActivePassiveOutOfCreditsDetectorTest,StartTrafficMonitor)242 TEST_F(ActivePassiveOutOfCreditsDetectorTest, StartTrafficMonitor) {
243 MockTrafficMonitor* traffic_monitor = new StrictMock<MockTrafficMonitor>();
244 SetTrafficMonitor(traffic_monitor); // Passes ownership.
245
246 // Traffic monitor should only start when the service is connected.
247 EXPECT_CALL(*traffic_monitor, Start()).Times(1);
248 SetMockServiceState(Service::kStateAssociating, Service::kStateConnected);
249 Mock::VerifyAndClearExpectations(traffic_monitor);
250
251 // Traffic monitor should not start for other state transitions.
252 EXPECT_CALL(*traffic_monitor, Start()).Times(0);
253 EXPECT_CALL(*traffic_monitor, Stop()).Times(AnyNumber());
254 SetMockServiceState(Service::kStateConnected, Service::kStateIdle);
255 SetMockServiceState(Service::kStateIdle, Service::kStateConfiguring);
256 SetMockServiceState(Service::kStateConfiguring, Service::kStateFailure);
257 SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
258 SetMockServiceState(Service::kStateConfiguring, Service::kStatePortal);
259 SetMockServiceState(Service::kStatePortal, Service::kStateOnline);
260 }
261
TEST_F(ActivePassiveOutOfCreditsDetectorTest,StopTrafficMonitor)262 TEST_F(ActivePassiveOutOfCreditsDetectorTest, StopTrafficMonitor) {
263 // Traffic monitor should stop when the service is disconnected.
264 MockTrafficMonitor* traffic_monitor = new StrictMock<MockTrafficMonitor>();
265 SetTrafficMonitor(traffic_monitor); // Passes ownership.
266 EXPECT_CALL(*traffic_monitor, Start());
267 EXPECT_CALL(*traffic_monitor, Stop());
268 SetMockServiceState(Service::kStateAssociating, Service::kStateConnected);
269 SetMockServiceState(Service::kStateConnected, Service::kStateIdle);
270 Mock::VerifyAndClearExpectations(traffic_monitor);
271
272 EXPECT_CALL(*traffic_monitor, Start());
273 EXPECT_CALL(*traffic_monitor, Stop());
274 SetMockServiceState(Service::kStateIdle, Service::kStateConnected);
275 SetMockServiceState(Service::kStateConnected, Service::kStateFailure);
276 Mock::VerifyAndClearExpectations(traffic_monitor);
277
278 // Need an additional call to Stop() because |traffic_monitor| destructor
279 // will call stop.
280 EXPECT_CALL(*traffic_monitor, Stop());
281 }
282
TEST_F(ActivePassiveOutOfCreditsDetectorTest,OnNoNetworkRouting)283 TEST_F(ActivePassiveOutOfCreditsDetectorTest, OnNoNetworkRouting) {
284 // Make sure the connection health checker starts when there is no network
285 // routing.
286 EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
287 MockConnectionHealthChecker* health_checker =
288 new MockConnectionHealthChecker(
289 service_->connection(),
290 modem_info_.dispatcher(),
291 manager_.health_checker_remote_ips(),
292 Bind(&ActivePassiveOutOfCreditsDetectorTest::
293 OnConnectionHealthCheckerResult,
294 Unretained(this)));
295 SetConnectionHealthChecker(health_checker); // Passes ownership.
296 EXPECT_CALL(*health_checker, Start());
297 out_of_credits_detector_->OnNoNetworkRouting(0);
298 EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
299 Mock::VerifyAndClearExpectations(health_checker);
300
301 // Make sure connection health checker does not start again if there is a
302 // health check in progress.
303 EXPECT_CALL(*health_checker, health_check_in_progress())
304 .WillOnce(Return(true));
305 EXPECT_CALL(*health_checker, Start()).Times(0);
306 out_of_credits_detector_->OnNoNetworkRouting(0);
307 }
308
TEST_F(ActivePassiveOutOfCreditsDetectorTest,OnConnectionHealthCheckerResult)309 TEST_F(ActivePassiveOutOfCreditsDetectorTest,
310 OnConnectionHealthCheckerResult) {
311 EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
312 EXPECT_CALL(*service_, Disconnect(_, _)).Times(0);
313 out_of_credits_detector_->OnConnectionHealthCheckerResult(
314 ConnectionHealthChecker::kResultUnknown);
315 EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
316 out_of_credits_detector_->OnConnectionHealthCheckerResult(
317 ConnectionHealthChecker::kResultConnectionFailure);
318 EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
319 Mock::VerifyAndClearExpectations(service_.get());
320
321 EXPECT_CALL(*service_, Disconnect(_,
322 ::testing::StrEq("out-of-credits"))).
323 Times(1);
324 out_of_credits_detector_->OnConnectionHealthCheckerResult(
325 ConnectionHealthChecker::kResultCongestedTxQueue);
326 EXPECT_TRUE(out_of_credits_detector_->out_of_credits());
327 }
328
329 } // namespace shill
330