1// Copyright (c) 2012 The Chromium 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 "chrome/browser/chromeos/mobile/mobile_activator.h"
6
7#include "base/message_loop/message_loop.h"
8#include "base/values.h"
9#include "chromeos/dbus/dbus_thread_manager.h"
10#include "chromeos/network/network_connection_handler.h"
11#include "chromeos/network/network_handler.h"
12#include "chromeos/network/network_state.h"
13#include "chromeos/network/network_state_handler.h"
14#include "content/public/browser/browser_thread.h"
15#include "testing/gmock/include/gmock/gmock.h"
16#include "testing/gtest/include/gtest/gtest.h"
17#include "third_party/cros_system_api/dbus/service_constants.h"
18
19using std::string;
20
21using content::BrowserThread;
22using testing::_;
23using testing::Eq;
24using testing::Invoke;
25using testing::Mock;
26using testing::Return;
27using testing::WithArgs;
28
29namespace {
30
31const char kTestServicePath[] = "/a/service/path";
32
33const size_t kNumOTASPStates = 3;
34
35chromeos::MobileActivator::PlanActivationState kOTASPStates[kNumOTASPStates] = {
36  chromeos::MobileActivator::PLAN_ACTIVATION_TRYING_OTASP,
37  chromeos::MobileActivator::PLAN_ACTIVATION_INITIATING_ACTIVATION,
38  chromeos::MobileActivator::PLAN_ACTIVATION_OTASP,
39};
40
41}  // namespace
42namespace chromeos {
43
44class TestMobileActivator : public MobileActivator {
45 public:
46  explicit TestMobileActivator(NetworkState* cellular_network) :
47        cellular_network_(cellular_network) {
48    // Provide reasonable defaults for basic things we're usually not testing.
49    ON_CALL(*this, ChangeState(_, _, _))
50        .WillByDefault(WithArgs<1>(
51            Invoke(this, &TestMobileActivator::set_state_for_test)));
52  }
53  virtual ~TestMobileActivator() {}
54
55  MOCK_METHOD3(RequestCellularActivation,
56               void(const NetworkState*,
57                    const base::Closure&,
58                    const network_handler::ErrorCallback&));
59  MOCK_METHOD3(ChangeState, void(const NetworkState*,
60                                 MobileActivator::PlanActivationState,
61                                 std::string));
62  MOCK_METHOD0(GetDefaultNetwork, const NetworkState*());
63  MOCK_METHOD1(EvaluateCellularNetwork, void(const NetworkState*));
64  MOCK_METHOD0(SignalCellularPlanPayment, void(void));
65  MOCK_METHOD0(StartOTASPTimer, void(void));
66  MOCK_CONST_METHOD0(HasRecentCellularPlanPayment, bool(void));
67  MOCK_METHOD1(ConnectNetwork, void(const NetworkState*));
68
69  virtual const NetworkState* GetNetworkState(const std::string& service_path) {
70    return cellular_network_;
71  }
72
73  void InvokeStartActivation() {
74    StartActivation();
75  }
76
77  void InvokeHandlePortalLoaded(bool success) {
78    HandlePortalLoaded(success);
79  }
80
81  void InvokeHandleSetTransactionStatus(bool success) {
82    HandleSetTransactionStatus(success);
83  }
84
85  PlanActivationState InvokePickNextState(
86      const NetworkState* network,
87      std::string* error_description) const {
88    return PickNextState(network, error_description);
89  }
90
91  void InvokeChangeState(const NetworkState* network,
92                         MobileActivator::PlanActivationState new_state,
93                         std::string error_description) {
94    MobileActivator::ChangeState(network, new_state, error_description);
95  }
96
97 private:
98  void DCheckOnThread(const BrowserThread::ID id) const {}
99
100  NetworkState* cellular_network_;
101
102  DISALLOW_COPY_AND_ASSIGN(TestMobileActivator);
103};
104
105class MobileActivatorTest : public testing::Test {
106 public:
107  MobileActivatorTest()
108      : cellular_network_(string(kTestServicePath)),
109        mobile_activator_(&cellular_network_) {
110    cellular_network_.PropertyChanged(shill::kTypeProperty,
111                                      base::StringValue(shill::kTypeCellular));
112  }
113  virtual ~MobileActivatorTest() {}
114
115 protected:
116  virtual void SetUp() {
117    DBusThreadManager::Initialize();
118    NetworkHandler::Initialize();
119  }
120  virtual void TearDown() {
121    NetworkHandler::Shutdown();
122    DBusThreadManager::Shutdown();
123  }
124
125  void set_activator_state(const MobileActivator::PlanActivationState state) {
126    mobile_activator_.set_state_for_test(state);
127  }
128  void set_network_activation_type(const std::string& activation_type) {
129    cellular_network_.activation_type_ = activation_type;
130  }
131  void set_network_activation_state(const std::string& activation_state) {
132    cellular_network_.activation_state_ = activation_state;
133  }
134  void set_connection_state(const std::string& state) {
135    cellular_network_.visible_ = true;
136    cellular_network_.connection_state_ = state;
137  }
138
139  base::MessageLoop message_loop_;
140  NetworkState cellular_network_;
141  TestMobileActivator mobile_activator_;
142
143 private:
144  DISALLOW_COPY_AND_ASSIGN(MobileActivatorTest);
145};
146
147TEST_F(MobileActivatorTest, OTAHasNetworkConnection) {
148  // Make sure if we have a network connection, the mobile activator does not
149  // connect to the network.
150  EXPECT_CALL(mobile_activator_, GetDefaultNetwork())
151      .WillRepeatedly(Return(&cellular_network_));
152  EXPECT_CALL(mobile_activator_, ConnectNetwork(_))
153      .Times(0);
154  set_connection_state(shill::kStatePortal);
155  set_network_activation_type(shill::kActivationTypeOTA);
156  set_network_activation_state(shill::kActivationStateNotActivated);
157  mobile_activator_.InvokeStartActivation();
158  EXPECT_EQ(mobile_activator_.state(),
159            MobileActivator::PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING);
160}
161
162TEST_F(MobileActivatorTest, OTANoNetworkConnection) {
163  // Make sure if we don't have a network connection, the mobile activator
164  // connects to the network.
165  EXPECT_CALL(mobile_activator_, GetDefaultNetwork())
166      .WillRepeatedly(Return(static_cast<NetworkState*>(NULL)));
167  EXPECT_CALL(mobile_activator_, ConnectNetwork(&cellular_network_));
168  set_connection_state(shill::kStateIdle);
169  set_network_activation_type(shill::kActivationTypeOTA);
170  set_network_activation_state(shill::kActivationStateNotActivated);
171  mobile_activator_.InvokeStartActivation();
172  EXPECT_EQ(mobile_activator_.state(),
173            MobileActivator::PLAN_ACTIVATION_WAITING_FOR_CONNECTION);
174}
175
176TEST_F(MobileActivatorTest, OTAActivationFlow) {
177  // Once a network connection is available, the OTA flow should look like the
178  // following:
179  //   - Loading payment portal
180  //   - Showing payment portal
181  //   - (User fills out payment portal and submits information)
182  //   - Activation complete
183  EXPECT_CALL(mobile_activator_, GetDefaultNetwork())
184      .WillRepeatedly(Return(&cellular_network_));
185  set_connection_state(shill::kStateOnline);
186  set_network_activation_type(shill::kActivationTypeOTA);
187  set_network_activation_state(shill::kActivationStateNotActivated);
188  mobile_activator_.InvokeStartActivation();
189  EXPECT_EQ(mobile_activator_.state(),
190            MobileActivator::PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING);
191  mobile_activator_.InvokeHandlePortalLoaded(true);
192  EXPECT_EQ(mobile_activator_.state(),
193            MobileActivator::PLAN_ACTIVATION_SHOWING_PAYMENT);
194  mobile_activator_.InvokeHandleSetTransactionStatus(true);
195  EXPECT_EQ(mobile_activator_.state(), MobileActivator::PLAN_ACTIVATION_DONE);
196}
197
198TEST_F(MobileActivatorTest, OTASPBasicFlowForNewDevices) {
199  // In a new device, we aren't connected to Verizon, we start at START
200  // because we haven't paid Verizon (ever), and the modem isn't even partially
201  // activated.
202  std::string error_description;
203  set_activator_state(MobileActivator::PLAN_ACTIVATION_START);
204  set_connection_state(shill::kStateIdle);
205  set_network_activation_type(shill::kActivationTypeOTASP);
206  set_network_activation_state(shill::kActivationStateNotActivated);
207  EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_INITIATING_ACTIVATION,
208            mobile_activator_.InvokePickNextState(&cellular_network_,
209                                                  &error_description));
210  // Now behave as if ChangeState() has initiated an activation.
211  set_activator_state(MobileActivator::PLAN_ACTIVATION_INITIATING_ACTIVATION);
212  set_network_activation_state(shill::kActivationStateActivating);
213  // We'll sit in this state while we wait for the OTASP to finish.
214  EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_INITIATING_ACTIVATION,
215            mobile_activator_.InvokePickNextState(&cellular_network_,
216                                                  &error_description));
217  set_network_activation_state(shill::kActivationStatePartiallyActivated);
218  // We'll sit in this state until we go online as well.
219  EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_INITIATING_ACTIVATION,
220            mobile_activator_.InvokePickNextState(&cellular_network_,
221                                                  &error_description));
222  set_connection_state(shill::kStatePortal);
223  // After we go online, we go back to START, which acts as a jumping off
224  // point for the two types of initial OTASP.
225  EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_START,
226            mobile_activator_.InvokePickNextState(&cellular_network_,
227                                                  &error_description));
228  set_activator_state(MobileActivator::PLAN_ACTIVATION_START);
229  EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_TRYING_OTASP,
230            mobile_activator_.InvokePickNextState(&cellular_network_,
231                                                  &error_description));
232  // Very similar things happen while we're trying OTASP.
233  set_activator_state(MobileActivator::PLAN_ACTIVATION_TRYING_OTASP);
234  set_network_activation_state(shill::kActivationStateActivating);
235  EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_TRYING_OTASP,
236            mobile_activator_.InvokePickNextState(&cellular_network_,
237                                                  &error_description));
238  set_network_activation_state(shill::kActivationStatePartiallyActivated);
239  set_connection_state(shill::kStatePortal);
240  // And when we come back online again and aren't activating, load the portal.
241  EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING,
242            mobile_activator_.InvokePickNextState(&cellular_network_,
243                                                  &error_description));
244  // The JS drives us through the payment portal.
245  set_activator_state(MobileActivator::PLAN_ACTIVATION_SHOWING_PAYMENT);
246  // The JS also calls us to signal that the portal is done.  This triggers us
247  // to start our final OTASP via the aptly named StartOTASP().
248  EXPECT_CALL(mobile_activator_, SignalCellularPlanPayment());
249  EXPECT_CALL(mobile_activator_,
250              ChangeState(Eq(&cellular_network_),
251                          Eq(MobileActivator::PLAN_ACTIVATION_START_OTASP),
252                          _));
253  EXPECT_CALL(mobile_activator_,
254              EvaluateCellularNetwork(Eq(&cellular_network_)));
255  mobile_activator_.InvokeHandleSetTransactionStatus(true);
256  // Evaluate state will defer to PickNextState to select what to do now that
257  // we're in START_ACTIVATION.  PickNextState should decide to start a final
258  // OTASP.
259  set_activator_state(MobileActivator::PLAN_ACTIVATION_START_OTASP);
260  EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_OTASP,
261            mobile_activator_.InvokePickNextState(&cellular_network_,
262                                                  &error_description));
263  // Similarly to TRYING_OTASP and INITIATING_OTASP above...
264  set_activator_state(MobileActivator::PLAN_ACTIVATION_OTASP);
265  set_network_activation_state(shill::kActivationStateActivating);
266  EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_OTASP,
267            mobile_activator_.InvokePickNextState(&cellular_network_,
268                                                  &error_description));
269  set_network_activation_state(shill::kActivationStateActivated);
270  EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_DONE,
271            mobile_activator_.InvokePickNextState(&cellular_network_,
272                                                  &error_description));
273}
274
275// A fake for MobileActivator::RequestCellularActivation that always succeeds.
276void FakeRequestCellularActivationSuccess(
277    const NetworkState* network,
278    const base::Closure& success_callback,
279    const network_handler::ErrorCallback& error_callback) {
280  success_callback.Run();
281}
282
283// A fake for MobileActivator::RequestCellularActivation that always fails.
284void FakeRequestCellularActivationFailure(
285    const NetworkState* network,
286    const base::Closure& success_callback,
287    const network_handler::ErrorCallback& error_callback) {
288  scoped_ptr<base::DictionaryValue> value;
289  error_callback.Run("", value.Pass());
290}
291
292TEST_F(MobileActivatorTest, OTASPScheduling) {
293  const std::string error;
294  for (size_t i = 0; i < kNumOTASPStates; ++i) {
295    // When activation works, we start a timer to watch for success.
296    EXPECT_CALL(mobile_activator_, RequestCellularActivation(_, _, _))
297        .Times(1)
298        .WillOnce(Invoke(FakeRequestCellularActivationSuccess));
299    EXPECT_CALL(mobile_activator_, StartOTASPTimer())
300         .Times(1);
301    set_activator_state(MobileActivator::PLAN_ACTIVATION_START);
302    mobile_activator_.InvokeChangeState(&cellular_network_,
303                                        kOTASPStates[i],
304                                        error);
305
306    // When activation fails, it's an error, unless we're trying for the final
307    // OTASP, in which case we try again via DELAY_OTASP.
308    EXPECT_CALL(mobile_activator_, RequestCellularActivation(_, _, _))
309        .Times(1)
310        .WillOnce(Invoke(FakeRequestCellularActivationFailure));
311    if (kOTASPStates[i] == MobileActivator::PLAN_ACTIVATION_OTASP) {
312      EXPECT_CALL(mobile_activator_, ChangeState(
313          Eq(&cellular_network_),
314          Eq(MobileActivator::PLAN_ACTIVATION_DELAY_OTASP),
315          _));
316    } else {
317      EXPECT_CALL(mobile_activator_, ChangeState(
318          Eq(&cellular_network_),
319          Eq(MobileActivator::PLAN_ACTIVATION_ERROR),
320          _));
321    }
322    set_activator_state(MobileActivator::PLAN_ACTIVATION_START);
323    mobile_activator_.InvokeChangeState(&cellular_network_,
324                                        kOTASPStates[i],
325                                        error);
326  }
327}
328
329TEST_F(MobileActivatorTest, OTASPStartAtStart) {
330  set_network_activation_type(shill::kActivationTypeOTASP);
331  EXPECT_CALL(mobile_activator_, HasRecentCellularPlanPayment())
332      .WillOnce(Return(false));
333  EXPECT_CALL(mobile_activator_,
334              EvaluateCellularNetwork(Eq(&cellular_network_)));
335  mobile_activator_.InvokeStartActivation();
336  EXPECT_EQ(mobile_activator_.state(), MobileActivator::PLAN_ACTIVATION_START);
337}
338
339TEST_F(MobileActivatorTest, ReconnectOnDisconnectFromPaymentPortal) {
340  // Most states either don't care if we're offline or expect to be offline at
341  // some point.  For instance the OTASP states expect to go offline during
342  // activation and eventually come back.  There are a few transitions states
343  // like START_OTASP and DELAY_OTASP which don't really depend on the state of
344  // the modem (offline or online) to work correctly.  A few places however,
345  // like when we're displaying the portal care quite a bit about going
346  // offline.  Lets test for those cases.
347  std::string error_description;
348  set_connection_state(shill::kStateFailure);
349  set_network_activation_state(shill::kActivationStatePartiallyActivated);
350  set_activator_state(MobileActivator::PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING);
351  EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_RECONNECTING,
352            mobile_activator_.InvokePickNextState(&cellular_network_,
353                                                  &error_description));
354  set_activator_state(MobileActivator::PLAN_ACTIVATION_SHOWING_PAYMENT);
355  EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_RECONNECTING,
356            mobile_activator_.InvokePickNextState(&cellular_network_,
357                                                  &error_description));
358}
359
360}  // namespace chromeos
361