| // 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/run_loop.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/scoped_task_environment.h" |
| #include "base/timer/mock_timer.h" |
| #include "chrome/browser/chromeos/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/chromeos_features.h" |
| #include "chromeos/chromeos_switches.h" |
| #include "chromeos/components/multidevice/remote_device_test_util.h" |
| #include "chromeos/components/multidevice/software_feature.h" |
| #include "chromeos/components/tether/fake_notification_presenter.h" |
| #include "chromeos/components/tether/fake_tether_component.h" |
| #include "chromeos/components/tether/fake_tether_host_fetcher.h" |
| #include "chromeos/components/tether/tether_component_impl.h" |
| #include "chromeos/components/tether/tether_host_fetcher_impl.h" |
| #include "chromeos/dbus/dbus_thread_manager.h" |
| #include "chromeos/dbus/fake_power_manager_client.h" |
| #include "chromeos/dbus/fake_shill_manager_client.h" |
| #include "chromeos/dbus/power_manager/suspend.pb.h" |
| #include "chromeos/dbus/power_manager_client.h" |
| #include "chromeos/dbus/shill_device_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 "chromeos/services/device_sync/cryptauth_device_manager.h" |
| #include "chromeos/services/device_sync/cryptauth_enroller.h" |
| #include "chromeos/services/device_sync/cryptauth_enrollment_manager.h" |
| #include "chromeos/services/device_sync/fake_cryptauth_enrollment_manager.h" |
| #include "chromeos/services/device_sync/fake_remote_device_provider.h" |
| #include "chromeos/services/device_sync/public/cpp/device_sync_client_impl.h" |
| #include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h" |
| #include "chromeos/services/device_sync/remote_device_provider_impl.h" |
| #include "chromeos/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.h" |
| #include "chromeos/services/multidevice_setup/public/cpp/multidevice_setup_client_impl.h" |
| #include "chromeos/services/multidevice_setup/public/cpp/prefs.h" |
| #include "chromeos/services/secure_channel/public/cpp/client/fake_secure_channel_client.h" |
| #include "chromeos/services/secure_channel/public/cpp/client/secure_channel_client_impl.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 "components/user_manager/scoped_user_manager.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 "third_party/cros_system_api/dbus/shill/dbus-constants.h" |
| |
| using testing::Invoke; |
| using testing::NiceMock; |
| using testing::Return; |
| |
| namespace { |
| |
| const char kTestUserPrivateKey[] = "kTestUserPrivateKey"; |
| const size_t kNumTestDevices = 5; |
| |
| chromeos::multidevice::RemoteDeviceRefList CreateTestDevices() { |
| chromeos::multidevice::RemoteDeviceRefList list; |
| for (size_t i = 0; i < kNumTestDevices; ++i) { |
| list.push_back( |
| chromeos::multidevice::RemoteDeviceRefBuilder() |
| .SetSupportsMobileHotspot(true) |
| .SetSoftwareFeatureState( |
| chromeos::multidevice::SoftwareFeature::kBetterTogetherHost, |
| chromeos::multidevice::SoftwareFeatureState::kSupported) |
| .Build()); |
| } |
| return list; |
| } |
| |
| 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, |
| cryptauth::CryptAuthService* cryptauth_service, |
| chromeos::device_sync::DeviceSyncClient* device_sync_client, |
| chromeos::secure_channel::SecureChannelClient* secure_channel_client, |
| chromeos::multidevice_setup::MultiDeviceSetupClient* |
| multidevice_setup_client, |
| chromeos::NetworkStateHandler* network_state_handler, |
| session_manager::SessionManager* session_manager) |
| : TetherService(profile, |
| power_manager_client, |
| cryptauth_service, |
| 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 chromeos::tether::FakeTetherComponent { |
| public: |
| FakeTetherComponentWithDestructorCallback( |
| const base::Closure& destructor_callback) |
| : FakeTetherComponent(false /* has_asynchronous_shutdown */), |
| destructor_callback_(destructor_callback) {} |
| |
| ~FakeTetherComponentWithDestructorCallback() override { |
| destructor_callback_.Run(); |
| } |
| |
| private: |
| base::Closure destructor_callback_; |
| }; |
| |
| class TestTetherComponentFactory final |
| : public chromeos::tether::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_; |
| } |
| |
| // chromeos::tether::TetherComponentImpl::Factory: |
| std::unique_ptr<chromeos::tether::TetherComponent> BuildInstance( |
| chromeos::device_sync::DeviceSyncClient* device_sync_client, |
| chromeos::secure_channel::SecureChannelClient* secure_channel_client, |
| chromeos::tether::TetherHostFetcher* tether_host_fetcher, |
| chromeos::tether::NotificationPresenter* notification_presenter, |
| chromeos::tether::GmsCoreNotificationsStateTrackerImpl* |
| gms_core_notifications_state_tracker, |
| 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, |
| session_manager::SessionManager* session_manager) override { |
| active_tether_component_ = new FakeTetherComponentWithDestructorCallback( |
| base::Bind(&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 chromeos::tether::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; |
| chromeos::tether::TetherComponent::ShutdownReason last_shutdown_reason_; |
| }; |
| |
| class FakeRemoteDeviceProviderFactory |
| : public chromeos::device_sync::RemoteDeviceProviderImpl::Factory { |
| public: |
| FakeRemoteDeviceProviderFactory() = default; |
| ~FakeRemoteDeviceProviderFactory() override = default; |
| |
| // chromeos::device_sync::RemoteDeviceProviderImpl::Factory: |
| std::unique_ptr<chromeos::device_sync::RemoteDeviceProvider> BuildInstance( |
| chromeos::device_sync::CryptAuthDeviceManager* device_manager, |
| const std::string& user_id, |
| const std::string& user_private_key) override { |
| return std::make_unique<chromeos::device_sync::FakeRemoteDeviceProvider>(); |
| } |
| }; |
| |
| class FakeTetherHostFetcherFactory |
| : public chromeos::tether::TetherHostFetcherImpl::Factory { |
| public: |
| FakeTetherHostFetcherFactory( |
| const chromeos::multidevice::RemoteDeviceRefList& initial_devices) |
| : initial_devices_(initial_devices) {} |
| virtual ~FakeTetherHostFetcherFactory() = default; |
| |
| chromeos::tether::FakeTetherHostFetcher* last_created() { |
| return last_created_; |
| } |
| |
| void SetNoInitialDevices() { initial_devices_.clear(); } |
| |
| // chromeos::tether::TetherHostFetcherImpl::Factory : |
| std::unique_ptr<chromeos::tether::TetherHostFetcher> BuildInstance( |
| chromeos::device_sync::DeviceSyncClient* device_sync_client, |
| chromeos::multidevice_setup::MultiDeviceSetupClient* |
| multidevice_setup_client) override { |
| last_created_ = |
| new chromeos::tether::FakeTetherHostFetcher(initial_devices_); |
| return base::WrapUnique(last_created_); |
| } |
| |
| private: |
| chromeos::multidevice::RemoteDeviceRefList initial_devices_; |
| chromeos::tether::FakeTetherHostFetcher* last_created_ = nullptr; |
| }; |
| |
| class FakeDeviceSyncClientImplFactory |
| : public chromeos::device_sync::DeviceSyncClientImpl::Factory { |
| public: |
| FakeDeviceSyncClientImplFactory() = default; |
| |
| ~FakeDeviceSyncClientImplFactory() override = default; |
| |
| // chromeos::device_sync::DeviceSyncClientImpl::Factory: |
| std::unique_ptr<chromeos::device_sync::DeviceSyncClient> BuildInstance( |
| service_manager::Connector* connector) override { |
| auto fake_device_sync_client = |
| std::make_unique<chromeos::device_sync::FakeDeviceSyncClient>(); |
| fake_device_sync_client->NotifyReady(); |
| return fake_device_sync_client; |
| } |
| }; |
| |
| class FakeSecureChannelClientImplFactory |
| : public chromeos::secure_channel::SecureChannelClientImpl::Factory { |
| public: |
| FakeSecureChannelClientImplFactory() = default; |
| |
| ~FakeSecureChannelClientImplFactory() override = default; |
| |
| // chromeos::secure_channel::SecureChannelClientImpl::Factory: |
| std::unique_ptr<chromeos::secure_channel::SecureChannelClient> BuildInstance( |
| service_manager::Connector* connector, |
| scoped_refptr<base::TaskRunner> task_runner) override { |
| return std::make_unique< |
| chromeos::secure_channel::FakeSecureChannelClient>(); |
| } |
| }; |
| |
| class FakeMultiDeviceSetupClientImplFactory |
| : public chromeos::multidevice_setup::MultiDeviceSetupClientImpl::Factory { |
| public: |
| FakeMultiDeviceSetupClientImplFactory() = default; |
| |
| ~FakeMultiDeviceSetupClientImplFactory() override = default; |
| |
| // chromeos::multidevice_setup::MultiDeviceSetupClientImpl::Factory: |
| std::unique_ptr<chromeos::multidevice_setup::MultiDeviceSetupClient> |
| BuildInstance(service_manager::Connector* connector) override { |
| auto fake_multidevice_setup_client = std::make_unique< |
| chromeos::multidevice_setup::FakeMultiDeviceSetupClient>(); |
| fake_multidevice_setup_client_ = fake_multidevice_setup_client.get(); |
| return fake_multidevice_setup_client; |
| } |
| |
| chromeos::multidevice_setup::FakeMultiDeviceSetupClient* |
| fake_multidevice_setup_client() { |
| return fake_multidevice_setup_client_; |
| } |
| |
| private: |
| chromeos::multidevice_setup::FakeMultiDeviceSetupClient* |
| fake_multidevice_setup_client_; |
| }; |
| |
| } // namespace |
| |
| class TetherServiceTest : public chromeos::NetworkStateTest { |
| protected: |
| TetherServiceTest() |
| : NetworkStateTest(), test_devices_(CreateTestDevices()) {} |
| ~TetherServiceTest() override {} |
| |
| void SetUp() override { |
| fake_notification_presenter_ = nullptr; |
| mock_timer_ = nullptr; |
| |
| chromeos::DBusThreadManager::Initialize(); |
| chromeos::NetworkStateTest::SetUp(); |
| |
| chromeos::NetworkConnect::Initialize(nullptr); |
| chromeos::NetworkHandler::Initialize(); |
| |
| TestingProfile::Builder builder; |
| profile_ = builder.Build(); |
| |
| fake_chrome_user_manager_ = new chromeos::FakeChromeUserManager(); |
| scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>( |
| base::WrapUnique(fake_chrome_user_manager_)); |
| |
| fake_power_manager_client_ = |
| std::make_unique<chromeos::FakePowerManagerClient>(); |
| |
| fake_device_sync_client_ = |
| std::make_unique<chromeos::device_sync::FakeDeviceSyncClient>(); |
| fake_device_sync_client_->NotifyReady(); |
| |
| fake_device_sync_client_impl_factory_ = |
| std::make_unique<FakeDeviceSyncClientImplFactory>(); |
| chromeos::device_sync::DeviceSyncClientImpl::Factory::SetInstanceForTesting( |
| fake_device_sync_client_impl_factory_.get()); |
| |
| fake_secure_channel_client_ = |
| std::make_unique<chromeos::secure_channel::FakeSecureChannelClient>(); |
| fake_secure_channel_client_impl_factory_ = |
| std::make_unique<FakeSecureChannelClientImplFactory>(); |
| chromeos::secure_channel::SecureChannelClientImpl::Factory:: |
| SetInstanceForTesting(fake_secure_channel_client_impl_factory_.get()); |
| |
| fake_multidevice_setup_client_ = std::make_unique< |
| chromeos::multidevice_setup::FakeMultiDeviceSetupClient>(); |
| fake_multidevice_setup_client_impl_factory_ = |
| std::make_unique<FakeMultiDeviceSetupClientImplFactory>(); |
| chromeos::multidevice_setup::MultiDeviceSetupClientImpl::Factory:: |
| SetInstanceForTesting( |
| fake_multidevice_setup_client_impl_factory_.get()); |
| initial_feature_state_ = |
| chromeos::multidevice_setup::mojom::FeatureState::kEnabledByUser; |
| |
| fake_cryptauth_service_ = |
| std::make_unique<cryptauth::FakeCryptAuthService>(); |
| fake_enrollment_manager_ = std::make_unique< |
| chromeos::device_sync::FakeCryptAuthEnrollmentManager>(); |
| fake_enrollment_manager_->set_user_private_key(kTestUserPrivateKey); |
| fake_cryptauth_service_->set_cryptauth_enrollment_manager( |
| fake_enrollment_manager_.get()); |
| |
| mock_adapter_ = |
| base::MakeRefCounted<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_tether_component_factory_ = |
| base::WrapUnique(new TestTetherComponentFactory()); |
| chromeos::tether::TetherComponentImpl::Factory::SetInstanceForTesting( |
| test_tether_component_factory_.get()); |
| shutdown_reason_verified_ = false; |
| |
| fake_remote_device_provider_factory_ = |
| base::WrapUnique(new FakeRemoteDeviceProviderFactory()); |
| chromeos::device_sync::RemoteDeviceProviderImpl::Factory:: |
| SetInstanceForTesting(fake_remote_device_provider_factory_.get()); |
| |
| fake_tether_host_fetcher_factory_ = |
| base::WrapUnique(new FakeTetherHostFetcherFactory(test_devices_)); |
| chromeos::tether::TetherHostFetcherImpl::Factory::SetInstanceForTesting( |
| fake_tether_host_fetcher_factory_.get()); |
| |
| TestingBrowserProcess::GetGlobal()->SetLocalState(&local_pref_service_); |
| RegisterLocalState(local_pref_service_.registry()); |
| } |
| |
| void TearDown() override { |
| TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr); |
| |
| chromeos::device_sync::DeviceSyncClientImpl::Factory::SetInstanceForTesting( |
| nullptr); |
| chromeos::secure_channel::SecureChannelClientImpl::Factory:: |
| SetInstanceForTesting(nullptr); |
| chromeos::multidevice_setup::MultiDeviceSetupClientImpl::Factory:: |
| SetInstanceForTesting(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::NetworkConnect::Shutdown(); |
| chromeos::NetworkHandler::Shutdown(); |
| |
| ShutdownNetworkState(); |
| chromeos::NetworkStateTest::TearDown(); |
| chromeos::DBusThreadManager::Shutdown(); |
| } |
| |
| void SetEnableUnifiedMultiDeviceSetup(bool enabled) { |
| static const std::vector<base::Feature> kFeatures{ |
| chromeos::features::kEnableUnifiedMultiDeviceSetup}; |
| |
| scoped_feature_list_.InitWithFeatures( |
| (enabled ? kFeatures |
| : std::vector<base::Feature>() /* enable_features */), |
| (enabled ? std::vector<base::Feature>() |
| : kFeatures /* disable_features */)); |
| } |
| |
| 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(bool enable_multidevice_apis) { |
| SetEnableUnifiedMultiDeviceSetup(enable_multidevice_apis); |
| |
| fake_multidevice_setup_client_->SetFeatureState( |
| chromeos::multidevice_setup::mojom::Feature::kInstantTethering, |
| initial_feature_state_); |
| |
| tether_service_ = base::WrapUnique(new TestTetherService( |
| profile_.get(), fake_power_manager_client_.get(), |
| fake_cryptauth_service_.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 chromeos::tether::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( |
| chromeos::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( |
| 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 RemoveWifiFromSystem() { |
| chromeos::DBusThreadManager::Get() |
| ->GetShillManagerClient() |
| ->GetTestInterface() |
| ->RemoveTechnology(shill::kTypeWifi); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| 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 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 chromeos::tether::TetherComponent::ShutdownReason& |
| expected_shutdown_reason) { |
| EXPECT_EQ(expected_shutdown_reason, |
| test_tether_component_factory_->last_shutdown_reason()); |
| shutdown_reason_verified_ = true; |
| } |
| |
| const chromeos::multidevice::RemoteDeviceRefList test_devices_; |
| const content::TestBrowserThreadBundle thread_bundle_; |
| base::test::ScopedFeatureList scoped_feature_list_; |
| |
| std::unique_ptr<TestingProfile> profile_; |
| chromeos::FakeChromeUserManager* fake_chrome_user_manager_; |
| std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_; |
| std::unique_ptr<chromeos::FakePowerManagerClient> fake_power_manager_client_; |
| 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_; |
| chromeos::tether::FakeNotificationPresenter* fake_notification_presenter_; |
| base::MockOneShotTimer* mock_timer_; |
| std::unique_ptr<chromeos::device_sync::FakeDeviceSyncClient> |
| fake_device_sync_client_; |
| std::unique_ptr<FakeDeviceSyncClientImplFactory> |
| fake_device_sync_client_impl_factory_; |
| std::unique_ptr<chromeos::secure_channel::FakeSecureChannelClient> |
| fake_secure_channel_client_; |
| std::unique_ptr<FakeSecureChannelClientImplFactory> |
| fake_secure_channel_client_impl_factory_; |
| std::unique_ptr<chromeos::multidevice_setup::FakeMultiDeviceSetupClient> |
| fake_multidevice_setup_client_; |
| std::unique_ptr<FakeMultiDeviceSetupClientImplFactory> |
| fake_multidevice_setup_client_impl_factory_; |
| std::unique_ptr<cryptauth::FakeCryptAuthService> fake_cryptauth_service_; |
| std::unique_ptr<chromeos::device_sync::FakeCryptAuthEnrollmentManager> |
| fake_enrollment_manager_; |
| |
| chromeos::multidevice_setup::mojom::FeatureState initial_feature_state_; |
| |
| scoped_refptr<MockExtendedBluetoothAdapter> 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_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(TetherServiceTest); |
| }; |
| |
| TEST_F(TetherServiceTest, TestShutdown) { |
| CreateTetherService(false /* enable_multidevice_apis */); |
| 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 */); |
| VerifyLastShutdownReason( |
| chromeos::tether::TetherComponent::ShutdownReason::USER_LOGGED_OUT); |
| } |
| |
| // TODO(https://crbug.com/893878): Fix disabled test. |
| TEST_F(TetherServiceTest, DISABLED_TestAsyncTetherShutdown) { |
| CreateTetherService(false /* enable_multidevice_apis */); |
| |
| // 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_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( |
| chromeos::tether::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( |
| chromeos::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( |
| chromeos::tether::TetherComponent::ShutdownReason::PREF_DISABLED); |
| } |
| |
| TEST_F(TetherServiceTest, TestSuspend) { |
| CreateTetherService(false /* enable_multidevice_apis */); |
| VerifyTetherActiveStatus(true /* expected_active */); |
| |
| fake_power_manager_client_->SendSuspendImminent( |
| power_manager::SuspendImminent_Reason_OTHER); |
| |
| 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( |
| power_manager::SuspendImminent_Reason_OTHER); |
| |
| VerifyTetherFeatureStateRecorded(TetherService::TetherFeatureState::SUSPENDED, |
| 2 /* expected_count */); |
| VerifyLastShutdownReason( |
| chromeos::tether::TetherComponent::ShutdownReason::USER_CLOSED_LID); |
| } |
| |
| TEST_F(TetherServiceTest, TestDeviceSyncClientNotReady) { |
| fake_device_sync_client_ = |
| std::make_unique<chromeos::device_sync::FakeDeviceSyncClient>(); |
| |
| CreateTetherService(true /* enable_multidevice_apis */); |
| |
| fake_device_sync_client_->NotifyReady(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Tether())); |
| VerifyTetherActiveStatus(true /* expected_active */); |
| |
| ShutdownTetherService(); |
| VerifyLastShutdownReason( |
| chromeos::tether::TetherComponent::ShutdownReason::USER_LOGGED_OUT); |
| } |
| |
| TEST_F(TetherServiceTest, |
| TestMultiDeviceSetupClientInitiallyHasNoVerifiedHost) { |
| fake_tether_host_fetcher_factory_->SetNoInitialDevices(); |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures( |
| {chromeos::features:: |
| kEnableUnifiedMultiDeviceSetup} /* enabled_features */, |
| {} /* disabled_features */); |
| |
| initial_feature_state_ = chromeos::multidevice_setup::mojom::FeatureState:: |
| kUnavailableNoVerifiedHost; |
| |
| CreateTetherService(true /* enable_multidevice_apis */); |
| |
| EXPECT_EQ( |
| chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Tether())); |
| VerifyTetherActiveStatus(false /* expected_active */); |
| |
| fake_tether_host_fetcher_factory_->last_created()->set_tether_hosts( |
| test_devices_); |
| fake_multidevice_setup_client_->SetFeatureState( |
| chromeos::multidevice_setup::mojom::Feature::kInstantTethering, |
| chromeos::multidevice_setup::mojom::FeatureState::kEnabledByUser); |
| |
| EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Tether())); |
| VerifyTetherActiveStatus(true /* expected_active */); |
| |
| ShutdownTetherService(); |
| VerifyLastShutdownReason( |
| chromeos::tether::TetherComponent::ShutdownReason::USER_LOGGED_OUT); |
| } |
| |
| TEST_F(TetherServiceTest, TestMultiDeviceSetupClientLosesVerifiedHost) { |
| CreateTetherService(true /* enable_multidevice_apis */); |
| |
| EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Tether())); |
| VerifyTetherActiveStatus(true /* expected_active */); |
| |
| fake_tether_host_fetcher_factory_->last_created()->set_tether_hosts({}); |
| fake_multidevice_setup_client_->SetFeatureState( |
| chromeos::multidevice_setup::mojom::Feature::kInstantTethering, |
| chromeos::multidevice_setup::mojom::FeatureState:: |
| kUnavailableNoVerifiedHost); |
| |
| EXPECT_EQ( |
| chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Tether())); |
| VerifyTetherActiveStatus(false /* expected_active */); |
| |
| mock_timer_->Fire(); |
| ShutdownTetherService(); |
| VerifyTetherFeatureStateRecorded( |
| TetherService::TetherFeatureState::NO_AVAILABLE_HOSTS, |
| 1 /* expected_count */); |
| VerifyLastShutdownReason(chromeos::tether::TetherComponent::ShutdownReason:: |
| MULTIDEVICE_HOST_UNVERIFIED); |
| } |
| |
| TEST_F(TetherServiceTest, TestBetterTogetherSuiteInitiallyDisabled) { |
| initial_feature_state_ = chromeos::multidevice_setup::mojom::FeatureState:: |
| kUnavailableSuiteDisabled; |
| |
| CreateTetherService(true /* enable_multidevice_apis */); |
| |
| EXPECT_EQ( |
| chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Tether())); |
| VerifyTetherActiveStatus(false /* expected_active */); |
| |
| fake_multidevice_setup_client_->SetFeatureState( |
| chromeos::multidevice_setup::mojom::Feature::kInstantTethering, |
| chromeos::multidevice_setup::mojom::FeatureState::kEnabledByUser); |
| |
| EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Tether())); |
| VerifyTetherActiveStatus(true /* expected_active */); |
| |
| ShutdownTetherService(); |
| VerifyLastShutdownReason( |
| chromeos::tether::TetherComponent::ShutdownReason::USER_LOGGED_OUT); |
| } |
| |
| TEST_F(TetherServiceTest, TestBetterTogetherSuiteBecomesDisabled) { |
| CreateTetherService(true /* enable_multidevice_apis */); |
| |
| EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Tether())); |
| VerifyTetherActiveStatus(true /* expected_active */); |
| |
| fake_multidevice_setup_client_->SetFeatureState( |
| chromeos::multidevice_setup::mojom::Feature::kInstantTethering, |
| chromeos::multidevice_setup::mojom::FeatureState:: |
| kUnavailableSuiteDisabled); |
| |
| EXPECT_EQ( |
| chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Tether())); |
| VerifyTetherActiveStatus(false /* expected_active */); |
| |
| ShutdownTetherService(); |
| VerifyTetherFeatureStateRecorded( |
| TetherService::TetherFeatureState::BETTER_TOGETHER_SUITE_DISABLED, |
| 1 /* expected_count */); |
| VerifyLastShutdownReason(chromeos::tether::TetherComponent::ShutdownReason:: |
| BETTER_TOGETHER_SUITE_DISABLED); |
| } |
| |
| TEST_F(TetherServiceTest, TestBleAdvertisingNotSupported) { |
| mock_adapter_->set_is_ble_advertising_supported(false); |
| |
| CreateTetherService(false /* enable_multidevice_apis */); |
| |
| EXPECT_EQ( |
| chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Tether())); |
| VerifyTetherActiveStatus(false /* expected_active */); |
| |
| VerifyTetherFeatureStateRecorded( |
| TetherService::TetherFeatureState::BLE_ADVERTISING_NOT_SUPPORTED, |
| 1 /* expected_count */); |
| VerifyLastShutdownReason( |
| chromeos::tether::TetherComponent::ShutdownReason::OTHER); |
| } |
| |
| TEST_F(TetherServiceTest, |
| TestBleAdvertisingNotSupported_BluetoothIsInitiallyNotPowered) { |
| SetIsBluetoothPowered(false); |
| |
| mock_adapter_->set_is_ble_advertising_supported(false); |
| |
| CreateTetherService(false /* enable_multidevice_apis */); |
| |
| // 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)); |
| |
| VerifyTetherFeatureStateRecorded( |
| TetherService::TetherFeatureState::BLE_ADVERTISING_NOT_SUPPORTED, |
| 1 /* expected_count */); |
| } |
| |
| 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(false /* enable_multidevice_apis */); |
| |
| 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 */); |
| |
| VerifyTetherFeatureStateRecorded( |
| TetherService::TetherFeatureState::BLE_ADVERTISING_NOT_SUPPORTED, |
| 1 /* expected_count */); |
| } |
| |
| 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(false /* enable_multidevice_apis */); |
| |
| 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)); |
| |
| VerifyTetherFeatureStateRecorded(TetherService::TetherFeatureState::ENABLED, |
| 1 /* expected_count */); |
| |
| ShutdownTetherService(); |
| VerifyLastShutdownReason( |
| chromeos::tether::TetherComponent::ShutdownReason::USER_LOGGED_OUT); |
| } |
| |
| 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( |
| chromeos::tether::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( |
| chromeos::tether::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, |
| chromeos::features:: |
| kEnableUnifiedMultiDeviceSetup} /* 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( |
| chromeos::multidevice_setup::mojom::Feature::kInstantTethering, |
| chromeos::multidevice_setup::mojom::FeatureState::kEnabledByUser); |
| |
| base::RunLoop().RunUntilIdle(); |
| tether_service->Shutdown(); |
| |
| VerifyLastShutdownReason( |
| chromeos::tether::TetherComponent::ShutdownReason::USER_LOGGED_OUT); |
| } |
| |
| TEST_F(TetherServiceTest, TestNoTetherHosts) { |
| fake_tether_host_fetcher_factory_->SetNoInitialDevices(); |
| CreateTetherService(false /* enable_multidevice_apis */); |
| |
| EXPECT_EQ( |
| chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, |
| network_state_handler()->GetTechnologyState( |
| chromeos::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( |
| chromeos::multidevice_setup::kInstantTetheringAllowedPrefName, false); |
| |
| CreateTetherService(false /* enable_multidevice_apis */); |
| |
| EXPECT_EQ( |
| chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_PROHIBITED, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Tether())); |
| VerifyTetherActiveStatus(false /* expected_active */); |
| |
| VerifyTetherFeatureStateRecorded( |
| TetherService::TetherFeatureState::PROHIBITED, 1 /* expected_count */); |
| } |
| |
| TEST_F(TetherServiceTest, TestBluetoothNotPresent) { |
| set_is_adapter_present(false); |
| |
| CreateTetherService(false /* enable_multidevice_apis */); |
| |
| EXPECT_EQ( |
| chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, |
| network_state_handler()->GetTechnologyState( |
| chromeos::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(false /* enable_multidevice_apis */); |
| |
| set_is_adapter_present(true); |
| SetIsBluetoothPowered(true); |
| |
| EXPECT_EQ( |
| chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, |
| network_state_handler()->GetTechnologyState( |
| chromeos::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( |
| chromeos::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( |
| chromeos::tether::TetherComponent::ShutdownReason::USER_LOGGED_OUT); |
| } |
| |
| TEST_F(TetherServiceTest, TestWifiNotPresent) { |
| RemoveWifiFromSystem(); |
| |
| CreateTetherService(false /* enable_multidevice_apis */); |
| |
| EXPECT_EQ( |
| chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Tether())); |
| |
| VerifyTetherFeatureStateRecorded( |
| TetherService::TetherFeatureState::WIFI_NOT_PRESENT, |
| 1 /* expected_count */); |
| } |
| |
| TEST_F(TetherServiceTest, TestIsBluetoothPowered) { |
| SetIsBluetoothPowered(false); |
| |
| CreateTetherService(false /* enable_multidevice_apis */); |
| |
| 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 */); |
| |
| VerifyTetherFeatureStateRecorded( |
| TetherService::TetherFeatureState::BLUETOOTH_DISABLED, |
| 2 /* expected_count */); |
| VerifyLastShutdownReason( |
| chromeos::tether::TetherComponent::ShutdownReason::BLUETOOTH_DISABLED); |
| } |
| |
| // TODO(https://crbug.com/893878): Fix disabled test. |
| TEST_F(TetherServiceTest, DISABLED_TestCellularIsUnavailable) { |
| test_manager_client()->RemoveTechnology(shill::kTypeCellular); |
| ASSERT_EQ( |
| chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_UNAVAILABLE, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Cellular())); |
| |
| CreateTetherService(false /* enable_multidevice_apis */); |
| |
| SetTetherTechnologyStateEnabled(false); |
| EXPECT_EQ( |
| chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Tether())); |
| VerifyTetherActiveStatus(false /* expected_active */); |
| VerifyLastShutdownReason( |
| chromeos::tether::TetherComponent::ShutdownReason::PREF_DISABLED); |
| |
| SetTetherTechnologyStateEnabled(true); |
| EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, |
| network_state_handler()->GetTechnologyState( |
| chromeos::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. |
| test_manager_client()->RemoveTechnology(shill::kTypeCellular); |
| test_manager_client()->AddTechnology(shill::kTypeCellular, false); |
| |
| CreateTetherService(false /* enable_multidevice_apis */); |
| |
| // 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); |
| |
| VerifyTetherFeatureStateRecorded( |
| TetherService::TetherFeatureState::CELLULAR_DISABLED, |
| 2 /* expected_count */); |
| VerifyLastShutdownReason( |
| chromeos::tether::TetherComponent::ShutdownReason::CELLULAR_DISABLED); |
| } |
| |
| // TODO(https://crbug.com/893878): Fix disabled test. |
| TEST_F(TetherServiceTest, DISABLED_TestDisabled) { |
| profile_->GetPrefs()->SetBoolean( |
| chromeos::multidevice_setup::kInstantTetheringEnabledPrefName, false); |
| |
| CreateTetherService(false /* enable_multidevice_apis */); |
| |
| EXPECT_EQ( |
| chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Tether())); |
| EXPECT_FALSE(profile_->GetPrefs()->GetBoolean( |
| chromeos::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(false /* enable_multidevice_apis */); |
| |
| 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( |
| chromeos::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( |
| chromeos::NetworkTypePattern::Tether())); |
| EXPECT_TRUE(profile_->GetPrefs()->GetBoolean( |
| chromeos::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( |
| chromeos::tether::TetherComponent::ShutdownReason::PREF_DISABLED); |
| } |
| |
| TEST_F(TetherServiceTest, TestUserPrefChangesViaFeatureStateChange) { |
| // Start with the feature disabled. |
| initial_feature_state_ = |
| chromeos::multidevice_setup::mojom::FeatureState::kDisabledByUser; |
| profile_->GetPrefs()->SetBoolean( |
| chromeos::multidevice_setup::kInstantTetheringEnabledPrefName, false); |
| CreateTetherService(true /* enable_multidevice_apis */); |
| |
| // Enable the feature. |
| profile_->GetPrefs()->SetBoolean( |
| chromeos::multidevice_setup::kInstantTetheringEnabledPrefName, true); |
| fake_multidevice_setup_client_->SetFeatureState( |
| chromeos::multidevice_setup::mojom::Feature::kInstantTethering, |
| chromeos::multidevice_setup::mojom::FeatureState::kEnabledByUser); |
| EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, |
| network_state_handler()->GetTechnologyState( |
| chromeos::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( |
| chromeos::multidevice_setup::kInstantTetheringEnabledPrefName, false); |
| fake_multidevice_setup_client_->SetFeatureState( |
| chromeos::multidevice_setup::mojom::Feature::kInstantTethering, |
| chromeos::multidevice_setup::mojom::FeatureState::kDisabledByUser); |
| EXPECT_EQ( |
| chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, |
| network_state_handler()->GetTechnologyState( |
| chromeos::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( |
| chromeos::multidevice_setup::kInstantTetheringEnabledPrefName, true); |
| fake_multidevice_setup_client_->SetFeatureState( |
| chromeos::multidevice_setup::mojom::Feature::kInstantTethering, |
| chromeos::multidevice_setup::mojom::FeatureState::kEnabledByUser); |
| EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Tether())); |
| VerifyTetherActiveStatus(true /* expected_active */); |
| VerifyTetherFeatureStateRecorded(TetherService::TetherFeatureState::ENABLED, |
| 2 /* expected_count */); |
| histogram_tester_.ExpectBucketCount( |
| "InstantTethering.UserPreference.OnToggle", true, |
| 2u /* expected_count */); |
| |
| VerifyLastShutdownReason( |
| chromeos::tether::TetherComponent::ShutdownReason::PREF_DISABLED); |
| } |
| |
| TEST_F(TetherServiceTest, TestUserPrefChangesViaTechnologyStateChange) { |
| CreateTetherService(true /* enable_multidevice_apis */); |
| |
| EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Tether())); |
| VerifyTetherActiveStatus(true /* expected_active */); |
| |
| SetTetherTechnologyStateEnabled(false); |
| fake_multidevice_setup_client_->InvokePendingSetFeatureEnabledStateCallback( |
| chromeos::multidevice_setup::mojom::Feature::kInstantTethering, |
| false /* expected_enabled */, base::nullopt /* expected_auth_token */, |
| true /* success */); |
| profile_->GetPrefs()->SetBoolean( |
| chromeos::multidevice_setup::kInstantTetheringEnabledPrefName, false); |
| fake_multidevice_setup_client_->SetFeatureState( |
| chromeos::multidevice_setup::mojom::Feature::kInstantTethering, |
| chromeos::multidevice_setup::mojom::FeatureState::kDisabledByUser); |
| EXPECT_EQ( |
| chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_AVAILABLE, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Tether())); |
| VerifyTetherActiveStatus(false /* expected_active */); |
| histogram_tester_.ExpectBucketCount( |
| "InstantTethering.UserPreference.OnToggle", false, |
| 1u /* expected_count */); |
| |
| SetTetherTechnologyStateEnabled(true); |
| fake_multidevice_setup_client_->InvokePendingSetFeatureEnabledStateCallback( |
| chromeos::multidevice_setup::mojom::Feature::kInstantTethering, |
| true /* expected_enabled */, base::nullopt /* expected_auth_token */, |
| false /* success */); |
| profile_->GetPrefs()->SetBoolean( |
| chromeos::multidevice_setup::kInstantTetheringEnabledPrefName, true); |
| fake_multidevice_setup_client_->SetFeatureState( |
| chromeos::multidevice_setup::mojom::Feature::kInstantTethering, |
| chromeos::multidevice_setup::mojom::FeatureState::kEnabledByUser); |
| EXPECT_EQ(chromeos::NetworkStateHandler::TechnologyState::TECHNOLOGY_ENABLED, |
| network_state_handler()->GetTechnologyState( |
| chromeos::NetworkTypePattern::Tether())); |
| VerifyTetherActiveStatus(true /* expected_active */); |
| histogram_tester_.ExpectBucketCount( |
| "InstantTethering.UserPreference.OnToggle", true, |
| 1u /* expected_count */); |
| |
| VerifyTetherFeatureStateRecorded(TetherService::TetherFeatureState::ENABLED, |
| 2 /* expected_count */); |
| VerifyLastShutdownReason( |
| chromeos::tether::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(false /* enable_multidevice_apis */); |
| |
| // 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( |
| chromeos::tether::TetherComponent::ShutdownReason::PREF_DISABLED); |
| } |