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_handler.h" 11 #include "chromeos/network/network_state.h" 12 #include "content/public/browser/browser_thread.h" 13 #include "testing/gmock/include/gmock/gmock.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 #include "third_party/cros_system_api/dbus/service_constants.h" 16 17 using std::string; 18 19 using content::BrowserThread; 20 using testing::_; 21 using testing::Eq; 22 using testing::Invoke; 23 using testing::Return; 24 25 namespace { 26 27 const char kTestServicePath[] = "/a/service/path"; 28 29 const size_t kNumOTASPStates = 3; 30 31 chromeos::MobileActivator::PlanActivationState kOTASPStates[kNumOTASPStates] = { 32 chromeos::MobileActivator::PLAN_ACTIVATION_TRYING_OTASP, 33 chromeos::MobileActivator::PLAN_ACTIVATION_INITIATING_ACTIVATION, 34 chromeos::MobileActivator::PLAN_ACTIVATION_OTASP, 35 }; 36 37 } // namespace 38 namespace chromeos { 39 40 class TestMobileActivator : public MobileActivator { 41 public: 42 explicit TestMobileActivator(NetworkState* cellular_network) : 43 cellular_network_(cellular_network) { 44 // Provide reasonable defaults for basic things we're usually not testing. 45 ON_CALL(*this, DCheckOnThread(_)) 46 .WillByDefault(Return()); 47 ON_CALL(*this, GetNetworkState(_)) 48 .WillByDefault(Return(cellular_network_)); 49 } 50 virtual ~TestMobileActivator() {} 51 52 MOCK_METHOD3(RequestCellularActivation, 53 void(const NetworkState*, 54 const base::Closure&, 55 const network_handler::ErrorCallback&)); 56 MOCK_METHOD3(ChangeState, void(const NetworkState*, 57 MobileActivator::PlanActivationState, 58 std::string)); 59 MOCK_METHOD1(GetNetworkState, const NetworkState*(const std::string&)); 60 MOCK_METHOD1(EvaluateCellularNetwork, void(const NetworkState*)); 61 MOCK_METHOD0(SignalCellularPlanPayment, void(void)); 62 MOCK_METHOD0(StartOTASPTimer, void(void)); 63 MOCK_CONST_METHOD0(HasRecentCellularPlanPayment, bool(void)); 64 65 void InvokeChangeState(const NetworkState* network, 66 MobileActivator::PlanActivationState new_state, 67 std::string error_description) { 68 MobileActivator::ChangeState(network, new_state, error_description); 69 } 70 71 private: 72 MOCK_CONST_METHOD1(DCheckOnThread, void(const BrowserThread::ID id)); 73 74 NetworkState* cellular_network_; 75 76 DISALLOW_COPY_AND_ASSIGN(TestMobileActivator); 77 }; 78 79 class MobileActivatorTest : public testing::Test { 80 public: 81 MobileActivatorTest() 82 : cellular_network_(string(kTestServicePath)), 83 mobile_activator_(&cellular_network_) { 84 } 85 virtual ~MobileActivatorTest() {} 86 87 protected: 88 virtual void SetUp() { 89 DBusThreadManager::InitializeWithStub(); 90 NetworkHandler::Initialize(); 91 } 92 virtual void TearDown() { 93 NetworkHandler::Shutdown(); 94 DBusThreadManager::Shutdown(); 95 } 96 97 void set_activator_state(const MobileActivator::PlanActivationState state) { 98 mobile_activator_.state_ = state; 99 } 100 void set_network_activation_state(const std::string& activation_state) { 101 cellular_network_.activation_state_ = activation_state; 102 } 103 void set_connection_state(const std::string& state) { 104 cellular_network_.connection_state_ = state; 105 } 106 107 base::MessageLoop message_loop_; 108 NetworkState cellular_network_; 109 TestMobileActivator mobile_activator_; 110 private: 111 DISALLOW_COPY_AND_ASSIGN(MobileActivatorTest); 112 }; 113 114 TEST_F(MobileActivatorTest, BasicFlowForNewDevices) { 115 // In a new device, we aren't connected to Verizon, we start at START 116 // because we haven't paid Verizon (ever), and the modem isn't even partially 117 // activated. 118 std::string error_description; 119 set_activator_state(MobileActivator::PLAN_ACTIVATION_START); 120 set_connection_state(shill::kStateIdle); 121 set_network_activation_state(shill::kActivationStateNotActivated); 122 EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_INITIATING_ACTIVATION, 123 mobile_activator_.PickNextState(&cellular_network_, 124 &error_description)); 125 // Now behave as if ChangeState() has initiated an activation. 126 set_activator_state(MobileActivator::PLAN_ACTIVATION_INITIATING_ACTIVATION); 127 set_network_activation_state(shill::kActivationStateActivating); 128 // We'll sit in this state while we wait for the OTASP to finish. 129 EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_INITIATING_ACTIVATION, 130 mobile_activator_.PickNextState(&cellular_network_, 131 &error_description)); 132 set_network_activation_state(shill::kActivationStatePartiallyActivated); 133 // We'll sit in this state until we go online as well. 134 EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_INITIATING_ACTIVATION, 135 mobile_activator_.PickNextState(&cellular_network_, 136 &error_description)); 137 set_connection_state(shill::kStatePortal); 138 // After we go online, we go back to START, which acts as a jumping off 139 // point for the two types of initial OTASP. 140 EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_START, 141 mobile_activator_.PickNextState(&cellular_network_, 142 &error_description)); 143 set_activator_state(MobileActivator::PLAN_ACTIVATION_START); 144 EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_TRYING_OTASP, 145 mobile_activator_.PickNextState(&cellular_network_, 146 &error_description)); 147 // Very similar things happen while we're trying OTASP. 148 set_activator_state(MobileActivator::PLAN_ACTIVATION_TRYING_OTASP); 149 set_network_activation_state(shill::kActivationStateActivating); 150 EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_TRYING_OTASP, 151 mobile_activator_.PickNextState(&cellular_network_, 152 &error_description)); 153 set_network_activation_state(shill::kActivationStatePartiallyActivated); 154 set_connection_state(shill::kStatePortal); 155 // And when we come back online again and aren't activating, load the portal. 156 EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING, 157 mobile_activator_.PickNextState(&cellular_network_, 158 &error_description)); 159 // The JS drives us through the payment portal. 160 set_activator_state(MobileActivator::PLAN_ACTIVATION_SHOWING_PAYMENT); 161 // The JS also calls us to signal that the portal is done. This triggers us 162 // to start our final OTASP via the aptly named StartOTASP(). 163 EXPECT_CALL(mobile_activator_, SignalCellularPlanPayment()); 164 EXPECT_CALL(mobile_activator_, 165 ChangeState(Eq(&cellular_network_), 166 Eq(MobileActivator::PLAN_ACTIVATION_START_OTASP), 167 _)); 168 EXPECT_CALL(mobile_activator_, 169 EvaluateCellularNetwork(Eq(&cellular_network_))); 170 mobile_activator_.HandleSetTransactionStatus(true); 171 // Evaluate state will defer to PickNextState to select what to do now that 172 // we're in START_ACTIVATION. PickNextState should decide to start a final 173 // OTASP. 174 set_activator_state(MobileActivator::PLAN_ACTIVATION_START_OTASP); 175 EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_OTASP, 176 mobile_activator_.PickNextState(&cellular_network_, 177 &error_description)); 178 // Similarly to TRYING_OTASP and INITIATING_OTASP above... 179 set_activator_state(MobileActivator::PLAN_ACTIVATION_OTASP); 180 set_network_activation_state(shill::kActivationStateActivating); 181 EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_OTASP, 182 mobile_activator_.PickNextState(&cellular_network_, 183 &error_description)); 184 set_network_activation_state(shill::kActivationStateActivated); 185 EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_DONE, 186 mobile_activator_.PickNextState(&cellular_network_, 187 &error_description)); 188 } 189 190 // A fake for MobileActivator::RequestCellularActivation that always succeeds. 191 void FakeRequestCellularActivationSuccess( 192 const NetworkState* network, 193 const base::Closure& success_callback, 194 const network_handler::ErrorCallback& error_callback) { 195 success_callback.Run(); 196 } 197 198 // A fake for MobileActivator::RequestCellularActivation that always fails. 199 void FakeRequestCellularActivationFailure( 200 const NetworkState* network, 201 const base::Closure& success_callback, 202 const network_handler::ErrorCallback& error_callback) { 203 scoped_ptr<base::DictionaryValue> value; 204 error_callback.Run("", value.Pass()); 205 } 206 207 TEST_F(MobileActivatorTest, OTASPScheduling) { 208 const std::string error; 209 for (size_t i = 0; i < kNumOTASPStates; ++i) { 210 // When activation works, we start a timer to watch for success. 211 EXPECT_CALL(mobile_activator_, RequestCellularActivation(_, _, _)) 212 .Times(1) 213 .WillOnce(Invoke(FakeRequestCellularActivationSuccess)); 214 EXPECT_CALL(mobile_activator_, StartOTASPTimer()) 215 .Times(1); 216 set_activator_state(MobileActivator::PLAN_ACTIVATION_START); 217 mobile_activator_.InvokeChangeState(&cellular_network_, 218 kOTASPStates[i], 219 error); 220 221 // When activation fails, it's an error, unless we're trying for the final 222 // OTASP, in which case we try again via DELAY_OTASP. 223 EXPECT_CALL(mobile_activator_, RequestCellularActivation(_, _, _)) 224 .Times(1) 225 .WillOnce(Invoke(FakeRequestCellularActivationFailure)); 226 if (kOTASPStates[i] == MobileActivator::PLAN_ACTIVATION_OTASP) { 227 EXPECT_CALL(mobile_activator_, ChangeState( 228 Eq(&cellular_network_), 229 Eq(MobileActivator::PLAN_ACTIVATION_DELAY_OTASP), 230 _)); 231 } else { 232 EXPECT_CALL(mobile_activator_, ChangeState( 233 Eq(&cellular_network_), 234 Eq(MobileActivator::PLAN_ACTIVATION_ERROR), 235 _)); 236 } 237 set_activator_state(MobileActivator::PLAN_ACTIVATION_START); 238 mobile_activator_.InvokeChangeState(&cellular_network_, 239 kOTASPStates[i], 240 error); 241 } 242 } 243 244 TEST_F(MobileActivatorTest, ReconnectOnDisconnectFromPaymentPortal) { 245 // Most states either don't care if we're offline or expect to be offline at 246 // some point. For instance the OTASP states expect to go offline during 247 // activation and eventually come back. There are a few transitions states 248 // like START_OTASP and DELAY_OTASP which don't really depend on the state of 249 // the modem (offline or online) to work correctly. A few places however, 250 // like when we're displaying the portal care quite a bit about going 251 // offline. Lets test for those cases. 252 std::string error_description; 253 set_connection_state(shill::kStateFailure); 254 set_network_activation_state(shill::kActivationStatePartiallyActivated); 255 set_activator_state(MobileActivator::PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING); 256 EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_RECONNECTING, 257 mobile_activator_.PickNextState(&cellular_network_, 258 &error_description)); 259 set_activator_state(MobileActivator::PLAN_ACTIVATION_SHOWING_PAYMENT); 260 EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_RECONNECTING, 261 mobile_activator_.PickNextState(&cellular_network_, 262 &error_description)); 263 } 264 265 TEST_F(MobileActivatorTest, StartAtStart) { 266 EXPECT_CALL(mobile_activator_, HasRecentCellularPlanPayment()) 267 .WillOnce(Return(false)); 268 EXPECT_CALL(mobile_activator_, 269 EvaluateCellularNetwork(Eq(&cellular_network_))); 270 mobile_activator_.StartActivation(); 271 EXPECT_EQ(mobile_activator_.state(), MobileActivator::PLAN_ACTIVATION_START); 272 } 273 274 } // namespace chromeos 275