blob: 13ec02993abfbcdd1ecd3d9747348251187a614c [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/mobile/mobile_activator.h"
#include "base/message_loop/message_loop.h"
#include "base/values.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/network/network_handler.h"
#include "chromeos/network/network_state.h"
#include "content/public/browser/browser_thread.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
using std::string;
using content::BrowserThread;
using testing::_;
using testing::Eq;
using testing::Invoke;
using testing::Return;
namespace {
const char kTestServicePath[] = "/a/service/path";
const size_t kNumOTASPStates = 3;
chromeos::MobileActivator::PlanActivationState kOTASPStates[kNumOTASPStates] = {
chromeos::MobileActivator::PLAN_ACTIVATION_TRYING_OTASP,
chromeos::MobileActivator::PLAN_ACTIVATION_INITIATING_ACTIVATION,
chromeos::MobileActivator::PLAN_ACTIVATION_OTASP,
};
} // namespace
namespace chromeos {
class TestMobileActivator : public MobileActivator {
public:
explicit TestMobileActivator(NetworkState* cellular_network) :
cellular_network_(cellular_network) {
// Provide reasonable defaults for basic things we're usually not testing.
ON_CALL(*this, DCheckOnThread(_))
.WillByDefault(Return());
ON_CALL(*this, GetNetworkState(_))
.WillByDefault(Return(cellular_network_));
}
virtual ~TestMobileActivator() {}
MOCK_METHOD3(RequestCellularActivation,
void(const NetworkState*,
const base::Closure&,
const network_handler::ErrorCallback&));
MOCK_METHOD3(ChangeState, void(const NetworkState*,
MobileActivator::PlanActivationState,
std::string));
MOCK_METHOD1(GetNetworkState, const NetworkState*(const std::string&));
MOCK_METHOD1(EvaluateCellularNetwork, void(const NetworkState*));
MOCK_METHOD0(SignalCellularPlanPayment, void(void));
MOCK_METHOD0(StartOTASPTimer, void(void));
MOCK_CONST_METHOD0(HasRecentCellularPlanPayment, bool(void));
void InvokeChangeState(const NetworkState* network,
MobileActivator::PlanActivationState new_state,
std::string error_description) {
MobileActivator::ChangeState(network, new_state, error_description);
}
private:
MOCK_CONST_METHOD1(DCheckOnThread, void(const BrowserThread::ID id));
NetworkState* cellular_network_;
DISALLOW_COPY_AND_ASSIGN(TestMobileActivator);
};
class MobileActivatorTest : public testing::Test {
public:
MobileActivatorTest()
: cellular_network_(string(kTestServicePath)),
mobile_activator_(&cellular_network_) {
}
virtual ~MobileActivatorTest() {}
protected:
virtual void SetUp() {
DBusThreadManager::InitializeWithStub();
NetworkHandler::Initialize();
}
virtual void TearDown() {
NetworkHandler::Shutdown();
DBusThreadManager::Shutdown();
}
void set_activator_state(const MobileActivator::PlanActivationState state) {
mobile_activator_.state_ = state;
}
void set_network_activation_state(const std::string& activation_state) {
cellular_network_.activation_state_ = activation_state;
}
void set_connection_state(const std::string& state) {
cellular_network_.connection_state_ = state;
}
base::MessageLoop message_loop_;
NetworkState cellular_network_;
TestMobileActivator mobile_activator_;
private:
DISALLOW_COPY_AND_ASSIGN(MobileActivatorTest);
};
TEST_F(MobileActivatorTest, BasicFlowForNewDevices) {
// In a new device, we aren't connected to Verizon, we start at START
// because we haven't paid Verizon (ever), and the modem isn't even partially
// activated.
std::string error_description;
set_activator_state(MobileActivator::PLAN_ACTIVATION_START);
set_connection_state(shill::kStateIdle);
set_network_activation_state(shill::kActivationStateNotActivated);
EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_INITIATING_ACTIVATION,
mobile_activator_.PickNextState(&cellular_network_,
&error_description));
// Now behave as if ChangeState() has initiated an activation.
set_activator_state(MobileActivator::PLAN_ACTIVATION_INITIATING_ACTIVATION);
set_network_activation_state(shill::kActivationStateActivating);
// We'll sit in this state while we wait for the OTASP to finish.
EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_INITIATING_ACTIVATION,
mobile_activator_.PickNextState(&cellular_network_,
&error_description));
set_network_activation_state(shill::kActivationStatePartiallyActivated);
// We'll sit in this state until we go online as well.
EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_INITIATING_ACTIVATION,
mobile_activator_.PickNextState(&cellular_network_,
&error_description));
set_connection_state(shill::kStatePortal);
// After we go online, we go back to START, which acts as a jumping off
// point for the two types of initial OTASP.
EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_START,
mobile_activator_.PickNextState(&cellular_network_,
&error_description));
set_activator_state(MobileActivator::PLAN_ACTIVATION_START);
EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_TRYING_OTASP,
mobile_activator_.PickNextState(&cellular_network_,
&error_description));
// Very similar things happen while we're trying OTASP.
set_activator_state(MobileActivator::PLAN_ACTIVATION_TRYING_OTASP);
set_network_activation_state(shill::kActivationStateActivating);
EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_TRYING_OTASP,
mobile_activator_.PickNextState(&cellular_network_,
&error_description));
set_network_activation_state(shill::kActivationStatePartiallyActivated);
set_connection_state(shill::kStatePortal);
// And when we come back online again and aren't activating, load the portal.
EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING,
mobile_activator_.PickNextState(&cellular_network_,
&error_description));
// The JS drives us through the payment portal.
set_activator_state(MobileActivator::PLAN_ACTIVATION_SHOWING_PAYMENT);
// The JS also calls us to signal that the portal is done. This triggers us
// to start our final OTASP via the aptly named StartOTASP().
EXPECT_CALL(mobile_activator_, SignalCellularPlanPayment());
EXPECT_CALL(mobile_activator_,
ChangeState(Eq(&cellular_network_),
Eq(MobileActivator::PLAN_ACTIVATION_START_OTASP),
_));
EXPECT_CALL(mobile_activator_,
EvaluateCellularNetwork(Eq(&cellular_network_)));
mobile_activator_.HandleSetTransactionStatus(true);
// Evaluate state will defer to PickNextState to select what to do now that
// we're in START_ACTIVATION. PickNextState should decide to start a final
// OTASP.
set_activator_state(MobileActivator::PLAN_ACTIVATION_START_OTASP);
EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_OTASP,
mobile_activator_.PickNextState(&cellular_network_,
&error_description));
// Similarly to TRYING_OTASP and INITIATING_OTASP above...
set_activator_state(MobileActivator::PLAN_ACTIVATION_OTASP);
set_network_activation_state(shill::kActivationStateActivating);
EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_OTASP,
mobile_activator_.PickNextState(&cellular_network_,
&error_description));
set_network_activation_state(shill::kActivationStateActivated);
EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_DONE,
mobile_activator_.PickNextState(&cellular_network_,
&error_description));
}
// A fake for MobileActivator::RequestCellularActivation that always succeeds.
void FakeRequestCellularActivationSuccess(
const NetworkState* network,
const base::Closure& success_callback,
const network_handler::ErrorCallback& error_callback) {
success_callback.Run();
}
// A fake for MobileActivator::RequestCellularActivation that always fails.
void FakeRequestCellularActivationFailure(
const NetworkState* network,
const base::Closure& success_callback,
const network_handler::ErrorCallback& error_callback) {
scoped_ptr<base::DictionaryValue> value;
error_callback.Run("", value.Pass());
}
TEST_F(MobileActivatorTest, OTASPScheduling) {
const std::string error;
for (size_t i = 0; i < kNumOTASPStates; ++i) {
// When activation works, we start a timer to watch for success.
EXPECT_CALL(mobile_activator_, RequestCellularActivation(_, _, _))
.Times(1)
.WillOnce(Invoke(FakeRequestCellularActivationSuccess));
EXPECT_CALL(mobile_activator_, StartOTASPTimer())
.Times(1);
set_activator_state(MobileActivator::PLAN_ACTIVATION_START);
mobile_activator_.InvokeChangeState(&cellular_network_,
kOTASPStates[i],
error);
// When activation fails, it's an error, unless we're trying for the final
// OTASP, in which case we try again via DELAY_OTASP.
EXPECT_CALL(mobile_activator_, RequestCellularActivation(_, _, _))
.Times(1)
.WillOnce(Invoke(FakeRequestCellularActivationFailure));
if (kOTASPStates[i] == MobileActivator::PLAN_ACTIVATION_OTASP) {
EXPECT_CALL(mobile_activator_, ChangeState(
Eq(&cellular_network_),
Eq(MobileActivator::PLAN_ACTIVATION_DELAY_OTASP),
_));
} else {
EXPECT_CALL(mobile_activator_, ChangeState(
Eq(&cellular_network_),
Eq(MobileActivator::PLAN_ACTIVATION_ERROR),
_));
}
set_activator_state(MobileActivator::PLAN_ACTIVATION_START);
mobile_activator_.InvokeChangeState(&cellular_network_,
kOTASPStates[i],
error);
}
}
TEST_F(MobileActivatorTest, ReconnectOnDisconnectFromPaymentPortal) {
// Most states either don't care if we're offline or expect to be offline at
// some point. For instance the OTASP states expect to go offline during
// activation and eventually come back. There are a few transitions states
// like START_OTASP and DELAY_OTASP which don't really depend on the state of
// the modem (offline or online) to work correctly. A few places however,
// like when we're displaying the portal care quite a bit about going
// offline. Lets test for those cases.
std::string error_description;
set_connection_state(shill::kStateFailure);
set_network_activation_state(shill::kActivationStatePartiallyActivated);
set_activator_state(MobileActivator::PLAN_ACTIVATION_PAYMENT_PORTAL_LOADING);
EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_RECONNECTING,
mobile_activator_.PickNextState(&cellular_network_,
&error_description));
set_activator_state(MobileActivator::PLAN_ACTIVATION_SHOWING_PAYMENT);
EXPECT_EQ(MobileActivator::PLAN_ACTIVATION_RECONNECTING,
mobile_activator_.PickNextState(&cellular_network_,
&error_description));
}
TEST_F(MobileActivatorTest, StartAtStart) {
EXPECT_CALL(mobile_activator_, HasRecentCellularPlanPayment())
.WillOnce(Return(false));
EXPECT_CALL(mobile_activator_,
EvaluateCellularNetwork(Eq(&cellular_network_)));
mobile_activator_.StartActivation();
EXPECT_EQ(mobile_activator_.state(), MobileActivator::PLAN_ACTIVATION_START);
}
} // namespace chromeos