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