blob: 47ab2325f02f25aa09d74a89b8db73d9caf275ec [file] [log] [blame]
// Copyright 2017 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/tether/tether_service.h"
#include <memory>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/test/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h"
#include "chrome/browser/chromeos/net/tether_notification_presenter.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/chromeos_switches.h"
#include "chromeos/components/tether/fake_initializer.h"
#include "chromeos/components/tether/fake_notification_presenter.h"
#include "chromeos/components/tether/initializer_impl.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/fake_power_manager_client.h"
#include "chromeos/dbus/fake_session_manager_client.h"
#include "chromeos/dbus/fake_shill_manager_client.h"
#include "chromeos/dbus/power_manager_client.h"
#include "chromeos/dbus/session_manager_client.h"
#include "chromeos/network/network_connect.h"
#include "chromeos/network/network_handler.h"
#include "chromeos/network/network_state_handler.h"
#include "chromeos/network/network_state_test.h"
#include "chromeos/network/network_type_pattern.h"
#include "components/cryptauth/cryptauth_device_manager.h"
#include "components/cryptauth/fake_cryptauth_service.h"
#include "components/prefs/testing_pref_service.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/message_center/message_center.h"
using testing::Invoke;
using testing::NiceMock;
using testing::Return;
namespace {
class ExtendedFakeSessionManagerClient
: public chromeos::FakeSessionManagerClient {
public:
bool IsScreenLocked() const override { return is_screen_locked_; }
void set_is_screen_locked(bool is_screen_locked) {
is_screen_locked_ = is_screen_locked;
}
private:
bool is_screen_locked_ = false;
};
class MockCryptAuthDeviceManager : public cryptauth::CryptAuthDeviceManager {
public:
~MockCryptAuthDeviceManager() override {}
MOCK_CONST_METHOD0(GetTetherHosts,
std::vector<cryptauth::ExternalDeviceInfo>());
};
class MockExtendedBluetoothAdapter : public device::MockBluetoothAdapter {
public:
void SetAdvertisingInterval(
const base::TimeDelta& min,
const base::TimeDelta& max,
const base::Closure& callback,
const AdvertisementErrorCallback& error_callback) override {
if (is_ble_advertising_supported_) {
callback.Run();
} else {
error_callback.Run(device::BluetoothAdvertisement::ErrorCode::
ERROR_INVALID_ADVERTISEMENT_INTERVAL);
}
}
void set_is_ble_advertising_supported(bool is_ble_advertising_supported) {
is_ble_advertising_supported_ = is_ble_advertising_supported;
}
protected:
~MockExtendedBluetoothAdapter() override {}
private:
bool is_ble_advertising_supported_ = true;
};
class TestTetherService : public TetherService {
public:
TestTetherService(Profile* profile,
chromeos::PowerManagerClient* power_manager_client,
chromeos::SessionManagerClient* session_manager_client,
cryptauth::CryptAuthService* cryptauth_service,
chromeos::NetworkStateHandler* network_state_handler)
: TetherService(profile,
power_manager_client,
session_manager_client,
cryptauth_service,
network_state_handler) {}
~TestTetherService() override {}
int updated_technology_state_count() {
return updated_technology_state_count_;
}
protected:
void UpdateTetherTechnologyState() override {
updated_technology_state_count_++;
TetherService::UpdateTetherTechnologyState();
}
private:
int updated_technology_state_count_ = 0;
};
class FakeInitializerWithDestructorCallback
: public chromeos::tether::FakeInitializer {
public:
FakeInitializerWithDestructorCallback(
const base::Closure& destructor_callback)
: FakeInitializer(false /* has_asynchronous_shutdown */),
destructor_callback_(destructor_callback) {}
~FakeInitializerWithDestructorCallback() override {
destructor_callback_.Run();
}
private:
base::Closure destructor_callback_;
};
class TestInitializerFactory final
: public chromeos::tether::InitializerImpl::Factory {
public:
TestInitializerFactory() {}
// Returns nullptr if no Initializer has been created or if the last one that
// was created has already been deleted.
FakeInitializerWithDestructorCallback* active_initializer() {
return active_initializer_;
}
// chromeos::tether::InitializerImpl::Factory:
std::unique_ptr<chromeos::tether::Initializer> BuildInstance(
cryptauth::CryptAuthService* cryptauth_service,
chromeos::tether::NotificationPresenter* notification_presenter,
PrefService* pref_service,
chromeos::NetworkStateHandler* network_state_handler,
chromeos::ManagedNetworkConfigurationHandler*
managed_network_configuration_handler,
chromeos::NetworkConnect* network_connect,
chromeos::NetworkConnectionHandler* network_connection_handler,
scoped_refptr<device::BluetoothAdapter> adapter) override {
active_initializer_ = new FakeInitializerWithDestructorCallback(
base::Bind(&TestInitializerFactory::OnActiveInitializerDeleted,
base::Unretained(this)));
return base::WrapUnique(active_initializer_);
}
private:
void OnActiveInitializerDeleted() { active_initializer_ = nullptr; }
FakeInitializerWithDestructorCallback* active_initializer_ = nullptr;
};
} // namespace
class TetherServiceTest : public chromeos::NetworkStateTest {
protected:
TetherServiceTest() : NetworkStateTest() {}
~TetherServiceTest() override {}
void SetUp() override {
chromeos::DBusThreadManager::Initialize();
chromeos::NetworkStateTest::SetUp();
message_center::MessageCenter::Initialize();
chromeos::NetworkConnect::Initialize(nullptr);
chromeos::NetworkHandler::Initialize();
TestingProfile::Builder builder;
profile_ = builder.Build();
fake_power_manager_client_ =
base::MakeUnique<chromeos::FakePowerManagerClient>();
fake_session_manager_client_ =
base::MakeUnique<ExtendedFakeSessionManagerClient>();
std::vector<cryptauth::ExternalDeviceInfo> test_device_infos;
test_device_infos.push_back(cryptauth::ExternalDeviceInfo());
test_device_infos.push_back(cryptauth::ExternalDeviceInfo());
mock_cryptauth_device_manager_ =
base::WrapUnique(new NiceMock<MockCryptAuthDeviceManager>());
ON_CALL(*mock_cryptauth_device_manager_, GetTetherHosts())
.WillByDefault(Return(test_device_infos));
fake_cryptauth_service_ =
base::MakeUnique<cryptauth::FakeCryptAuthService>();
fake_cryptauth_service_->set_cryptauth_device_manager(
mock_cryptauth_device_manager_.get());
mock_adapter_ =
make_scoped_refptr(new NiceMock<MockExtendedBluetoothAdapter>());
SetIsBluetoothPowered(true);
is_adapter_present_ = true;
ON_CALL(*mock_adapter_, IsPresent())
.WillByDefault(Invoke(this, &TetherServiceTest::IsBluetoothPresent));
ON_CALL(*mock_adapter_, IsPowered())
.WillByDefault(Invoke(this, &TetherServiceTest::IsBluetoothPowered));
device::BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter_);
test_initializer_factory_ = base::WrapUnique(new TestInitializerFactory());
chromeos::tether::InitializerImpl::Factory::SetInstanceForTesting(
test_initializer_factory_.get());
}
void TearDown() override {
ShutdownTetherService();
message_center::MessageCenter::Shutdown();
chromeos::NetworkConnect::Shutdown();
chromeos::NetworkHandler::Shutdown();
ShutdownNetworkState();
chromeos::NetworkStateTest::TearDown();
chromeos::DBusThreadManager::Shutdown();
}
void CreateTetherService() {
tether_service_ = base::WrapUnique(new TestTetherService(
profile_.get(), fake_power_manager_client_.get(),
fake_session_manager_client_.get(), fake_cryptauth_service_.get(),
network_state_handler()));
fake_notification_presenter_ =
new chromeos::tether::FakeNotificationPresenter();
tether_service_->SetNotificationPresenterForTest(
base::WrapUnique(fake_notification_presenter_));
// Ensure that TetherService does not prematurely update its TechnologyState
// before it fetches the BluetoothAdapter.
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
base::RunLoop().RunUntilIdle();
}
void ShutdownTetherService() {
if (tether_service_)
tether_service_->Shutdown();
}
void SetIsScreenLocked(bool is_screen_locked) {
fake_session_manager_client_->set_is_screen_locked(is_screen_locked);
if (is_screen_locked)
tether_service_->ScreenIsLocked();
else
tether_service_->ScreenIsUnlocked();
}
void SetTetherTechnologyStateEnabled(bool enabled) {
network_state_handler()->SetTetherTechnologyState(
enabled
? chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED
: chromeos::NetworkStateHandler::TechnologyState::
TECHNOLOGY_AVAILABLE);
}
void SetCellularTechnologyStateEnabled(bool enabled) {
network_state_handler()->SetTechnologyEnabled(
chromeos::NetworkTypePattern::Cellular(), enabled,
chromeos::network_handler::ErrorCallback());
base::RunLoop().RunUntilIdle();
}
void SetIsBluetoothPowered(bool powered) {
is_adapter_powered_ = powered;
for (auto& observer : mock_adapter_->GetObservers())
observer.AdapterPoweredChanged(mock_adapter_.get(), powered);
}
void set_is_adapter_present(bool present) { is_adapter_present_ = present; }
bool IsBluetoothPresent() { return is_adapter_present_; }
bool IsBluetoothPowered() { return is_adapter_powered_; }
void DisconnectDefaultShillNetworks() {
const chromeos::NetworkState* default_state;
while ((default_state = network_state_handler()->DefaultNetwork())) {
SetServiceProperty(default_state->path(), shill::kStateProperty,
base::Value(shill::kStateIdle));
}
}
void ShutdownAndVerifyFinalTetherFeatureState(
TetherService::TetherFeatureState expected_technology_state_and_reason) {
ShutdownTetherService();
histogram_tester_.ExpectUniqueSample("InstantTethering.FinalFeatureState",
expected_technology_state_and_reason,
1);
}
void VerifyTetherActiveStatus(bool expected_active) {
EXPECT_EQ(expected_active,
test_initializer_factory_->active_initializer() != nullptr);
}
const content::TestBrowserThreadBundle thread_bundle_;
std::unique_ptr<TestingProfile> profile_;
std::unique_ptr<chromeos::FakePowerManagerClient> fake_power_manager_client_;
std::unique_ptr<ExtendedFakeSessionManagerClient>
fake_session_manager_client_;
std::unique_ptr<TestingPrefServiceSimple> test_pref_service_;
std::unique_ptr<NiceMock<MockCryptAuthDeviceManager>>
mock_cryptauth_device_manager_;
std::unique_ptr<TestInitializerFactory> test_initializer_factory_;
chromeos::tether::FakeNotificationPresenter* fake_notification_presenter_;
std::unique_ptr<cryptauth::FakeCryptAuthService> fake_cryptauth_service_;
scoped_refptr<MockExtendedBluetoothAdapter> mock_adapter_;
bool is_adapter_present_;
bool is_adapter_powered_;
std::unique_ptr<TestTetherService> tether_service_;
base::HistogramTester histogram_tester_;
private:
DISALLOW_COPY_AND_ASSIGN(TetherServiceTest);
};
TEST_F(TetherServiceTest, TestShutdown) {
CreateTetherService();
VerifyTetherActiveStatus(true /* expected_active */);
ShutdownTetherService();
// The TechnologyState should not have changed due to Shutdown() being called.
// If it had changed, any settings UI that was previously open would have
// shown visual jank.
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
}
TEST_F(TetherServiceTest, TestAsyncTetherShutdown) {
CreateTetherService();
// Tether should be ENABLED, and there should be no AsyncShutdownTask.
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
// Use an asynchronous shutdown.
test_initializer_factory_->active_initializer()
->set_has_asynchronous_shutdown(true);
// Disable the Tether preference. This should trigger the asynchrnous
// shutdown.
SetTetherTechnologyStateEnabled(false);
// Tether should be active, but shutting down.
VerifyTetherActiveStatus(true /* expected_active */);
EXPECT_EQ(chromeos::tether::Initializer::Status::SHUTTING_DOWN,
test_initializer_factory_->active_initializer()->status());
// Tether should be AVAILABLE.
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
// Complete the shutdown process; TetherService should delete its
// Initializer instance.
test_initializer_factory_->active_initializer()->FinishAsynchronousShutdown();
VerifyTetherActiveStatus(false /* expected_active */);
}
TEST_F(TetherServiceTest, TestSuspend) {
CreateTetherService();
VerifyTetherActiveStatus(true /* expected_active */);
fake_power_manager_client_->SendSuspendImminent();
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
fake_power_manager_client_->SendSuspendDone();
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
fake_power_manager_client_->SendSuspendImminent();
ShutdownAndVerifyFinalTetherFeatureState(
TetherService::TetherFeatureState::OTHER_OR_UNKNOWN);
}
TEST_F(TetherServiceTest, TestBleAdvertisingNotSupported) {
mock_adapter_->set_is_ble_advertising_supported(false);
CreateTetherService();
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
ShutdownAndVerifyFinalTetherFeatureState(
TetherService::TetherFeatureState::BLE_ADVERTISING_NOT_SUPPORTED);
}
TEST_F(TetherServiceTest,
TestBleAdvertisingNotSupported_BluetoothIsInitiallyNotPowered) {
SetIsBluetoothPowered(false);
mock_adapter_->set_is_ble_advertising_supported(false);
CreateTetherService();
// TetherService has not yet been able to find out that BLE advertising is not
// supported.
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
EXPECT_TRUE(profile_->GetPrefs()->GetBoolean(
prefs::kInstantTetheringBleAdvertisingSupported));
SetIsBluetoothPowered(true);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
EXPECT_FALSE(profile_->GetPrefs()->GetBoolean(
prefs::kInstantTetheringBleAdvertisingSupported));
ShutdownAndVerifyFinalTetherFeatureState(
TetherService::TetherFeatureState::BLE_ADVERTISING_NOT_SUPPORTED);
}
TEST_F(
TetherServiceTest,
TestBleAdvertisingNotSupportedAndRecorded_BluetoothIsInitiallyNotPowered) {
SetIsBluetoothPowered(false);
mock_adapter_->set_is_ble_advertising_supported(false);
// Simulate a login after we determined that BLE advertising is not supported.
profile_->GetPrefs()->SetBoolean(
prefs::kInstantTetheringBleAdvertisingSupported, false);
CreateTetherService();
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
SetIsBluetoothPowered(true);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
ShutdownAndVerifyFinalTetherFeatureState(
TetherService::TetherFeatureState::BLE_ADVERTISING_NOT_SUPPORTED);
}
TEST_F(TetherServiceTest, TestBleAdvertisingSupportedButIncorrectlyRecorded) {
// Simulate a login after we incorrectly determined that BLE advertising is
// not supported (this is not an expected case, but may have happened if
// BluetoothAdapter::SetAdvertisingInterval() failed for a weird, one-off
// reason).
profile_->GetPrefs()->SetBoolean(
prefs::kInstantTetheringBleAdvertisingSupported, false);
CreateTetherService();
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
EXPECT_TRUE(profile_->GetPrefs()->GetBoolean(
prefs::kInstantTetheringBleAdvertisingSupported));
ShutdownAndVerifyFinalTetherFeatureState(
TetherService::TetherFeatureState::ENABLED);
}
TEST_F(TetherServiceTest, TestScreenLock) {
CreateTetherService();
VerifyTetherActiveStatus(true /* expected_active */);
SetIsScreenLocked(true);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
SetIsScreenLocked(false);
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
SetIsScreenLocked(true);
ShutdownAndVerifyFinalTetherFeatureState(
TetherService::TetherFeatureState::SCREEN_LOCKED);
}
TEST_F(TetherServiceTest, TestFeatureFlagDisabled) {
EXPECT_FALSE(TetherService::Get(profile_.get()));
}
TEST_F(TetherServiceTest, TestFeatureFlagEnabled) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(features::kInstantTethering);
TetherService* tether_service = TetherService::Get(profile_.get());
ASSERT_TRUE(tether_service);
base::RunLoop().RunUntilIdle();
tether_service->Shutdown();
}
TEST_F(TetherServiceTest, TestNoTetherHosts) {
ON_CALL(*mock_cryptauth_device_manager_, GetTetherHosts())
.WillByDefault(Return(std::vector<cryptauth::ExternalDeviceInfo>()));
CreateTetherService();
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
ShutdownAndVerifyFinalTetherFeatureState(
TetherService::TetherFeatureState::NO_AVAILABLE_HOSTS);
}
TEST_F(TetherServiceTest, TestProhibitedByPolicy) {
profile_->GetPrefs()->SetBoolean(prefs::kInstantTetheringAllowed, false);
CreateTetherService();
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_PROHIBITED,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
ShutdownAndVerifyFinalTetherFeatureState(
TetherService::TetherFeatureState::PROHIBITED);
}
TEST_F(TetherServiceTest, TestBluetoothNotPresent) {
set_is_adapter_present(false);
CreateTetherService();
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
ShutdownAndVerifyFinalTetherFeatureState(
TetherService::TetherFeatureState::BLE_NOT_PRESENT);
}
TEST_F(TetherServiceTest, TestIsBluetoothPowered) {
SetIsBluetoothPowered(false);
CreateTetherService();
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
SetIsBluetoothPowered(true);
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
SetIsBluetoothPowered(false);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
ShutdownAndVerifyFinalTetherFeatureState(
TetherService::TetherFeatureState::BLUETOOTH_DISABLED);
}
TEST_F(TetherServiceTest, TestCellularIsUnavailable) {
test_manager_client()->RemoveTechnology(shill::kTypeCellular);
ASSERT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Cellular()));
CreateTetherService();
SetTetherTechnologyStateEnabled(false);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
SetTetherTechnologyStateEnabled(true);
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
ShutdownAndVerifyFinalTetherFeatureState(
TetherService::TetherFeatureState::ENABLED);
}
TEST_F(TetherServiceTest, TestCellularIsAvailable) {
// TODO (lesliewatkins): Investigate why cellular needs to be removed and
// re-added for NetworkStateHandler to return the correct TechnologyState.
test_manager_client()->RemoveTechnology(shill::kTypeCellular);
test_manager_client()->AddTechnology(shill::kTypeCellular, false);
CreateTetherService();
// Cellular disabled
SetCellularTechnologyStateEnabled(false);
ASSERT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Cellular()));
VerifyTetherActiveStatus(false /* expected_active */);
SetTetherTechnologyStateEnabled(false);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
SetTetherTechnologyStateEnabled(true);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
// Cellular enabled
SetCellularTechnologyStateEnabled(true);
ASSERT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Cellular()));
VerifyTetherActiveStatus(true /* expected_active */);
SetTetherTechnologyStateEnabled(false);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
SetTetherTechnologyStateEnabled(true);
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
SetCellularTechnologyStateEnabled(false);
ShutdownAndVerifyFinalTetherFeatureState(
TetherService::TetherFeatureState::CELLULAR_DISABLED);
}
TEST_F(TetherServiceTest, TestDisabled) {
profile_->GetPrefs()->SetBoolean(prefs::kInstantTetheringEnabled, false);
CreateTetherService();
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
EXPECT_FALSE(
profile_->GetPrefs()->GetBoolean(prefs::kInstantTetheringEnabled));
VerifyTetherActiveStatus(false /* expected_active */);
ShutdownAndVerifyFinalTetherFeatureState(
TetherService::TetherFeatureState::USER_PREFERENCE_DISABLED);
}
TEST_F(TetherServiceTest, TestEnabled) {
CreateTetherService();
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
SetTetherTechnologyStateEnabled(false);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
EXPECT_FALSE(
profile_->GetPrefs()->GetBoolean(prefs::kInstantTetheringEnabled));
VerifyTetherActiveStatus(false /* expected_active */);
SetTetherTechnologyStateEnabled(true);
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
chromeos::NetworkTypePattern::Tether()));
EXPECT_TRUE(
profile_->GetPrefs()->GetBoolean(prefs::kInstantTetheringEnabled));
VerifyTetherActiveStatus(true /* expected_active */);
ShutdownAndVerifyFinalTetherFeatureState(
TetherService::TetherFeatureState::ENABLED);
}
// Test against a past defect that made TetherService and NetworkStateHandler
// repeatly update technology state after the other did so. TetherService should
// only update technology state if NetworkStateHandler has provided a different
// state than the user preference.
TEST_F(TetherServiceTest, TestEnabledMultipleChanges) {
CreateTetherService();
// CreateTetherService calls RunUntilIdle() so UpdateTetherTechnologyState()
// may be called multiple times in the initialization process.
int updated_technology_state_count =
tether_service_->updated_technology_state_count();
SetTetherTechnologyStateEnabled(false);
SetTetherTechnologyStateEnabled(false);
SetTetherTechnologyStateEnabled(false);
updated_technology_state_count++;
EXPECT_EQ(updated_technology_state_count,
tether_service_->updated_technology_state_count());
SetTetherTechnologyStateEnabled(true);
SetTetherTechnologyStateEnabled(true);
SetTetherTechnologyStateEnabled(true);
updated_technology_state_count++;
EXPECT_EQ(updated_technology_state_count,
tether_service_->updated_technology_state_count());
}