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: 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 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 87 virtual void TearDown() { 88 cellular_->service_ = nullptr; // Break circular reference. 89 } 90 91 void OnConnectionHealthCheckerResult( 92 ConnectionHealthChecker::Result result) {} 93 94 protected: 95 static const char kAddress[]; 96 97 void SetMockServiceState(Service::ConnectState old_state, 98 Service::ConnectState new_state) { 99 out_of_credits_detector_->NotifyServiceStateChanged(old_state, new_state); 100 } 101 102 void SetTrafficMonitor(TrafficMonitor* traffic_monitor) { 103 out_of_credits_detector_->set_traffic_monitor(traffic_monitor); 104 } 105 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 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 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 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 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 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 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 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 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 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 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 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