cellular_service_unittest.cc revision 608ec29525f553d51f0a92e84176e3d4b45930a9
1// Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "shill/cellular/cellular_service.h" 6 7#include <chromeos/dbus/service_constants.h> 8#include <gtest/gtest.h> 9#include <mm/mm-modem.h> 10 11#include "shill/cellular/cellular_capability.h" 12#include "shill/cellular/cellular_capability_cdma.h" 13#include "shill/cellular/mock_cellular.h" 14#include "shill/cellular/mock_modem_info.h" 15#include "shill/cellular/mock_out_of_credits_detector.h" 16#include "shill/mock_adaptors.h" 17#include "shill/mock_manager.h" 18#include "shill/mock_metrics.h" 19#include "shill/mock_profile.h" 20#include "shill/mock_store.h" 21#include "shill/nice_mock_control.h" 22#include "shill/service_property_change_test.h" 23 24using std::string; 25using testing::_; 26using testing::InSequence; 27using testing::Mock; 28using testing::NiceMock; 29using testing::Return; 30using testing::SetArgumentPointee; 31 32namespace shill { 33 34class CellularServiceTest : public testing::Test { 35 public: 36 CellularServiceTest() 37 : modem_info_(nullptr, &dispatcher_, nullptr, nullptr, nullptr), 38 device_(new MockCellular(&modem_info_, 39 "usb0", 40 kAddress, 41 3, 42 Cellular::kTypeCDMA, 43 "", 44 "", 45 "")), 46 service_(new CellularService(&modem_info_, device_)), 47 adaptor_(nullptr) {} 48 49 virtual ~CellularServiceTest() { 50 adaptor_ = nullptr; 51 } 52 53 virtual void SetUp() { 54 adaptor_ = 55 dynamic_cast<ServiceMockAdaptor*>(service_->adaptor()); 56 out_of_credits_detector_ = 57 new MockOutOfCreditsDetector(nullptr, nullptr, nullptr, service_.get()); 58 // Passes ownership. 59 service_->set_out_of_credits_detector(out_of_credits_detector_); 60 } 61 62 CellularCapabilityCDMA* GetCapabilityCDMA() { 63 return dynamic_cast<CellularCapabilityCDMA*>(device_->capability_.get()); 64 } 65 66 protected: 67 static const char kAddress[]; 68 69 string GetFriendlyName() const { return service_->friendly_name(); } 70 71 EventDispatcher dispatcher_; 72 MockModemInfo modem_info_; 73 scoped_refptr<MockCellular> device_; 74 CellularServiceRefPtr service_; 75 ServiceMockAdaptor* adaptor_; // Owned by |service_|. 76 MockOutOfCreditsDetector* out_of_credits_detector_; // Owned by |service_|. 77}; 78 79const char CellularServiceTest::kAddress[] = "000102030405"; 80 81TEST_F(CellularServiceTest, Constructor) { 82 EXPECT_TRUE(service_->connectable()); 83} 84 85TEST_F(CellularServiceTest, SetActivationState) { 86 { 87 InSequence call_sequence; 88 EXPECT_CALL(*adaptor_, EmitStringChanged( 89 kActivationStateProperty, 90 kActivationStateNotActivated)); 91 EXPECT_CALL(*adaptor_, EmitBoolChanged( 92 kConnectableProperty, false)); 93 EXPECT_CALL(*adaptor_, EmitStringChanged( 94 kActivationStateProperty, 95 kActivationStateActivating)); 96 EXPECT_CALL(*adaptor_, EmitBoolChanged( 97 kConnectableProperty, true)); 98 EXPECT_CALL(*adaptor_, EmitStringChanged( 99 kActivationStateProperty, 100 kActivationStatePartiallyActivated)); 101 EXPECT_CALL(*adaptor_, EmitStringChanged( 102 kActivationStateProperty, 103 kActivationStateActivated)); 104 EXPECT_CALL(*adaptor_, EmitStringChanged( 105 kActivationStateProperty, 106 kActivationStateNotActivated)); 107 EXPECT_CALL(*adaptor_, EmitBoolChanged( 108 kConnectableProperty, false)); 109 } 110 EXPECT_CALL(*modem_info_.mock_manager(), HasService(_)) 111 .WillRepeatedly(Return(false)); 112 113 EXPECT_TRUE(service_->activation_state().empty()); 114 EXPECT_TRUE(service_->connectable()); 115 116 service_->SetActivationState(kActivationStateNotActivated); 117 EXPECT_EQ(kActivationStateNotActivated, service_->activation_state()); 118 EXPECT_FALSE(service_->connectable()); 119 120 service_->SetActivationState(kActivationStateActivating); 121 EXPECT_EQ(kActivationStateActivating, service_->activation_state()); 122 EXPECT_TRUE(service_->connectable()); 123 124 service_->SetActivationState(kActivationStatePartiallyActivated); 125 EXPECT_EQ(kActivationStatePartiallyActivated, service_->activation_state()); 126 EXPECT_TRUE(service_->connectable()); 127 128 service_->SetActivationState(kActivationStateActivated); 129 EXPECT_EQ(kActivationStateActivated, service_->activation_state()); 130 EXPECT_TRUE(service_->connectable()); 131 132 service_->SetActivationState(kActivationStateNotActivated); 133 EXPECT_EQ(kActivationStateNotActivated, service_->activation_state()); 134 EXPECT_FALSE(service_->connectable()); 135} 136 137TEST_F(CellularServiceTest, SetNetworkTechnology) { 138 EXPECT_CALL(*adaptor_, EmitStringChanged(kNetworkTechnologyProperty, 139 kNetworkTechnologyUmts)); 140 EXPECT_TRUE(service_->network_technology().empty()); 141 service_->SetNetworkTechnology(kNetworkTechnologyUmts); 142 EXPECT_EQ(kNetworkTechnologyUmts, service_->network_technology()); 143 service_->SetNetworkTechnology(kNetworkTechnologyUmts); 144} 145 146TEST_F(CellularServiceTest, SetRoamingState) { 147 EXPECT_CALL(*adaptor_, EmitStringChanged(kRoamingStateProperty, 148 kRoamingStateHome)); 149 EXPECT_TRUE(service_->roaming_state().empty()); 150 service_->SetRoamingState(kRoamingStateHome); 151 EXPECT_EQ(kRoamingStateHome, service_->roaming_state()); 152 service_->SetRoamingState(kRoamingStateHome); 153} 154 155TEST_F(CellularServiceTest, SetStorageIdentifier) { 156 EXPECT_EQ(string(kTypeCellular) + "_" + 157 kAddress + "_" + GetFriendlyName(), 158 service_->GetStorageIdentifier()); 159 service_->SetStorageIdentifier("a b c"); 160 EXPECT_EQ("a_b_c", service_->GetStorageIdentifier()); 161} 162 163TEST_F(CellularServiceTest, SetServingOperator) { 164 static const char kCode[] = "123456"; 165 static const char kName[] = "Some Cellular Operator"; 166 Stringmap test_operator; 167 service_->set_serving_operator(test_operator); 168 test_operator[kOperatorCodeKey] = kCode; 169 test_operator[kOperatorNameKey] = kName; 170 EXPECT_CALL(*adaptor_, 171 EmitStringmapChanged(kServingOperatorProperty, _)); 172 service_->set_serving_operator(test_operator); 173 const Stringmap& serving_operator = service_->serving_operator(); 174 ASSERT_NE(serving_operator.end(), serving_operator.find(kOperatorCodeKey)); 175 ASSERT_NE(serving_operator.end(), serving_operator.find(kOperatorNameKey)); 176 EXPECT_EQ(kCode, serving_operator.find(kOperatorCodeKey)->second); 177 EXPECT_EQ(kName, serving_operator.find(kOperatorNameKey)->second); 178 Mock::VerifyAndClearExpectations(adaptor_); 179 EXPECT_CALL(*adaptor_, 180 EmitStringmapChanged(kServingOperatorProperty, _)).Times(0); 181 service_->set_serving_operator(serving_operator); 182} 183 184TEST_F(CellularServiceTest, SetOLP) { 185 const char kMethod[] = "GET"; 186 const char kURL[] = "payment.url"; 187 const char kPostData[] = "post_man"; 188 Stringmap olp; 189 190 service_->SetOLP("", "", ""); 191 olp = service_->olp(); // Copy to simplify assertions below. 192 EXPECT_EQ("", olp[kPaymentPortalURL]); 193 EXPECT_EQ("", olp[kPaymentPortalMethod]); 194 EXPECT_EQ("", olp[kPaymentPortalPostData]); 195 196 EXPECT_CALL(*adaptor_, 197 EmitStringmapChanged(kPaymentPortalProperty, _)); 198 service_->SetOLP(kURL, kMethod, kPostData); 199 olp = service_->olp(); // Copy to simplify assertions below. 200 EXPECT_EQ(kURL, olp[kPaymentPortalURL]); 201 EXPECT_EQ(kMethod, olp[kPaymentPortalMethod]); 202 EXPECT_EQ(kPostData, olp[kPaymentPortalPostData]); 203} 204 205TEST_F(CellularServiceTest, SetUsageURL) { 206 static const char kUsageURL[] = "usage.url"; 207 EXPECT_CALL(*adaptor_, EmitStringChanged(kUsageURLProperty, 208 kUsageURL)); 209 EXPECT_TRUE(service_->usage_url().empty()); 210 service_->SetUsageURL(kUsageURL); 211 EXPECT_EQ(kUsageURL, service_->usage_url()); 212 service_->SetUsageURL(kUsageURL); 213} 214 215TEST_F(CellularServiceTest, SetApn) { 216 static const char kApn[] = "TheAPN"; 217 static const char kUsername[] = "commander.data"; 218 ProfileRefPtr profile(new NiceMock<MockProfile>( 219 modem_info_.control_interface(), modem_info_.metrics(), 220 modem_info_.manager())); 221 service_->set_profile(profile); 222 Error error; 223 Stringmap testapn; 224 testapn[kApnProperty] = kApn; 225 testapn[kApnUsernameProperty] = kUsername; 226 { 227 InSequence seq; 228 EXPECT_CALL(*adaptor_, 229 EmitStringmapChanged(kCellularLastGoodApnProperty, 230 _)); 231 EXPECT_CALL(*adaptor_, 232 EmitStringmapChanged(kCellularApnProperty, _)); 233 } 234 service_->SetApn(testapn, &error); 235 EXPECT_TRUE(error.IsSuccess()); 236 Stringmap resultapn = service_->GetApn(&error); 237 EXPECT_TRUE(error.IsSuccess()); 238 EXPECT_EQ(2, resultapn.size()); 239 Stringmap::const_iterator it = resultapn.find(kApnProperty); 240 EXPECT_TRUE(it != resultapn.end() && it->second == kApn); 241 it = resultapn.find(kApnUsernameProperty); 242 EXPECT_TRUE(it != resultapn.end() && it->second == kUsername); 243 EXPECT_NE(nullptr, service_->GetUserSpecifiedApn()); 244} 245 246TEST_F(CellularServiceTest, ClearApn) { 247 static const char kApn[] = "TheAPN"; 248 static const char kUsername[] = "commander.data"; 249 ProfileRefPtr profile(new NiceMock<MockProfile>( 250 modem_info_.control_interface(), modem_info_.metrics(), 251 modem_info_.manager())); 252 service_->set_profile(profile); 253 Error error; 254 // Set up an APN to make sure that it later gets cleared. 255 Stringmap testapn; 256 testapn[kApnProperty] = kApn; 257 testapn[kApnUsernameProperty] = kUsername; 258 { 259 InSequence seq; 260 EXPECT_CALL(*adaptor_, 261 EmitStringmapChanged(kCellularLastGoodApnProperty, 262 _)); 263 EXPECT_CALL(*adaptor_, 264 EmitStringmapChanged(kCellularApnProperty, _)); 265 } 266 service_->SetApn(testapn, &error); 267 Stringmap resultapn = service_->GetApn(&error); 268 ASSERT_TRUE(error.IsSuccess()); 269 ASSERT_EQ(2, service_->GetApn(&error).size()); 270 271 Stringmap emptyapn; 272 EXPECT_CALL(*adaptor_, 273 EmitStringmapChanged(kCellularLastGoodApnProperty, 274 _)).Times(0); 275 EXPECT_CALL(*adaptor_, 276 EmitStringmapChanged(kCellularApnProperty, _)).Times(1); 277 service_->SetApn(emptyapn, &error); 278 EXPECT_TRUE(error.IsSuccess()); 279 resultapn = service_->GetApn(&error); 280 EXPECT_TRUE(resultapn.empty()); 281 EXPECT_EQ(nullptr, service_->GetUserSpecifiedApn());; 282} 283 284TEST_F(CellularServiceTest, LastGoodApn) { 285 static const char kApn[] = "TheAPN"; 286 static const char kUsername[] = "commander.data"; 287 ProfileRefPtr profile(new NiceMock<MockProfile>( 288 modem_info_.control_interface(), modem_info_.metrics(), 289 modem_info_.manager())); 290 service_->set_profile(profile); 291 Stringmap testapn; 292 testapn[kApnProperty] = kApn; 293 testapn[kApnUsernameProperty] = kUsername; 294 EXPECT_CALL(*adaptor_, 295 EmitStringmapChanged(kCellularLastGoodApnProperty, _)); 296 service_->SetLastGoodApn(testapn); 297 Stringmap* resultapn = service_->GetLastGoodApn(); 298 EXPECT_NE(nullptr, resultapn); 299 EXPECT_EQ(2, resultapn->size()); 300 Stringmap::const_iterator it = resultapn->find(kApnProperty); 301 EXPECT_TRUE(it != resultapn->end() && it->second == kApn); 302 it = resultapn->find(kApnUsernameProperty); 303 EXPECT_TRUE(it != resultapn->end() && it->second == kUsername); 304 // Now set the user-specified APN, and check that LastGoodApn got 305 // cleared. 306 Stringmap userapn; 307 userapn[kApnProperty] = kApn; 308 userapn[kApnUsernameProperty] = kUsername; 309 { 310 InSequence seq; 311 EXPECT_CALL(*adaptor_, 312 EmitStringmapChanged(kCellularLastGoodApnProperty, 313 _)); 314 EXPECT_CALL(*adaptor_, 315 EmitStringmapChanged(kCellularApnProperty, _)); 316 } 317 Error error; 318 service_->SetApn(userapn, &error); 319 EXPECT_EQ(nullptr, service_->GetLastGoodApn());; 320} 321 322TEST_F(CellularServiceTest, IsAutoConnectable) { 323 const char* reason = nullptr; 324 325 ON_CALL(*out_of_credits_detector_, IsDetecting()) 326 .WillByDefault(Return(false)); 327 328 // Auto-connect should be suppressed if the device is not running. 329 device_->running_ = false; 330 EXPECT_FALSE(service_->IsAutoConnectable(&reason)); 331 EXPECT_STREQ(CellularService::kAutoConnDeviceDisabled, reason); 332 333 device_->running_ = true; 334 335 // If we're waiting on a disconnect before an activation, don't auto-connect. 336 GetCapabilityCDMA()->activation_starting_ = true; 337 EXPECT_FALSE(service_->IsAutoConnectable(&reason)); 338 339 // If we're waiting on an activation, also don't auto-connect. 340 GetCapabilityCDMA()->activation_starting_ = false; 341 GetCapabilityCDMA()->activation_state_ = 342 MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING; 343 EXPECT_FALSE(service_->IsAutoConnectable(&reason)); 344 345 GetCapabilityCDMA()->activation_state_ = 346 MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED; 347 348 // Auto-connect should be suppressed if the we're undergoing an 349 // out-of-credits detection. 350 EXPECT_CALL(*out_of_credits_detector_, IsDetecting()) 351 .WillOnce(Return(true)); 352 EXPECT_FALSE(service_->IsAutoConnectable(&reason)); 353 EXPECT_STREQ(CellularService::kAutoConnOutOfCreditsDetectionInProgress, 354 reason); 355 Mock::VerifyAndClearExpectations(out_of_credits_detector_); 356 357 // Auto-connect should be suppressed if we're out of credits. 358 EXPECT_CALL(*out_of_credits_detector_, IsDetecting()) 359 .WillOnce(Return(false)); 360 EXPECT_CALL(*out_of_credits_detector_, out_of_credits()) 361 .WillOnce(Return(true)); 362 EXPECT_FALSE(service_->IsAutoConnectable(&reason)); 363 EXPECT_STREQ(CellularService::kAutoConnOutOfCredits, reason); 364 Mock::VerifyAndClearExpectations(out_of_credits_detector_); 365 366 EXPECT_CALL(*out_of_credits_detector_, out_of_credits()) 367 .WillRepeatedly(Return(false)); 368 369 // But other activation states are fine. 370 GetCapabilityCDMA()->activation_state_ = 371 MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED; 372 EXPECT_TRUE(service_->IsAutoConnectable(&reason)); 373 GetCapabilityCDMA()->activation_state_ = 374 MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED; 375 EXPECT_TRUE(service_->IsAutoConnectable(&reason)); 376 GetCapabilityCDMA()->activation_state_ = 377 MM_MODEM_CDMA_ACTIVATION_STATE_PARTIALLY_ACTIVATED; 378 EXPECT_TRUE(service_->IsAutoConnectable(&reason)); 379 380 // A PPP authentication failure means the Service is not auto-connectable. 381 service_->SetFailure(Service::kFailurePPPAuth); 382 EXPECT_FALSE(service_->IsAutoConnectable(&reason)); 383 384 // Reset failure state, to make the Service auto-connectable again. 385 service_->SetState(Service::kStateIdle); 386 EXPECT_TRUE(service_->IsAutoConnectable(&reason)); 387 388 // The following test cases are copied from ServiceTest.IsAutoConnectable 389 390 service_->SetConnectable(true); 391 EXPECT_TRUE(service_->IsAutoConnectable(&reason)); 392 393 // We should not auto-connect to a Service that a user has 394 // deliberately disconnected. 395 Error error; 396 service_->UserInitiatedDisconnect(&error); 397 EXPECT_FALSE(service_->IsAutoConnectable(&reason)); 398 EXPECT_STREQ(Service::kAutoConnExplicitDisconnect, reason); 399 400 // But if the Service is reloaded, it is eligible for auto-connect 401 // again. 402 NiceMock<MockStore> storage; 403 EXPECT_CALL(storage, ContainsGroup(service_->GetStorageIdentifier())) 404 .WillOnce(Return(true)); 405 EXPECT_TRUE(service_->Load(&storage)); 406 EXPECT_TRUE(service_->IsAutoConnectable(&reason)); 407 408 // A non-user initiated Disconnect doesn't change anything. 409 service_->Disconnect(&error, "in test"); 410 EXPECT_TRUE(service_->IsAutoConnectable(&reason)); 411 412 // A resume also re-enables auto-connect. 413 service_->UserInitiatedDisconnect(&error); 414 EXPECT_FALSE(service_->IsAutoConnectable(&reason)); 415 service_->OnAfterResume(); 416 EXPECT_TRUE(service_->IsAutoConnectable(&reason)); 417 418 service_->SetState(Service::kStateConnected); 419 EXPECT_FALSE(service_->IsAutoConnectable(&reason)); 420 EXPECT_STREQ(Service::kAutoConnConnected, reason); 421 422 service_->SetState(Service::kStateAssociating); 423 EXPECT_FALSE(service_->IsAutoConnectable(&reason)); 424 EXPECT_STREQ(Service::kAutoConnConnecting, reason); 425} 426 427TEST_F(CellularServiceTest, LoadResetsPPPAuthFailure) { 428 NiceMock<MockStore> storage; 429 EXPECT_CALL(storage, ContainsGroup(_)).WillRepeatedly(Return(true)); 430 EXPECT_CALL(storage, GetString(_, _, _)).WillRepeatedly(Return(true)); 431 432 const string kDefaultUser; 433 const string kDefaultPass; 434 const string kNewUser("new-username"); 435 const string kNewPass("new-password"); 436 for (const auto change_username : { false, true }) { 437 for (const auto change_password : { false, true }) { 438 service_->ppp_username_ = kDefaultUser; 439 service_->ppp_password_ = kDefaultPass; 440 service_->SetFailure(Service::kFailurePPPAuth); 441 EXPECT_TRUE(service_->IsFailed()); 442 EXPECT_EQ(Service::kFailurePPPAuth, service_->failure()); 443 if (change_username) { 444 EXPECT_CALL(storage, 445 GetString(_, CellularService::kStoragePPPUsername, _)) 446 .WillOnce(DoAll(SetArgumentPointee<2>(kNewUser), Return(true))) 447 .RetiresOnSaturation(); 448 } 449 if (change_password) { 450 EXPECT_CALL(storage, 451 GetString(_, CellularService::kStoragePPPPassword, _)) 452 .WillOnce(DoAll(SetArgumentPointee<2>(kNewPass), Return(true))) 453 .RetiresOnSaturation(); 454 } 455 EXPECT_TRUE(service_->Load(&storage)); 456 if (change_username || change_password) { 457 EXPECT_NE(Service::kFailurePPPAuth, service_->failure()); 458 } else { 459 EXPECT_EQ(Service::kFailurePPPAuth, service_->failure()); 460 } 461 } 462 } 463} 464 465// Some of these tests duplicate signals tested above. However, it's 466// convenient to have all the property change notifications documented 467// (and tested) in one place. 468TEST_F(CellularServiceTest, PropertyChanges) { 469 TestCommonPropertyChanges(service_, adaptor_); 470 TestAutoConnectPropertyChange(service_, adaptor_); 471 472 EXPECT_CALL(*adaptor_, 473 EmitStringChanged(kActivationTypeProperty, _)); 474 service_->SetActivationType(CellularService::kActivationTypeOTA); 475 Mock::VerifyAndClearExpectations(adaptor_); 476 477 EXPECT_NE(kActivationStateNotActivated, service_->activation_state()); 478 EXPECT_CALL(*adaptor_, EmitStringChanged(kActivationStateProperty, _)); 479 service_->SetActivationState(kActivationStateNotActivated); 480 Mock::VerifyAndClearExpectations(adaptor_); 481 482 string network_technology = service_->network_technology(); 483 EXPECT_CALL(*adaptor_, EmitStringChanged(kNetworkTechnologyProperty, _)); 484 service_->SetNetworkTechnology(network_technology + "and some new stuff"); 485 Mock::VerifyAndClearExpectations(adaptor_); 486 487 bool out_of_credits = true; 488 EXPECT_CALL(*adaptor_, 489 EmitBoolChanged(kOutOfCreditsProperty, out_of_credits)); 490 service_->SignalOutOfCreditsChanged(out_of_credits); 491 Mock::VerifyAndClearExpectations(adaptor_); 492 493 string roaming_state = service_->roaming_state(); 494 EXPECT_CALL(*adaptor_, EmitStringChanged(kRoamingStateProperty, _)); 495 service_->SetRoamingState(roaming_state + "and some new stuff"); 496 Mock::VerifyAndClearExpectations(adaptor_); 497} 498 499// Custom property setters should return false, and make no changes, if 500// the new value is the same as the old value. 501TEST_F(CellularServiceTest, CustomSetterNoopChange) { 502 // Test that we didn't break any setters provided by the base class. 503 TestCustomSetterNoopChange(service_, modem_info_.mock_manager()); 504 505 // Test the new setter we added. 506 // First set up our environment... 507 static const char kApn[] = "TheAPN"; 508 static const char kUsername[] = "commander.data"; 509 Error error; 510 Stringmap testapn; 511 ProfileRefPtr profile(new NiceMock<MockProfile>(nullptr, nullptr, nullptr)); 512 service_->set_profile(profile); 513 testapn[kApnProperty] = kApn; 514 testapn[kApnUsernameProperty] = kUsername; 515 // ... then set to a known value ... 516 EXPECT_TRUE(service_->SetApn(testapn, &error)); 517 EXPECT_TRUE(error.IsSuccess()); 518 // ... then set to same value. 519 EXPECT_FALSE(service_->SetApn(testapn, &error)); 520 EXPECT_TRUE(error.IsSuccess()); 521} 522 523} // namespace shill 524