blob: 11a910145446593f12b303f6d7b6d4043fd1c4e8 [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/ash/tether/tether_service.h"
#include <memory>
#include "ash/components/multidevice/remote_device_test_util.h"
#include "ash/components/multidevice/software_feature.h"
#include "ash/components/tether/fake_notification_presenter.h"
#include "ash/components/tether/fake_tether_component.h"
#include "ash/components/tether/fake_tether_host_fetcher.h"
#include "ash/components/tether/tether_component_impl.h"
#include "ash/components/tether/tether_host_fetcher_impl.h"
#include "ash/constants/ash_features.h"
#include "ash/services/device_sync/cryptauth_device_manager.h"
#include "ash/services/device_sync/cryptauth_enroller.h"
#include "ash/services/device_sync/cryptauth_enrollment_manager.h"
#include "ash/services/device_sync/fake_cryptauth_enrollment_manager.h"
#include "ash/services/device_sync/fake_remote_device_provider.h"
#include "ash/services/device_sync/public/cpp/device_sync_client_impl.h"
#include "ash/services/device_sync/public/cpp/fake_device_sync_client.h"
#include "ash/services/device_sync/remote_device_provider_impl.h"
#include "ash/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.h"
#include "ash/services/multidevice_setup/public/cpp/multidevice_setup_client_impl.h"
#include "ash/services/multidevice_setup/public/cpp/prefs.h"
#include "ash/services/secure_channel/public/cpp/client/fake_secure_channel_client.h"
#include "ash/services/secure_channel/public/cpp/client/secure_channel_client_impl.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/timer/mock_timer.h"
#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/browser/ui/ash/network/tether_notification_presenter.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/ash/components/network/network_connect.h"
#include "chromeos/ash/components/network/network_handler.h"
#include "chromeos/ash/components/network/network_handler_test_helper.h"
#include "chromeos/ash/components/network/network_state_handler.h"
#include "chromeos/ash/components/network/network_type_pattern.h"
#include "chromeos/dbus/power/fake_power_manager_client.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "chromeos/dbus/power_manager/suspend.pb.h"
#include "chromeos/dbus/shill/shill_device_client.h"
#include "chromeos/dbus/shill/shill_manager_client.h"
#include "chromeos/dbus/shill/shill_service_client.h"
#include "components/prefs/testing_pref_service.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "components/user_manager/scoped_user_manager.h"
#include "content/public/test/browser_task_environment.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 "third_party/cros_system_api/dbus/shill/dbus-constants.h"
namespace ash {
namespace tether {
namespace {
using ::testing::Invoke;
using ::testing::NiceMock;
const char kTestUserPrivateKey[] = "kTestUserPrivateKey";
const size_t kNumTestDevices = 5;
multidevice::RemoteDeviceRefList CreateTestDevices() {
multidevice::RemoteDeviceRefList list;
for (size_t i = 0; i < kNumTestDevices; ++i) {
list.push_back(multidevice::RemoteDeviceRefBuilder()
.SetSupportsMobileHotspot(true)
.SetSoftwareFeatureState(
multidevice::SoftwareFeature::kBetterTogetherHost,
multidevice::SoftwareFeatureState::kSupported)
.Build());
}
return list;
}
class TestTetherService : public TetherService {
public:
TestTetherService(
Profile* profile,
chromeos::PowerManagerClient* power_manager_client,
device_sync::DeviceSyncClient* device_sync_client,
secure_channel::SecureChannelClient* secure_channel_client,
multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client,
chromeos::NetworkStateHandler* network_state_handler,
session_manager::SessionManager* session_manager)
: TetherService(profile,
power_manager_client,
device_sync_client,
secure_channel_client,
multidevice_setup_client,
network_state_handler,
session_manager) {}
~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 FakeTetherComponentWithDestructorCallback : public FakeTetherComponent {
public:
FakeTetherComponentWithDestructorCallback(
base::OnceClosure destructor_callback)
: FakeTetherComponent(/*has_asynchronous_shutdown=*/false),
destructor_callback_(std::move(destructor_callback)) {}
~FakeTetherComponentWithDestructorCallback() override {
std::move(destructor_callback_).Run();
}
private:
base::OnceClosure destructor_callback_;
};
class TestTetherComponentFactory final : public TetherComponentImpl::Factory {
public:
TestTetherComponentFactory() {}
// Returns nullptr if no TetherComponent has been created or if the last one
// that was created has already been deleted.
FakeTetherComponentWithDestructorCallback* active_tether_component() {
return active_tether_component_;
}
// TetherComponentImpl::Factory:
std::unique_ptr<TetherComponent> CreateInstance(
device_sync::DeviceSyncClient* device_sync_client,
secure_channel::SecureChannelClient* secure_channel_client,
TetherHostFetcher* tether_host_fetcher,
NotificationPresenter* notification_presenter,
GmsCoreNotificationsStateTrackerImpl*
gms_core_notifications_state_tracker,
PrefService* pref_service,
chromeos::NetworkStateHandler* network_state_handler,
ManagedNetworkConfigurationHandler* managed_network_configuration_handler,
NetworkConnect* network_connect,
NetworkConnectionHandler* network_connection_handler,
scoped_refptr<device::BluetoothAdapter> adapter,
session_manager::SessionManager* session_manager) override {
active_tether_component_ =
new FakeTetherComponentWithDestructorCallback(base::BindOnce(
&TestTetherComponentFactory::OnActiveTetherComponentDeleted,
base::Unretained(this)));
was_tether_component_active_ = true;
return base::WrapUnique(active_tether_component_);
}
bool was_tether_component_active() { return was_tether_component_active_; }
const TetherComponent::ShutdownReason& last_shutdown_reason() {
return last_shutdown_reason_;
}
private:
void OnActiveTetherComponentDeleted() {
last_shutdown_reason_ = *active_tether_component_->last_shutdown_reason();
active_tether_component_ = nullptr;
}
FakeTetherComponentWithDestructorCallback* active_tether_component_ = nullptr;
bool was_tether_component_active_ = false;
TetherComponent::ShutdownReason last_shutdown_reason_;
};
class FakeRemoteDeviceProviderFactory
: public device_sync::RemoteDeviceProviderImpl::Factory {
public:
FakeRemoteDeviceProviderFactory() = default;
~FakeRemoteDeviceProviderFactory() override = default;
// device_sync::RemoteDeviceProviderImpl::Factory:
std::unique_ptr<device_sync::RemoteDeviceProvider> CreateInstance(
device_sync::CryptAuthDeviceManager* device_manager,
device_sync::CryptAuthV2DeviceManager* v2_device_manager,
const std::string& user_email,
const std::string& user_private_key) override {
return std::make_unique<device_sync::FakeRemoteDeviceProvider>();
}
};
class FakeTetherHostFetcherFactory : public TetherHostFetcherImpl::Factory {
public:
FakeTetherHostFetcherFactory(
const multidevice::RemoteDeviceRefList& initial_devices)
: initial_devices_(initial_devices) {}
virtual ~FakeTetherHostFetcherFactory() = default;
FakeTetherHostFetcher* last_created() { return last_created_; }
void SetNoInitialDevices() { initial_devices_.clear(); }
// TetherHostFetcherImpl::Factory :
std::unique_ptr<TetherHostFetcher> CreateInstance(
device_sync::DeviceSyncClient* device_sync_client,
multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client)
override {
last_created_ = new FakeTetherHostFetcher(initial_devices_);
return base::WrapUnique(last_created_);
}
private:
multidevice::RemoteDeviceRefList initial_devices_;
FakeTetherHostFetcher* last_created_ = nullptr;
};
class FakeDeviceSyncClientImplFactory
: public device_sync::DeviceSyncClientImpl::Factory {
public:
FakeDeviceSyncClientImplFactory() = default;
~FakeDeviceSyncClientImplFactory() override = default;
// device_sync::DeviceSyncClientImpl::Factory:
std::unique_ptr<device_sync::DeviceSyncClient> CreateInstance() override {
auto fake_device_sync_client =
std::make_unique<device_sync::FakeDeviceSyncClient>();
fake_device_sync_client->NotifyReady();
return fake_device_sync_client;
}
};
class FakeSecureChannelClientImplFactory
: public secure_channel::SecureChannelClientImpl::Factory {
public:
FakeSecureChannelClientImplFactory() = default;
~FakeSecureChannelClientImplFactory() override = default;
// secure_channel::SecureChannelClientImpl::Factory:
std::unique_ptr<secure_channel::SecureChannelClient> CreateInstance(
mojo::PendingRemote<secure_channel::mojom::SecureChannel> channel,
scoped_refptr<base::TaskRunner> task_runner) override {
return std::make_unique<secure_channel::FakeSecureChannelClient>();
}
};
class FakeMultiDeviceSetupClientImplFactory
: public multidevice_setup::MultiDeviceSetupClientImpl::Factory {
public:
FakeMultiDeviceSetupClientImplFactory() = default;
~FakeMultiDeviceSetupClientImplFactory() override = default;
// multidevice_setup::MultiDeviceSetupClientImpl::Factory:
std::unique_ptr<multidevice_setup::MultiDeviceSetupClient> CreateInstance(
mojo::PendingRemote<multidevice_setup::mojom::MultiDeviceSetup>)
override {
auto fake_multidevice_setup_client =
std::make_unique<multidevice_setup::FakeMultiDeviceSetupClient>();
fake_multidevice_setup_client_ = fake_multidevice_setup_client.get();
return fake_multidevice_setup_client;
}
multidevice_setup::FakeMultiDeviceSetupClient*
fake_multidevice_setup_client() {
return fake_multidevice_setup_client_;
}
private:
multidevice_setup::FakeMultiDeviceSetupClient* fake_multidevice_setup_client_;
};
} // namespace
class TetherServiceTest : public testing::Test {
public:
TetherServiceTest(const TetherServiceTest&) = delete;
TetherServiceTest& operator=(const TetherServiceTest&) = delete;
protected:
TetherServiceTest() : test_devices_(CreateTestDevices()) {}
~TetherServiceTest() override {}
void SetUp() override {
fake_notification_presenter_ = nullptr;
mock_timer_ = nullptr;
NetworkConnect::Initialize(nullptr);
TestingProfile::Builder builder;
profile_ = builder.Build();
fake_chrome_user_manager_ = new FakeChromeUserManager();
scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
base::WrapUnique(fake_chrome_user_manager_));
chromeos::PowerManagerClient::InitializeFake();
fake_device_sync_client_ =
std::make_unique<device_sync::FakeDeviceSyncClient>();
fake_device_sync_client_->NotifyReady();
fake_device_sync_client_impl_factory_ =
std::make_unique<FakeDeviceSyncClientImplFactory>();
device_sync::DeviceSyncClientImpl::Factory::SetFactoryForTesting(
fake_device_sync_client_impl_factory_.get());
fake_secure_channel_client_ =
std::make_unique<secure_channel::FakeSecureChannelClient>();
fake_secure_channel_client_impl_factory_ =
std::make_unique<FakeSecureChannelClientImplFactory>();
secure_channel::SecureChannelClientImpl::Factory::SetFactoryForTesting(
fake_secure_channel_client_impl_factory_.get());
fake_multidevice_setup_client_ =
std::make_unique<multidevice_setup::FakeMultiDeviceSetupClient>();
fake_multidevice_setup_client_impl_factory_ =
std::make_unique<FakeMultiDeviceSetupClientImplFactory>();
multidevice_setup::MultiDeviceSetupClientImpl::Factory::
SetFactoryForTesting(fake_multidevice_setup_client_impl_factory_.get());
initial_feature_state_ =
multidevice_setup::mojom::FeatureState::kEnabledByUser;
fake_enrollment_manager_ =
std::make_unique<device_sync::FakeCryptAuthEnrollmentManager>();
fake_enrollment_manager_->set_user_private_key(kTestUserPrivateKey);
mock_adapter_ =
base::MakeRefCounted<NiceMock<device::MockBluetoothAdapter>>();
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_tether_component_factory_ =
base::WrapUnique(new TestTetherComponentFactory());
TetherComponentImpl::Factory::SetFactoryForTesting(
test_tether_component_factory_.get());
shutdown_reason_verified_ = false;
fake_remote_device_provider_factory_ =
base::WrapUnique(new FakeRemoteDeviceProviderFactory());
device_sync::RemoteDeviceProviderImpl::Factory::SetFactoryForTesting(
fake_remote_device_provider_factory_.get());
fake_tether_host_fetcher_factory_ =
base::WrapUnique(new FakeTetherHostFetcherFactory(test_devices_));
TetherHostFetcherImpl::Factory::SetFactoryForTesting(
fake_tether_host_fetcher_factory_.get());
TestingBrowserProcess::GetGlobal()->SetLocalState(&local_pref_service_);
RegisterLocalState(local_pref_service_.registry());
}
void TearDown() override {
TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
device_sync::DeviceSyncClientImpl::Factory::SetFactoryForTesting(nullptr);
secure_channel::SecureChannelClientImpl::Factory::SetFactoryForTesting(
nullptr);
multidevice_setup::MultiDeviceSetupClientImpl::Factory::
SetFactoryForTesting(nullptr);
ShutdownTetherService();
if (tether_service_) {
// As of crbug.com/798605, SHUT_DOWN should not be logged since it does
// not contribute meaningful data.
histogram_tester_.ExpectBucketCount(
"InstantTethering.FeatureState",
TetherService::TetherFeatureState::SHUT_DOWN, 0 /* count */);
tether_service_.reset();
}
EXPECT_EQ(test_tether_component_factory_->was_tether_component_active(),
shutdown_reason_verified_);
chromeos::PowerManagerClient::Shutdown();
NetworkConnect::Shutdown();
}
void SetPrimaryUserLoggedIn() {
const AccountId account_id(
AccountId::FromUserEmail(profile_->GetProfileUserName()));
const user_manager::User* user =
fake_chrome_user_manager_->AddPublicAccountUser(account_id);
fake_chrome_user_manager_->UserLoggedIn(account_id, user->username_hash(),
false /* browser_restart */,
false /* is_child */);
}
void CreateTetherService() {
fake_multidevice_setup_client_->SetFeatureState(
multidevice_setup::mojom::Feature::kInstantTethering,
initial_feature_state_);
tether_service_ = base::WrapUnique(new TestTetherService(
profile_.get(), chromeos::FakePowerManagerClient::Get(),
fake_device_sync_client_.get(), fake_secure_channel_client_.get(),
fake_multidevice_setup_client_.get(), network_state_handler(),
nullptr /* session_manager */));
fake_notification_presenter_ = new FakeNotificationPresenter();
mock_timer_ = new base::MockOneShotTimer();
tether_service_->SetTestDoubles(
base::WrapUnique(fake_notification_presenter_),
base::WrapUnique(mock_timer_));
SetPrimaryUserLoggedIn();
// 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(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
if (!fake_device_sync_client_->is_ready()) {
return;
}
// Allow the posted task to fetch the BluetoothAdapter to finish.
base::RunLoop().RunUntilIdle();
}
void ShutdownTetherService() {
if (tether_service_)
tether_service_->Shutdown();
}
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(
NetworkTypePattern::Cellular(), enabled,
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 RemoveWifiFromSystem() {
manager_test()->RemoveTechnology(shill::kTypeWifi);
base::RunLoop().RunUntilIdle();
}
void DisconnectDefaultShillNetworks() {
const NetworkState* default_state;
while ((default_state = network_state_handler()->DefaultNetwork())) {
network_handler_test_helper_.service_test()->SetServiceProperty(
default_state->path(), shill::kStateProperty,
base::Value(shill::kStateIdle));
base::RunLoop().RunUntilIdle();
}
}
void VerifyTetherFeatureStateRecorded(
TetherService::TetherFeatureState expected_technology_state_and_reason,
int expected_count) {
histogram_tester_.ExpectBucketCount("InstantTethering.FeatureState",
expected_technology_state_and_reason,
expected_count);
}
void VerifyTetherActiveStatus(bool expected_active) {
EXPECT_EQ(
expected_active,
test_tether_component_factory_->active_tether_component() != nullptr);
}
void VerifyLastShutdownReason(
const TetherComponent::ShutdownReason& expected_shutdown_reason) {
EXPECT_EQ(expected_shutdown_reason,
test_tether_component_factory_->last_shutdown_reason());
shutdown_reason_verified_ = true;
}
chromeos::ShillManagerClient::TestInterface* manager_test() {
return network_handler_test_helper_.manager_test();
}
chromeos::NetworkStateHandler* network_state_handler() {
return chromeos::NetworkHandler::Get()->network_state_handler();
}
const multidevice::RemoteDeviceRefList test_devices_;
const content::BrowserTaskEnvironment task_environment_;
NetworkHandlerTestHelper network_handler_test_helper_;
std::unique_ptr<TestingProfile> profile_;
FakeChromeUserManager* fake_chrome_user_manager_;
std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
std::unique_ptr<sync_preferences::TestingPrefServiceSyncable>
test_pref_service_;
std::unique_ptr<TestTetherComponentFactory> test_tether_component_factory_;
std::unique_ptr<FakeRemoteDeviceProviderFactory>
fake_remote_device_provider_factory_;
std::unique_ptr<FakeTetherHostFetcherFactory>
fake_tether_host_fetcher_factory_;
FakeNotificationPresenter* fake_notification_presenter_;
base::MockOneShotTimer* mock_timer_;
std::unique_ptr<device_sync::FakeDeviceSyncClient> fake_device_sync_client_;
std::unique_ptr<FakeDeviceSyncClientImplFactory>
fake_device_sync_client_impl_factory_;
std::unique_ptr<secure_channel::FakeSecureChannelClient>
fake_secure_channel_client_;
std::unique_ptr<FakeSecureChannelClientImplFactory>
fake_secure_channel_client_impl_factory_;
std::unique_ptr<multidevice_setup::FakeMultiDeviceSetupClient>
fake_multidevice_setup_client_;
std::unique_ptr<FakeMultiDeviceSetupClientImplFactory>
fake_multidevice_setup_client_impl_factory_;
std::unique_ptr<device_sync::FakeCryptAuthEnrollmentManager>
fake_enrollment_manager_;
multidevice_setup::mojom::FeatureState initial_feature_state_;
scoped_refptr<device::MockBluetoothAdapter> mock_adapter_;
bool is_adapter_present_;
bool is_adapter_powered_;
bool shutdown_reason_verified_;
// PrefService which contains the browser process' local storage.
TestingPrefServiceSimple local_pref_service_;
std::unique_ptr<TestTetherService> tether_service_;
base::HistogramTester histogram_tester_;
};
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(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
VerifyLastShutdownReason(TetherComponent::ShutdownReason::USER_LOGGED_OUT);
}
// TODO(https://crbug.com/893878): Fix disabled test.
TEST_F(TetherServiceTest, DISABLED_TestAsyncTetherShutdown) {
CreateTetherService();
// Tether should be ENABLED, and there should be no AsyncShutdownTask.
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
// Use an asynchronous shutdown.
test_tether_component_factory_->active_tether_component()
->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(
TetherComponent::Status::SHUTTING_DOWN,
test_tether_component_factory_->active_tether_component()->status());
// Tether should be AVAILABLE.
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
// Complete the shutdown process; TetherService should delete its
// TetherComponent instance.
test_tether_component_factory_->active_tether_component()
->FinishAsynchronousShutdown();
VerifyTetherActiveStatus(false /* expected_active */);
VerifyLastShutdownReason(TetherComponent::ShutdownReason::PREF_DISABLED);
}
TEST_F(TetherServiceTest, TestSuspend) {
CreateTetherService();
VerifyTetherActiveStatus(true /* expected_active */);
chromeos::FakePowerManagerClient::Get()->SendSuspendImminent(
power_manager::SuspendImminent_Reason_OTHER);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
chromeos::FakePowerManagerClient::Get()->SendSuspendDone();
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
chromeos::FakePowerManagerClient::Get()->SendSuspendImminent(
power_manager::SuspendImminent_Reason_OTHER);
VerifyTetherFeatureStateRecorded(TetherService::TetherFeatureState::SUSPENDED,
2 /* expected_count */);
VerifyLastShutdownReason(TetherComponent::ShutdownReason::USER_CLOSED_LID);
}
TEST_F(TetherServiceTest, TestDeviceSyncClientNotReady) {
fake_device_sync_client_ =
std::make_unique<device_sync::FakeDeviceSyncClient>();
CreateTetherService();
fake_device_sync_client_->NotifyReady();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
ShutdownTetherService();
VerifyLastShutdownReason(TetherComponent::ShutdownReason::USER_LOGGED_OUT);
}
TEST_F(TetherServiceTest,
TestMultiDeviceSetupClientInitiallyHasNoVerifiedHost) {
fake_tether_host_fetcher_factory_->SetNoInitialDevices();
initial_feature_state_ = multidevice_setup::mojom::FeatureState::
kUnavailableNoVerifiedHost_NoEligibleHosts;
CreateTetherService();
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
fake_tether_host_fetcher_factory_->last_created()->set_tether_hosts(
test_devices_);
fake_multidevice_setup_client_->SetFeatureState(
multidevice_setup::mojom::Feature::kInstantTethering,
multidevice_setup::mojom::FeatureState::kEnabledByUser);
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
ShutdownTetherService();
VerifyLastShutdownReason(TetherComponent::ShutdownReason::USER_LOGGED_OUT);
}
TEST_F(TetherServiceTest, TestMultiDeviceSetupClientLosesVerifiedHost) {
CreateTetherService();
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
fake_tether_host_fetcher_factory_->last_created()->set_tether_hosts({});
fake_multidevice_setup_client_->SetFeatureState(
multidevice_setup::mojom::Feature::kInstantTethering,
multidevice_setup::mojom::FeatureState::
kUnavailableNoVerifiedHost_HostExistsButNotSetAndVerified);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
mock_timer_->Fire();
ShutdownTetherService();
VerifyTetherFeatureStateRecorded(
TetherService::TetherFeatureState::NO_AVAILABLE_HOSTS,
1 /* expected_count */);
VerifyLastShutdownReason(
TetherComponent::ShutdownReason::MULTIDEVICE_HOST_UNVERIFIED);
}
TEST_F(TetherServiceTest, TestBetterTogetherSuiteInitiallyDisabled) {
initial_feature_state_ =
multidevice_setup::mojom::FeatureState::kUnavailableSuiteDisabled;
CreateTetherService();
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
fake_multidevice_setup_client_->SetFeatureState(
multidevice_setup::mojom::Feature::kInstantTethering,
multidevice_setup::mojom::FeatureState::kEnabledByUser);
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
ShutdownTetherService();
VerifyLastShutdownReason(TetherComponent::ShutdownReason::USER_LOGGED_OUT);
}
TEST_F(TetherServiceTest, TestBetterTogetherSuiteBecomesDisabled) {
CreateTetherService();
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
fake_multidevice_setup_client_->SetFeatureState(
multidevice_setup::mojom::Feature::kInstantTethering,
multidevice_setup::mojom::FeatureState::kUnavailableSuiteDisabled);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
ShutdownTetherService();
VerifyTetherFeatureStateRecorded(
TetherService::TetherFeatureState::BETTER_TOGETHER_SUITE_DISABLED,
1 /* expected_count */);
VerifyLastShutdownReason(
TetherComponent::ShutdownReason::BETTER_TOGETHER_SUITE_DISABLED);
}
TEST_F(TetherServiceTest, TestGet_NotPrimaryUser_FeatureFlagDisabled) {
EXPECT_FALSE(TetherService::Get(profile_.get()));
}
TEST_F(TetherServiceTest, TestGet_PrimaryUser_FeatureFlagDisabled) {
SetPrimaryUserLoggedIn();
EXPECT_FALSE(TetherService::Get(profile_.get()));
}
TEST_F(TetherServiceTest, TestGet_NotPrimaryUser_FeatureFlagEnabled) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(chromeos::features::kInstantTethering);
EXPECT_FALSE(TetherService::Get(profile_.get()));
}
// TODO(https://crbug.com/893878): Fix disabled test.
TEST_F(TetherServiceTest, DISABLED_TestGet_PrimaryUser_FeatureFlagEnabled) {
SetPrimaryUserLoggedIn();
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeatures(
{chromeos::features::kInstantTethering} /* enabled_features */,
{} /* disabled_features */);
TetherService* tether_service = TetherService::Get(profile_.get());
ASSERT_TRUE(tether_service);
base::RunLoop().RunUntilIdle();
tether_service->Shutdown();
VerifyLastShutdownReason(TetherComponent::ShutdownReason::USER_LOGGED_OUT);
}
// TODO(https://crbug.com/893878): Fix disabled test.
TEST_F(
TetherServiceTest,
DISABLED_TestGet_PrimaryUser_FeatureFlagEnabled_MultiDeviceApiFlagEnabled) {
SetPrimaryUserLoggedIn();
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeatures(
{chromeos::features::kInstantTethering} /* enabled_features */,
{} /* disabled_features */);
TetherService* tether_service = TetherService::Get(profile_.get());
ASSERT_TRUE(tether_service);
base::RunLoop().RunUntilIdle();
tether_service->Shutdown();
VerifyLastShutdownReason(TetherComponent::ShutdownReason::USER_LOGGED_OUT);
}
// TODO(https://crbug.com/893878): Fix disabled test.
TEST_F(
TetherServiceTest,
DISABLED_TestGet_PrimaryUser_FeatureFlagEnabled_MultiDeviceApiAndMultiDeviceSetupFlagsEnabled) {
SetPrimaryUserLoggedIn();
base::test::ScopedFeatureList feature_list;
feature_list.InitWithFeatures(
{chromeos::features::kInstantTethering} /* enabled_features */,
{} /* disabled_features */);
TetherService* tether_service = TetherService::Get(profile_.get());
ASSERT_TRUE(tether_service);
fake_multidevice_setup_client_impl_factory_->fake_multidevice_setup_client()
->SetFeatureState(multidevice_setup::mojom::Feature::kInstantTethering,
multidevice_setup::mojom::FeatureState::kEnabledByUser);
base::RunLoop().RunUntilIdle();
tether_service->Shutdown();
VerifyLastShutdownReason(TetherComponent::ShutdownReason::USER_LOGGED_OUT);
}
TEST_F(TetherServiceTest, TestNoTetherHosts) {
fake_tether_host_fetcher_factory_->SetNoInitialDevices();
CreateTetherService();
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
// Simulate this being the final state of Tether by passing time.
mock_timer_->Fire();
VerifyTetherFeatureStateRecorded(
TetherService::TetherFeatureState::NO_AVAILABLE_HOSTS,
1 /* expected_count */);
}
// TODO(https://crbug.com/893878): Fix disabled test.
TEST_F(TetherServiceTest, DISABLED_TestProhibitedByPolicy) {
profile_->GetPrefs()->SetBoolean(
multidevice_setup::kInstantTetheringAllowedPrefName, false);
CreateTetherService();
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_PROHIBITED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
VerifyTetherFeatureStateRecorded(
TetherService::TetherFeatureState::PROHIBITED, 1 /* expected_count */);
}
TEST_F(TetherServiceTest, TestBluetoothNotPresent) {
set_is_adapter_present(false);
CreateTetherService();
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
// Simulate this being the final state of Tether by passing time.
mock_timer_->Fire();
VerifyTetherFeatureStateRecorded(
TetherService::TetherFeatureState::BLE_NOT_PRESENT,
1 /* expected_count */);
}
TEST_F(TetherServiceTest, TestMetricsFalsePositives) {
set_is_adapter_present(false);
fake_tether_host_fetcher_factory_->SetNoInitialDevices();
CreateTetherService();
set_is_adapter_present(true);
SetIsBluetoothPowered(true);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
fake_tether_host_fetcher_factory_->last_created()->set_tether_hosts(
test_devices_);
fake_tether_host_fetcher_factory_->last_created()->NotifyTetherHostsUpdated();
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
// No metric should have been recorded for BLE_NOT_PRESENT and
// NO_AVAILABLE_HOSTS, but ENABLED should have been recorded.
VerifyTetherFeatureStateRecorded(
TetherService::TetherFeatureState::BLE_NOT_PRESENT,
0 /* expected_count */);
VerifyTetherFeatureStateRecorded(
TetherService::TetherFeatureState::NO_AVAILABLE_HOSTS,
0 /* expected_count */);
VerifyTetherFeatureStateRecorded(TetherService::TetherFeatureState::ENABLED,
1 /* expected_count */);
// Ensure that the pending state recording has been canceled.
ASSERT_FALSE(mock_timer_->IsRunning());
ShutdownTetherService();
VerifyLastShutdownReason(TetherComponent::ShutdownReason::USER_LOGGED_OUT);
}
TEST_F(TetherServiceTest, TestWifiNotPresent) {
RemoveWifiFromSystem();
CreateTetherService();
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherFeatureStateRecorded(
TetherService::TetherFeatureState::WIFI_NOT_PRESENT,
1 /* expected_count */);
}
TEST_F(TetherServiceTest, TestIsBluetoothPowered) {
SetIsBluetoothPowered(false);
CreateTetherService();
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
SetIsBluetoothPowered(true);
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
SetIsBluetoothPowered(false);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNINITIALIZED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
VerifyTetherFeatureStateRecorded(
TetherService::TetherFeatureState::BLUETOOTH_DISABLED,
2 /* expected_count */);
VerifyLastShutdownReason(TetherComponent::ShutdownReason::BLUETOOTH_DISABLED);
}
// TODO(https://crbug.com/893878): Fix disabled test.
TEST_F(TetherServiceTest, DISABLED_TestCellularIsUnavailable) {
manager_test()->RemoveTechnology(shill::kTypeCellular);
ASSERT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Cellular()));
CreateTetherService();
SetTetherTechnologyStateEnabled(false);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
VerifyLastShutdownReason(TetherComponent::ShutdownReason::PREF_DISABLED);
SetTetherTechnologyStateEnabled(true);
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
VerifyTetherFeatureStateRecorded(TetherService::TetherFeatureState::ENABLED,
2 /* expected_count */);
}
// TODO(https://crbug.com/893878): Fix disabled test.
TEST_F(TetherServiceTest, DISABLED_TestCellularIsAvailable) {
// TODO (lesliewatkins): Investigate why cellular needs to be removed and
// re-added for NetworkStateHandler to return the correct TechnologyState.
manager_test()->RemoveTechnology(shill::kTypeCellular);
manager_test()->AddTechnology(shill::kTypeCellular, false);
CreateTetherService();
// Cellular disabled
SetCellularTechnologyStateEnabled(false);
ASSERT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Cellular()));
VerifyTetherActiveStatus(false /* expected_active */);
SetTetherTechnologyStateEnabled(false);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
SetTetherTechnologyStateEnabled(true);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
// Cellular enabled
SetCellularTechnologyStateEnabled(true);
ASSERT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Cellular()));
VerifyTetherActiveStatus(true /* expected_active */);
SetTetherTechnologyStateEnabled(false);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
SetTetherTechnologyStateEnabled(true);
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
SetCellularTechnologyStateEnabled(false);
VerifyTetherFeatureStateRecorded(
TetherService::TetherFeatureState::CELLULAR_DISABLED,
2 /* expected_count */);
VerifyLastShutdownReason(TetherComponent::ShutdownReason::CELLULAR_DISABLED);
}
// TODO(https://crbug.com/893878): Fix disabled test.
TEST_F(TetherServiceTest, DISABLED_TestDisabled) {
profile_->GetPrefs()->SetBoolean(
multidevice_setup::kInstantTetheringEnabledPrefName, false);
CreateTetherService();
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
EXPECT_FALSE(profile_->GetPrefs()->GetBoolean(
multidevice_setup::kInstantTetheringEnabledPrefName));
VerifyTetherActiveStatus(false /* expected_active */);
VerifyTetherFeatureStateRecorded(
TetherService::TetherFeatureState::USER_PREFERENCE_DISABLED,
1 /* expected_count */);
}
// TODO(https://crbug.com/893878): Fix disabled test.
TEST_F(TetherServiceTest, DISABLED_TestEnabled) {
CreateTetherService();
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
SetTetherTechnologyStateEnabled(false);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
EXPECT_FALSE(profile_->GetPrefs()->GetBoolean(
multidevice_setup::kInstantTetheringEnabledPrefName));
VerifyTetherActiveStatus(false /* expected_active */);
histogram_tester_.ExpectBucketCount(
"InstantTethering.UserPreference.OnToggle", false,
1u /* expected_count */);
SetTetherTechnologyStateEnabled(true);
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
EXPECT_TRUE(profile_->GetPrefs()->GetBoolean(
multidevice_setup::kInstantTetheringEnabledPrefName));
VerifyTetherActiveStatus(true /* expected_active */);
histogram_tester_.ExpectBucketCount(
"InstantTethering.UserPreference.OnToggle", true,
1u /* expected_count */);
VerifyTetherFeatureStateRecorded(TetherService::TetherFeatureState::ENABLED,
2 /* expected_count */);
VerifyLastShutdownReason(TetherComponent::ShutdownReason::PREF_DISABLED);
}
TEST_F(TetherServiceTest, TestUserPrefChangesViaFeatureStateChange) {
// Start with the feature disabled.
initial_feature_state_ =
multidevice_setup::mojom::FeatureState::kDisabledByUser;
profile_->GetPrefs()->SetBoolean(
multidevice_setup::kInstantTetheringEnabledPrefName, false);
CreateTetherService();
// Enable the feature.
profile_->GetPrefs()->SetBoolean(
multidevice_setup::kInstantTetheringEnabledPrefName, true);
fake_multidevice_setup_client_->SetFeatureState(
multidevice_setup::mojom::Feature::kInstantTethering,
multidevice_setup::mojom::FeatureState::kEnabledByUser);
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
VerifyTetherFeatureStateRecorded(TetherService::TetherFeatureState::ENABLED,
1 /* expected_count */);
histogram_tester_.ExpectBucketCount(
"InstantTethering.UserPreference.OnToggle", true,
1u /* expected_count */);
// Disable the feature.
profile_->GetPrefs()->SetBoolean(
multidevice_setup::kInstantTetheringEnabledPrefName, false);
fake_multidevice_setup_client_->SetFeatureState(
multidevice_setup::mojom::Feature::kInstantTethering,
multidevice_setup::mojom::FeatureState::kDisabledByUser);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
VerifyTetherFeatureStateRecorded(
TetherService::TetherFeatureState::USER_PREFERENCE_DISABLED,
2 /* expected_count */);
histogram_tester_.ExpectBucketCount(
"InstantTethering.UserPreference.OnToggle", false,
1u /* expected_count */);
// Enable the feature.
profile_->GetPrefs()->SetBoolean(
multidevice_setup::kInstantTetheringEnabledPrefName, true);
fake_multidevice_setup_client_->SetFeatureState(
multidevice_setup::mojom::Feature::kInstantTethering,
multidevice_setup::mojom::FeatureState::kEnabledByUser);
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
VerifyTetherFeatureStateRecorded(TetherService::TetherFeatureState::ENABLED,
2 /* expected_count */);
histogram_tester_.ExpectBucketCount(
"InstantTethering.UserPreference.OnToggle", true,
2u /* expected_count */);
VerifyLastShutdownReason(TetherComponent::ShutdownReason::PREF_DISABLED);
}
TEST_F(TetherServiceTest, TestUserPrefChangesViaTechnologyStateChange) {
CreateTetherService();
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
SetTetherTechnologyStateEnabled(false);
fake_multidevice_setup_client_->InvokePendingSetFeatureEnabledStateCallback(
multidevice_setup::mojom::Feature::kInstantTethering,
false /* expected_enabled */, absl::nullopt /* expected_auth_token */,
true /* success */);
profile_->GetPrefs()->SetBoolean(
multidevice_setup::kInstantTetheringEnabledPrefName, false);
fake_multidevice_setup_client_->SetFeatureState(
multidevice_setup::mojom::Feature::kInstantTethering,
multidevice_setup::mojom::FeatureState::kDisabledByUser);
EXPECT_EQ(
chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(false /* expected_active */);
histogram_tester_.ExpectBucketCount(
"InstantTethering.UserPreference.OnToggle", false,
1u /* expected_count */);
SetTetherTechnologyStateEnabled(true);
fake_multidevice_setup_client_->InvokePendingSetFeatureEnabledStateCallback(
multidevice_setup::mojom::Feature::kInstantTethering,
true /* expected_enabled */, absl::nullopt /* expected_auth_token */,
false /* success */);
profile_->GetPrefs()->SetBoolean(
multidevice_setup::kInstantTetheringEnabledPrefName, true);
fake_multidevice_setup_client_->SetFeatureState(
multidevice_setup::mojom::Feature::kInstantTethering,
multidevice_setup::mojom::FeatureState::kEnabledByUser);
EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED,
network_state_handler()->GetTechnologyState(
NetworkTypePattern::Tether()));
VerifyTetherActiveStatus(true /* expected_active */);
histogram_tester_.ExpectBucketCount(
"InstantTethering.UserPreference.OnToggle", true,
1u /* expected_count */);
VerifyTetherFeatureStateRecorded(TetherService::TetherFeatureState::ENABLED,
2 /* expected_count */);
VerifyLastShutdownReason(TetherComponent::ShutdownReason::PREF_DISABLED);
}
// TODO(https://crbug.com/893878): Fix disabled test.
// 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, DISABLED_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());
VerifyLastShutdownReason(TetherComponent::ShutdownReason::PREF_DISABLED);
}
} // namespace tether
} // namespace ash