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