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/cellular/cellular_capability_gsm.h" 18 19#include <base/bind.h> 20#if defined(__ANDROID__) 21#include <dbus/service_constants.h> 22#else 23#include <chromeos/dbus/service_constants.h> 24#endif // __ANDROID__ 25#include <mm/mm-modem.h> 26 27#include "shill/cellular/cellular.h" 28#include "shill/cellular/cellular_service.h" 29#include "shill/cellular/mock_modem_cdma_proxy.h" 30#include "shill/cellular/mock_modem_gobi_proxy.h" 31#include "shill/cellular/mock_modem_gsm_card_proxy.h" 32#include "shill/cellular/mock_modem_gsm_network_proxy.h" 33#include "shill/cellular/mock_modem_info.h" 34#include "shill/cellular/mock_modem_proxy.h" 35#include "shill/cellular/mock_modem_simple_proxy.h" 36#include "shill/error.h" 37#include "shill/mock_adaptors.h" 38#include "shill/mock_control.h" 39#include "shill/mock_profile.h" 40#include "shill/net/mock_rtnl_handler.h" 41#include "shill/test_event_dispatcher.h" 42#include "shill/testing.h" 43 44using base::Bind; 45using base::Unretained; 46using std::string; 47using testing::InSequence; 48using testing::NiceMock; 49using testing::_; 50 51namespace shill { 52 53class CellularCapabilityTest : public testing::Test { 54 public: 55 CellularCapabilityTest() 56 : control_interface_(this), 57 modem_info_(&control_interface_, &dispatcher_, nullptr, nullptr), 58 create_gsm_card_proxy_from_factory_(false), 59 proxy_(new MockModemProxy()), 60 simple_proxy_(new MockModemSimpleProxy()), 61 cdma_proxy_(new MockModemCDMAProxy()), 62 gsm_card_proxy_(new MockModemGSMCardProxy()), 63 gsm_network_proxy_(new MockModemGSMNetworkProxy()), 64 gobi_proxy_(new MockModemGobiProxy()), 65 capability_(nullptr), 66 device_adaptor_(nullptr), 67 cellular_(new Cellular(&modem_info_, 68 "", 69 "", 70 0, 71 Cellular::kTypeGSM, 72 "", 73 "")) { 74 modem_info_.metrics()->RegisterDevice(cellular_->interface_index(), 75 Technology::kCellular); 76 } 77 78 virtual ~CellularCapabilityTest() { 79 cellular_->service_ = nullptr; 80 capability_ = nullptr; 81 device_adaptor_ = nullptr; 82 } 83 84 virtual void SetUp() { 85 static_cast<Device*>(cellular_.get())->rtnl_handler_ = &rtnl_handler_; 86 87 capability_ = static_cast<CellularCapabilityClassic*>( 88 cellular_->capability_.get()); 89 device_adaptor_ = 90 static_cast<DeviceMockAdaptor*>(cellular_->adaptor()); 91 ASSERT_NE(nullptr, device_adaptor_);; 92 } 93 94 virtual void TearDown() { 95 capability_->control_interface_ = nullptr; 96 } 97 98 void CreateService() { 99 // The following constants are never directly accessed by the tests. 100 const char kStorageIdentifier[] = "default_test_storage_id"; 101 const char kFriendlyServiceName[] = "default_test_service_name"; 102 const char kOperatorCode[] = "10010"; 103 const char kOperatorName[] = "default_test_operator_name"; 104 const char kOperatorCountry[] = "us"; 105 106 // Simulate all the side-effects of Cellular::CreateService 107 auto service = new CellularService(&modem_info_, cellular_); 108 service->SetStorageIdentifier(kStorageIdentifier); 109 service->SetFriendlyName(kFriendlyServiceName); 110 111 Stringmap serving_operator; 112 serving_operator[kOperatorCodeKey] = kOperatorCode; 113 serving_operator[kOperatorNameKey] = kOperatorName; 114 serving_operator[kOperatorCountryKey] = kOperatorCountry; 115 116 service->set_serving_operator(serving_operator); 117 cellular_->set_home_provider(serving_operator); 118 cellular_->service_ = service; 119 } 120 121 CellularCapabilityGSM* GetGsmCapability() { 122 return static_cast<CellularCapabilityGSM*>(cellular_->capability_.get()); 123 } 124 125 void ReleaseCapabilityProxies() { 126 capability_->ReleaseProxies(); 127 } 128 129 void InvokeEnable(bool enable, Error* error, 130 const ResultCallback& callback, int timeout) { 131 callback.Run(Error()); 132 } 133 void InvokeEnableFail(bool enable, Error* error, 134 const ResultCallback& callback, int timeout) { 135 callback.Run(Error(Error::kOperationFailed)); 136 } 137 void InvokeDisconnect(Error* error, const ResultCallback& callback, 138 int timeout) { 139 callback.Run(Error()); 140 } 141 void InvokeDisconnectFail(Error* error, const ResultCallback& callback, 142 int timeout) { 143 callback.Run(Error(Error::kOperationFailed)); 144 } 145 void InvokeGetModemStatus(Error* error, 146 const KeyValueStoreCallback& callback, 147 int timeout) { 148 KeyValueStore props; 149 props.SetString("carrier", kTestCarrier); 150 props.SetString("unknown-property", "irrelevant-value"); 151 callback.Run(props, Error()); 152 } 153 void InvokeGetModemInfo(Error* error, const ModemInfoCallback& callback, 154 int timeout) { 155 callback.Run(kManufacturer, kModelID, kHWRev, Error()); 156 } 157 void InvokeSetCarrier(const string& carrier, Error* error, 158 const ResultCallback& callback, int timeout) { 159 callback.Run(Error()); 160 } 161 162 MOCK_METHOD1(TestCallback, void(const Error& error)); 163 164 protected: 165 static const char kTestMobileProviderDBPath[]; 166 static const char kTestCarrier[]; 167 static const char kManufacturer[]; 168 static const char kModelID[]; 169 static const char kHWRev[]; 170 171 class TestControl : public MockControl { 172 public: 173 explicit TestControl(CellularCapabilityTest* test) : test_(test) {} 174 175 virtual ModemProxyInterface* CreateModemProxy( 176 const string& /*path*/, 177 const string& /*service*/) { 178 return test_->proxy_.release(); 179 } 180 181 virtual ModemSimpleProxyInterface* CreateModemSimpleProxy( 182 const string& /*path*/, 183 const string& /*service*/) { 184 return test_->simple_proxy_.release(); 185 } 186 187 virtual ModemCDMAProxyInterface* CreateModemCDMAProxy( 188 const string& /*path*/, 189 const string& /*service*/) { 190 return test_->cdma_proxy_.release(); 191 } 192 193 virtual ModemGSMCardProxyInterface* CreateModemGSMCardProxy( 194 const string& /*path*/, 195 const string& /*service*/) { 196 // TODO(benchan): This code conditionally returns a nullptr to avoid 197 // CellularCapabilityGSM::InitProperties (and thus 198 // CellularCapabilityGSM::GetIMSI) from being called during the 199 // construction. Remove this workaround after refactoring the tests. 200 return test_->create_gsm_card_proxy_from_factory_ ? 201 test_->gsm_card_proxy_.release() : nullptr; 202 } 203 204 virtual ModemGSMNetworkProxyInterface* CreateModemGSMNetworkProxy( 205 const string& /*path*/, 206 const string& /*service*/) { 207 return test_->gsm_network_proxy_.release(); 208 } 209 210 virtual ModemGobiProxyInterface* CreateModemGobiProxy( 211 const string& /*path*/, 212 const string& /*service*/) { 213 return test_->gobi_proxy_.release(); 214 } 215 216 private: 217 CellularCapabilityTest* test_; 218 }; 219 220 void SetProxy() { 221 capability_->proxy_.reset(proxy_.release()); 222 } 223 224 void SetSimpleProxy() { 225 capability_->simple_proxy_.reset(simple_proxy_.release()); 226 } 227 228 void SetGSMNetworkProxy() { 229 CellularCapabilityGSM* gsm_capability = 230 static_cast<CellularCapabilityGSM*>(cellular_->capability_.get()); 231 gsm_capability->network_proxy_.reset(gsm_network_proxy_.release()); 232 } 233 234 void SetCellularType(Cellular::Type type) { 235 cellular_->InitCapability(type); 236 capability_ = static_cast<CellularCapabilityClassic*>( 237 cellular_->capability_.get()); 238 } 239 240 void AllowCreateGSMCardProxyFromFactory() { 241 create_gsm_card_proxy_from_factory_ = true; 242 } 243 244 EventDispatcherForTest dispatcher_; 245 TestControl control_interface_; 246 MockModemInfo modem_info_; 247 MockRTNLHandler rtnl_handler_; 248 bool create_gsm_card_proxy_from_factory_; 249 std::unique_ptr<MockModemProxy> proxy_; 250 std::unique_ptr<MockModemSimpleProxy> simple_proxy_; 251 std::unique_ptr<MockModemCDMAProxy> cdma_proxy_; 252 std::unique_ptr<MockModemGSMCardProxy> gsm_card_proxy_; 253 std::unique_ptr<MockModemGSMNetworkProxy> gsm_network_proxy_; 254 std::unique_ptr<MockModemGobiProxy> gobi_proxy_; 255 CellularCapabilityClassic* capability_; // Owned by |cellular_|. 256 DeviceMockAdaptor* device_adaptor_; // Owned by |cellular_|. 257 CellularRefPtr cellular_; 258}; 259 260const char CellularCapabilityTest::kTestMobileProviderDBPath[] = 261 "provider_db_unittest.bfd"; 262const char CellularCapabilityTest::kTestCarrier[] = "The Cellular Carrier"; 263const char CellularCapabilityTest::kManufacturer[] = "Company"; 264const char CellularCapabilityTest::kModelID[] = "Gobi 2000"; 265const char CellularCapabilityTest::kHWRev[] = "A00B1234"; 266 267TEST_F(CellularCapabilityTest, GetModemStatus) { 268 SetCellularType(Cellular::kTypeCDMA); 269 EXPECT_CALL(*simple_proxy_, 270 GetModemStatus(_, _, CellularCapability::kTimeoutDefault)). 271 WillOnce(Invoke(this, &CellularCapabilityTest::InvokeGetModemStatus)); 272 EXPECT_CALL(*this, TestCallback(IsSuccess())); 273 SetSimpleProxy(); 274 ResultCallback callback = 275 Bind(&CellularCapabilityTest::TestCallback, Unretained(this)); 276 capability_->GetModemStatus(callback); 277 EXPECT_EQ(kTestCarrier, cellular_->carrier()); 278} 279 280TEST_F(CellularCapabilityTest, GetModemInfo) { 281 EXPECT_CALL(*proxy_, GetModemInfo(_, _, CellularCapability::kTimeoutDefault)) 282 .WillOnce(Invoke(this, &CellularCapabilityTest::InvokeGetModemInfo)); 283 EXPECT_CALL(*this, TestCallback(IsSuccess())); 284 SetProxy(); 285 ResultCallback callback = 286 Bind(&CellularCapabilityTest::TestCallback, Unretained(this)); 287 capability_->GetModemInfo(callback); 288 EXPECT_EQ(kManufacturer, cellular_->manufacturer()); 289 EXPECT_EQ(kModelID, cellular_->model_id()); 290 EXPECT_EQ(kHWRev, cellular_->hardware_revision()); 291} 292 293TEST_F(CellularCapabilityTest, EnableModemSucceed) { 294 EXPECT_CALL(*proxy_, Enable(true, _, _, CellularCapability::kTimeoutEnable)) 295 .WillOnce(Invoke(this, &CellularCapabilityTest::InvokeEnable)); 296 EXPECT_CALL(*this, TestCallback(IsSuccess())); 297 ResultCallback callback = 298 Bind(&CellularCapabilityTest::TestCallback, Unretained(this)); 299 SetProxy(); 300 capability_->EnableModem(callback); 301} 302 303TEST_F(CellularCapabilityTest, EnableModemFail) { 304 EXPECT_CALL(*proxy_, Enable(true, _, _, CellularCapability::kTimeoutEnable)) 305 .WillOnce(Invoke(this, &CellularCapabilityTest::InvokeEnableFail)); 306 EXPECT_CALL(*this, TestCallback(IsFailure())); 307 ResultCallback callback = 308 Bind(&CellularCapabilityTest::TestCallback, Unretained(this)); 309 SetProxy(); 310 capability_->EnableModem(callback); 311} 312 313TEST_F(CellularCapabilityTest, FinishEnable) { 314 EXPECT_CALL(*gsm_network_proxy_, 315 GetRegistrationInfo(nullptr, _, 316 CellularCapability::kTimeoutDefault)); 317 EXPECT_CALL( 318 *gsm_network_proxy_, 319 GetSignalQuality(nullptr, _, CellularCapability::kTimeoutDefault)); 320 EXPECT_CALL(*this, TestCallback(IsSuccess())); 321 SetGSMNetworkProxy(); 322 capability_->FinishEnable( 323 Bind(&CellularCapabilityTest::TestCallback, Unretained(this))); 324} 325 326TEST_F(CellularCapabilityTest, UnsupportedOperation) { 327 Error error; 328 EXPECT_CALL(*this, TestCallback(IsSuccess())).Times(0); 329 capability_->CellularCapability::Reset( 330 &error, 331 Bind(&CellularCapabilityTest::TestCallback, Unretained(this))); 332 EXPECT_TRUE(error.IsFailure()); 333 EXPECT_EQ(Error::kNotSupported, error.type()); 334} 335 336TEST_F(CellularCapabilityTest, AllowRoaming) { 337 EXPECT_FALSE(cellular_->GetAllowRoaming(nullptr)); 338 cellular_->SetAllowRoaming(false, nullptr); 339 EXPECT_FALSE(cellular_->GetAllowRoaming(nullptr)); 340 341 { 342 InSequence seq; 343 EXPECT_CALL(*device_adaptor_, 344 EmitBoolChanged(kCellularAllowRoamingProperty, true)); 345 EXPECT_CALL(*device_adaptor_, 346 EmitBoolChanged(kCellularAllowRoamingProperty, false)); 347 } 348 349 cellular_->state_ = Cellular::kStateConnected; 350 static_cast<CellularCapabilityGSM*>(capability_)->registration_state_ = 351 MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING; 352 cellular_->SetAllowRoaming(true, nullptr); 353 EXPECT_TRUE(cellular_->GetAllowRoaming(nullptr)); 354 EXPECT_EQ(Cellular::kStateConnected, cellular_->state_); 355 356 EXPECT_CALL(*proxy_, Disconnect(_, _, CellularCapability::kTimeoutDisconnect)) 357 .WillOnce(Invoke(this, &CellularCapabilityTest::InvokeDisconnect)); 358 SetProxy(); 359 cellular_->state_ = Cellular::kStateConnected; 360 cellular_->SetAllowRoaming(false, nullptr); 361 EXPECT_FALSE(cellular_->GetAllowRoaming(nullptr)); 362 EXPECT_EQ(Cellular::kStateRegistered, cellular_->state_); 363} 364 365TEST_F(CellularCapabilityTest, SetCarrier) { 366 static const char kCarrier[] = "Generic UMTS"; 367 EXPECT_CALL( 368 *gobi_proxy_, 369 SetCarrier(kCarrier, _, _, 370 CellularCapabilityClassic::kTimeoutSetCarrierMilliseconds)) 371 .WillOnce(Invoke(this, &CellularCapabilityTest::InvokeSetCarrier)); 372 EXPECT_CALL(*this, TestCallback(IsSuccess())); 373 Error error; 374 capability_->SetCarrier(kCarrier, &error, 375 Bind(&CellularCapabilityTest::TestCallback, 376 Unretained(this))); 377 EXPECT_TRUE(error.IsSuccess()); 378} 379 380MATCHER_P(HasApn, apn, "") { 381 return arg.ContainsString(kApnProperty) && apn == arg.GetString(kApnProperty); 382} 383 384MATCHER(HasNoApn, "") { 385 return !arg.ContainsString(kApnProperty); 386} 387 388TEST_F(CellularCapabilityTest, TryApns) { 389 static const string kLastGoodApn("remembered.apn"); 390 static const string kLastGoodUsername("remembered.user"); 391 static const string kSuppliedApn("my.apn"); 392 static const string kTmobileApn1("epc.tmobile.com"); 393 static const string kTmobileApn2("wap.voicestream.com"); 394 static const string kTmobileApn3("internet2.voicestream.com"); 395 static const string kTmobileApn4("internet3.voicestream.com"); 396 const Stringmaps kDatabaseApnList {{{ kApnProperty, kTmobileApn1 }}, 397 {{ kApnProperty, kTmobileApn2 }}, 398 {{ kApnProperty, kTmobileApn3 }}, 399 {{ kApnProperty, kTmobileApn4 }}}; 400 401 402 CreateService(); 403 // Supply the database APNs to |cellular_| object. 404 cellular_->set_apn_list(kDatabaseApnList); 405 ProfileRefPtr profile(new NiceMock<MockProfile>( 406 modem_info_.control_interface(), modem_info_.metrics(), 407 modem_info_.manager())); 408 cellular_->service()->set_profile(profile); 409 410 Error error; 411 Stringmap apn_info; 412 KeyValueStore props; 413 CellularCapabilityGSM* gsm_capability = GetGsmCapability(); 414 415 apn_info[kApnProperty] = kLastGoodApn; 416 apn_info[kApnUsernameProperty] = kLastGoodUsername; 417 cellular_->service()->SetLastGoodApn(apn_info); 418 props.Clear(); 419 EXPECT_TRUE(props.IsEmpty()); 420 gsm_capability->SetupConnectProperties(&props); 421 // We expect the list to contain the last good APN, plus 422 // the 4 APNs from the mobile provider info database. 423 EXPECT_EQ(5, gsm_capability->apn_try_list_.size()); 424 EXPECT_TRUE(props.ContainsString(kApnProperty)); 425 EXPECT_EQ(kLastGoodApn, props.GetString(kApnProperty)); 426 EXPECT_TRUE(props.ContainsString(kApnUsernameProperty)); 427 EXPECT_EQ(kLastGoodUsername, 428 props.GetString(kApnUsernameProperty)); 429 430 apn_info.clear(); 431 props.Clear(); 432 apn_info[kApnProperty] = kSuppliedApn; 433 // Setting the APN has the side effect of clearing the LastGoodApn, 434 // so the try list will have 5 elements, with the first one being 435 // the supplied APN. 436 cellular_->service()->SetApn(apn_info, &error); 437 EXPECT_TRUE(props.IsEmpty()); 438 gsm_capability->SetupConnectProperties(&props); 439 EXPECT_EQ(5, gsm_capability->apn_try_list_.size()); 440 EXPECT_TRUE(props.ContainsString(kApnProperty)); 441 EXPECT_EQ(kSuppliedApn, props.GetString(kApnProperty)); 442 443 apn_info.clear(); 444 props.Clear(); 445 apn_info[kApnProperty] = kLastGoodApn; 446 apn_info[kApnUsernameProperty] = kLastGoodUsername; 447 // Now when LastGoodAPN is set, it will be the one selected. 448 cellular_->service()->SetLastGoodApn(apn_info); 449 EXPECT_TRUE(props.IsEmpty()); 450 gsm_capability->SetupConnectProperties(&props); 451 // We expect the list to contain the last good APN, plus 452 // the user-supplied APN, plus the 4 APNs from the mobile 453 // provider info database. 454 EXPECT_EQ(6, gsm_capability->apn_try_list_.size()); 455 EXPECT_TRUE(props.ContainsString(kApnProperty)); 456 EXPECT_EQ(kLastGoodApn, props.GetString(kApnProperty)); 457 458 // Now try all the given APNs. 459 using testing::InSequence; 460 { 461 InSequence dummy; 462 EXPECT_CALL(*simple_proxy_, Connect(HasApn(kLastGoodApn), _, _, _)); 463 EXPECT_CALL(*simple_proxy_, Connect(HasApn(kSuppliedApn), _, _, _)); 464 EXPECT_CALL(*simple_proxy_, Connect(HasApn(kTmobileApn1), _, _, _)); 465 EXPECT_CALL(*simple_proxy_, Connect(HasApn(kTmobileApn2), _, _, _)); 466 EXPECT_CALL(*simple_proxy_, Connect(HasApn(kTmobileApn3), _, _, _)); 467 EXPECT_CALL(*simple_proxy_, Connect(HasApn(kTmobileApn4), _, _, _)); 468 EXPECT_CALL(*simple_proxy_, Connect(HasNoApn(), _, _, _)); 469 } 470 SetSimpleProxy(); 471 gsm_capability->Connect(props, &error, ResultCallback()); 472 Error cerror(Error::kInvalidApn); 473 gsm_capability->OnConnectReply(ResultCallback(), cerror); 474 EXPECT_EQ(5, gsm_capability->apn_try_list_.size()); 475 gsm_capability->OnConnectReply(ResultCallback(), cerror); 476 EXPECT_EQ(4, gsm_capability->apn_try_list_.size()); 477 gsm_capability->OnConnectReply(ResultCallback(), cerror); 478 EXPECT_EQ(3, gsm_capability->apn_try_list_.size()); 479 gsm_capability->OnConnectReply(ResultCallback(), cerror); 480 EXPECT_EQ(2, gsm_capability->apn_try_list_.size()); 481 gsm_capability->OnConnectReply(ResultCallback(), cerror); 482 EXPECT_EQ(1, gsm_capability->apn_try_list_.size()); 483 gsm_capability->OnConnectReply(ResultCallback(), cerror); 484 EXPECT_EQ(0, gsm_capability->apn_try_list_.size()); 485} 486 487TEST_F(CellularCapabilityTest, StopModemDisconnectSuccess) { 488 EXPECT_CALL(*proxy_, Disconnect(_, _, CellularCapability::kTimeoutDisconnect)) 489 .WillOnce(Invoke(this, 490 &CellularCapabilityTest::InvokeDisconnect)); 491 EXPECT_CALL(*proxy_, Enable(_, _, _, CellularCapability::kTimeoutEnable)) 492 .WillOnce(Invoke(this, 493 &CellularCapabilityTest::InvokeEnable)); 494 EXPECT_CALL(*this, TestCallback(IsSuccess())); 495 SetProxy(); 496 497 Error error; 498 capability_->StopModem( 499 &error, Bind(&CellularCapabilityTest::TestCallback, Unretained(this))); 500 dispatcher_.DispatchPendingEvents(); 501} 502 503TEST_F(CellularCapabilityTest, StopModemDisconnectFail) { 504 EXPECT_CALL(*proxy_, Disconnect(_, _, CellularCapability::kTimeoutDisconnect)) 505 .WillOnce(Invoke(this, 506 &CellularCapabilityTest::InvokeDisconnectFail)); 507 EXPECT_CALL(*proxy_, Enable(_, _, _, CellularCapability::kTimeoutEnable)) 508 .WillOnce(Invoke(this, 509 &CellularCapabilityTest::InvokeEnable)); 510 EXPECT_CALL(*this, TestCallback(IsSuccess())); 511 SetProxy(); 512 513 Error error; 514 capability_->StopModem( 515 &error, Bind(&CellularCapabilityTest::TestCallback, Unretained(this))); 516 dispatcher_.DispatchPendingEvents(); 517} 518 519TEST_F(CellularCapabilityTest, DisconnectNoProxy) { 520 Error error; 521 ResultCallback disconnect_callback; 522 EXPECT_CALL(*proxy_, Disconnect(_, _, CellularCapability::kTimeoutDisconnect)) 523 .Times(0); 524 ReleaseCapabilityProxies(); 525 capability_->Disconnect(&error, disconnect_callback); 526} 527 528} // namespace shill 529